Eclipse 動的WebプロジェクトでAjaxを使ってみる(jQueryバージョン)

Javaフレームワークを使わない場合のAjaxの使い方の情報が少なかったので、苦労しましたが、トライしてみました。

Ajax(Asynchronous JavaScript + XML)とは?

 Ajaxは、ウェブブラウザ内で非同期通信を行いながらインターフェイスの構築を行うプログラミング手法であるXMLHttpRequestHTTP通信を行うためのJavaScript組み込みクラス)による非同期通信を利用し、通信結果に応じてダイナミックHTMLで動的にページの一部を書き換えるというアプローチを取る

Ajax - Wikipedia

 GoogleMapで利用されたことで一躍有名になったようです。非同期通信が実装できます。Ajaxは、XMLHttpRequest (XHR)が組み込みオブジェクトとして利用することで可能のようです。

同期通信と非同期通信

通常のWebサイトは同期通信が基本のようです。これは、例えば、Httpというプロトコルを使っている場合、ブラウザとサーバー間では「HttpリクエストとHttpレスポンス」のセットでやり取りが行われています。

その際、同期通信では、ブラウザからサーバー側にHttpリクエストを送り、ブラウザ側はサーバー側からHttpレスポンスが返るまで他の処理が行えないようです。

同期通信の場合

f:id:ts0818:20170824175336p:plain

非同期通信の場合

f:id:ts0818:20170824175332p:plain

非同期通信は、サーバー側に何かリクエストを送ってサーバー側で処理をしている間、ブラウザ側でも他の処理を進めていけるということが可能のようです。

『GoogleMap』が、位置座標などをサーバー側にリクエストしサーバー側が座標計算などを行っている間、ブラウザの表示も更新していけるのは、このような非同期通信の仕組みを利用しているためのようです。

⇩  『Googleサジェスト』というものにもAjaxが利用されているようです。

 

f:id:ts0818:20170824180457j:plain

 

ゼロから始めるJavaScript講座Vol23 Ajaxとは | Tech2GO

同一生成元ポリシー(Same Origin Policy)

「スキーム、ホスト、ポート」の組み合わせをオリジンと定め、それらが同じものは同一のオリジンとして同じ保護範囲のリソースとして取り扱うということらしいです。

Same-Origin Policy とは何なのか。 - 葉っぱ日記

  • スキーム(プロトコル)が一致している。
  • ホスト(FQDN; Fully Qualified Domain Name)が一致している。
  • ポート番号が一致している。

同一生成元(同一オリジン)ポリシー - Qiita

クロスオリジン

2つのオリジンが同一でない場合、すなわち異なるオリジンを「クロスオリジン」と言います。クロスオリジンでのリソースでアクセスする方法については、Cross-Origin Resource Sharing(CORS)がルールとして定められています。

セキュリティ上の理由からブラウザは、スクリプトによって開始されるクロスオリジン HTTP リクエストを制限します。

