V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
javahih
V2EX  ›  Java

Spring Data Jpa+SpringMVC+Jquery.pagination.js 实现分页

  •  
  •   javahih · 2017-12-26 09:22:02 +08:00 · 3496 次点击
    这是一个创建于 2306 天前的主题,其中的信息可能已经有所发展或是发生改变。

    本博客介绍基于 Spring Data 这款 orm 框架加上 Jquery.pagination 插件实现的分页功能。

    本博客是基于一款正在开发中的 github 开源项目的,项目代码地址: https://github.com/u014427391/jeeplatform 欢迎 star(收藏)或者可以下载去学习,还在开发...

    介绍一下 Spring Data 框架 spring Data : Spring 的一个子项目。用于简化数据库访问,支持 NoSQL 和 关系数据存储。 下面给出 SpringData 项目所支持 NoSQL 存储:

    • MongoDB (文档数据库)
    • Neo4j (图形数据库)
    • Redis (键 /值存储)
    • Hbase (列族数据库)

    SpringData 项目所支持的关系数据存储技术:

    • JDBC
    • JPA

    JPA Spring Data : 致力于减少数据访问层 (DAO) 的开发量。开发者只要写好持久层接口就好,然后其它的框架会帮程序员实现。

    开发步骤: [ Spring Data 实现数据获取] 本项目是采用 maven 的,所以可以参考一下项目的 maven 配置:

    设计好数据库,编写一个实体类: 这里写图片描述

    package org.muses.jeeplatform.model.entity;
    
    import java.util.Date;
    import java.util.Set;
    
    import javax.persistence.CascadeType;
    import javax.persistence.Column;
    import javax.persistence.Entity;
    import javax.persistence.FetchType;
    import javax.persistence.GeneratedValue;
    import javax.persistence.GenerationType;
    import javax.persistence.Id;
    import javax.persistence.JoinColumn;
    import javax.persistence.JoinTable;
    import javax.persistence.ManyToMany;
    import javax.persistence.Table;
    import javax.persistence.Temporal;
    import javax.persistence.TemporalType;
    
    /**
     * 用户信息的实体类
     * @author Nicky
     */
    @Entity
    @Table(name="sys_user")
    public class User {
    
    	/** 用户 Id**/
    	private int id;
    	
    	/** 用户名**/
    	private String username;
    	
    	/** 用户密码**/
    	private String password;
    	
    	/** 手机号**/
    	private int phone;
    	
    	/** 性别**/
    	private String sex;
    	
    	/** 邮件**/
    	private String email;
    	
    	/** 备注**/
    	private String mark;
    	
    	/** 用户级别**/
    	private String rank;
    	
    	/** 最后一次时间**/
    	private Date lastLogin;
    	
    	/** 登录 ip**/
    	private String loginIp;
    	
    	/** 图片路径**/
    	private String imageUrl;
    	
    	/** 注册时间**/
    	private Date regTime;
    	
    	/** 账号是否被锁定**/
    	private Boolean locked = Boolean.FALSE;
    	
    	private Set<Role> roles;		
    	
    	@GeneratedValue(strategy=GenerationType.IDENTITY)
    	@Id
    	public int getId() {
    		return id;
    	}
    
    	public void setId(int id) {
    		this.id = id;
    	}
    
    	@Column(unique=true,length=100,nullable=false)
    	public String getUsername() {
    		return username;
    	}
    
    	public void setUsername(String username) {
    		this.username = username;
    	}
    
    	@Column(length=100,nullable=false)
    	public String getPassword() {
    		return password;
    	}
    
    	public void setPassword(String password) {
    		this.password = password;
    	}
    
    	public int getPhone() {
    		return phone;
    	}
    
    	public void setPhone(int phone) {
    		this.phone = phone;
    	}
    
    	@Column(length=6)
    	public String getSex() {
    		return sex;
    	}
    
    	public void setSex(String sex) {
    		this.sex = sex;
    	}
    
    	@Column(length=100)
    	public String getEmail() {
    		return email;
    	}
    
    	public void setEmail(String email) {
    		this.email = email;
    	}
    
    	@Column(length=30)
    	public String getMark() {
    		return mark;
    	}
    
    	public void setMark(String mark) {
    		this.mark = mark;
    	}
    
    	@Column(length=10)
    	public String getRank() {
    		return rank;
    	}
    
    	public void setRank(String rank) {
    		this.rank = rank;
    	}
    
    	@Temporal(TemporalType.DATE)
    	public Date getLastLogin() {
    		return lastLogin;
    	}
    
    	public void setLastLogin(Date lastLogin) {
    		this.lastLogin = lastLogin;
    	}
    
    	@Column(length=100)
    	public String getLoginIp() {
    		return loginIp;
    	}
    
    	public void setLoginIp(String loginIp) {
    		this.loginIp = loginIp;
    	}
    
    	@Column(length=100)
    	public String getImageUrl() {
    		return imageUrl;
    	}
    
    	public void setImageUrl(String imageUrl) {
    		this.imageUrl = imageUrl;
    	}
    
    	@Temporal(TemporalType.DATE)
    	@Column(nullable=false)
    	public Date getRegTime() {
    		return regTime;
    	}
    
    	public void setRegTime(Date regTime) {
    		this.regTime = regTime;
    	}
    
    	 public Boolean getLocked() {
    		return locked;
    	}
    
    	public void setLocked(Boolean locked) {
    		this.locked = locked;
    	}
    	
    }
    
    

    编写接口实现 Spring Data 框架的 PagingAndSortingRepository 接口

    package org.muses.jeeplatform.repository;
    
    import org.muses.jeeplatform.model.entity.User;
    import org.springframework.data.domain.Page;
    import org.springframework.data.domain.Pageable;
    import org.springframework.data.jpa.repository.JpaRepository;
    import org.springframework.data.jpa.repository.Query;
    import org.springframework.data.repository.PagingAndSortingRepository;
    import org.springframework.data.repository.query.Param;
    
    import java.util.Date;
    
    public interface UserRepository extends PagingAndSortingRepository<User, Integer> {
    
    	/*User findByUsername(String username);
    
    	@Query("from User u where u.username=:username and u.password=:password")
    	User findByUsernameAndPassword(@Param("username") String username, @Param("password") String password);
    
    	@Query("from User u where u.id=:id")
    	User findById(@Param("id") int id);
    
    	@Query("from User u where date_format(u.lastLogin,'yyyy-MM-dd') between date_format((:startDate),'yyyy-MM-dd') and date_format((:endDate),'yyyy-MM-dd')")
    	Page<User> searchU(@Param("startDate")Date startDate,@Param("endDate")Date endDate, Pageable pageable);
    */
    }
    
    

    业务类实现:

    package org.muses.jeeplatform.service;
    
    import java.util.*;
    
    import org.muses.jeeplatform.model.entity.User;
    import org.muses.jeeplatform.repository.UserRepository;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.data.domain.Page;
    import org.springframework.data.domain.PageRequest;
    import org.springframework.data.domain.Sort;
    import org.springframework.data.jpa.domain.Specification;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Transactional;
    
    import javax.persistence.criteria.CriteriaBuilder;
    import javax.persistence.criteria.CriteriaQuery;
    
    /**
     * @description 用户信息管理的业务类
     * @author Nicky 
     * @date 2017 年 3 月 6 日
     */
    @Service
    public class UserService {
    
    	@Autowired
        UserRepository userRepository;
    	
    	/**
    	 * 构建 PageRequest 对象
    	 * @param num
    	 * @param size
    	 * @param asc
    	 * @param string
    	 * @return
    	 */
    	private PageRequest buildPageRequest(int num, int size, Sort.Direction asc,
    										 String string) {
    		return new PageRequest(num-1, size,null,string);
    	}
    
    	/**
    	 * 获取所有的菜单信息并分页显示
    	 * @param pageNo
    	 * 			当前页面数
    	 * @param pageSize
    	 * 			每一页面的页数
    	 * @return
    	 */
    	@Transactional
    	public Page<User> findAll(int pageNo, int pageSize, Sort.Direction dir, String str){
    		PageRequest request = buildPageRequest(pageNo, pageSize, dir, str);
    		Page<User> users = userRepository.findAll(request);
    		return users;
    	}
    }
    
    

    控制类,采用 SpringMVC 框架,先编写一个 baseController,实现一些通用功能的封装:

    package org.muses.jeeplatform.web.controller;
    
    import javax.servlet.http.HttpServletRequest;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.web.context.request.RequestContextHolder;
    import org.springframework.web.context.request.ServletRequestAttributes;
    import org.springframework.web.servlet.ModelAndView;
    
    public class BaseController {
    
    	Logger log = null;
    
    	/**
    	 * 获取日志对象
    	 * @return
    	 */
    	public Logger getInstance(){
    		if(log == null){
    			log = LoggerFactory.getLogger(BaseController.class);
    		}
    		return log;
    	}
    
    	/**
    	 * 得到 request 对象
    	 */
    	public HttpServletRequest getRequest() {
    		HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();
    		return request;
    	}
    	
    	/**
    	 * 得到 ModelAndView
    	 */
    	public ModelAndView getModelAndView(){
    		return new ModelAndView();
    	}
    
    }
    
    

    控制类实现:

    package org.muses.jeeplatform.web.controller;
    
    import net.sf.json.JSONArray;
    import net.sf.json.JSONObject;
    import net.sf.json.JsonConfig;
    import org.apache.commons.collections.map.HashedMap;
    import org.muses.jeeplatform.core.Constants;
    import org.muses.jeeplatform.core.ExcelViewWrite;
    import org.muses.jeeplatform.core.JavaEmailSender;
    import org.muses.jeeplatform.model.entity.User;
    import org.muses.jeeplatform.service.UserService;
    import org.muses.jeeplatform.utils.DateJsonValueProcessor;
    import org.muses.jeeplatform.utils.DateUtils;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.data.domain.Page;
    import org.springframework.data.domain.Sort;
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.bind.annotation.ResponseBody;
    import org.springframework.web.servlet.ModelAndView;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.PrintWriter;
    import java.util.*;
    
    
    /**
     * Created by Nicky on 2017/7/29.
     */
    @RequestMapping("/user")
    @Controller
    public class UserController extends BaseController{
    
        @Autowired
        UserService userService;
    
        /**
         * 查询所有管理员信息并分页显示
         * @param request
         * @param response
         * @param model
         * @return
         */
        @RequestMapping(value = "/queryAll",produces = "application/json;charset=UTF-8")
        @ResponseBody
        public ModelAndView findAll(HttpServletRequest request, HttpServletResponse response, Model model){
            //当前页
            String pageIndexStr = request.getParameter("pageIndex");
    
            //每一页的页数
            int pageSize = Constants.PAGE_SIZE;
            ModelAndView mv = this.getModelAndView();
            Page<User> userPage;
    
            if(pageIndexStr==null||"".equals(pageIndexStr)){
                pageIndexStr = "0";
            }
    
            int pageIndex = Integer.parseInt(pageIndexStr);
    
            userPage = userService.findAll(pageIndex+1, pageSize, Sort.Direction.ASC,"id");
            mv.addObject("totalCount",userPage.getTotalElements());
            mv.addObject("pageIndex",pageIndex);
    //        JsonConfig cfg = new JsonConfig();
    //        cfg.setExcludes(new String[]{"handler","hibernateLazyInitializer"});
            JsonConfig jcg = new JsonConfig();
            jcg.registerJsonValueProcessor(Date.class,
                    new DateJsonValueProcessor("yyyy-mm-dd"));
            JSONArray jsonArray = JSONArray.fromObject(userPage.getContent(),jcg);
            //System.out.println(jsonArray.toString());
            mv.addObject("users",jsonArray.toString());
            mv.setViewName("admin/user/sys_user_list");
            return mv;
        }
    
       
    }
    
    

    [前端页面实现] 页面 View 实现,引用 jquery.pagination.js (分页 js ),跟 pagination.css (分页样式 css )。 可以去这里下载 http://www.cnblogs.com/knowledgesea/archive/2013/01/03/2841554.html

    <%@ page contentType="text/html; charset=utf-8" pageEncoding="utf-8"%>
    <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
    <%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>
    <%
        String path = request.getContextPath();
        String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
    %>
    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
        <base href="<%=basePath %>">
        <meta charset="UTF-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width,initial-scale=1">
        <title>Insert title here</title>
        <!-- bootstrap 样式-->
        <link type="text/css" rel="stylesheet"
              href="<%=basePath%>plugins/page/css/bootstrap-3.3.5.min.css" />
        <!-- jquery.pagination 所需 CSS -->
        <link type="text/css" rel="stylesheet" href="<%=basePath%>plugins/page/css/pagination.css" />
        <script type="text/javascript" src="<%=basePath%>plugins/page/js/jquery.min.js"></script>
        <!-- jquery.pagination 所需 JS 注意必须放在 jquery.js 后面 -->
        <script type="text/javascript" src="<%=basePath%>plugins/page/js/jquery.pagination.js"></script>
        <script type="text/javascript">
    
            /** 分页操作,使用 jquery.pagination 插件 add by nicky 20170729 start **/
            //当前页
            var pageIndex = Number(${pageIndex});
    
            //数据量
            var totalCount = Number(${totalCount});
    
            $(document).ready(function () {
                //加入分页的绑定
                $("#Pagination").pagination(totalCount, {
                    callback : pageselectCallback,
                    prev_text : '< 上一页',
                    next_text: '下一页 >',
                    items_per_page : 6,
                    num_display_entries : 6,
                    current_page : pageIndex,
                    num_edge_entries : 1,
                    link_to: "user/queryAll?pageIndex=__id__"  //分页的 js 中会自动把"__id__"替换为当前的数。0
                });
    
                var html = "";
                var data = ${users};
                $.each(data,function(idx,obj){
                    var id = obj.id;
                    var username = obj.username;
                    var mark = obj.mark;
                    var phone = obj.phone;
                    var email = obj.email;
                    var lastLogin = obj.lastLogin;
                    var loginIp = obj.loginIp;
    
                    html += "<tr><td><input type='checkbox' name='id' id='id' value=" + id + " /></td>" +
                        "<td>"+id+"</td>"+
                        "<td>"+username+"</td>"+
                        "<td>"+mark+"</td>"+
                        "<td>"+phone+"</td>"+
                        "<td>"+email+"</td>"+
                        "<td>"+lastLogin+"</td>"+
                        "<td>"+loginIp+"</td>"+
                        "<td><a href='javascript:openEditDialog("+id+");' class='bounceIn'>配置角色</a>"+
                        "</tr>";
                });
                $("#content").append(html);
    
    
            });
    
            //这个事件是在翻页时候用的
            function pageselectCallback(index, jq) {
    
            }
            /** 分页操作,使用 jquery.pagination 插件 add by nicky 20170729 end **/
    
            //checkbox 的全选 /反选
            var isCheckAll = false;
            function doCheck(){
                if(isCheckAll){
                    $("input[type='checkbox']").each(function(){
                        this.checked = false;
                    });
                    isCheckAll = false;
                }else{
                    $("input[type='checkbox']").each(function(){
                        this.checked = true;
                    });
                    isCheckAll = true;
                }
            }
    
            
    
        </script>
    </head>
    <body>
    <br>
    <div class="container-fluid">
        <div class="row">
            <div class="col-xs-12 col-md-12">
                <div class="panel panel-default">
                    <div class="panel-body">
                        <form class="form-inline">
                            <input type="button" class="btn btn-default" value="发送邮件" onclick="sendEmail();" />
                            <input type="button" class="btn btn-default" value="发送短信" onclick="sendSms();" />
                            <input type="button" class="btn btn-default" value="导出 Excel 表" onclick="exportExcel();" />
                            <br><br><!--
                            <input type="text" class="form-control" id="keyword" placeholder="请输入关键词">
                            &nbsp;&nbsp;&nbsp;&nbsp;
                            日期从<input type="text" class="form-control" placeholder="请输入开始日期" value="${startdate }" id="startDate" name="startdate" onclick="WdatePicker({dateFmt:'yyyy-MM-dd' ,maxDate:'#F{$dp.$D(\'endDate\')}'});"/>
                            到<input type="text" class="form-control" placeholder="请输入结束日期" value="${enddate }" id="endDate" name="enddate" onclick="WdatePicker({dateFmt:'yyyy-MM-dd' ,minDate:'#F{$dp.$D(\'startDate\')}'});" />&nbsp;&nbsp;&nbsp;&nbsp;
                            <input type="button" class="btn btn-default" value="Search" onclick="doSearch();"/>-->
                        </form>
                        <table class="table" id="mTable">
                            <thead>
                            <tr>
                                <th><input type="checkbox" onclick="doCheck();" /></th>
                                <th>序号</th>
                                <th>用户名</th>
                                <th>描述</th>
                                <th>手机</th>
                                <th>邮箱</th>
                                <th>最近登录</th>
                                <th>上次登录 IP</th>
                                <th>操作</th>
                            </tr>
                            </thead>
                            <tbody id="content">
    
                            </tbody>
                        </table>
                        <div id="Pagination" class="pagination"></div>
                        <!-- demo  -->
                    </div>
                </div>
            </div>
        </div>
    </div>
    </body>
    </html>
    

    前端页面展示: 这里写图片描述

    ok,本博客是基于一款正在开发中的 github 开源项目的,项目代码地址: https://github.com/u014427391/jeeplatform 欢迎 star(收藏)或者可以下载去学习,不过还在开发...

    15 条回复    2017-12-26 22:01:44 +08:00
    evolify
        1
    evolify  
       2017-12-26 09:33:30 +08:00
    v2 上面都是不用 jq 的
    acrisliu
        2
    acrisliu  
       2017-12-26 09:50:06 +08:00
    V2 不建议全文转载,建议直接贴你 CSDN 博客链接就好了,虽然 V2 的排版比 CSDN 好看很多。(逃
    nicevar
        3
    nicevar  
       2017-12-26 10:12:45 +08:00
    这种系统还是采用 ExtJS 开发最方便,你这分页还能写出一篇文章,ExtJS 里面直接一个控件放进去就搞定了,所有的逻辑已经跟 jpa 无缝对接了,不用自己写一句代码
    jeffpan
        4
    jeffpan  
       2017-12-26 10:15:31 +08:00
    Spring MVC 太多冗余代码了,既然用 JPA,何不用 Spring Boot ?
    loveCoding
        5
    loveCoding  
       2017-12-26 10:25:21 +08:00   ❤️ 2
    这... 一个分页都能写篇文章啦
    jalena
        6
    jalena  
       2017-12-26 10:25:28 +08:00
    代码写的好。!
    gbin
        7
    gbin  
       2017-12-26 10:27:03 +08:00 via Android
    @loveCoding 都是从基础过来的
    jalena
        8
    jalena  
       2017-12-26 10:27:32 +08:00
    话说既然都用 jquery,为毛不直接再用个 table 框架,,人家都找好了轮子了嘛!
    loveCoding
        9
    loveCoding  
       2017-12-26 10:32:20 +08:00
    @gbin #7 哈哈 ,没有嘲讽的意思
    hantsy
        10
    hantsy  
       2017-12-26 13:09:02 +08:00
    好多年没见 JSP 了,我快十年没用了,现在用的人还很多吗? JSP 本身从 J2EE1.4(2003 年)到现在,快 15 年没更新了。

    差不多四五年前开始全部用 RESTful APIs + 前端 SPA 了。之前一段时间用模板技术比较多一些,freemarker, thymeleaf 都不错。

    Spring 分页 Controller method 同样可以接受 Pageable, 只需要加入 Pageable 就可以获取分页参数, 直接添加 page 到 Model 中,返回就完了,在页面都可能用 SPEL 读取。

    Spring Data 同样可以接受 Pageable, 返回 Page 就行了 。

    哪这么麻烦? 这哪一年的 Spring ?

    BaseController 的 getInstance, getRequest,ModelAndView 这种垃圾代码, 我真的醉了。

    早年使用 Struts 的人,对继承使用有切肤之痛,我早不再用这种无关紧要的继承。

    Logger 一般在当然类中声明为 static final 即可(想简单一点用 Lombok Annotation ),Request,ModelAndView 直接注入到方法就行了。

    findALL 注入了 Model, 又用 getModelAndView 来处理 Model ???@ResponseBody 和 produces="application/json" 是针对于 REST API 开发。而 ModelAndView 是为了处理传统 MVC。

    混成一团,我真怀疑有没有读过 Spring 参考文档啊??? 哪怕读一次也不可能写出这种代码。
    qinxi
        11
    qinxi  
       2017-12-26 13:53:57 +08:00
    @hantsy 这种人 b 了就是了,你看他从 8 月注册到现在除了推广 并没有任何互动。
    推广就算了。还是些垃圾代码。
    就是来骗小白的 star 的
    hantsy
        12
    hantsy  
       2017-12-26 14:31:57 +08:00
    @qinxi 关键现在很多人只喜欢 Copy 别人代码,根本不愿意动脑,或者去读原始参考文档,来甄别一些垃圾代码。B 掉了。
    xuminzhong
        13
    xuminzhong  
       2017-12-26 14:58:58 +08:00
    Java 写这种东西,冗余太多,不好看。
    建议别使用 Spring,直接返回 JSON。

    前端:html += "<tr><td><input type='checkbox' ...... 这种已经是上个世纪的写法了,非常难看。
    建议你了解下数据驱动的写法,比如 vue.js 是个入门好选择。
    xuminzhong
        14
    xuminzhong  
       2017-12-26 15:08:00 +08:00
    另外,Java Bean 写 Web 是一种浪费资源多余的做法,建议直接 Map。 ( public class User...)

    用接口写 Web 也是不推荐的,Java 有专门设计 Jsp tag 来处理这块东西,UserService、UserRepository 没必要存在。
    cobert
        15
    cobert  
       2017-12-26 22:01:44 +08:00
    我艹,我的代码基本上就和楼主的差不多,看了楼上几位大神的回复,我感觉这几年代码白写了....
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   2586 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 45ms · UTC 15:28 · PVG 23:28 · LAX 08:28 · JFK 11:28
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.