反射是所有框架的基础,是java语言的一种机制,通过反射可以动态的实例化对象,读写属性,调用方法,更加灵活。
一般可以用在一些通用工具类的封装和自定义框架
一切反射相关的代码都从获得类对象开始
获得类对象有三种方法
1.Class.forName(完整的类名)
2.类名.class
3.对象.getClass()
1、像我们平常连接数据库加载驱动时就会用到:
Class.forName(cname);
2、实例化时
JobDao jd=Class.forName(com.wangjuanxia.dao.JobAction).newInstance();
解析:通用分页就是就是把分页方法的共同代码封装起来,利用泛型去传递类对象,然后利用反射获取对象属性给对象属性赋值,这样在之后的项目中就可以直接用了,节省代码,更加方便。
这里我画了一个图,可看图理解:
为了更加灵活的完成开发需求,通俗点说就是可以自己去定义我开发时需要的功能的标签
<开始标签>标签体结束标签>
// 例如:文字标签
<span>123</span>
空标签,空标签就没有标签体
// 例如:换行
<br/>
1、创建一个标签助手类,要继承BodyTagSupport,标签属性必须和助手类的属性对应,
且要提供对应的get,set方法。(这里拿下面通用分页要用到的page标签做例)
public class PageTag extends BodyTagSupport{
private static final long serialVersionUID = 1L;
private PageBean pageBean;
//封装
public PageBean getPageBean() {
return pageBean;
}
public void setPageBean(PageBean pageBean) {
this.pageBean = pageBean;
}
@Override
public int doStartTag() throws JspException {
// TODO Auto-generated method stub
try {
JspWriter out=this.pageContext.getOut();
out.println(toHtml());
return SKIP_BODY;
} catch (Exception e) {
// TODO: handle exception
throw new RuntimeException(e);
}
}
private String toHtml() {
// TODO Auto-generated method stub
StringBuffer sb=new StringBuffer();
//防止pageBean空指针异常
if(null==pageBean||!pageBean.isPagination()) {
return sb.toString();
}
//这里拼接分页按钮
sb.append("");
//分页隐藏域表单 专门用来传递数据
sb.append(");
sb.append("");
//从map集合中获取参数
Map<String, String[]> parameterMap=pageBean.getParameterMap();
//遍历集合
for (Map.Entry<String, String[]> entry : parameterMap.entrySet()) {
String name=entry.getKey();
String[] value=entry.getValue();
if("page".equals(name)) {//将上一次的页码抛掉
continue;//退出当前循环,进入下一个循环
}
//遍历数组
for (int i = 0; i < value.length; i++) {
sb.append("");
}
}
sb.append("");
//这里动态拼接js
sb.append(" ");
return sb.toString();
}
}
2、创建标签库描述文件(.tld),添加自定义标签的配置
注意:.tld文件必须保存到WEB-INF目录或其子目录下
<!DOCTYPE taglib
PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN"
"http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
<!-- 标签库描述符 -->
<taglib xmlns="http://java.sun.com/JSP/TagLibraryDescriptor">
<tlib-version>1.0</tlib-version>
<jsp-version>1.2</jsp-version>
<short-name>Simple Tags</short-name>
<!-- 这里放jsp界面taglib命令调用的路径 -->
<uri>/wangjuanxia</uri>
<tag>
<!-- 标签名 -->
<name>page</name>
<!-- 标签助手类 -->
<tag-class>com.solar.tag.PageTag</tag-class>
<!-- 标签的内容类型:empty表示空标签,jsp表示可以为任何合法的JSP元素 -->
<body-content>empty</body-content>
<!-- 自定义标签的属性定义,请注意一定要在标签类中提供对应的get/set方法 -->
<attribute>
<!-- 自定义标签的属性名称 -->
<name>pageBean</name>
<!-- true表示必填 -->
<required>true</required>
<!-- true支持动态值,可以向值里面填jsp表达式、EL表达式,false则不支持 -->
<rtexprvalue>true</rtexprvalue>
<description></description><!-- 属性的描述,可有可无,要放在属性的最后 -->
</attribute>
</tag>
</taglib>
3、在JSP通过taglib指令导入标签描述文件,并通过指定后缀访问自定义标签
通过taglib指令导入
<%@taglib prefix="z" uri="/wangjuanxia" %>
访问
<z:page pageBean="${pageBean }"/>
最后效果
1、连接数据库,最基本的操作这里就不细讲了(调用分页我用的mysql的数据库)
导jar包
2、定义工具类pageBean,来控制是否分页,页数,每页数量
/**
* 分页工具类
*/
public class PageBean {
private int page = 1;// 页码
private int rows = 10;// 页大小
private int total = 0;// 总记录数,从数据库中统计的
private boolean pagination = true;// 是否分页 默认分页
private String url;
private Map<String, String[]> ParameterMap = new HashMap<String, String[]>();
//专门写一个方法,做pageBean的初始化
public void setRequest(HttpServletRequest request) {
System.out.println("pagebean初始化");
String page= request.getParameter("page");
String rows= request.getParameter("rows");
String pagination = request.getParameter("pagination");
this.setPage(page);
this.setRows(rows);
this.setPagination(pagination);
this.url=request.getContextPath()+request.getServletPath();
this.ParameterMap =request.getParameterMap();
}
//上一页
public int getPreviousPage() {
System.out.println("getPreviousPage");
int previousPage=this.page-1;
if(0==previousPage) {
previousPage=1;
}
return previousPage;
}
//下一页
public int getNextPage() {
System.out.println("getNextPage");
int nextPage=this.page+1;
if(nextPage>getMaxPage()) {//大于最大页
nextPage=getMaxPage();
}
return nextPage;
}
public int getPage() {
return page;
}
public void setPage(int page) {
this.page = page;
}
public void setPage(String page) {
if(null!=page &&!"".equals(page.trim())){
this.page =Integer.parseInt(page);
}
}
public Map<String, String[]> getParameterMap() {
return ParameterMap;
}
public void setParameterMap(Map<String, String[]> parameterMap) {
ParameterMap = parameterMap;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public int getRows() {
return rows;
}
public void setRows(int rows) {
this.rows = rows;
}
public void setRows(String rows) {
if(null!=rows &&!"".equals(rows.trim())){
this.rows =Integer.parseInt(rows);
}
}
public int getTotal() {
return total;
}
public void setTotal(int total) {
this.total = total;
}
public void setTotal(String total) {
this.total = Integer.parseInt(total);
}
public boolean isPagination() {
return pagination;
}
public void setPagination(boolean pagination) {
this.pagination = pagination;
}
public void setPagination(String pagination) {
if("false".equals(pagination)) {
this.pagination = Boolean.parseBoolean(pagination);
}
}
public PageBean() {
super();
}
/**
* 获得起始记录的下标
*
* @return
*/
public int getStartIndex() {
return (this.page-1)*this.rows;
}
/**
* 获取最大页数
* @return
*/
public int getMaxPage() {
int maxPage=this.total/this.rows;
if(0!=this.total%this.rows) {
maxPage++;
}
return maxPage;
}
@Override
public String toString() {
return "PageBean [page=" + page + ", rows=" + rows + ", total=" + total + ", pagination=" + pagination + "]";
}
}
3、实体类(字段,封装,构造方法)
4、工具类
从上至下,依次为(连接数据库工具类、字符编码过滤工具类、分页工具类、连接各种数据库配置工具类)
5、将一般增删改查重复的部分写一个泛型,专门写一个方法用来拼接查询语句的统计满足条件的总行数,专门写一个方法用来存储拼接分页的sql,再在里面写一个内部类将不同的遍历部分放进去,解决每个表字段不一样的问题。
//SOLAR
public class BaseDao<k> {
public interface Callback<k>{
public List<k> foreach(ResultSet rs) throws SQLException;
}
public String getCountSql(String sql) {
return "select count(*) from ("+sql+") t1";
}
public String getPageSql(String sql,PageBean pageBean) {
return sql+"limit "+pageBean.getStartIndex()+","+pageBean.getRows()+"";
}
public List<k> executeQuery(String sql,PageBean pageBean,Callback<k> callback){
Connection con=null;
PreparedStatement ps=null;
ResultSet rs=null;
if(null!=pageBean&&pageBean.isPagination()) {
//1、统计满足条件的总行数
try {
con=DBAccess.getConnection();
String countSql=this.getCountSql(sql);
ps=con.prepareStatement(countSql);
rs=ps.executeQuery();
if(rs.next()) {
int total=rs.getInt(1);
pageBean.setTotal(total);
}
} catch (Exception e) {
// TODO: handle exception
throw new RuntimeException(e);
}finally {
DBAccess.close(null, ps, rs);//不能把连接关闭
}
}
//2、查询指定页码并满足条件的总记录数
try {
if(con==null) {
con=DBAccess.getConnection();
}
String pageSql=sql;
if(null!=pageBean&&pageBean.isPagination()) {
pageSql=getPageSql(sql, pageBean);
}
ps=con.prepareStatement(pageSql);
rs=ps.executeQuery();
return callback.foreach(rs);
} catch (Exception e) {
// TODO: handle exception
throw new RuntimeException(e);
}finally {
DBAccess.close(con, ps, rs);
}
}
}
5.在dao类里继承第4步里创建的BaseDao,重写executeQuery方法,遍历存储取出来的字段,返回结果集
public List<Job> find(PageBean pageBean){
String sql="select * from t_solr_job where 1=1 ";
return this.executeQuery(sql, pageBean, new Callback<Job>() {
@Override
public List<Job> foreach(ResultSet rs) throws SQLException {
List<Job> jobList = new ArrayList<Job>();
Job j = null;
while(rs.next()) {
j = new Job();
j.setId(rs.getString("id"));
j.setJob(rs.getString("job"));
j.setCompany(rs.getString("company"));
j.setAddress(rs.getString("address"));
j.setSalary(rs.getString("salary"));
j.setUrl(rs.getString("url"));
j.setLimit(rs.getString("limit"));
j.setTime(rs.getString("time"));
j.setDesc(rs.getString("desc"));
j.setJobHandle(rs.getString("jobHandle"));
j.setAddressHandle(rs.getString("addressHandle"));
jobList.add(j);
}
return jobList;
}
});
}
6、写servlet,继承HttpServlet,写两个方法(doget,dopost),实例化分页工具类,调用方法
public class JobServlet extends HttpServlet{
private static final long serialVersionUID = 1L;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// TODO Auto-generated method stub
doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// TODO Auto-generated method stub
//设置字符编码
req.setCharacterEncoding("utf-8");
resp.setContentType("text/html;charset=utf-8");
//实例化dao方法
JobDao jd = new JobDao();
//实例化分页工具类,调用方法
PageBean pageBean = new PageBean();
pageBean.setRequest(req);
req.setAttribute("pageBean", pageBean);
//调用分页方法
List<Job> joblist= jd.find(pageBean);
//存储
req.setAttribute("joblist", joblist);
//跳转界面
req.getRequestDispatcher("index.jsp").forward(req, resp);
}
}
7.jsp界面
<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8"%>
<!-- taglib指令导入标签描述文件 -->
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@taglib prefix="z" uri="/wangjuanxia" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Insert title here</title>
</head>
<body>
<!-- 判断结果集是否有值 -->
<c:if test="${empty joblist }">
<jsp:forward page="jobServlet.action"></jsp:forward>
</c:if>
<table border="1px" width="100%">
<tr>
<td>id</td>
<td>job</td>
<td>company</td>
<td>address</td>
<td>salary</td>
<td>url</td>
<td>limit</td>
<td>time</td>
<td>desc</td>
<td>jobHandle</td>
<td>addressHandle</td>
</tr>
<!-- 遍历 -->
<c:forEach items="${joblist}" var="j" >
<tr>
<td>${j.id }</td>
<td>${j.job }</td>
<td>${j.company }</td>
<td>${j.address }</td>
<td>${j.salary }</td>
<td>${j.url }</td>
<td>${j.limit }</td>
<td>${j.time }</td>
<td>${j.desc }</td>
<td>${j.jobHandle }</td>
<td>${j.addressHandle }</td>
</tr>
</c:forEach>
</table>
<!-- 自定义标签分页按钮 -->
<z:page pageBean="${pageBean }"/>
</body>
</html>
通用分页更简化了代码,不用每个对象都再写一遍dao方法增删改查,只要写一遍,其他对象都可以调用。