要するに、なんかスクリプトJavaScriptのようなもの)を使って他のURLとの通信(例えば、「http://hoge.com」から「http://fuga.com」のような異なるサイト間)は原則NGだよってことですかね。

jQueryAjaxで、クロスドメインAjaxのための準備

今回、jspJavaAjaxを行ったのですが、もし、他のサイトととの通信を行うことが出てくることを考慮し、クロスオリジンでのAjax(クロスドメインAjaxという?)を実装してみたいと思います。

jQueryを使う場合は、jQuery本体の読み込みが必要です。

  • CDNを利用する
  • ファイルをインストール

の2つの方法があります。

CDNの場合は、Googleなどのサーバーにアップされているものを利用することができますが、インターネットにつながっていないと利用できません。

ファイルをインストールする場合は、インターネットにつながっていなくても利用はできますが、どちらにせよ、公開されているサイト同士で通信するにはインターネットにつながっている必要があります。

今回は、jQueryをインストールして利用したいと思います。

jQuery 3系のインストール

2017年8月24日(木)現在、jQueryのバージョンは3系まで出てるようです。jQueryは大規模な開発には向いていないので使うことがためらわれますが、 今回は、jQueryをインストールして利用します。

https://jquery.com/ にアクセスします。『Download jQuery』をクリック。

f:id:ts0818:20170824192931j:plain

『Download the uncompressed, development jQuery 3.2.1』をクリックでインストールされます。

f:id:ts0818:20170824192927j:plain

 

Eclipseで動的Webプロジェクト

Eclipse で、「パースペクティブ」が「Java EE」になっているのを確認し、「ファイル(N)」>「新規(N)」>「動的 Web プロジェクト」を選択。

f:id:ts0818:20170824195055j:plain

「プロジェクト名(M):」を入力し、「次へ(N)>」をクリック。

f:id:ts0818:20170824195050j:plain

「次へ(N)>」をクリック。

f:id:ts0818:20170824195046j:plain

web.xmlを使う場合は、「web.xml デプロイメント記述子の生成(G)」にチェックを入れますが、今回はチェックなし。

f:id:ts0818:20170824195042j:plain

プロジェクトができました。

f:id:ts0818:20170824195038j:plain

 

WebContentフォルダの中にフォルダを作りインストールしたjQueryを配置

「プロジェクト・エクスプローラー」で作成されたプロジェクトの中の「WebContent」を選択し右クリックし、「新規(N)」>「フォルダ」を選択。

f:id:ts0818:20170824200512j:plain

「フォルダー名(N):」を入力し、「完了(F)」。

f:id:ts0818:20170824200507j:plain

作成されたフォルダにインストールしておいたjQueryのファイルを配置します。ドラッグ&ドロップで、作成したフォルダにインストールしておいたjQueryファイルを配置。

f:id:ts0818:20170824201101j:plain

 配置できました。 

f:id:ts0818:20170824201056j:plain

Ajaxの処理を記述する用のjsファイルを作成しておきます。作成したフォルダを選択した状態で右クリックし、「新規(N)」>「ファイル」を選択。

f:id:ts0818:20170824201539j:plain

「ファイル名(M):」を入力し(拡張子は「js」にします。)、「完了(F)」をクリック。

f:id:ts0818:20170824201536j:plain

jsファイルが準備できました。

f:id:ts0818:20170824202115j:plain

 

jspファイルとServletファイルの準備

続いて、jspファイルとServletファイルを用意します。 まずはjspファイルから。今回はフォルダにjspファイルを入れるようにしてます。「WebContent」を選択した状態で右クリックし、「新規(N)」>「フォルダー」を選択。

f:id:ts0818:20170824202938j:plain

「フォルダ名(N):」を入力し、「完了(F)」をクリック。

f:id:ts0818:20170824202933j:plain

続いてjspファイルを作成。

f:id:ts0818:20170824202930j:plain

「ファイル名(M):」を入力し、「次へ(N)」をクリック。

f:id:ts0818:20170824202923j:plain

「完了(F)」をクリック。

f:id:ts0818:20170824202918j:plain

次に、Servletファイルを作成します。「Javaリソース」>「src」を選択した状態で右クリックし、「新規(N)」>「サーブレット」を選択。

f:id:ts0818:20170824204157j:plain

Java パッケージ(K):」、「クラス名(M):」を入力し、「次へ(N)>」をクリック。

f:id:ts0818:20170824204153j:plain

「次へ(N)>」をクリック。

f:id:ts0818:20170824204148j:plain

「完了(F)」をクリック。

f:id:ts0818:20170824204142j:plain

ファイルが準備できました。

f:id:ts0818:20170824204138j:plain

「src」フォルダを選択した状態で、「新規(N)」>「クラス」を選択で、

f:id:ts0818:20170824234950j:plain

「パッケージ(K):」、「名前(M):」を入力し、「インターフェイス(I):」を「追加(A)...」。

f:id:ts0818:20170824235003j:plain

「Serializable - java.io」を選択し、「OK」をクリック。「一致する項目(M):」に表示されてない場合は、「インターフェイスを選択してください(C):」で「Seriali」とかまで入力すれば表示されると思います。

f:id:ts0818:20170824234959j:plain

追加されたのを確認し、「完了(F)」をクリック。

f:id:ts0818:20170824234955j:plain

続いて、DAOクラスを作成。

f:id:ts0818:20170824235008j:plain

「パッケージ(K):」、「名前(M):」を入力し、「完了(F)」。

f:id:ts0818:20170824235100j:plain

DAOパッケージにはもう一つクラス(データベース接続)を追加します。

それと、「feature」というパッケージに、Pager.javaとSafePassword.javaを作成しておきます。後でファイルを編集していきます。

 

「プロジェクト・エクスプローラー」にこんな感じで追加されていればひとまずOK。

f:id:ts0818:20170825173710j:plain

並びがおかしくなったときは、f:id:ts0818:20170805222455j:plainをクリックし、「プロジェクト表示(R)」>「フラット」か「階層」どちらかをクリック。

f:id:ts0818:20170825000213j:plain

 

Gsonなどの外部jarファイルの追加

今回、jsonを使っていく際に、Java SE標準のライブラリでも利用は可能らしいのですが、Gsonという外部ライブラリを利用することにします。

他にもMySQLと、jstlを利用したいので、「WebContent」>「WEB-INF」>「lib」 にそれらのjarファイルも配置します。

Java用のJSONライブラリには

  • Gson
  • Genson
  • Jackson

などいろいろな外部ライブラリがあるようです。

Gsonをインストールします。https://github.com/google/gson にアクセスします。

f:id:ts0818:20170824232808j:plain

下の方にスクロールします。「Gson Download and Maven」というところの「Gson Download」のリンクをクリックします。

f:id:ts0818:20170824232759j:plain

真ん中あたりの「com.google.code.gson : gson : 2.8.1」というリンクをクリック。

f:id:ts0818:20170824232755j:plain

「gson-2.8.1.jar」をクリックするとインストールされます。

f:id:ts0818:20170824232752j:plain

jstlのインストールについては、こちらを参考。

Java Eclipseで動的 Webプロジェクト ユーザー検索 JSTLも導入してます

MySQLのドライバーは、MySQLをインストールする際に一緒にインストールしていれば、『C:¥Program Files (x86MySQL¥Connector.J 5.1¥mysql-connector-java-5.1.41-bin.jar』にあると思われます。

それでは、jarファイルを配置。

f:id:ts0818:20170824234043j:plain

 

MySQLにデータベースとテーブルを用意

今回は、前回作成していたdaiaryデータベースのpostテーブルを利用します。

⇩  こちらを参考ください 

Windows 10 HomeにてMySQLのテーブルにcsvファイルでデータをインポート

ファイルの編集

ajaxtest.js

$(function() {
	$('.ajax-button a').on('click', function(event){
	  var url = "http://localhost:8080/AjaxTest/AjaxTestServlet?ACTION=";
	  var action = $(this).data('action');
	  var page = $(this).data('page');
	  var data = {page: page};
	  url += action;
	  // aリンクによる遷移をキャンセル
	  event.preventDefault();
	  // ajaxスタート
	  ajaxTest(url, data)
	    .done(function(result) {
	      console.log("ajax success!");
	      console.log(result);
	      // 取得した記事に書き換え
	      for(var index = 0; index < result.length; index++) {
	    	 $('.date').eq(index).html(result[index].postDate);
	    	 $('.title').eq(index).html(result[index].postTitle);
	    	 $('.content').eq(index).html(result[index].postContent);
	      }
	    })
	    .fail(function(XHLHttpRequest, testStatus, errorThrown) {
          console.log("ajax失敗!");
	    });
	});


	// ajax用
	function ajaxTest(url, data) {
	  return $.ajax({
		url: url,
		dataType: "jsonp",
		type: "POST",
		data: data,
		xhrFields: {
		  withCredentials: true
		},
		beforeSend: function(xhr) {
		  xhr.setRequestHeader('X-CSRF-Token', $('meta[name=csrf-token]').attr('content'));
		  xhr.withCredentials = true;
		}
	  });
	}
});

ajaxTest.jsp

<%@page import="feature.SafePassword"%>
<%@page import="java.security.NoSuchAlgorithmException"%>
<%@page import="java.security.SecureRandom"%>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%
SecureRandom secRandom = null;
byte bytes[] = new byte[16];
try {
  secRandom = SecureRandom.getInstance("SHA1PRNG");
  secRandom.nextBytes(bytes);
} catch(NoSuchAlgorithmException e) {

}
String secure = String.valueOf(secRandom.nextDouble());
String csrf_token = SafePassword.getStretchedPassword(secure + secure, secure);

%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="csrf-token" content="<%= csrf_token %>">
<title>Ajax Test</title>
<script src="./js/jquery-3.2.1.js"></script>
<script src="./js/ajaxtest.js"></script>
</head>
<body>

  <div id="content">
	  <div class="ajax">
      <div class="posts">
      <c:forEach var="post" items="${posts}">
        <div class="post">
          <div class="post-head">
            <div class="date">${post.postDate}</div>
            <div class="title">${post.postTitle}</div>
          </div><!-- .post-head -->
          <div class="post-body">
            <div class="content">${post.postContent}</div>
          </div><!-- .post-body -->
        </div><!-- .post -->
        </c:forEach>
      </div><!-- .posts -->
	  </div>
	  <div class="ajax-button">
	    <c:forEach var="page" begin="1" end="${pager}" step="1">
	    <a href="AjaxTest/AjaxTestServlet" data-action="pager" data-page="${page}"><c:out value="${page}"></c:out></a>
	    </c:forEach>
	  </div>
  </div><!-- #content -->
</body>
</html>

Post.java

package model;

import java.io.Serializable;
import java.sql.Date;

public class Post implements Serializable {

	/**
	 * フィールド
	 */
	private int postId;
	private String postTitle;
	private String postDescription;
	private String postContent;
	private Date postDate;

	public Post() {}

	public Post(int postId, String postTitle, String postDescription, String postContent, Date postDate) {
		this.postId = postId;
		this.postTitle = postTitle;
		this.postDescription = postDescription;
		this.postContent = postContent;
		this.postDate = postDate;
	}

	public int getPostId() {
		return postId;
	}

	public void setPostId(int postId) {
		this.postId = postId;
	}

	public String getPostTitle() {
		return postTitle;
	}

	public void setPostTitle(String postTitle) {
		this.postTitle = postTitle;
	}

	public String getPostDescription() {
		return postDescription;
	}

	public void setPostDescription(String postDescription) {
		this.postDescription = postDescription;
	}

	public String getPostContent() {
		return postContent;
	}

	public void setPostContent(String postContent) {
		this.postContent = postContent;
	}

	public Date getPostDate() {
		return postDate;
	}

	public void setPostDate(Date postDate) {
		this.postDate = postDate;
	}

}

PostDAO.java

package dao;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

import model.Post;

public class PostDAO {

	/**
	 * 全件の記事数取得
	 * @return List posts
	 */
	public int selectAllPost() {

		ConnectionManager cm = ConnectionManager.getInstance();
		String sql = "SELECT COUNT(*) FROM post";
		int count = 0;
		try(Connection conn = cm.getConnection();
				Statement stmt = conn.createStatement()) {

			ResultSet res = stmt.executeQuery(sql);
      if(res.next()) {
      	count = res.getInt(1);
      }
		} catch(Exception e) {
			System.out.println("PostDAO.javaの[selectAllPost()]でエラー" + e);
		}
		return count;
	}

	/**
	 * 1ページ分の記事取得
	 */
	public List selectPost(int perPage, int pageNumber) {
		ConnectionManager cm = ConnectionManager.getInstance();
		String sql = "SELECT * FROM post LIMIT ? OFFSET ?";
		List posts = new ArrayList();
		Post post = null;
		try(Connection conn = cm.getConnection();
				PreparedStatement pstmt = conn.prepareStatement(sql)) {
			pstmt.setInt(1, perPage);
			pstmt.setInt(2, pageNumber);

			ResultSet res = pstmt.executeQuery();

			while(res.next()) {
				post = new Post(
				  res.getInt("post_id"),
				  res.getString("post_title"),
				  res.getString("post_description"),
				  res.getString("post_content"),
				  res.getDate("post_date")
				);
				posts.add(post);
			}

		} catch(Exception e) {
			System.out.println("PostDAO.javaの[selectPost()]でエラー" + e);
		}
		return posts;
	}
}

ConnectionManager.java

package dao;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public class ConnectionManager {

	/**
	 * フィールド変数
	 */
	// データベース接続情報
	public final static String URL      = "jdbc:mysql://localhost:3306/diary?useSSL=false";
	public final static String USER     = "owner";
	public final static String PASSWORD = "owner1";

	// コネクションオブジェクト
	private Connection connection = null;

	// このクラスに唯一のインスタンス
	private static ConnectionManager instance = new ConnectionManager();

	/**
	 * static初期化子
	 */
	static {
		// JDBCドライバのロード
		String drv = "com.mysql.jdbc.Driver";
		try {
			Class.forName(drv);
		} catch(ClassNotFoundException e) {
			System.out.println("ドライバがありません" + e.getMessage());
		}
	}

	/**
	 * コンストラクタ
	 */
	private ConnectionManager() { }

	/**
	 * インスタンス取得メソッド
	 */
	public static ConnectionManager getInstance() {
		return instance;
	}

	/**
	 * DB接続
	 */
	public synchronized Connection getConnection() {
		// コネクションの確立
		try {
			connection = DriverManager.getConnection(URL, USER, PASSWORD);
		} catch(SQLException e) {
			connection = null;
			System.out.println("ConnectionManager.javaの[getConnection()]でエラー " + e);
		}
		return connection;
	}

	/**
	 * データベースの切断
	 */
	public void closeConnection() {
		try {
			if(connection != null) {
				connection.close();
			}
		} catch(SQLException e) {
			System.out.println("ConnectionManager.javaの[closeConnection()]でエラー " + e);
		} finally {
			connection = null;
		}
	}
}

AjaxTestServlet.java

package servlet;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

import dao.PostDAO;
import feature.Pager;
import model.Post;

/**
 * Servlet implementation class AjaxTestServlet
 */
@WebServlet("/AjaxTestServlet")
public class AjaxTestServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	PostDAO postDao = new PostDAO();
	Pager pager = new Pager();
    /**
     * @see HttpServlet#HttpServlet()
     */
    public AjaxTestServlet() {
        super();
        // TODO Auto-generated constructor stub
    }

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		//
		String action = request.getParameter("ACTION");
		String url = null;
		List posts = null;
		HttpSession session = request.getSession();
		int maxPageCount = postDao.selectAllPost();
		int perPage = 10;
    pager.initPagination(maxPageCount, perPage);

		// 初期画面表示
		if(action == null) {
			posts = postDao.selectPost(perPage, perPage * (pager.getCurrent() -1));
			session.setAttribute("posts", posts);
			session.setAttribute("pager", maxPageCount / perPage);
			session.setAttribute("currentPage", pager.getCurrent());
			url = "jsp/ajaxTest.jsp";
			System.out.println(posts);
		}

		RequestDispatcher dispatcher = request.getRequestDispatcher(url);
		dispatcher.forward(request, response);
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		//
		response.setContentType("text/javascript; charset=utf-8");
		// 「credentials flag」を有効にした場合、「Access-Control-Allow-Origin」ヘッダーにはワイルドカード「*」は使用できない。
		response.setHeader("Access-Control-Allow-Origin", "http://127.0.0.1:8080");
		// 「credentials flag」を有効
		response.addHeader("Access-Control-Allow-Credentials", "true");
		// 許可するメソッド
    response.addHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE, HEAD");
    response.addHeader("Access-Control-Allow-Headers", "X-PINGOTHER, Origin, X-Requested-With, Content-Type, Accept");

    String action = request.getParameter("ACTION");
    int page      = 0;
    HttpSession session = request.getSession();
    List posts = (List)session.getAttribute("posts");
    String callback = request.getParameter("callback");

    if(action == null) {

    } else {
      // Gson json = new Gson();
    	// Date型メンバの日付のフォーマットを指定できる
      Gson json = new GsonBuilder().setDateFormat("yyyy-MM-dd").create();
      PrintWriter out = response.getWriter();

      if(action.equals("pager")) {
        // 今現在選択されたページ番号
        if(request.getParameter("page") != null) {
        	page = Integer.parseInt(request.getParameter("page"));
        }
        System.out.println(page);
        posts = postDao.selectPost(pager.getPerPage(), (pager.getPerPage() * (page -1)));
        session.setAttribute("posts", posts);
        out.println(callback + "(" + json.toJson(posts) + ")");
      }
    }
	}
}

