0
点赞
收藏
分享

微信扫一扫

分页标签02

幺幺零 2022-04-13 阅读 20
java

文章目录

  • 前言
  • 一、重构-提取公用方法
  • 二、分页标签
    • 准备一个Servlet
    • 结果展示页面
    • 过滤器解决中文乱码问题


前言


提示:以下是本篇文章正文内容,下面案例可供参考

一、后台分页数据查询

1)为了进行公共方法的抽取,需要找出上面实习中的可通用部分,和差异化部分。

  • 只要是分页,就会统计总记录数,而总记录数的统计是在业务sql外封装了一个select count(*)是有规律可循的,可以通用

  • 只要是分页,则封装分页sql也是有规律可循的(在业务sql后加limit子句即可),可以通用

  • 因为每个查询对应的业务实体(即模型)不同,所以ORM映射部分不能通用

2)公用方法封装思路

  • 将可通用的部分封装到模板中

  • 差异化部分(即不可通用部分),可以定义一个处理接口,以便于通过参数传入个性化的实现部分

3) 具体实现

通用分页查询模板类:

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.commons.beanutils.BeanUtils;

import com.mysql.jdbc.NotUpdatable;


/**
 * 用于操作数据库的工具类
 * @author Administrator
 */
public final class DbTemplate {
	
	private DbTemplate() {
	}
	
	//用于缓存数据库字段到实体属性名的映射关系: 列名 --> 属性名
	private static Map<String, Map<String, String>> columnFieldMapCache = new ConcurrentHashMap<>();
	
