Fight the Future

Java言語とJVM、そしてJavaエコシステム全般にまつわること

Servlet(Spring MVC) + JSP + jQueryでTwitterライクなmoreボタンを実装する

ひとまず初期表示する。

DAOでは10件など固定の件数を取得する。

このサンプルでは、IDの順番に表示していく。

	@RequestMapping(method = { RequestMethod.GET })
	public ModelAndView index(@RequestParam(defaultValue = "0") Long Id) {

		// limit 10などのSQLを使って10件だけ取得する
		List<Dto> dtoList = this.service.list(Id);

		ModelAndView view = new ModelAndView();
		view.addObject("list", dtoList);
		view.setViewName("index");

		return view;
	}

moreボタンを押したらローディング画像を表示する。

リクエストパラメータで最後のIDを送り、

サーバーサイドのDAOではそのID以降の10件を取得するイメージ。

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions"%>
<c:set value="<%= request.getContextPath() %>" var="contextRoot"></c:set>
<link href="${contextRoot}/css/style.css" rel="stylesheet"
	type="text/css" media="all">
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<script src="http://www.google.com/jsapi"></script>
<script>
	google.load("jquery", "1.4.2");
</script>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<script type="text/javascript">
$( function() {
	$("#more").click(
		function() {
			$("#moreButton").html('<img src="${contextRoot}/images/roller.gif" />');
			$.ajax({
				type: "GET",
				url: "more.html",
				data: {"id": $("#lastid").val()},
				cache: false,
				success: function(html) {
					$("#lastId").remove();
					$("#moreButton").remove();
					$("#list").append(html);
				}
			});			
		}
	);
});
</script>
</head>

<body>
<div id="list"><c:forEach items="${list}" var="hoge"
	varStatus="status">
	${hoge.name}
	<c:if test="${status.last}">
		<c:set var="lastId" value="${hoge.id}"></c:set>
	</c:if>

</c:forEach>
<input id="lastId" type="hidden" value="${lastId}">
<div id="moreButton"><a id="more" href="javascript:void( 0 )"></a></div>
</div>
</body>
</html>

サーバーからは部分的なHTMLを返し、子要素としてappendする。これで動的に画面下部にリストを追加できる。

新しいlastIdとmoreボタンも一緒に返すので、Ajaxリクエストが成功すれば古いものをremoveしておく。

さらにmoreボタンを押す。

	@RequestMapping(method = RequestMethod.GET)
	public ModelAndView more(Long id) {
		
		List<Dto> dtoList = this.service.list(id);
		
		ModelAndView view = new ModelAndView();
		view.setViewName("partial");
		view.addObject("list", dtoList);
		return view;
	}

現在表示している最後のIDがlastIdとして送られてくる。

それを使って次の10件を取得し、部分HTMLを返す。

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>

<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions"%>
<c:set value="<%= request.getContextPath() %>" var="contextRoot"></c:set>

<script type="text/javascript">
$( function() {
	$("#more").click(
		function() {
			$("#moreButton").html('<img src="${contextRoot}/images/roller.gif" />');
			$.ajax({
				type: "GET",
				url: "more.html",
				data: {"id": $("#lastId").val()},
				cache: false,
				success: function(html) {
					$("#lastId").remove();
					$("#moreButton").remove();
					$("#list").append(html);
				}
			});			
		}
	);
});
</script>

<c:forEach items="${list}" var="hoge" varStatus="status">
	${hoge.name}
	<c:if test="${status.last}">
		<c:set var="lastId" value="${hoge.id}"></c:set>
	</c:if>

</c:forEach>

<c:if test="${not empty list}">
	<input id="lastId" type="hidden" value="${lastId}">
	<div id="moreButton"><a id="more" href="javascript:void( 0 )"></a></div>
</c:if>

初期表示の部分抜粋にすぎないが、とすることで、

Ajaxリクエストの結果が1件も取得できなければ、もうmoreボタンを表示しないようにできる。