Pager.java

package feature;

import java.io.Serializable;

public class Pager implements Serializable {

	/**
	 *
	 */
	private int allData;  // データ全件
	private int perPage;  // ページ当たりの表示件数
	private int maxPage;  // 総ページ数
	private int current;  // 現在のページ

	/**
	 * すべてのフィールドの初期化
	 * @param allData  データの総件数
	 * @param perPage  1ページ当たりの表示件数
	 */
	public void initPagination(int allData, int perPage) {
		this.allData = allData;
		this.perPage = perPage;
		this.maxPage = allData / perPage + (allData % perPage == 0 ? 0 : 1);
		this.current = 1;
	}

	/**
	 * 表示するデータの先頭位置
	 * @return データの位置を示すint型の値
	 */
	public int findTopData() {
		return (current -1) * perPage;
	}

	/**
	 * 次ページを表示
	 */
	public void moveNext() {
		if(maxPage > current) {
			++current;
		}
	}

	/**
	 * 前ページを表示
	 */
	public void movePrev() {
		if(current > 1) {
			--current;
		}
	}

	/**
	 * 末尾のページを表示
	 */
	public void moveLast() {
		current = maxPage;
	}

	/**
	 * 先頭のページを表示
	 */
	public void moveTop() {
		current = 1;
	}