	//用于缓存实体属性名到数据库字段名的映射关系: 属性名 --> 列名
	private static Map<String, Map<String, String>> fieldColumnMapCache = new ConcurrentHashMap<>();
	
	
	/**
	 * 分页查询功能
	 * @param sql sql语句
	 * @param args 查询参数,对象数组
	 * @param pageBean 分页对象
	 * @param clazz 数据记录对应的实体对象类型
	 * @return
	 */
	public static <E> List<E> query(String sql, 
			Object[] args, 
			PageBean pageBean,
			Class<E> clazz) {
		
		List<E> datas = new ArrayList<>();
		
		Connection con = null;
		PreparedStatement ps = null;
		ResultSet rs = null;
		
		//如果需要分页,则统计总记录数
		if(pageBean != null && pageBean.isPagination()) {
			String sqlCount = "SELECT COUNT(*) FROM (" + sql + ") t";
			
			try {
				con = DBUtil.getConection();
				ps = con.prepareStatement(sqlCount);
				
				//设置查询参数
				int i = 1;
				for(Object arg: args) {
					ps.setObject(i, arg);
					i++;
				}
				
				rs = ps.executeQuery();
				
				while(rs.next()) {
					pageBean.setTotal(rs.getInt(1));
				}
			} catch (SQLException e) {
				DBUtil.closeDB(rs, ps, con);
				throw new RuntimeException("统计总记录数异常", e);
			} finally {
				DBUtil.closeDB(rs, ps);
			}
			
			if(pageBean.getTotal()== 0) {
				return datas;
			}
		}
		
		
		try {
			String pagingSql = sql;
			if(pageBean != null && pageBean.isPagination()) {
				pagingSql = sql + " limit "
						+ pageBean.getStartIndex() + "," + pageBean.getRows();
			}
			
			con = con == null ? DBUtil.getConection() : con;
			ps = con.prepareStatement(pagingSql);
			
			//设置查询参数
			int i = 1;
			for(Object arg: args) {
				ps.setObject(i, arg);
				i++;
			}
			
			rs = ps.executeQuery();
			
			Map<String, String> columnFieldMap = getColumnFieldMap(clazz);
			
			int columnNum = rs.getMetaData().getColumnCount(); 
			while(rs.next()) {
				E bean = clazz.newInstance();
				for(int index = 1; index <= columnNum; index++) {
					String cn = rs.getMetaData().getColumnName(index);
					//如果实体类中没有定义与列名对应的属性,则直接放弃
					if(!columnFieldMap.containsKey(cn) || rs.getObject(index) == null) continue;
					//通过反射机制进行赋值
					BeanUtils.setProperty(bean, columnFieldMap.get(cn), rs.getObject(index));
				}
				datas.add(bean);
			}
			
		} catch (SQLException e) {
			throw new RuntimeException("查询分页数据异常", e);
		} catch (InstantiationException | IllegalAccessException e) {
			throw new RuntimeException("查询分页数据异常", e);
		} catch (InvocationTargetException e) {
			throw new RuntimeException("查询分页数据异常", e);
		} finally {
			DBUtil.closeDB(rs, ps, con);
		}
 		
		return datas;
	}

	
	/**
	 * 获取数据库字段和实体属性之间的映射
	 * @param clazz 类型
	 * @return Map<String, String>
	 */
	private static <E> Map<String, String> getColumnFieldMap(Class<E> clazz) {
		
		if(columnFieldMapCache.containsKey(clazz.getName())) {
			return columnFieldMapCache.get(clazz.getName());
		}
		
		Map<String, String> map = new HashMap<>();
		Field[] fields = clazz.getDeclaredFields();
		for(Field f: fields) {
			//如果具有Ignore注解则表示忽略
			if(f.getAnnotation(Ignore.class) != null) {
				continue;
			}
			if(f.getAnnotation(Column.class) == null) {
				map.put(f.getName(), f.getName());
			}else {
				map.put(f.getAnnotation(Column.class).value(), f.getName());
			}
		}
		
		columnFieldMapCache.put(clazz.getName(), map);
		
		return map;
	}
	
	
	/**
	 * 执行查询,不分页
	 * @param sql sql语句
	 * @param args 查询参数,对象数组
	 * @param clazz 数据记录对应的实体对象类型
	 * @return list
	 */
	public static <E> List<E> query(String sql, 
			Object[] args, 
			Class<E> clazz) { 
		
		return query(sql, args, null, clazz);
	}
	
	
	/**
	 * 执行查询,不分页,没有条件
	 * @param sql 查询语句
	 * @param clazz 存放数据的实体类型
	 * @return list
	 */
	public static <E> List<E> query(String sql,
			Class<E> clazz) { 
		return query(sql, new Object[]{}, null, clazz);
	}
	
	
	/**
	 * 执行查询,分页,没有条件
	 * @param sql 查询语句
	 * @param pageBean 分页条件
	 * @param clazz 存放数据的实体类型
	 * @return list
	 */
	public static <E> List<E> query(String sql,
			PageBean pageBean,
			Class<E> clazz) { 
		return query(sql, new Object[]{}, pageBean, clazz);
	}
	
	
	/**
	 * 保存数据实体,如果传入连接,则使用传入的数据库连接。如果为空创建一个连接,
	 * 如果调用者自己传入连接对象,则需要自行处理连接的关闭,需要传入调用者自行
	 * 传入连接的情况主要出现的需要事务控制的时候。
	 * @param connection 数据库连接
	 * @param entity
	 * @return
	 */
	public static <E> int save(Connection connection, E entity) {
		Table table = entity.getClass().getAnnotation(Table.class);
		if(table == null) {
			throw new SaveEntityException("需要在实体类上需要使用@Table来标记表名");
		}
		
		String tableName = entity.getClass().getAnnotation(Table.class).value();
		String sql = buildInsertSqlByEntity(entity);
		
		Connection con = null;
		PreparedStatement ps = null;
		try {
			con = (connection == null || connection.isClosed()) ? DBUtil.getConection() : connection;
			ps = con.prepareStatement(sql);
			
			int i = 1;
			for(Field f:  entity.getClass().getDeclaredFields()) {
				f.setAccessible(true);
				
				if(f.getAnnotation(AutoIncrement.class) != null
						|| f.getAnnotation(Ignore.class) != null) {
					continue;
				}
				
				if(f.getAnnotation(Key.class) != null) {
					if(f.get(entity) == null) {
						throw new SaveEntityException("保存"+tableName+"记录时,"+f.getName() +"为主键属性不允许为空");
					}
				}
				if (f.getAnnotation(NotNull.class) != null) {
					if(f.get(entity) == null) {
						throw new SaveEntityException("保存"+tableName+"记录时,"+f.getName() +"属性不允许为空");
					}
				}
				
				ps.setObject(i, f.get(entity));
				i++;
			}
			
			return ps.executeUpdate();
			
		} catch (SQLException e) {
			throw new SaveEntityException("保存"+tableName+"记录时报异常",e );
		} catch (IllegalArgumentException | IllegalAccessException e) {
			throw new SaveEntityException("保存"+tableName+"记录时报异常",e );
		} finally {
			
			//外部传入的数据库连接,由外部程序自行关闭
			if(connection != null) {
				DBUtil.closeDB(null, ps);
			} else {
				DBUtil.closeDB(null, ps, con);
			}
			
		}
	}
	
	
	/**
	 * 保存实体中的数据到对应的表中去,实体对应的表可以通过在实体类上使用
	 * 注解@Table来进行标记,对应自增长的字段可以通过@AutoIncrement
	 * 来进行注解
	 * @param entity 实体类
	 * @return int 影响行数
	 */
	public static <E> int save(E entity) {
		return save(null, entity);
	}

	
	/**
	 * 通过实体类构造insert语句
	 * @param entity 需要持久化的实体bean
	 * @return string 
	 */
	private static <E> String buildInsertSqlByEntity(E entity) {
	
		String tableName = entity.getClass().getAnnotation(Table.class).value();
		StringBuilder sql = new StringBuilder("insert into "+tableName + "(");
		
		Map<String, String> fieldColumnMap = getFieldColumnMap(entity);
		
		Field[] fields = entity.getClass().getDeclaredFields();
		for(int i = 0; i < fields.length; i++) {
			
			//如果字段表明是自增长的或者是忽略的属性,则不需要构造到insert语句中
			if(fields[i].getAnnotation(AutoIncrement.class) != null
					|| fields[i].getAnnotation(Ignore.class) != null) {
				if(fields.length == (i+1)) {
					sql.deleteCharAt(sql.length()-1);
					sql.append(")");
				}
				continue;
			}
			
			//除最后一列外,各列中间用","分割
			if(fields.length == (i+1)) {
				sql.append(fieldColumnMap.get(fields[i].getName())+")");
			} else {
				sql.append(fieldColumnMap.get(fields[i].getName())+",");
			}
		}
		
		sql.append("VALUES (");
		
		for(int i = 0; i < fields.length; i++) {
			
			//排除自增长的字段及忽略的属性
			if(fields[i].getAnnotation(AutoIncrement.class) != null
					|| fields[i].getAnnotation(Ignore.class) != null) {
				if(fields.length == (i+1)) {
					sql.deleteCharAt(sql.length()-1);
					sql.append(")");
				}
				continue;
			}
			
			//除最后一列外,各列中间用","分割
			if(fields.length == (i+1)) {
				sql.append("?)");
			} else {
				sql.append("?,");
			}
		}
		
		System.out.println("生成Insert语句如下: " + sql.toString());
		return sql.toString();
	}

	
	/**
	 * 构建  属性 -> 数据库字段名   映射
	 * @param entity 实体
	 * @return Map<String, String>
	 */
	private static <E> Map<String, String> getFieldColumnMap(E entity) {
		
		if(fieldColumnMapCache.containsKey(entity.getClass().getName())) {
			return fieldColumnMapCache.get(entity.getClass().getName());
		}
		
		Map<String, String> fieldColumnMap = new HashMap<>();
		Field[] fields = entity.getClass().getDeclaredFields();
		for(Field f: fields) {
			if(f.getAnnotation(Ignore.class) != null) continue;
			if(f.getAnnotation(Column.class) == null) {
				fieldColumnMap.put(f.getName(), f.getName());
			}else {
				fieldColumnMap.put(f.getName(), f.getAnnotation(Column.class).value());
			}
		}
		
		fieldColumnMapCache.put(entity.getClass().getName(), fieldColumnMap);
		
		return fieldColumnMap;
	}
	
	
	/**
	 * 新增,更新,或删除记录
	 * @param sql 更新sql语句
	 * @param args 参数数组
	 * @return int 影响的行数
	 */
	public static <E> int update(String sql, Object[] args) {
		
		Connection con = null;
		PreparedStatement ps = null;
		
		try {
			con = DBUtil.getConection();
			ps = con.prepareStatement(sql);
			
			int i = 1;
			for(Object arg: args) {
				ps.setObject(i, arg);
				i++;
			}
			
			return ps.executeUpdate();
		} catch (SQLException e) {
			throw new UpdateRecordException("执行:"+ sql, e);
		} finally {
			DBUtil.closeDB(null, ps, con);
		}
	}
	
