6. 利用JUnit测试框架进行测试数据
1. JUnit 简介
JUnit是一个Java编程语言的单元测试框架。它提供了一组注解和断言方法来编写和运行单元测试。开发人员可以使用注解来标记测试方法,并使用断言方法来验证预期结果与实际结果是否相符。
使用JUnit进行单元测试的好处包括:
- 自动化测试:JUnit提供自动化的测试过程,减少了手动测试的工作量。
- 快速反馈:运行单元测试可以快速发现代码中的问题,帮助开发人员及早修复错误。
- 可重复性:通过编写可重复执行的测试案例,确保代码在不同环境下的行为一致性。
- 重构支持:运行单元测试可以验证重构后的代码仍然按预期工作,避免引入新问题。
总之,JUnit是一个常用的单元测试框架,可以帮助开发人员编写、运行和管理Java代码的单元测试,以确保代码质量和功能正确性。
2. 配置JUnit步骤
1. 右击项目划到Build Path -- 点击 Configure Build Path...
2. 点击右侧列表 Add Libray 双击JUnit
3. 选择JUnit4 直接Finish 就配置好啦!
3. 测试实例
通过@Test 进行标记
/** * 配置Junit可测试多个方法 * * @throws Exception */ @Test public void text() throws Exception { System.out.println("Text1..."); BookDao bookDao = new BookDao(); Book book = new Book(); PageBean pageBean = new PageBean(); List<Book> list = bookDao.list(book, pageBean); for (Book book1 : list) { System.out.println(book1.toString()); } } @Test public void text2() throws Exception { System.out.println("Text2..."); BookDao bookDao = new BookDao(); Book book = new Book(); book.setBname("圣墟"); PageBean pageBean = new PageBean(); // 设置页码 pageBean.setPage(2); pageBean.setPagination(true); List<Book> list = bookDao.list(book, pageBean); for (Book book1 : list) { System.out.println(book1.toString()); } }
3.1 直接运行界面结果
将同时运行输出所有内容
3.2 单击方法名运行
运行结果:
三、JSP通用分页实例(前端)
1. 分业核心思想
1. 第一次查询 :执行pageBean默认参数
bname=null page=1 rows=10 pagination=true
2. 第二次查询 :在输入框输入‘ 圣墟 ’ 查询 ,后台会拿到一下参数
bname=圣墟 page=1 rows=10 pagination=true
3. 第三次查询 :点击下一页
bname=圣墟 page=2 rows=10 pagination=true
4. 第四次查询:
结论 :相比上一次查询除了页码改变,其他参数都不改变,所以相比后端还需添加两个参数。
2. 优化PageBean工具类
package com.ycxw.utils; import java.util.HashMap; import java.util.Map; import javax.servlet.http.HttpServletRequest; /** * 分页工具类 * * @author 云村小威 */ public class PageBean { private int page = 1;// 页码 private int rows = 10;// 页大小 private int total = 0;// 总记录数 private boolean pagination = true;// 是否分页 // 上一次查询的url private String url; // 上一次查询所携带的查询条件 private Map<String, String[]> parameterMap = new HashMap<String, String[]>(); // 对pagebean进行初始化 public void setRequest(HttpServletRequest req) { // 初始化jsp页面传递过来的当前页 this.setPage(req.getParameter("page")); // 初始化jsp页面传递过来的页大小 this.setRows(req.getParameter("rows")); // 初始化jsp页面传递过来是否分页 this.setPagination(req.getParameter("pagination")); // 保留上一次的查询请求 this.setUrl(req.getRequestURL().toString()); // 保留上一次的查询条件 this.setParameterMap(req.getParameterMap()); } private void setPagination(String pagination) { // 只有填写了false字符串,才代表不分页 this.setPagination(!"false".equals(pagination)); } private void setRows(String rows) { //判空处理 if (StringUtils.isNotBlank(rows)) this.setRows(Integer.valueOf(rows)); } private void setPage(String page) { //判空处理 if (StringUtils.isNotBlank(page)) this.setPage(Integer.valueOf(page)); } /** * 获得起始记录的下标 * * @return */ public int getStartIndex() { return (this.page - 1) * this.rows; } // 上一页 public int getPrevPage() { return this.page > 1 ? this.page - 1 : this.page; } // 下一页 public int getNextPage() { return this.page < this.getMaxPage() ? this.page + 1 : this.page; } // 最大页 public int getMaxPage() { return this.total % this.rows == 0 ? this.total / this.rows : (this.total / this.rows) + 1; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } public Map<String, String[]> getParameterMap() { return parameterMap; } public void setParameterMap(Map<String, String[]> parameterMap) { this.parameterMap = parameterMap; } public PageBean() { super(); } public int getPage() { return page; } public void setPage(int page) { this.page = page; } public int getRows() { return rows; } public void setRows(int rows) { this.rows = 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; } @Override public String toString() { return "PageBean [page=" + page + ", rows=" + rows + ", total=" + total + ", pagination=" + pagination + "]"; } }
3. 自定义page标签描述文件
<!-- page.tld --> <taglib xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd" version="2.0"> <description>My custom tag library</description> <display-name>My Tag Library</display-name> <tlib-version>1.0</tlib-version><!-- 代表标签库的版本号 --> <short-name>w</short-name><!-- 你的标签库简称 --> <uri>com.ycxw</uri><!-- taglib引入标签名字 --> <tag> <name>page</name> <tag-class>com.ycxw.tag.PageTag</tag-class> <body-content>JSP</body-content> <attribute> <name>pageBean</name> <required>true</required> <rtexprvalue>true</rtexprvalue> </attribute> </tag> </taglib>
4. Page助手类
package com.ycxw.tag; import com.ycxw.utils.PageBean; import javax.servlet.jsp.JspException; import javax.servlet.jsp.JspWriter; import javax.servlet.jsp.tagext.BodyTagSupport; import java.io.IOException; import java.util.Map; import java.util.Set; /** * Page助手类 * * @author 云村小威 * */ 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 { // 获取流 JspWriter out = pageContext.getOut(); try { out.print(toHTML()); } catch (IOException e) { e.printStackTrace(); } return SKIP_BODY; } /** * JSP自定义页面内容展示 * * @return */ private String toHTML() { StringBuilder sb = new StringBuilder(); // 这里拼接的是一个上一次发送的请求以及携带的参数,唯一改变的就是页码 sb.append("<form id='pageBeanForm' action='" + pageBean.getUrl() + "' method='post'>"); sb.append("<input type='hidden' name='page'>"); // 重要设置拼接操作,将上一次请求参数携带到下一次 Map<String, String[]> paMap = pageBean.getParameterMap(); if (paMap != null && paMap.size() > 0) { Set<Map.Entry<String, String[]>> entrySet = paMap.entrySet(); for (Map.Entry<String, String[]> entry : entrySet) { for (String val : entry.getValue()) { if (!"page".equals(entry.getKey())) { sb.append("<input type='hidden' name='" + entry.getKey() + "' value='" + val + "'>"); } } } } sb.append("</form>"); /** * 页码数据配置 */ int page = pageBean.getPage(); //当前页码 int max = pageBean.getMaxPage();//最大页码 int before = page > 4 ? 4 : page - 1;//当前页码前面的页码 int after = 10 - 1 - before;//当前页码后面的页码 //如果最大页码没有10页,就显示当前页面后面的所有页码 max - page after = page + after > max ? max - page : after; // 初始页码和结束页码值判断 disabled boolean startFlag = page == 1; boolean endFlag = max == page; // 拼接分页条 sb.append("<ul class='pagination'>"); sb.append("<li class='page-item " + (startFlag ? "disabled" : "") + "'><a class='page-link' href='javascript:gotoPage(1)'>首页</a></li>"); sb.append("<li class='page-item " + (startFlag ? "disabled" : "") + "'><a class='page-link' href='javascript:gotoPage(" + pageBean.getPrevPage() + ")'><</a></li>"); // 代表了当前页的前4页 for (int i = before; i > 0; i--) { sb.append("<li class='page-item'><a class='page-link' href='javascript:gotoPage(" + (page - i) + ")'>" + (page - i) + "</a></li>"); } sb.append("<li class='page-item active'><a class='page-link' href='javascript:gotoPage(" + pageBean.getPage() + ")'>" + pageBean.getPage() + "</a></li>"); // 代表了当前页的后5页 for (int i = 1; i <= after; i++) { sb.append("<li class='page-item'><a class='page-link' href='javascript:gotoPage(" + (page + i) + ")'>" + (page + i) + "</a></li>"); } sb.append("<li class='page-item " + (endFlag ? "disabled" : "") + "'><a class='page-link' href='javascript:gotoPage(" + pageBean.getNextPage() + ")'>></a></li>"); sb.append("<li class='page-item " + (endFlag ? "disabled" : "") + "'><a class='page-link' href='javascript:gotoPage(" + pageBean.getMaxPage() + ")'>尾页</a></li>"); sb.append( "<li class='page-item go-input'><b>到第</b><input class='page-link' type='text' id='skipPage' name='' /><b>页</b></li>"); sb.append("<li class='page-item go'><a class='page-link' href='javascript:skipPage()'>确定</a></li>"); sb.append("<li class='page-item'><b>共" + pageBean.getTotal() + "条</b></li>"); sb.append("</ul>"); // 拼接分页的js代码 sb.append("<script type='text/javascript'>"); sb.append("function gotoPage(page) {"); sb.append("document.getElementById('pageBeanForm').page.value = page;"); sb.append("document.getElementById('pageBeanForm').submit();"); sb.append("}"); sb.append("function skipPage() {"); sb.append("var page = document.getElementById('skipPage').value;"); sb.append("if (!page || isNaN(page) || parseInt(page) < 1 || parseInt(page) > " + max + ") {"); sb.append("alert('请输入1~N的数字');"); sb.append("return;"); sb.append("}"); sb.append("gotoPage(page);"); sb.append("}"); sb.append("</script>"); return sb.toString(); } }
5. BookServlet类
package com.ycxw.serlvet; 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.ycxw.dao.BookDao; import com.ycxw.entity.Book; import com.ycxw.utils.PageBean; @WebServlet("/book.action") public class BookServlet extends HttpServlet { private static final long serialVersionUID = 1L; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { BookDao bookDao = new BookDao(); PageBean page = new PageBean(); // 调用pageBean初始化方法 page.setRequest(request); Book book = new Book(); // 获取模糊查询字段值并设置到book对象中 book.setBname(request.getParameter("bname")); try { // 调用BookDao模糊加分页查询方法 List<Book> list = bookDao.list(book, page); // 将对象保存到作用域中 request.setAttribute("books", list); request.setAttribute("pageBean", page); // 转发到分页界面 request.getRequestDispatcher("/BookPage.jsp").forward(request, response); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
6. JSP页面编写
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> <%@ taglib uri="com.ycxw" prefix="w"%> <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <!-- 导入bootstrap网络路径样式 --> <link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/4.5.0/css/bootstrap.css" rel="stylesheet"> <script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/4.5.0/js/bootstrap.js"></script> <title>书籍列表</title> <style type="text/css"> .page-item input { padding: 0; width: 40px; height: 100%; text-align: center; margin: 0 6px; } .page-item input, .page-item b { line-height: 38px; float: left; font-weight: 400; } .page-item.go-input { margin: 0 10px; } </style> </head> <body> <form class="form-inline" action="${pageContext.request.contextPath }/book.action" method="post"> <div class="form-group mb-2"> <input type="text" class="form-control-plaintext" name="bname" placeholder="请输入书籍名称"> </div> <button type="submit" class="btn btn-primary mb-2">查询</button> </form> <table class="table table-striped"> <thead> <tr> <th scope="col">书籍ID</th> <th scope="col">书籍名</th> <th scope="col">价格</th> </tr> </thead> <tbody> <!-- 遍历数据 --> <c:forEach items="${books }" var="b"> <tr> <td>${b.bid }</td> <td>${b.bname }</td> <td>${b.price }</td> </tr> </c:forEach> </tbody> </table> <!-- 自定义分页标签 --> <w:page pageBean="${pageBean }"></w:page> </body> </html>
7. 前端界面展示
总结 :
通用分页就是方便我们简化代码的,所以我们需要将它们共同的代码进行分装。但在我们还不熟悉的时候应该先不考虑封装,先将分页写出来,然后提取公共部分,进行封装和继承。通用分页步骤就是先分析分页条的属性,然后封装属性实体,然后编写dao层方法提取公共部分,接着编写分页助手类,为了避免出现乱码问题,在编写一个字符过滤器,过滤所有请求,最后在标签库描述文件中添加分页标签,就可以按自己需求来使用了。通用分页的思想就是将能提取的部分给提取出来然后拼接,供以后调用。