	/**
	 * 表示するデータの範囲を返す
	 */
	public int[] procRange() {
		int[] n = new int[2];
		n[0] = findTopData();
		n[1] = n[0] + perPage -1;
		return n;
	}

	/**
	 * DBなどから取得した総件数を取得
	 * @return
	 */
	public int getAllData() {
		return allData;
	}

	/**
	 * 1ページ当たりの表示件数の取得
	 * @return
	 */
	public int getPerPage() {
		return perPage;
	}

	/**
	 * 最大ページ数を取得
	 * @return
	 */
	public int getMaxPage() {
		return maxPage;
	}

	/**
	 * 今現在のページを取得
	 * @return
	 */
	public int getCurrent() {
		return current;
	}

}

SafePassword.java

package feature;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class SafePassword {

  private static int STRETCH_COUNT = 1000;

  /**
   * salt + ハッシュ化したパスワード
   */
  public static String getSalttedPassword(String password, String userId) {
    String salt = getSha256(userId);
    return getSha256(salt + userId);
  }

  /**
   * salt + ストレッチングしたパスワード
   */
  public static String getStretchedPassword(String password, String userId) {
	String salt = getSha256(userId);
	String hash = "";

	for(int i = 0; i < STRETCH_COUNT; i++) {
	  hash = getSha256(hash + salt + password);
	}
    return hash;
  }

  /**
   * 文字列から、SHA256のハッシュ値を取得
   */
  private static String getSha256(String target) {
	MessageDigest md = null;
	StringBuffer buf = new StringBuffer();
	String algorithm = "SHA-256";

	try {
		md = MessageDigest.getInstance(algorithm);
		md.update(target.getBytes());
		byte[] digest = md.digest();

		for(int i = 0; i < digest.length; i++) {
	      buf.append(String.format("%02x", digest[i]));
		}

	} catch(NoSuchAlgorithmException e) {

	}

    return buf.toString();
  }

}

サーバー起動で確認してみます。「プロジェクト・エクスプローラー」の「servlet」>「AjaxTestServlet.java」を選択した状態で右クリックし、「実行(R)」>「サーバーで実行」を選択。

f:id:ts0818:20170825194411j:plain

http://localhost:8080/AjaxTest/AjaxTestServlet」にアクセスすると表示されました。

f:id:ts0818:20170825193607j:plain

動的なページングにはなっていませんが、ページングを実装できました。

セッションを有効にしつつAjaxするには、Servlet側で、responseのHeaderにいろいろ追加するのと、HTML部分のmetaタグで、「csrf-token」を追加しておく必要があるようです。あとは、$.ajaxの中で、「csrf-token」を利用するような記述も必要になるようです。

それにしても、Javaはページングの実装参考が全然見当たらないので改良するのが厳しそうですね。MySQL のOFFSETを使う方法も宜しくないようです。

課題は山積みですね...。

 

Gson - 覚えたら書く