	/**
	 * 更新,适合针对摸个实体类进行整体更新的情况
	 * @param entity  需要跟新的实体对象
	 * @return 影响的行数,如果成功则返回1
	 */
	public static <E> int update(E entity) {
		
		Table table = entity.getClass().getAnnotation(Table.class);
		if(table == null) {
			throw new SaveEntityException("需要在实体类上需要使用@Table来标记表名");
		}
		
		String tableName = entity.getClass().getAnnotation(Table.class).value();
		
		Field[] fields = entity.getClass().getDeclaredFields();
		
		Map<String, String> fcMap = getFieldColumnMap(entity);
		List<Object> args = new ArrayList<>();
		
		StringBuilder setStr = new StringBuilder();
		int i = 0;
		try {
			for(Field f: fields) {
				if(f.getAnnotation(Ignore.class) != null) continue;
				if(f.getAnnotation(Key.class) == null) {
					if (i == 0) {
						setStr.append(" set "+ fcMap.get(f.getName()) + "=?");
						f.setAccessible(true);
						args.add(f.get(entity));
					} else {
						setStr.append(","+fcMap.get(f.getName()) + "=?");
						f.setAccessible(true);
						args.add(f.get(entity));
					}
					i++;
				}
			}
		} catch (IllegalArgumentException | IllegalAccessException e) {
			throw new RuntimeException("在生成update语句时发生异常",e);
		}
		
		if(setStr.toString().length() == 0) {
			throw new RuntimeException("在使用update(E entity)方法执行更新没有指定任何需要更新的字段...");
		}
		
		StringBuilder whereStr = new StringBuilder();
		int j = 0;
		try {			
			for(Field f: fields) {
				
				if(f.getAnnotation(Ignore.class) != null) continue;
				
				if(f.getAnnotation(Key.class) != null) {
					if(j == 0) {
						whereStr.append(" where "+fcMap.get(f.getName()) + "=?");
						f.setAccessible(true);
						args.add(f.get(entity));
					} else {
						whereStr.append(" and " + fcMap.get(f.getName()) + "=?");
						f.setAccessible(true);
						args.add(f.get(entity));
					}
					j++;
				}
			}
		} catch (IllegalArgumentException | IllegalAccessException e) {
			throw new RuntimeException("在生成update语句时发生异常",e);
		}
		
		if(whereStr.toString().length() == 0 ) {
			throw new RuntimeException("在使用update(E entity)方法执行更新时需要指定@key");
		}
		
		Object[] argArr = args.toArray();
		
		String updateSql = "update " + tableName + setStr + whereStr;
		System.out.println("生成的update语句:" + updateSql);
		
		return update(updateSql, argArr);
	}
	
	
	public static void main(String[] args) {
		
		/*Student student = new Student();
		student.setAge(39);
		student.setSname("欧阳晓峰");
		student.setRemark("测试save");
		DbTemplate.save(student);*/
		
		/*String sql = "update t_student set sname=? where sid=?";
		DbTemplate.update(sql, new Object[] {"欧阳乔峰456", 170});
		
		String del = "delete from t_student where sid=?";
		DbTemplate.update(del, new Object[] {169});*/
		
		/*String sql = "select * from test";
		
		List<TestOrm> list = DbTemplate.query(sql, TestOrm.class);
		for(TestOrm orm:  list) {
			System.out.println(orm);
		}
		*/
		
		TestOrm orm = new TestOrm();
		orm.setTaType("类型3");
		orm.settName("许志强");
		orm.setRemark("测试保存");
		
		DbTemplate.save(orm);
		
		DbTemplate.update(orm);
		
		String sql = "select * from test where t_id = ?";
		List<TestOrm> list= DbTemplate.query(sql, new Object[] {1},TestOrm.class);
		
		TestOrm testOrm = list.get(0);
		testOrm.setRemark("测试update(E entity)方法");
		
		DbTemplate.update(testOrm);
	}

二、分页标签

1.准备一个Servlet

准备一个servlet用于处理请求,获取数据库中的数据,并转发到结果显示页面。

import java.io.IOException;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.zking.mymvc.dao.StudentDao03;
import com.zking.mymvc.model.Student;
import com.zking.mymvc.util.PageBean;

@WebServlet("/students")
public class StudentServlet extends HttpServlet {
	
