前言
GitHub地址:
https://github.com/ZhongFuCheng3y/CustomerSystem
成果图
我们完成的就是下面的项目!
搭建配置环境
CREATE TABLE customer ( id VARCHAR(40) PRIMARY KEY, name VARCHAR(20) NOT NULL, gender VARCHAR(10) NOT NULL, birthday DATE, cellphone VARCHAR(30) NOT NULL, email VARCHAR(30), preference VARCHAR(200), type VARCHAR(20), description VARCHAR(255) );TABLE customer (
id VARCHAR(40) PRIMARY KEY,
name VARCHAR(20) NOT NULL,
gender VARCHAR(10) NOT NULL,
birthday DATE,
cellphone VARCHAR(30) NOT NULL,
email VARCHAR(30),
preference VARCHAR(200),
type VARCHAR(20),
description VARCHAR(255)
);
开发DAO
DAO应该提供增加客户和查询用户的功能
增加用户
public void addCustomer(Customer customer) { QueryRunner queryRunner = new QueryRunner(Utils2DB.getDataSource()); String sql = "INSERT INTO customer (id,name, gender, birthday, cellphone, preference, type, description) VALUES (?, ?, ?, ?, ?, ?, ?, ?,?)"; //得到用户传递进来的数据 String id = customer.getId(); String name = customer.getName(); String gender = customer.getGender(); String cellphone = customer.getCellphone(); String email = customer.getEmail(); String preference = customer.getPreference(); String type = customer.getType(); String description = customer.getDescription(); //对于日期,要转换一下 Date date = customer.getBirthday(); SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd"); String birthday = simpleDateFormat.format(date); try { //向数据库插入数据 queryRunner.update(sql, new Object[]{id, name, gender, birthday, cellphone, email, preference, type, description}); //插入记录成功! } catch (SQLException e) { //如果出现了异常,就抛出Dao异常吧(自定义的异常) e.printStackTrace(); throw new DaoException("添加用户出错了!"); } }
QueryRunner queryRunner = new QueryRunner(Utils2DB.getDataSource());
String sql = "INSERT INTO customer (id,name, gender, birthday, cellphone, preference, type, description) VALUES (?, ?, ?, ?, ?, ?, ?, ?,?)";
//得到用户传递进来的数据
String id = customer.getId();
String name = customer.getName();
String gender = customer.getGender();
String cellphone = customer.getCellphone();
String email = customer.getEmail();
String preference = customer.getPreference();
String type = customer.getType();
String description = customer.getDescription();
//对于日期,要转换一下
Date date = customer.getBirthday();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
String birthday = simpleDateFormat.format(date);
try {
//向数据库插入数据
queryRunner.update(sql, new Object[]{id, name, gender, birthday, cellphone, email, preference, type, description});
//插入记录成功!
} catch (SQLException e) {
//如果出现了异常,就抛出Dao异常吧(自定义的异常)
e.printStackTrace();
throw new DaoException("添加用户出错了!");
}
}
开发servic
提供UI,增加客户的Servlet
//直接跳转到显示增加用户页面的jsp request.getRequestDispatcher("/WEB-INF/addCustomer.jsp").forward(request, response);
request.getRequestDispatcher("/WEB-INF/addCustomer.jsp").forward(request, response);
我们发现,在日期的下拉框中,只有一个数据(因为我们在value中只写了一个数据)
要想在下拉框中可以选择很多的数据,那么value的值就不能单单只有一个。当然了,也不可能在JSP页面中写下面的代码
<option value="1900">1900</option> <option value="1901">1900</option> <option value="1902">1900</option> <option value="1903">1900</option></option>
<option value="1901">1900</option>
<option value="1902">1900</option>
<option value="1903">1900</option>
我们用javaScript生成下拉框的数据就行了!!
function makeYear() { //得到下拉框的控件 var year = document.getElementById("year"); //要想下拉框有更多的数据,就需要有更多的option控件 //js获取得到年份是getFullYear(),单单的getYear()只是获取两位数 for (var i=1901; i<= new Date().getFullYear(); i++) { //生成option控件 var option = document.createElement("option"); //option控件的值和文本内容为循环生成的年分! option.value = i; option.innerText = i; //将生成option控件绑定到select控件上 year.appendChild(option); } }
//得到下拉框的控件
var year = document.getElementById("year");
//要想下拉框有更多的数据,就需要有更多的option控件
//js获取得到年份是getFullYear(),单单的getYear()只是获取两位数
for (var i=1901; i<= new Date().getFullYear(); i++) {
//生成option控件
var option = document.createElement("option");
//option控件的值和文本内容为循环生成的年分!
option.value = i;
option.innerText = i;
//将生成option控件绑定到select控件上
year.appendChild(option);
}
}
function makeMonth() { var month = document.getElementById("month"); for (var i = 2; i <= 12; i++) { var option = document.createElement("option"); if (i < 10) { option.value = '0' + i; option.innerText = '0' + i; } else { option.value = i; option.innerText = i; } month.appendChild(option); } } function makeDay() { var day = document.getElementById("day"); for(var i=2;i<=12;i++) { var option = document.createElement("option"); if(i<10) { option.value = '0' + i; option.innerText = '0' + i; }else{ option.value = i; option.innerText = i; } day.appendChild(option); } }
var month = document.getElementById("month");
for (var i = 2; i <= 12; i++) {
var option = document.createElement("option");
if (i < 10) {
option.value = '0' + i;
option.innerText = '0' + i;
} else {
option.value = i;
option.innerText = i;
}
month.appendChild(option);
}
}
function makeDay()
{
var day = document.getElementById("day");
for(var i=2;i<=12;i++)
{
var option = document.createElement("option");
if(i<10)
{
option.value = '0' + i;
option.innerText = '0' + i;
}else{
option.value = i;
option.innerText = i;
}
day.appendChild(option);
}
}
<script type="text/javascript" src="${pageContext.request.contextPath}/customer.js" ></script>"${pageContext.request.contextPath}/customer.js" ></script>
function pageInit() { makeYear(); makeMonth(); makeDay(); } <body onload="pageInit()">
makeYear();
makeMonth();
makeDay();
}
<body onload="pageInit()">
开发处理表单数据的Servlet
public static <T> T request2Bean(HttpServletRequest httpServletRequest, Class<T> aClass) { try { //获取Bean的对象 T bean = aClass.newInstance(); //获取表单中所有的名字 Enumeration enumeration = httpServletRequest.getParameterNames(); //遍历表单提交过来的名字 while (enumeration.hasMoreElements()) { //每个名字 String name = (String) enumeration.nextElement(); //获取得到值 String value = httpServletRequest.getParameter(name); //如果用户提交的数据不为空,那么将数据封装到Bean中 if (!value.equals("") && value != null) { BeanUtils.setProperty(bean, name, value); } } return bean; } catch (Exception e) { e.printStackTrace(); throw new RuntimeException("封装数据到Bean中,失败了!"); } }static <T> T request2Bean(HttpServletRequest httpServletRequest, Class<T> aClass) {
try {
//获取Bean的对象
T bean = aClass.newInstance();
//获取表单中所有的名字
Enumeration enumeration = httpServletRequest.getParameterNames();
//遍历表单提交过来的名字
while (enumeration.hasMoreElements()) {
//每个名字
String name = (String) enumeration.nextElement();
//获取得到值
String value = httpServletRequest.getParameter(name);
//如果用户提交的数据不为空,那么将数据封装到Bean中
if (!value.equals("") && value != null) {
BeanUtils.setProperty(bean, name, value);
}
}
return bean;
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("封装数据到Bean中,失败了!");
}
}
//将表单的数据弄到Bean对象中 Customer customer = WebUtils.request2Bean(request, Customer.class); try { //调用BusinessService层的方法,添加客户 BusinessService businessService = new BusinessService(); businessService.addCustomer(customer); //如果执行到这里,说明成功了,如果被catch了,说明失败了。 request.setAttribute("message", "添加成功!"); } catch (Exception e) { e.printStackTrace(); request.setAttribute("message", "添加失败"); } request.getRequestDispatcher("/message.jsp").forward(request, response);
Customer customer = WebUtils.request2Bean(request, Customer.class);
try {
//调用BusinessService层的方法,添加客户
BusinessService businessService = new BusinessService();
businessService.addCustomer(customer);
//如果执行到这里,说明成功了,如果被catch了,说明失败了。
request.setAttribute("message", "添加成功!");
} catch (Exception e) {
e.printStackTrace();
request.setAttribute("message", "添加失败");
}
request.getRequestDispatcher("/message.jsp").forward(request, response);
提供查询客户界面的Servlet
//跳转到显示客户界面信息的jsp request.getRequestDispatcher("/WEB-INF/lookCustomer.jsp").forward(request, response);
request.getRequestDispatcher("/WEB-INF/lookCustomer.jsp").forward(request, response);
查询总记录数
查询总记录数也就是查询数据库表的记录有多少条,这是关于对数据库数据的操作,所以肯定是在dao层做!
public Long getTotalRecord() { QueryRunner queryRunner = new QueryRunner(Utils2DB.getDataSource()); String sql = "SELECT * FROM customer"; try { //获取查询的结果 Long l = (Long) queryRunner.query(sql, new ScalarHandler()); return l; } catch (SQLException e) { e.printStackTrace(); throw new RuntimeException("查询总记录数失败了!"); } }
QueryRunner queryRunner = new QueryRunner(Utils2DB.getDataSource());
String sql = "SELECT * FROM customer";
try {
//获取查询的结果
Long l = (Long) queryRunner.query(sql, new ScalarHandler());
return l;
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException("查询总记录数失败了!");
}
}
查询分页的数据
获取分页的数据也是查询数据库的记录,这也是关于对数据库的操作,所以也是在Dao层做的!
/*查询分页数据*/ //获取分页的数据是需要start和end两个变量的【从哪条开始取,取到哪一条】 public List<Customer> getPageData(int start, int end) { QueryRunner queryRunner = new QueryRunner(Utils2DB.getDataSource()); String sql = "SELECT * FROM customer LIMIT ?,?"; try { List<Customer> customers = (List<Customer>) queryRunner.query(sql, new BeanListHandler(Customer.class), new Object[]{start, end}); return customers; } catch (SQLException e) { e.printStackTrace(); throw new DaoException("获取分页数据失败了!"); } }
//获取分页的数据是需要start和end两个变量的【从哪条开始取,取到哪一条】
public List<Customer> getPageData(int start, int end) {
QueryRunner queryRunner = new QueryRunner(Utils2DB.getDataSource());
String sql = "SELECT * FROM customer LIMIT ?,?";
try {
List<Customer> customers = (List<Customer>) queryRunner.query(sql, new BeanListHandler(Customer.class), new Object[]{start, end});
return customers;
} catch (SQLException e) {
e.printStackTrace();
throw new DaoException("获取分页数据失败了!");
}
}
分析
现在我们已经可以知道总记录数了,对于其他3个变量(每页显示记录数【由程序员来指定】,当前是多少页【由用户来指定】,总页数【由总记录数和每页显示记录数来算数来的】)
现在要分析的是,这些变量应该放在哪里呢???全部放在Dao层??全部放在Dao层是可以实现功能的,但是,这样MVC结构就被破坏掉了(Dao层只用来对数据进行CRUD操作,4个变量存在Dao层,是不合理的)
最好的做法是这样的:创建一个实体Page,将分页用到的信息全部封装在Page中实现!Page就代表着分页的数据这样就非常符合面向对象的思想了!
将数据封装到Page中并在页面上显示分页的数据
①:创建Page类
//保存着分页的数据 private List<Customer> list; //总记录数 private long totalRecord; //每页显示记录数,这里我规定每页显示3条 private int linesize = 3; //总页数 private int totalPageCount; //当前显示的页数 private long currentPageCount; //...各种的setter、getter
private List<Customer> list;
//总记录数
private long totalRecord;
//每页显示记录数,这里我规定每页显示3条
private int linesize = 3;
//总页数
private int totalPageCount;
//当前显示的页数
private long currentPageCount;
//...各种的setter、getter
②:BusinessService应该提供获取分页数据的服务
//既然Page对象代表是分页数据,那么返回Page对象即可! //web层应该传入想要看哪一页数据的参数! public Page getPageData(String currentPageCount) { Page page = new Page(); //获取数据库中有多少条记录,并封装到Page对象中 Long totalRecord = customerDao.getTotalRecord(); page.setTotalRecord(totalRecord); //算出总页数,并封装到Page对象中 int totalPagecount = (int) (totalRecord % page.getLinesize() == 0 ? totalRecord / page.getLinesize() : totalRecord / page.getLinesize() + 1); page.setTotalPageCount(totalPagecount); int start ; int end = page.getLinesize(); //现在又分两种情况了,如果传递进来的参数是null的,那么说明外界是第一次查询的 if (currentPageCount == null) { //第一次查询,就应该设置当前页数是第一页 page.setCurrentPageCount(1); start = (int) ((page.getCurrentPageCount() - 1) * page.getLinesize()); List<Customer> customers = customerDao.getPageData(start, end); page.setList(customers); } else { //如果不是第一次,就把外界传递进来的页数封装到Page对象中 page.setCurrentPageCount(Long.parseLong(currentPageCount)); start = (int) ((page.getCurrentPageCount() - 1) * page.getLinesize()); List<Customer> customers = customerDao.getPageData(start, end); page.setList(customers); } return page; }
//web层应该传入想要看哪一页数据的参数!
public Page getPageData(String currentPageCount) {
Page page = new Page();
//获取数据库中有多少条记录,并封装到Page对象中
Long totalRecord = customerDao.getTotalRecord();
page.setTotalRecord(totalRecord);
//算出总页数,并封装到Page对象中
int totalPagecount = (int) (totalRecord % page.getLinesize() == 0 ? totalRecord / page.getLinesize() : totalRecord / page.getLinesize() + 1);
page.setTotalPageCount(totalPagecount);
int start ;
int end = page.getLinesize();
//现在又分两种情况了,如果传递进来的参数是null的,那么说明外界是第一次查询的
if (currentPageCount == null) {
//第一次查询,就应该设置当前页数是第一页
page.setCurrentPageCount(1);
start = (int) ((page.getCurrentPageCount() - 1) * page.getLinesize());
List<Customer> customers = customerDao.getPageData(start, end);
page.setList(customers);
} else {
//如果不是第一次,就把外界传递进来的页数封装到Page对象中
page.setCurrentPageCount(Long.parseLong(currentPageCount));
start = (int) ((page.getCurrentPageCount() - 1) * page.getLinesize());
List<Customer> customers = customerDao.getPageData(start, end);
page.setList(customers);
}
return page;
}
③:web层调用BusinessService层的功能,获取得到Page对象
//获取用户想要看的页数,如果是第一次,那肯定为null String currentPageCount = request.getParameter("currentPageCount"); //调用BusinessService的方法,获取得到所有客户信息 BusinessService businessService = new BusinessService(); Page page = businessService.getPageData(currentPageCount); //把客户信息带过去给jsp页面 request.setAttribute("page", page); //跳转到显示客户界面信息的jsp request.getRequestDispatcher("/WEB-INF/lookCustomer.jsp").forward(request, response);
String currentPageCount = request.getParameter("currentPageCount");
//调用BusinessService的方法,获取得到所有客户信息
BusinessService businessService = new BusinessService();
Page page = businessService.getPageData(currentPageCount);
//把客户信息带过去给jsp页面
request.setAttribute("page", page);
//跳转到显示客户界面信息的jsp
request.getRequestDispatcher("/WEB-INF/lookCustomer.jsp").forward(request, response);
④:在JSP页面中,使用EL表达式获取到Page对象,从而输出数据
<c:forEach items="${page.list}" var="customer"> <tr> <td>${customer.name}</td> <td>${customer.gender}</td> <td>${customer.birthday}</td> <td>${customer.cellphone}</td> <td>${customer.email}</td> <td>${customer.preference}</td> <td>${customer.type}</td> <td>${customer.description}</td> </tr> </c:forEach>"customer">
<tr>
<td>${customer.name}</td>
<td>${customer.gender}</td>
<td>${customer.birthday}</td>
<td>${customer.cellphone}</td>
<td>${customer.email}</td>
<td>${customer.preference}</td>
<td>${customer.type}</td>
<td>${customer.description}</td>
</tr>
</c:forEach>
⑤:在JSP页面中显示页码,同时把码数绑定到超链接去!
<%--提供页数的界面--%> <c:forEach var="pageNum" begin="1" end="${page.totalPageCount}"> <a href="${pageContext.request.contextPath}/LookCustomer?currentPageCount=${pageNum}"> ${pageNum} </a> </c:forEach>"pageNum" begin="1" end="${page.totalPageCount}">
<a href="${pageContext.request.contextPath}/LookCustomer?currentPageCount=${pageNum}">
${pageNum}
</a>
</c:forEach>
让分页的功能更加完善
显示当前页数,总页数,总记录数
当前页数是:[${page.currentPageCount}] 总页数是:${page.totalPageCount} 总记录数是:${page.totalRecord}
总页数是:${page.totalPageCount}
总记录数是:${page.totalRecord}
跳转到某页上
<input type="text" id="currentPageCount"> <input type="button" value="跳转">"currentPageCount">
<input type="button" value="跳转">
我们现在要做的就是:怎么样才能输入框输入内容,然后点击跳转按钮,将输入框的数据发送到Servlet上,然后实现跳转到某页上功能
明显地,我们肯定要使用JavaScript代码!
<script type="text/javascript"> /*既然写上了JavaScript代码了,就顺便验证输入框输入的数据是否合法吧*/ function goPage() { /*获取输入框控件*/ var input = document.getElementById("currentPageCount"); /*获取输入框的数据*/ var value = input.value; if(value==null || value==""){ alert("请输入页码"); return false; } if(!value.match("\\d+")){ alert("请输入数字"); return false; } if(value<1 || value>${page.totalPageCount}){ alert("请输入合法数据"); return false ; } window.location.href="${pageContext.request.contextPath}/LookCustomer?currentPageCount="+value; }</script>
/*既然写上了JavaScript代码了,就顺便验证输入框输入的数据是否合法吧*/
function goPage() {
/*获取输入框控件*/
var input = document.getElementById("currentPageCount");
/*获取输入框的数据*/
var value = input.value;
if(value==null || value==""){
alert("请输入页码");
return false;
}
if(!value.match("\\d+")){
alert("请输入数字");
return false;
}
if(value<1 || value>${page.totalPageCount}){
alert("请输入合法数据");
return false ;
}
window.location.href="${pageContext.request.contextPath}/LookCustomer?currentPageCount="+value;
}
</script>
记录JSP页面的开始页和结束页
为什么我们要记录JSP页面的开始页和结束页呢?经过上面层层地优化,我们感觉不出有什么问题了。那是因为数据量太少!
我们试着多添加点记录进数据库,再回来看看!
从上面的图我们可以发现页数有多少,JSP页面就显示多少!这明显不合理的,如果有100页也显示100页吗?
我们做一个规定,一次只能显示10页的数据。那么显示哪10页呢?这又是一个问题了,如果我们在看第11页的数据,应该显示的是第7到第16页的数据(显示11附近的页数),我们在看第2页的数据,应该显示第1到第10页的数据。用户想要看的页数是不明确的,我们显示附近的页数也是不明确的!。我们应该把用户想要看的页数记录下来,然后根据逻辑判断,显示附近的页数
我们显示页数的代码是这样的:
很明显,我们只要控制了begin和end中的数据,就控制显示哪10页了!
①在Page类中多定义两个成员变量
//记录JSP页面开始的页数和结束的页数 private int startPage; private int endPage; //Setter,Getter方法
private int startPage;
private int endPage;
//Setter,Getter方法
②开始页数和结束页数受用户想看的页数影响,在BusinessService的getPageData()加入下面的逻辑
//第一次访问 page.setStartPage(1); page.setEndPage(10); //不是第一次访问 if (page.getCurrentPageCount() <= 10) { page.setStartPage(1); page.setEndPage(10); } else { page.setStartPage((int) (page.getCurrentPageCount() - 4)); page.setEndPage((int) (page.getCurrentPageCount() + 5)); //如果因为加减角标越界了,那么就设置最前10页,或者最后10页 if (page.getStartPage() < 1) { page.setStartPage(1); page.setEndPage(10); } if (page.getEndPage() > page.getTotalPageCount()) { page.setEndPage(page.getTotalPageCount()); page.setStartPage(page.getTotalPageCount() - 9); } }
page.setStartPage(1);
page.setEndPage(10);
//不是第一次访问
if (page.getCurrentPageCount() <= 10) {
page.setStartPage(1);
page.setEndPage(10);
} else {
page.setStartPage((int) (page.getCurrentPageCount() - 4));
page.setEndPage((int) (page.getCurrentPageCount() + 5));
//如果因为加减角标越界了,那么就设置最前10页,或者最后10页
if (page.getStartPage() < 1) {
page.setStartPage(1);
page.setEndPage(10);
}
if (page.getEndPage() > page.getTotalPageCount()) {
page.setEndPage(page.getTotalPageCount());
page.setStartPage(page.getTotalPageCount() - 9);
}
}
③:在JSP显示页数时,获取得到开始页和结束页就行了
<%--提供页数的界面--%> <c:forEach var="pageNum" begin="${page.startPage}" end="${page.endPage}"> <a href="${pageContext.request.contextPath}/LookCustomer?currentPageCount=${pageNum}"> [${pageNum}] </a> </c:forEach>"pageNum" begin="${page.startPage}" end="${page.endPage}">
<a href="${pageContext.request.contextPath}/LookCustomer?currentPageCount=${pageNum}">
[${pageNum}]
</a>
</c:forEach>
重构优化
分页重构
我们再回头看看BusinessService中获取分页数据的代码:
//既然Page对象代表是分页数据,那么返回Page对象即可! //web层应该传入想要看哪一页数据的参数! public Page getPageData(String currentPageCount) { Page page = new Page(); //获取数据库中有多少条记录,并封装到Page对象中 Long totalRecord = customerDao.getTotalRecord(); page.setTotalRecord(totalRecord); //算出总页数,并封装到Page对象中 int totalPagecount = (int) (totalRecord % page.getLinesize() == 0 ? totalRecord / page.getLinesize() : totalRecord / page.getLinesize() + 1); page.setTotalPageCount(totalPagecount); int start ; int end = page.getLinesize(); //现在又分两种情况了,如果传递进来的参数是null的,那么说明外界是第一次查询的 if (currentPageCount == null) { //第一次查询,就应该设置当前页数是第一页 page.setCurrentPageCount(1); page.setStartPage(1); page.setEndPage(10); start = (int) ((page.getCurrentPageCount() - 1) * page.getLinesize()); List<Customer> customers = customerDao.getPageData(start, end); page.setList(customers); } else { //如果不是第一次,就把外界传递进来的页数封装到Page对象中 page.setCurrentPageCount(Long.parseLong(currentPageCount)); start = (int) ((page.getCurrentPageCount() - 1) * page.getLinesize()); if (page.getCurrentPageCount() <= 10) { page.setStartPage(1); page.setEndPage(10); } else { page.setStartPage((int) (page.getCurrentPageCount() - 4)); page.setEndPage((int) (page.getCurrentPageCount() + 5)); //如果因为加减角标越界了,那么就设置最前10页,或者最后10页 if (page.getStartPage() < 1) { page.setStartPage(1); page.setEndPage(10); } if (page.getEndPage() > page.getTotalPageCount()) { page.setEndPage(page.getTotalPageCount()); page.setStartPage(page.getTotalPageCount() - 9); } } List<Customer> customers = customerDao.getPageData(start, end); page.setList(customers); } return page; }
//web层应该传入想要看哪一页数据的参数!
public Page getPageData(String currentPageCount) {
Page page = new Page();
//获取数据库中有多少条记录,并封装到Page对象中
Long totalRecord = customerDao.getTotalRecord();
page.setTotalRecord(totalRecord);
//算出总页数,并封装到Page对象中
int totalPagecount = (int) (totalRecord % page.getLinesize() == 0 ? totalRecord / page.getLinesize() : totalRecord / page.getLinesize() + 1);
page.setTotalPageCount(totalPagecount);
int start ;
int end = page.getLinesize();
//现在又分两种情况了,如果传递进来的参数是null的,那么说明外界是第一次查询的
if (currentPageCount == null) {
//第一次查询,就应该设置当前页数是第一页
page.setCurrentPageCount(1);
page.setStartPage(1);
page.setEndPage(10);
start = (int) ((page.getCurrentPageCount() - 1) * page.getLinesize());
List<Customer> customers = customerDao.getPageData(start, end);
page.setList(customers);
} else {
//如果不是第一次,就把外界传递进来的页数封装到Page对象中
page.setCurrentPageCount(Long.parseLong(currentPageCount));
start = (int) ((page.getCurrentPageCount() - 1) * page.getLinesize());
if (page.getCurrentPageCount() <= 10) {
page.setStartPage(1);
page.setEndPage(10);
} else {
page.setStartPage((int) (page.getCurrentPageCount() - 4));
page.setEndPage((int) (page.getCurrentPageCount() + 5));
//如果因为加减角标越界了,那么就设置最前10页,或者最后10页
if (page.getStartPage() < 1) {
page.setStartPage(1);
page.setEndPage(10);
}
if (page.getEndPage() > page.getTotalPageCount()) {
page.setEndPage(page.getTotalPageCount());
page.setStartPage(page.getTotalPageCount() - 9);
}
}
List<Customer> customers = customerDao.getPageData(start, end);
page.setList(customers);
}
return page;
}
太太太太太tm复杂,太太太太tm长了!!!!!我们BusinessService要做的仅仅是调用Dao层的功能,为web层提供数据,但我们在方法中使用大量了逻辑判断,而且这些逻辑判断都是属于Page类的!
明确一下:只有获取数据库总记录数是在BusinessService中做的,其他的数据变量都是应该在Page类中完成!
在BusinessService获取了总记录数之后,我们要对其他变量进行初始化(根据总记录数,用户想要看哪一页的数据),算出其他的数据(JSP记录开始页数、结束页数、总页数等等),最好的办法就是通过Page的构造函数来实现初始化!
public Page getPageData2(String currentPageCount) { //获取得到总记录数 Long totalPageCount = customerDao.getTotalRecord(); if (currentPageCount == null) { //如果是第一次,那么就将用户想看的页数设置为1 Page page = new Page(1, totalPageCount); List<Customer> customers = customerDao.getPageData(page.getStartIndex(), page.getLinesize()); page.setList(customers); return page; } else { //如果不是第一次,就将获取得到的页数传递进去 Page page = new Page(Integer.parseInt(currentPageCount), totalPageCount); List<Customer> customers = customerDao.getPageData(page.getStartIndex(), page.getLinesize()); page.setList(customers); return page; } }
//获取得到总记录数
Long totalPageCount = customerDao.getTotalRecord();
if (currentPageCount == null) {
//如果是第一次,那么就将用户想看的页数设置为1
Page page = new Page(1, totalPageCount);
List<Customer> customers = customerDao.getPageData(page.getStartIndex(), page.getLinesize());
page.setList(customers);
return page;
} else {
//如果不是第一次,就将获取得到的页数传递进去
Page page = new Page(Integer.parseInt(currentPageCount), totalPageCount);
List<Customer> customers = customerDao.getPageData(page.getStartIndex(), page.getLinesize());
page.setList(customers);
return page;
}
}
public Page(int currentPageCount, long totalRecord) { //将传递进来的currentPageCount初始化 this.currentPageCount = currentPageCount; //总页数 totalPageCount = (int) (totalRecord % linesize == 0 ? totalRecord / linesize : totalRecord / linesize + 1); //总记录数 this.totalRecord = totalRecord; //开始取数据的位置 startIndex = (currentPageCount - 1) * linesize; //如果当前页小于10,那么开始页为1,结束页为10就行了 if (this.currentPageCount <= 10) { this.startPage = 1; this.endPage = 10; } else { startPage = this.currentPageCount - 4; endPage = this.currentPageCount + 5; //加减后页数越界的情况 if (startPage < 1) { this.startPage = 1; this.endPage = 10; } if (endPage > totalPageCount) { this.startPage = this.currentPageCount - 9; this.endPage = this.totalPageCount; } } }
//将传递进来的currentPageCount初始化
this.currentPageCount = currentPageCount;
//总页数
totalPageCount = (int) (totalRecord % linesize == 0 ? totalRecord / linesize : totalRecord / linesize + 1);
//总记录数
this.totalRecord = totalRecord;
//开始取数据的位置
startIndex = (currentPageCount - 1) * linesize;
//如果当前页小于10,那么开始页为1,结束页为10就行了
if (this.currentPageCount <= 10) {
this.startPage = 1;
this.endPage = 10;
} else {
startPage = this.currentPageCount - 4;
endPage = this.currentPageCount + 5;
//加减后页数越界的情况
if (startPage < 1) {
this.startPage = 1;
this.endPage = 10;
}
if (endPage > totalPageCount) {
this.startPage = this.currentPageCount - 9;
this.endPage = this.totalPageCount;
}
}
}
分页显示页面重构
分页的显示页面都是永恒不变的,我们可以把代码重构成一个jsp,需要用到分页显示页面的地方,就包含进去就行了!
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%--显示当前页数--%> 当前页数是:[${page.currentPageCount}] <%--如果当前的页码大于1,才显示上一步--%> <c:if test="${page.currentPageCount>1}"> <%--把传递过去的页码-1就行了--%> <a href="${pageContext.request.contextPath}/LookCustomer?currentPageCount=${page.currentPageCount-1}"> 上一步 </a> </c:if> <%--提供页数的界面--%> <c:forEach var="page" begin="${page.startPage}" end="${page.endPage}"> <a href="${pageContext.request.contextPath}/LookCustomer?currentPageCount=${page}"> [${page}] </a> </c:forEach> <%--如果当前的页码小于总页数,才显示下一步--%> <c:if test="${page.currentPageCount<page.totalPageCount}"> <%--把传递过去的页码-1就行了--%> <a href="${pageContext.request.contextPath}/LookCustomer?currentPageCount=${page.currentPageCount+1}"> 下一步 </a> </c:if> <input type="text" id="currentPageCount"> <input type="button" value="跳转" onclick="goPage()"> 总页数是:${page.totalPageCount} 总记录数是:${page.totalRecord} <script type="text/javascript"> /*既然写上了JavaScript代码了,就顺便验证输入框输入的数据是否合法吧*/ function goPage() { /*获取输入框控件*/ var input = document.getElementById("currentPageCount"); /*获取输入框的数据*/ var value = input.value; if(value==null || value==""){ alert("请输入页码"); return false; } if(!value.match("\\d+")){ alert("请输入数字"); return false; } if(value<1 || value>${page.totalPageCount}){ alert("请输入合法数据"); return false ; } window.location.href="${pageContext.request.contextPath}/LookCustomer?currentPageCount="+value; } </script>"java" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%--显示当前页数--%>
当前页数是:[${page.currentPageCount}]
<%--如果当前的页码大于1,才显示上一步--%>
<c:if test="${page.currentPageCount>1}">
<%--把传递过去的页码-1就行了--%>
<a href="${pageContext.request.contextPath}/LookCustomer?currentPageCount=${page.currentPageCount-1}">
上一步
</a>
</c:if>
<%--提供页数的界面--%>
<c:forEach var="page" begin="${page.startPage}" end="${page.endPage}">
<a href="${pageContext.request.contextPath}/LookCustomer?currentPageCount=${page}">
[${page}]
</a>
</c:forEach>
<%--如果当前的页码小于总页数,才显示下一步--%>
<c:if test="${page.currentPageCount<page.totalPageCount}">
<%--把传递过去的页码-1就行了--%>
<a href="${pageContext.request.contextPath}/LookCustomer?currentPageCount=${page.currentPageCount+1}">
下一步
</a>
</c:if>
<input type="text" id="currentPageCount">
<input type="button" value="跳转" onclick="goPage()">
总页数是:${page.totalPageCount}
总记录数是:${page.totalRecord}
<script type="text/javascript">
/*既然写上了JavaScript代码了,就顺便验证输入框输入的数据是否合法吧*/
function goPage() {
/*获取输入框控件*/
var input = document.getElementById("currentPageCount");
/*获取输入框的数据*/
var value = input.value;
if(value==null || value==""){
alert("请输入页码");
return false;
}
if(!value.match("\\d+")){
alert("请输入数字");
return false;
}
if(value<1 || value>${page.totalPageCount}){
alert("请输入合法数据");
return false ;
}
window.location.href="${pageContext.request.contextPath}/LookCustomer?currentPageCount="+value;
}
</script>
用需要用到的地方,导入即可!
<jsp:include page="page.jsp"></jsp:include>
为了做到更好的通用性,处理分页数据的url应该由Servlet传进去给Page类,让Page类封装起来!要使用的时候,再用Page取出来就行了。
下面写法已经固定了,不够灵活!也就是说,下面的url地址不应该写死的
${pageContext.request.contextPath}/LookCustomer?currentPageCount=${page.currentPageCount+1}
我们可以这样做:
String servletName = this.getServletName(); //调用BusinessService的方法,获取得到所有客户信息 BusinessService businessService = new BusinessService(); //把Servlet的url也传递进去 Page page = businessService.getPageData2(currentPageCount, request.getContextPath() + "/" + servletName);
//调用BusinessService的方法,获取得到所有客户信息
BusinessService businessService = new BusinessService();
//把Servlet的url也传递进去
Page page = businessService.getPageData2(currentPageCount, request.getContextPath() + "/" + servletName);
private String url; public String getUrl() { return url; } public void setUrl(String url) { this.url = url; }
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
page.setUrl(url);
我们在jsp页面跳转到处理分页数据的Servlet上,就再不用写死了。直接用Page对象中获取出来就行了!
<%--把传递过去的页码-1就行了--%> <a href="${page.url}?currentPageCount=${page.currentPageCount-1}"> 上一步 </a>
<a href="${page.url}?currentPageCount=${page.currentPageCount-1}">
上一步
</a>
开发web的删除和修改
在查询jsp页面上,增添删除和修改的操作链接!
开发处理删除操作的Servlet
超链接绑定要删除用户的id,带过去给Controller
<a href="${pageContext.request.contextPath}/DeleteCustomer?id=${customer.id}">删除</a></a>
controller的代码也十分简单:
String id = request.getParameter("id"); //调用BusinessService层的功能,就可以完成删除操作了 BusinessService businessService = new BusinessService(); businessService.deleteCustomer(id);
//调用BusinessService层的功能,就可以完成删除操作了
BusinessService businessService = new BusinessService();
businessService.deleteCustomer(id);
删除客户记录也是一件非常重要的事情,应该提供JavaSrcript代码询问是否要真的删除
在超链接控件上绑定事件!
<a href="${pageContext.request.contextPath}/DeleteCustomer?id=${customer.id}" onclick=" return sureDelete()">删除</a></a>
function sureDelete() { var b = window.confirm("你确定要删除吗?"); if(b) { return true; }else { return false; } }
var b = window.confirm("你确定要删除吗?");
if(b) {
return true;
}else {
return false;
}
}
修改操作
修改操作的流程是这样的:点击修改超链接,跳转到该用户的详细信息页面,在详细信息页面中修改数据,再提交修改!【跳转到用户详细信息页面时,用户的id还在的,在提交数据的时候,记得把id也给到服务器,【id是不包含在表单中的,要我们自己提交过去】!】
<a href="${pageContext.request.contextPath}/UpdateCustomerUI?=${customer.id}">修改</a></a>
开发提供用户详细信息的Servlet
String id = request.getParameter("id"); BusinessService businessService = new BusinessService(); //通过id获取得到用户的详细信息 Customer customer = businessService.findCustomer(id); request.setAttribute("customer", customer); //跳转到显示用户详细信息的jsp页面上 request.getRequestDispatcher("/WEB-INF/customerInformation").forward(request, response);
BusinessService businessService = new BusinessService();
//通过id获取得到用户的详细信息
Customer customer = businessService.findCustomer(id);
request.setAttribute("customer", customer);
//跳转到显示用户详细信息的jsp页面上
request.getRequestDispatcher("/WEB-INF/customerInformation").forward(request, response);
开发显示用户信息的JSP【数据回显】
想要日期能够选择,记得导入JavaScript代码,响应事件!
注意:在显示页面上,一定要把id传递过去给处理表单的Servlet,不然服务器是不知道你要修改哪一条数据的!
总结
在dao层中,我们有添加客户、通过id查找用户、删除用户、修改用户信息的方法。
日期我们一般用下拉框来给用户选取,要想下拉框的信息有足够多的数据,我们需要用到JavaScript【DOM编程动态增加和修改数据】
javasrcipt文件不能放在WEB-INF目录下面
日期的数据通过下拉框选取,年、月、日是分散的,我们需要把他们拼接,于是我们也用JavaScript来拼接【减低服务器端的压力】
开发工具方法request2Bean,主要用到了BeanUtils框架,这样就不用在Servlet一个一个封装了。
在JSP判断集合是否有元素时,我们可以用EL表达式${empty(集合)}。
如果记录数有很多,我们应该使用分页技术,一般地,我们使用Page类来封装分页的数据
要使用分页技术,就必须在数据库用查询总记录数,通过总记录数,就可以算出总页数了【每页显示多少条记录由我们说了算】
在dao层还要编写获取具体的分页数据,从哪里开始,哪里结束,返回一个List集合,再把List集合封装到Page对象上
由于获取分页数据需要当前的页数是多少,(所以在service中要判断当前页数是否存在,如果不存在,那么就设置为1)【更新,我认为在Controller判断会好一点】
分页中,我们还支持上一页和下一页的功能,如果页数大于1,才显示上一页,如果页数小于1,才显示下一页。
给出下拉框进行页数跳转,使用JavaScript事件机制,获取页数,再提交给Servlet处理即可
我们还要控制页数的显示,因为不可能有100页,我们就显示100页,这样是不可能的。在Page类中维护两个变量,startPage,endPage。我们规定每次只能显示10页数据,如果第一次访问就显示1-10页。如果当前页数大于10,那么就显示6-15页。如果角标越界了,那么就显示前10页或者后10页
我们把显示分页的页面封装成单独的jsp,使用的Servlet连接也可以用url变量来维护。
前台数据做拼接,最终都是把拼接好的数据用一个隐藏域封装起来,随后让form表单一起提交
如果文章有错的地方欢迎指正,大家互相交流。习惯在微信看技术文章的同学,想要获取更多的Java资源的同学,可以关注微信公众号:Java3y