从头开始基于Maven搭建SpringMVC+Mybatis项目(3)
接上文内容,本节介绍基于Mybatis的查询和分页功能,并展示一个自定义的分页标签,可重复使用以简化JSP页面的开发。
在上一节中,我们已经使用Maven搭建好了项目的基础结构,包括一个父项目petstore-parent和数据库持久层模块petstore-persist及Web站点petstore-web,现在来为petstore-web添加一些功能。对于初学者来说,可能第一个遇到的较复杂问题就是分页查询,那么就先从解决它开始。
看一下完成的效果:
上面是四个可选的查询条件,用户可以根据需要组合查询条件。
中间是符合条件的数据展示表格,对查询结果可以执行修改和删除操作,但是暂未实现。
最下面是一个分页导航栏,以自定义标签(Tag)技术实现,可复用到多个jsp页面。
下面来介绍关键步骤和代码。首先是petstore-persist模块,目录结构如下:
Product.Java是一个普通的JavaBean,这里略过。ProductMapper.java中定义了两个方法:
- package com.example.petstore.persist.model;
- import java.util.List;
- import org.apache.ibatis.annotations.Param;
- public interface ProductMapper {
- /**
- * 查询符合条件的记录总数
- * @param id
- * @param name
- * @param fromPrice
- * @param toPrice
- * @return
- */
- int matches(@Param(value="id") int id, @Param(value="name") String name, @Param(value="fromPrice") float fromPrice, @Param(value="toPrice") float toPrice);
- /**
- * 按查询条件及分页条件分段查询记录
- * @param id
- * @param name
- * @param fromPrice
- * @param toPrice
- * @param fetchIndex
- * @param fetchCount
- * @return
- */
- List<Product> findProducts(@Param(value="id") int id, @Param(value="name") String name, @Param(value="fromPrice") float fromPrice, @Param(value="toPrice") float toPrice, @Param(value="fetchIndex") int fetchIndex, @Param(value="fetchCount") int fetchCount);
- }
使用时,首先调用matches方法获得符合条件的记录总数,然后根据每页显示的记录数和当前页数计算读取数据的Limit偏移量和记录数,再调用findProducts方法读取数据。两个方法的参数都使用了@Param注解,例如@Param(value="id") int id,在映射文件中,可通过#{id}的格式来使用这个参数。
在Product.xml中添加两个方法的SQL映射:
- <?xml version="1.0" encoding="UTF-8"?>
- <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
- <mapper namespace="com.example.petstore.persist.model.ProductMapper">
- <resultMap type="com.example.petstore.persist.model.Product"
- id="productMap">
- <id column="p_id" property="id" />
- <result column="p_name" property="name" />
- <result column="p_price" property="price" />
- </resultMap>
- <select id="matches" resultType="int">
- select count(*) from t_product
- <where>
- <if test="id>0">
- p_id=#{id}
- </if>
- <if test="name!=null and name!='' ">
- and locate(#{name},p_name)>0
- </if>
- <if test="fromPrice>-1">
- and p_price>=#{fromPrice}
- </if>
- <if test="toPrice>-1">
- and p_price<=#{toPrice}
- </if>
- </where>
- </select>
- <select id="findProducts" resultMap="productMap">
- select * from t_product
- <where>
- <if test="id>0">
- p_id=#{id}
- </if>
- <if test="name!=null and name!='' ">
- and locate(#{name},p_name)>0
- </if>
- <if test="fromPrice>-1">
- and p_price>=#{fromPrice}
- </if>
- <if test="toPrice>-1">
- and p_price<=#{toPrice}
- </if>
- </where>
- limit #{fetchIndex},#{fetchCount}
- </select>
- </mapper>
可以看到上面两个方法中,就是通过<where><if>等元素来组装查询SQL。Mybatis的优点之一就是直接使用SQL语法,有SQL基础的情况下非常容易上手。
下面进入petstore-web模块,先来看整体结构:
其中com.example.petstore.web.tag.PagingTag.java是分页标签类,关键代码:
- private int pageIndex = 1; //当前页数
- private int pageSize = 20; //默认每页行数
- private int pageCount = 0; //记录总页数
- private int itemCount = 0; //记录总条数
- private int numCount = 10; //分页栏数字导航链接个数
- @Override
- public void doTag() throws JspException, IOException {
- JspWriter out = this.getJspContext().getOut();
- out.write("<script type=\"text/javascript\">function navigatorPage(pageIndex) {document.getElementById('pageIndex').value = pageIndex;document.forms[0].submit();}</script>");
- out.write("每页显示");
- out.write("<select id='pageSize' name='pageSize' onchange='navigatorPage(" + pageIndex + ")'>");
- out.write("<option value='5'" + (pageSize == 5 ? " selected='true'" : "") + ">5</option>");
- out.write("<option value='10'" + (pageSize == 10 ? " selected='true'" : "") + ">10</option>");
- out.write("<option value='20'" + (pageSize == 20 ? " selected='true'" : "") + ">20</option>");
- out.write("<option value='50'" + (pageSize == 50 ? " selected='true'" : "") + ">50</option>");
- out.write("<option value='100'" + (pageSize == 100 ? " selected='true'" : "") + ">100</option>");
- out.write("<option value='500'" + (pageSize == 500 ? " selected='true'" : "") + ">500</option>");
- out.write("</select>");
- out.write("条 ");
- out.write(pageIndex + "/" + pageCount + "页 ");
- out.write("共" + itemCount + "条记录 ");
- out.write("<input type='button' value='第一页' onclick='javascript:navigatorPage(1);'" + (pageIndex > 1 ? "" : " disabled='true'") + " /> ");
- out.write("<input type='button' value='上一页' onclick='javascript:navigatorPage(" + (pageIndex - 1) + ");'" + (pageIndex > 1 ? "" : " disabled='true'") + " /> ");
- //数字导航栏
- int iStartIndex = 1;
- int iEndIndex = pageCount;
- if(pageCount <= numCount) {
- } else if ((pageIndex + (numCount + 1) / 2) > pageCount) {
- iStartIndex = pageCount - (numCount - 1);
- iEndIndex = pageCount;
- } else if (pageIndex <= (numCount + 1) / 2) {
- iEndIndex = numCount;
- } else {
- if (numCount % 2 == 0) {
- iStartIndex = pageIndex - numCount / 2;
- iEndIndex = pageIndex + (numCount - 1) / 2;
- } else {
- iStartIndex = pageIndex - numCount / 2;
- iEndIndex = pageIndex + numCount / 2;
- }
- }
- for(int i = iStartIndex; i <= iEndIndex; i++) {
- if(i == pageIndex) {
- out.write("<strong>" + i + "</strong> ");
- } else {
- out.write("<a href='javascript:navigatorPage(" + i + ");'>" + i + "</a> ");
- }
- }
- out.write("<input type='button' value='下一页' onclick='javascript:navigatorPage(" + (pageIndex + 1) + ");'" + (pageIndex < pageCount ? "" : " disabled='true'") + " /> ");
- out.write("<input type='button' value='最后页' onclick='javascript:navigatorPage(" + pageCount + ");'" + (pageIndex < pageCount ? "" : " disabled='true'") + " />");
- out.write("<input type='hidden' id='pageIndex' name='pageIndex' value='" + pageIndex + "'/>");
- }
接下来还需要一个标签配置文件来声明这个标签的使用方法。
在WEB-INF下建立目录tld,然后添加pagingTag.tld,内容如下:
- <?xml version="1.0" encoding="UTF-8"?>
- <!DOCTYPE taglib
- PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN"
- "http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
- <taglib>
- <tlib-version>2.0</tlib-version>
- <jsp-version>1.2</jsp-version>
- <short-name>Paging</short-name>
- <uri>http://blog.csdn.net/autfish/tag/</uri>
- <display-name>Paging Tag</display-name>
- <description>Paging Tag library</description>
- <tag>
- <name>pagingTag</name>
- <tag-class>com.example.petstore.web.tag.PagingTag</tag-class>
- <body-content>empty</body-content>
- <description>create navigation for paging</description>
- <attribute>
- <name>pageIndex</name>
- <rtexprvalue>true</rtexprvalue>
- </attribute>
- <attribute>
- <name>pageSize</name>
- <rtexprvalue>true</rtexprvalue>
- </attribute>
- <attribute>
- <name>pageCount</name>
- <rtexprvalue>true</rtexprvalue>
- </attribute>
- <attribute>
- <name>itemCount</name>
- <rtexprvalue>true</rtexprvalue>
- </attribute>
- </tag>
- </taglib>
注意其中的uri元素,这里并不需要配置真实存在的url,但该uri在你的classpath中应保持唯一,不能被其他组件声明使用。
在web.xml中启用这个标签:
- <jsp-config>
- <taglib>
- <taglib-uri>http://blog.csdn.net/autfish/tag/</taglib-uri>
- <taglib-location>/WEB-INF/tld/pagingTag.tld</taglib-location>
- </taglib>
- </jsp-config>
在jsp中使用:
- <%@ taglib prefix="my" uri="http://blog.csdn.net/autfish/tag/" %>
- <my:pagingTag pageIndex="${contentModel.pageIndex}" pageSize="${contentModel.pageSize}" pageCount="${contentModel.pageCount}" itemCount="${contentModel.itemCount}" />
对于四个属性的赋值,contentModel是一个PagingList.java类的实例,用于辅助分页,由分页属性和数据表构成,在Controller中填充数据并传递到视图JSP。属性如下:
- private int pageIndex = 1;
- private int pageSize = 20;
- private int pageCount = 0;
- private int itemCount = 0;
- private List<T> items;
Controller代码:
- @Controller
- @RequestMapping("/product")
- public class ProductController {
- @Autowired
- private ProductService productService;
- @RequestMapping(value="/list")
- public String listProduct(Model model, @ModelAttribute("searchModel") SearchModel formModel,
- @RequestParam(value=PagingList.PAGE_INDEX_NAME, defaultValue="1") int pageIndex,
- @RequestParam(value=PagingList.PAGE_SIZE_NAME, defaultValue="10") int pageSize) {
- int id = 0;
- String name = "";
- float fromPrice = -1;
- float toPrice = -1;
- if(formModel != null) {
- id = NumberUtils.toInt(formModel.getId(), 0);
- name = formModel.getName();
- fromPrice = NumberUtils.toFloat(formModel.getFromPrice(), -1);
- toPrice = NumberUtils.toFloat(formModel.getToPrice(), -1);
- }
- model.addAttribute("searchModel", formModel);
- PagingList<Product> contentModel = this.productService.findProducts(id, name, fromPrice, toPrice, pageIndex, pageSize);
- model.addAttribute("contentModel", contentModel);
- return "product/list";
- }
- }
Controller中注入了一个ProductService的实例,用于管理持久层的调用,主要代码如下:
- @Service
- public class ProductServiceStdImpl implements ProductService {
- @Autowired
- private ProductMapper productMapper;
- @Override
- public PagingList<Product> findProducts(int id, String name,
- float fromPrice, float toPrice, int pageIndex, int pageSize) {
- int total = this.productMapper.matches(id, name, fromPrice, toPrice);
- int pageCount = total % pageSize == 0 ? total / pageSize : total / pageSize + 1;
- if(pageIndex > pageCount)
- pageIndex = pageCount;
- int fetchIndex = (pageIndex - 1) * pageSize;
- int fetchCount = fetchIndex + pageSize > total ? (total - fetchIndex) : pageSize;
- List<Product> list = this.productMapper.findProducts(id, name, fromPrice, toPrice, fetchIndex, fetchCount);
- PagingList<Product> paging = new PagingList<Product>();
- paging.setItemCount(total);
- paging.setPageCount(pageCount);
- paging.setPageIndex(pageIndex);
- paging.setPageSize(pageSize);
- paging.setItems(list);
- return paging;
- }
- }
限于篇幅,不能把所有的源码一一粘贴,有兴趣可以下载源码。
在WEB容器如tomcat中运行petstore-web模块,使用http://localhost:8080/petstore-web/product/list访问,顺利的话就看到了一开始的画面。如果出错,比对源码检查差异即可。
总结
分页查询功能使用频繁,且开发比较复杂,按需定制一套可复用的分页组件对提高开发效率有很大的帮助。下一节我们继续完善Web模块,增加增删改查以及权限控制功能。
从头开始基于Maven搭建SpringMVC+Mybatis项目(3)的更多相关文章
- 从头开始基于Maven搭建SpringMVC+Mybatis项目(1)
技术发展日新月异,许多曾经拥有霸主地位的流行技术短短几年间已被新兴技术所取代. 在Java的世界中,框架之争可能比语言本身的改变更让人关注.近几年,SpringMVC凭借简单轻便.开发效率高.与spr ...
- 从头开始基于Maven搭建SpringMVC+Mybatis项目(2)
接上文内容,本节介绍Maven的聚合和继承. 从头阅读传送门 互联网时代,软件正在变得越来越复杂,开发人员通常会对软件划分模块,以获得清晰的设计.良好的分工及更高的可重用性.Maven的聚合特性能把多 ...
- 从头开始基于Maven搭建SpringMVC+Mybatis项目(4)
接上文内容,上一节中的示例中完成了支持分页的商品列表查询功能,不过我们的目标是打造一个商品管理后台,本节中还需要补充添加.修改.删除商品的功能,这些功能依靠Mybatis操作数据库,并通过Spring ...
- maven搭建springmvc+mybatis项目
上一篇中已经成功使用maven搭建了一个web项目,本篇描述在此基础上怎么搭建一个基于springmvc+mybatis环境的项目. 说了这么久,为什么那么多人都喜欢用maven搭建项目?我们都知道m ...
- Maven搭建SpringMVC+Mybatis项目详解
前言 最近比较闲,复习搭建一下项目,这次主要使用spring+SpringMVC+Mybatis.项目持久层使用Mybatis3,控制层使用SpringMVC4.1,使用Spring4.1管理控制器, ...
- Maven搭建SpringMVC+MyBatis+Json项目(多模块项目)
一.开发环境 Eclipse:eclipse-jee-luna-SR1a-win32; JDK:jdk-8u121-windows-i586.exe; MySql:MySQL Server 5.5; ...
- Maven搭建SpringMVC+Hibernate项目详解 【转】
前言 今天复习一下SpringMVC+Hibernate的搭建,本来想着将Spring-Security权限控制框架也映入其中的,但是发现内容太多了,Spring-Security的就留在下一篇吧,这 ...
- Maven搭建SpringMVC + SpringJDBC项目详解
前言 上一次复习搭建了SpringMVC+Mybatis,这次搭建一下SpringMVC,采用的是SpringJDBC,没有采用任何其他的ORM框架,SpringMVC提供了一整套的WEB框架,所以如 ...
- Maven搭建SpringMVC+Hibernate项目详解
前言 今天复习一下SpringMVC+Hibernate的搭建,本来想着将Spring-Security权限控制框架也映入其中的,但是发现内容太多了,Spring-Security的就留在下一篇吧,这 ...
随机推荐
- 对Java中多态,封装,继承的认识(重要)
一.Java面向对象编程有三大特性:封装,继承,多态 在了解多态之前我觉得应该先了解一下 ...
- [转]winform 自动伸缩控件xpandercontrols 使用说明
链接地址:http://blog.sina.com.cn/s/blog_b5b004920101f5h3.html
- JDBC 程序实例小练习
JDBC 程序实例问题 编程实现如下功能:在数据库中建立一个表,表名为student,其结构为学号.姓名.性别.年龄.英语.JavaSE程序设计.初级日语.总分,在表中输入多条记录. 学生的总分信息, ...
- 转:一篇讲线上优化查 CPU的脚本
原文链接:https://my.oschina.net/leejun2005/blog/1524687 摘要: 本文主要针对 Java 服务而言 0.背景 经常做后端服务开发的同学,或多或少都遇到 ...
- [置顶]
bootstrap自定义样式-bootstrap侧边导航栏的实现
前言 bootstrap自带的响应式导航栏是向下滑动的,有时满足不了个性化的需求,需要做一个类似于android drawerLayout 侧滑的菜单,这就是我要实现的bootstrap自定义侧滑菜单 ...
- bzoj 3566: [SHOI2014]概率充电器
Description 著名的电子产品品牌 SHOI 刚刚发布了引领世界潮流的下一代电子产品--概率充电器:"采用全新纳米级加工技术,实现元件与导线能否通电完全由真随机数决定!SHOI 概率 ...
- 编译Twitter的Heron时一直报错“heron/bazel_configure.py", line 25, in <module> import semver ImportError: No module named semver”如何处理。
今天编译heron的时候,从官方git到的源码bazel_configure的时候一直报错如下: Traceback (most recent call last): File , in <mo ...
- VMware_ubuntu设置共享文件夹
1. 点击安装VMware tools 2.将/media/vmtool的压缩包复制到/home/pc/vm_tool下,应为原路径在root权限下竟然也是只读的,并且无法更改. 3.进入/home/ ...
- 中文代码示例之Angular入门教程尝试
原址: https://zhuanlan.zhihu.com/p/30853705 原文: 中文代码示例教程之Angular尝试 为了检验中文命名在Angular中的支持程度, 把Angular官方入 ...
- HTML学习 表格和表单
<table></table> 表格标签 width 宽度 border 边框 cellpadding 内容和单元格之间的 ...