	private StudentDao03 studentDao = new StudentDao03();
	
	@Override
	protected void doGet(HttpServletRequest request, HttpServletResponse response) 
			throws ServletException, IOException {
		doPost(request, response);
	}
	
	@Override
	protected void doPost(HttpServletRequest request, HttpServletResponse response) 
			throws ServletException, IOException {
		PageBean pageBean = new PageBean();
		pageBean.setRequest(request);
		
		String sname = request.getParameter("sname");
		List<Student> students = studentDao.getStudents(sname, pageBean);
		
		request.setAttribute("students", students);
		request.getRequestDispatcher("/students/stuList.jsp").forward(request, response);
	}

}

 2.结果展示页面

创建一个页面,该页面用于显示结果, 使用jstl的c标签来展示结果,为正常使用c标签,需要引入jstl-1.2.jar和standard-1.1.2.jar。

<%@ page language="java" contentType="text/html; charset=utf-8"
    pageEncoding="utf-8"%>
<%@taglib prefix="z" uri="/zking" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
	<h1>学生信息</h1>
	
	<form action="<%=request.getContextPath()%>/students" method="post">
		<input type="text" name="sname">
		<input type="submit" value="查询">
	</form>
	
	<table border="1" style="width: 98%;">
	
		<tr>
			<td>学号</td>
			<td>姓名</td>
			<td>年龄</td>
			<td>备注</td>
		</tr>
		
