从头开始基于Maven搭建SpringMVC+Mybatis项目(3)

接上文内容,本节介绍基于Mybatis的查询和分页功能,并展示一个自定义的分页标签,可重复使用以简化JSP页面的开发。

从头阅读传送门

在上一节中,我们已经使用Maven搭建好了项目的基础结构,包括一个父项目petstore-parent和数据库持久层模块petstore-persist及Web站点petstore-web,现在来为petstore-web添加一些功能。对于初学者来说,可能第一个遇到的较复杂问题就是分页查询,那么就先从解决它开始。

看一下完成的效果:

从头开始基于Maven搭建SpringMVC+Mybatis项目(3)_第1张图片

上面是四个可选的查询条件,用户可以根据需要组合查询条件。

中间是符合条件的数据展示表格,对查询结果可以执行修改和删除操作,但是暂未实现。

最下面是一个分页导航栏,以自定义标签(Tag)技术实现,可复用到多个jsp页面。

下面来介绍关键步骤和代码。首先是petstore-persist模块,目录结构如下:

从头开始基于Maven搭建SpringMVC+Mybatis项目(3)_第2张图片

Product.java是一个普通的Java Bean,这里略过。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 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映射:




	
		
		
		
	
	
	

可以看到上面两个方法中,就是通过等元素来组装查询SQL。Mybatis的优点之一就是直接使用SQL语法,有SQL基础的情况下非常容易上手。

下面进入petstore-web模块,先来看整体结构:

从头开始基于Maven搭建SpringMVC+Mybatis项目(3)_第3张图片

其中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("");
		
		out.write("每页显示");
		out.write("");
		out.write("条    ");
		
		out.write(pageIndex + "/" + pageCount + "页    ");
		out.write("共" + itemCount + "条记录    ");
		
		out.write(" 1 ? "" : " disabled='true'") + " />  ");
		out.write(" 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("" + i + "  ");
			} else {
				out.write("" + i + "  ");
			}
		}
		
		out.write("  ");
		out.write("");
		out.write("");
	}
接下来还需要一个标签配置文件来声明这个标签的使用方法。

在WEB-INF下建立目录tld,然后添加pagingTag.tld,内容如下:




	2.0
	1.2
	Paging
	http://blog.csdn.net/autfish/tag/
	Paging Tag
	Paging Tag library

	
		pagingTag
		com.example.petstore.web.tag.PagingTag
		empty
		create navigation for paging
		
			pageIndex
			true
		
		
			pageSize
			true
		
		
			pageCount
			true
		
		
			itemCount
			true
		
	
注意其中的uri元素,这里并不需要配置真实存在的url,但该uri在你的classpath中应保持唯一,不能被其他组件声明使用。

在web.xml中启用这个标签:

	
		
			http://blog.csdn.net/autfish/tag/
			/WEB-INF/tld/pagingTag.tld
		
	
在jsp中使用:

<%@ taglib prefix="my" uri="http://blog.csdn.net/autfish/tag/" %>
对于四个属性的赋值,contentModel是一个PagingList.java类的实例,用于辅助分页,由分页属性和数据表构成,在Controller中填充数据并传递到视图JSP。属性如下:

	private int pageIndex = 1;
	private int pageSize = 20;
	private int pageCount = 0;
	private int itemCount = 0;
	
	private List 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 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 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 list = this.productMapper.findProducts(id, name, fromPrice, toPrice, fetchIndex, fetchCount);
		PagingList paging = new PagingList();
		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项目(1)
从头开始基于Maven搭建SpringMVC+Mybatis项目(2)
从头开始基于Maven搭建SpringMVC+Mybatis项目(3)
从头开始基于Maven搭建SpringMVC+Mybatis项目(4)

你可能感兴趣的:(JAVA)