第08课:首页展示及分页(PageHelper)
在正式实现首页和分页功能之前,我们首先思考两个问题:
1.index.jsp 页面动态数据怎么获取? 2.如果用 AJAX 获取,点击下一页的时候又要怎么办?
前期准备
引入 index.jsp 文件,将原 index.jsp 文件替换。
启动 Tomcat 后访问,效果如下:
因为页面都是死数据,无法完成分页功能,所以先导入文章的数据 SQL,SQL 文件会放入文末的百度网盘链接中。
说明: 因为 user_content
表存在外键关系,所以要先解除外键约束,否则无法删除和修改表:
SET FOREIGN_KEY_CHECKS=0 ;
等插入数据之后,再设置外键约束:
SET FOREIGN_KEY_CHECKS=1 ;
导入 SQL 文件和之前一样,如图:
再将 image 文件夹拷贝到 dreamland\dreamland-web\target\dreamland-web\images\
目录下,主要是网页用到的网页图片,image 文件夹也在文末的百度网盘链接中。
index 页面
右上角的登录、注册
index.jsp 页面逻辑判断代码,如下所示:
< div style= "position: absolute;margin-left: 980px;margin-top: -40px;" >
< c: if test= "${empty user}" >
< a name= "tj_login" class = "lb" href= "login?error=login" style= "color: black" > [ 登录] < / a>
& nbsp; & nbsp;
< a name= "tj_login" class = "lb" href= "register" style= "color: black" > [ 注册] < / a>
< / c: if >
< c: if test= "${not empty user}" >
< a name= "tj_loginp" href= "void(0);" class = "lb" onclick= "personal('${user.id}');" style= "color: black" > < font color= "#9370db" > ${ user. nickName} , 欢迎您!< / font> < / a>
& nbsp; & nbsp;
< a name= "tj_login" class = "lb" href= "${ctx}/loginout" style= "color: black" > [ 退出] < / a>
< / c: if >
< / div>
通过 EL 表达式判断:
如果用户为空,则显示“登录”、“注册”; 如果不为空,则显示“xxx,欢迎您!”和“退出”。
引入天气预报
只需将最底下的 div,如下:
< div class = "col-md-3" style = "background-color: #C6E2FF;position:absolute;top:0px;left: 873px;width: 268px" >
< h2 > Sidebar</ h2 >
< ul class = "nav nav-tabs nav-stacked" >
< li > < a href = '#' > Another Link 1</ a > </ li >
< li > < a href = '#' > Another Link 2</ a > </ li >
< li > < a href = '#' > Another Link 3</ a > </ li >
</ ul >
</ div >
替换成下面的代码,即可:
< div class = "col-md-3" style = "position:absolute;top:0px;left: 880px;width: 268px;" >
< div style = "background-color: white;width: 250px;height: 440px" >
< iframe name = "weather_inc" src = "http://i.tianqi.com/index.php?c=code&id=82" width = "250" height = "440" frameborder = "0" marginwidth = "0" marginheight = "0" scrolling = "no" > </ iframe >
</ div >
</ div >
这个只是简单的引用,且必须联网才能使用。效果如下:
关于 index 页面的数据获取
首先,通过 AJAX 请求获取数据,JavaScript 代码大概是这样的(看看就好,不建议):
< script language= javascript>
$. ajax ( {
type: "post" ,
dataType: "json" ,
url: '${ctx}/index' ,
success: function ( data) {
var Data= data;
var content = null ;
var page = null ;
for ( var key in Data) {
if ( key == "page" ) {
page = Data[ key] ;
}
if ( key == "content" ) {
content = Data[ key] ;
}
}
if ( data!= null && data != "" ) {
$ ( content) . each ( function ( ) {
var ll = this . title;
$ ( "#content_col" ) . append ( "<div class='content-text' ><div class='author clearfix'><div>"
+ "<a href='#' target='_blank' rel='nofollow' style='height: 35px' οnclick=''>"
+ "<img src='" + this . imgUrl+ "'></a></div><a href='' target='_blank' οnclick=''>"
+ "<h2 class='author-h2'>" + this . nickName+ "</h2></a></div>"
+ "<h2>" + this . title+ "</h2>" + this . content+
"<div style='height: 5px'></div><div class='stats'><span class='stats-vote'><i class='number'>" + this . upvote+ "</i> 赞</span>"
+ "<span class='stats-comments'><span class='dash'> · </span>"
+ "<a href='#' class='comments' target='_blank' οnclick=''>"
+ "<i class='number'>" + this . commentNum+ "</i> 评论 </a></span> </div><div style='height: 5px'></div>"
+ "<div class='stats-buttons bar clearfix'><a><i class='icon icon-thumbs-o-up icon-2x'></i><span class='number hidden'>" + this . upvote+ "</span></a>"
+ " <a><i class='icon icon-thumbs-o-down icon-2x'></i><span class='number hidden'>" + this . downvote+ "</span></a> <a><i class='icon icon-comment-alt icon-2x'></i></a>"
+ "</div><div class='single-share'><a class='share-wechat' data-type='wechat' title='分享到微信' rel='nofollow' style='margin-left:18px;color: grey'>"
+ "<i class='icon icon-wechat icon-2x'></i></a><a class='share-qq' data-type='qq' title='分享到QQ' rel='nofollow' style='margin-left:18px;color: grey'>"
+ "<i class='icon icon-qq icon-2x'></i> </a><a class='share-weibo' data-type='weibo' title='分享到微博' rel='nofollow' style='margin-left:18px;color: grey'>"
+ "<i class='icon icon-weibo icon-2x'></i></a></div><br/> <div class='single-clear'></div></div>"
+ "<div style='position: absolute;width:900px;background-color: #EBEBEB;height: 10px;left: 0px'></div>"
) ;
} ) ;
var cnt = "<ul class='pager pager-loose'>" ;
if ( page. pageNum <= 1 ) {
cnt += "<li><a href='void(0);'>« 上一页</a></li>" ;
} else {
var pNum = page. pageNum- 1 ;
cnt += "<li class='previous'><a href='${ctx}/index_list?pageNum=" + pNum+ "&&id=${user.id}'>« 上一页</a></li>" ;
}
for ( var i= 1 ; i<= page. pages; i++ ) {
if ( page. pageNum == i) {
cnt += "<li class='active'><a href='void(0);'>" + i+ "</a></li>" ;
} else {
cnt += "<li ><a href='${ctx}/index_list?pageNum=" + i+ "&&id=${user.id}'>" + i+ "</a></li>" ;
}
}
if ( page. pageNum >= page. pages) {
cnt += "<li><a href='void(0);'>下一页 »</a></li>" ;
} else {
var pNum = page. pageNum+ 1 ;
cnt += "<li><a href='${ctx}/index_list?pageNum=" + pNum+ "&&id=${user.id}'>下一页 »</a></li></ul>" ;
}
$ ( "#page-info" ) . append ( cnt) ;
}
}
} ) ;
< / script>
主要是通过 AJAX 获取数据后再添加到 div 中,这样只是解决了 index 页面的首次正常访问,有动态数据,但当点击下一页的时候就会产生新问题。这时可以新建一个和 index.jsp 一样的页面 index2.jsp,只不过这次不是用 AJAX 从后台获取数据,而是通过点击下一页或者其他页码,先经过 Controller,将分页数据封装后返回到 index2.jsp。这样做费时费力还耗资源,所以也不可取。
推荐的解决办法是:在进入 index.jsp 之前进行过滤器拦截,先获取页面数据,之后再返回 index.jsp 页面。
实现步骤如下:
(1)在 web.xml 中,引入自定义过滤器 filter:
< filter >
< filter-name > dispatcherDemoFilter</ filter-name >
< filter-class > wang.dreamland.www.interceptor.IndexJspFilter</ filter-class >
</ filter >
< filter-mapping >
< filter-name > dispatcherDemoFilter</ filter-name >
< url-pattern > /index.jsp</ url-pattern >
</ filter-mapping >
在访问 index.jsp 之前进入自定义过滤器 dispatcherDemoFilter,通过该名字找到自定义过滤器具体路径 wang.dreamland.www.interceptor.IndexJspFilter
。
(2)在 wang.dreamland.www 下新建包 interceptor,在 interceptor 包下新建 IndexJspFilter.java:
public class IndexJspFilter implements Filter {
public void init ( FilterConfig filterConfig) throws ServletException {
}
public void doFilter ( ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System. out. println ( "===========自定义过滤器==========" ) ;
ServletContext context = request. getServletContext ( ) ;
ApplicationContext ctx = WebApplicationContextUtils. getWebApplicationContext ( context) ;
UserContentMapper userContentMapper = ctx. getBean ( UserContentMapper. class ) ;
PageHelper. startPage ( null, null) ;
List< UserContent> list = userContentMapper. select ( null ) ;
PageHelper. Page endPage = PageHelper. endPage ( ) ;
request. setAttribute ( "page" , endPage ) ;
chain. doFilter ( request, response) ;
}
public void destroy ( ) {
}
}
代码解读如下:
filter 初始化时,注解的 bean 还没初始化,加 @Autowired
注解不会起作用,所以通过 ApplicationContext 手动获取 UserContentMapper 对象。
UserContentMapper userContentMapper = ctx.getBean(UserContentMapper.class );
在开始分页和结束分页之间查询数据,PageHelper 会对分页开始之后的第一个查询语句进行分页,封装在 Page 对象中。
PageHelper.startPage(null , null );
List <UserContent> list = userContentMapper.select( null );
PageHelper.Page endPage = PageHelper.endPage();
pageNum 如果为 Null 则默认为第一页,pageSize 为 null 则默认每页显示7条数据,在 PageHelper 中有设默认值:
public Page ( Integer pageNum, Integer pageSize ) {
if (pageNum == null || pageNum < 1 ) {
pageNum = 1 ;
}
if (pageSize == null || pageSize < 1 ) {
pageSize = 7 ;
}
this .pageNum = pageNum;
this .pageSize = pageSize;
}
然后将 Page 对象放在 request 域中,前台可通过 EL 表达式 ${page}
获取:
request .setAttribute("page" , endPage );
(3)index.jsp 页面获取数据的代码如下:
< c: forEach var = "cont" items= "${page.result}" varStatus= "i" >
< ! -- 正文开始 -- >
< div class = "content-text" >
< div class = "author clearfix" >
< div>
< a href= "#" target= "_blank" rel= "nofollow" style= "height: 35px" >
< img src= "${cont.imgUrl}" >
< / a>
< / div>
< a href= "#" target= "_blank" >
< h2 class = "author-h2" >
${ cont. nickName}
< / h2>
< / a>
< / div>
< h2> ${ cont. title} < / h2>
${ cont. content}
< div style= "height: 5px" > < / div>
< div class = "stats" >
< ! -- 笑脸、评论数等 -- >
< span class = "stats-vote" > < i id= "${cont.id}" class = "number" > ${ cont. upvote} < / i> 赞< / span>
< span class = "stats-comments" >
< span class = "dash" > · < / span>
< a onclick= "reply(${cont.id},${cont.uId});" >
< i class = "number" id= "comment_num_${cont.id}" > ${ cont. commentNum} < / i> 评论
< / a>
< / span>
< / div>
< div style= "height: 5px" > < / div>
< div class = "stats-buttons bar clearfix" >
< a style= "cursor: pointer;" onclick= "upvote_click(${cont.id},1);" >
< i class = "icon icon-thumbs-o-up icon-2x" > < / i>
< span class = "number hidden" id= "up_${cont.id}" > ${ cont. upvote} < / span>
< / a>
& nbsp;
< a style= "cursor: pointer;" onclick= "upvote_click(${cont.id},-1);" >
< i class = "icon icon-thumbs-o-down icon-2x" > < / i>
< span class = "number hidden" id= "down_${cont.id}" > ${ cont. downvote} < / span>
< / a>
& nbsp;
< a style= "cursor: pointer;" onclick= "reply(${cont.id},${cont.uId});" title= "点击打开或关闭" >
< i class = "icon icon-comment-alt icon-2x" > < / i>
< / a>
< / div>
< div class = "single-share" >
< a class = "share-wechat" data- type= "wechat" title= "分享到微信" rel= "nofollow" style= "margin-left:18px;color: grey;cursor: pointer; text-decoration:none;" >
< i class = "icon icon-wechat icon-2x" > < / i>
< / a>
< a class = "share-qq" data- type= "qq" title= "分享到QQ" rel= "nofollow" style= "margin-left:18px;color: grey;cursor: pointer; text-decoration:none;" >
< i class = "icon icon-qq icon-2x" > < / i>
< / a>
< a class = "share-weibo" data- type= "weibo" title= "分享到微博" rel= "nofollow" style= "margin-left:18px;color: grey;cursor: pointer; text-decoration:none;" >
< i class = "icon icon-weibo icon-2x" > < / i>
< / a>
< / div>
< br/ >
& nbsp;
< div class = "commentAll" style= "display:none" id= "comment_reply_${cont.id}" >
< ! -- 评论区域 begin-- >
< div class = "reviewArea clearfix" >
< textarea class = "content comment-input" placeholder= "Please enter a comment…" onkeyup= "keyUP(this)" > < / textarea>
< a class = "plBtn" id= "comment_${cont.id}" onclick= "_comment(${cont.id},${user.id==null?0:user.id},${cont.uId})" style= "color: white;cursor: pointer;" > 评论< / a>
< / div>
< ! -- 评论区域 end-- >
< div class = "comment-show-first" id= "comment-show-${cont.id}" >
< / div>
< / div>
< div class = "single-clear" >
< / div>
< / div>
< ! -- 正文结束 -- >
< div style= "position: absolute;width:900px;background-color: #EBEBEB;height: 10px;left: 0px" >
< / div>
< / c: forEach>
代码解读如下:
通过 <c:forEach></c:forEach>
循环获取文章内容 Content。 items="${page.result}"
中,item 是 List<Content>
集合。“var="cont"
中,cont 是每一个 Content,通过 ${cont.属性}
即可获得对应的属性值。varStatus="i"
中,i.index 就是从0开始的迭代索引,i.count 就是从1开始迭代计数。
(4)分页信息如下:
< div id= "page-info" style= "position: absolute;width:900px;background-color: #EBEBEB;height: 80px;left: 0px;" >
< ul class = "pager pager-loose" >
< c: if test= "${page.pageNum <= 1}" >
< li> < a href= "void(0);" > « 上一页< / a> < / li>
< / c: if >
< c: if test= "${page.pageNum > 1}" >
< li class = "previous" > < a href= "${ctx}/index_list?pageNum=${page.pageNum-1}&&id=${user.id}" > « 上一页< / a> < / li>
< / c: if >
< c: forEach begin= "1" end= "${page.pages}" var = "pn" >
< c: if test= "${page.pageNum==pn}" >
< li class = "active" > < a href= "void(0);" > ${ pn} < / a> < / li>
< / c: if >
< c: if test= "${page.pageNum!=pn}" >
< li > < a href= "${ctx}/index_list?pageNum=${pn}&&id=${user.id}" > ${ pn} < / a> < / li>
< / c: if >
< / c: forEach>
< c: if test= "${page.pageNum>=page.pages}" >
< li> < a href= "void(0);" > 下一页 »< / a> < / li>
< / c: if >
< c: if test= "${page.pageNum<page.pages}" >
< li> < a href= "${ctx}/index_list?pageNum=${page.pageNum+1}&&id=${user.id}" > 下一页 »< / a> < / li>
< / c: if >
< / ul>
< / div>
判断过程如下:
页数 <=1 显示上一页,但是不能点击(点击无效); 页数 >1 显示上一页,点击返回上一页; 页数 >= 最后一页 ,显示下一页,但是点击无效; 页数 < 最后一页,显示下一页,点击跳转到下一页。
(5)中间页数循环。
代码如下:
<c: for Each begin ="1" end =" ${page.pages} " var="pn" >
从第一页开始,最后一页结束,变量 pn=当前页数。
(6)如果 pageNum 等于当前页 pn,说明被选中,不能被再次点击(点击无效):
< c:if test = "${page.pageNum==pn}" >
< li class = "active" > < a href = "void(0);" > ${pn}</ a > </ li >
</ c:if >
(7)如果 pageNum 不是当前页,既不是被选中页,可以被点击,点击后跳转到该页:
<c:if test =" ${page.pageNum!=pn} " >
<li ><a href=" ${ctx} /index_list?pageNum= ${pn} &&id= ${user.id} " >${pn} </a></li>
</c:if >
重启 Tomcat,访问:http://localhost:8080/,页面已经有动态数据了,但是点击下一页或者其他页还没实现。
IndexJspController
在 wang.dreamland.www 包下新建 IndexJspController.java,并继承 BaseController,将关于首页有关的方法都放在这里,创建映射 URL 为 /index_list
的方法:
@Controller
public class IndexJspController extends BaseController {
private final static Logger log = Logger. getLogger ( IndexJspController. class ) ;
@RequestMapping ( "/index_list" )
public String findAllList ( Model model, @RequestParam ( value = "id" , required = false ) String id ,
@RequestParam ( value = "pageNum" , required = false ) Integer pageNum ,
@RequestParam ( value = "pageSize" , required = false ) Integer pageSize) {
log. info ( "===========进入index_list=========" ) ;
User user = ( User) getSession ( ) . getAttribute ( "user" ) ;
if ( user!= null) {
model. addAttribute ( "user" , user ) ;
}
Page< UserContent> page = findAll ( null, pageNum, pageSize) ;
model. addAttribute ( "page" , page ) ;
return "../index" ;
}
}
代码解读如下:
通过 Session 获取 User 信息,如果不为空则把 User 添加到 Model 中;
调用 BaseController 中的 findAll 方法查询分页并将结果封装到 Page 对象中,参数分别是 null 代表查询所有、pageNum 当前页、pageSize 每页显示条数;
将 Page 对象添加到 Model 中,并返回到 index.jsp 页面。
最后重启 Tomcat 访问:http://localhost:8080/,分页完成!
第08课百度网盘地址:
链接:https://pan.baidu.com/s/1iyTbvLepD07MUeFVbpMxRw 密码:1xxw