		<c:forEach items="${students}" var="student">
			<tr>
				<td>${student.sid}</td>
				<td>${student.sname}</td>
				<td>${student.age}</td>
				<td>${student.remark}</td>
			</tr>
		</c:forEach>
		
	</table>
</body>
</html>

3过滤器解决中文乱码问题

import java.io.IOException;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 中文乱码处理
 */
//@WebFilter("/*") //该过滤器过滤所有的请求
public class EncodingFilter implements Filter {

	private String encoding = "UTF-8";// 默认字符集

	public EncodingFilter() {
		super();
	}

	public void destroy() {
	}

	public void doFilter(ServletRequest request, ServletResponse response,
			FilterChain chain) throws IOException, ServletException {
		HttpServletRequest req = (HttpServletRequest) request;
		HttpServletResponse res = (HttpServletResponse) response;

		// 中文处理必须放到 chain.doFilter(request, response)方法前面
		//res.setContentType("text/html;charset=" + this.encoding);
		res.setCharacterEncoding(this.encoding);
		if (req.getMethod().equalsIgnoreCase("post")) {
			req.setCharacterEncoding(this.encoding);
		} else {
			Map map = req.getParameterMap();// 保存所有参数名=参数值(数组)的Map集合
			Set set = map.keySet();// 取出所有参数名
			Iterator it = set.iterator();
			while (it.hasNext()) {
				String name = (String) it.next();
				String[] values = (String[]) map.get(name);// 取出参数值[注:参数值为一个数组]
				for (int i = 0; i < values.length; i++) {
					values[i] = new String(values[i].getBytes("ISO-8859-1"),
							this.encoding);
				}
			}
		}

		//放行,执行过滤器链中的下一个链条
		chain.doFilter(request, response);
	}

	public void init(FilterConfig filterConfig) throws ServletException {
		String s = filterConfig.getInitParameter("encoding");// 读取web.xml文件中配置的字符集
		if (null != s && !s.trim().equals("")) {
			this.encoding = s.trim();
		}
	}

}


举报

相关推荐

0 条评论