BaseDao
和BaseServlet
见此项目 【JSP+Servlet】实现登录和注册
文章目录
1. 数据库建表
book表
2. 对应的javaBean(Bean/Book)
public class Book {
private int id;
private String name;
private String author;
private int price;
3. Dao层操作数据库
BookDaoImpl
public class BookDaoImpl extends BaseDao<Book> implements BookDao {
@Override
public List<Book> getAllBook() {
String sql = "select id, name, author, price from book";
List<Book> beanList = getBeanList(sql);
return beanList;
}
// 根据id获取一个图书信息
@Override
public Book getBook(Book book) {
String sql = "select id, name, author, price from book where id = ?";
Book bean = getBean(sql, book.getId());
return bean;
}
// 添加图书
@Override
public boolean addBook(Book book) {
String sql = "insert into book (name, author, price,sales ) values(?,?,?,?,?,?)";
int update = update(sql, book.getName(), book.getAuthor(), book.getPrice());
return update>0;
}
// 删除图书
@Override
public boolean delBook(Book book) {
String sql = "delete from book where id = ?";
int update = update(sql, book.getId());
if (update>0)
return true;
else
return false;
}
// 修改图书
@Override
public boolean updateBook(Book book) {
String sql = "update book set name = ? ,author = ? ,price = ? , where id = ?";
int update = update(sql, book.getName(), book.getAuthor(), book.getPrice(), book.getId());
return update>0;
}
4. 业务逻辑层 service
BookServiceImpl
public class BookServiceImpl implements BookService {
private BookDao bd = new BookDaoImpl();
@Override
public boolean add(Book book) {
return bd.addBook(book);
}
@Override
public boolean delete(Book book) {
return bd.delBook(book);
}
@Override
public boolean update(Book book) {
return bd.updateBook(book);
}
@Override
public Book getOne(Book book) {
return bd.getBook(book);
}
@Override
public List<Book> getAll() {
return bd.getAllBook();
}
}
5. Servlet 控制器Controller,用来控制页面转发
-
显示所有图书
点击图书管理-》交给servlet->查出数据-》交给页面显示
-
index
界面a标签href调用BookManagerServlet
index.html
<a href="/BookManagerServlet?method=list">图书管理</a>
BookManagerServlet
list() 处理显示图书列表的请求
public void list(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { List<Book> books = bookService.queryAllBook(); request.setAttribute("books", books); request.getRequestDispatcher("/pages/book_manager.jsp").forward(request,response); }
book_manager.jsp
<tr> <td>名称</td> <td>价格</td> <td>作者</td> <td>销量</td> <td>库存</td> <td colspan="2">操作</td> </tr> <c:forEach items="${ requestScope.list }" var="book"> <tr> <td>${ book.name }</td> <td>${ book.price }</td> <td>${ book.author }</td> <td>${ book.sales }</td> <td>${ book.stock }</td> <td><a href="#">修改</a></td> <td><a href="#">删除</a></td> </tr> </c:forEach>
-
-
添加图书
book_edit
<form action="/BookManagerServlet" method="post"> <input type="hidden" name="pageNo" value="${add }" />
protected void add(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 将提交的图书信息封装为book对象,表单的name应该和对象的属性一致 Book book = WebUtils.param2bean2(request,new Book()); // 将提交的图书保存到数据库 boolean b = bookService.add(book); // 保存成功,重回列表界面 response.sendRedirect(request.getContextPath()+"/BookManagerServlet?method=list"); }
-
删除图书
用户点击删除-》servlet接受请求-》按照图书id删除图书-》返回图书列表界面
<a class="deleteBtn" href="/BookManagerServlet?method=delete&id=${book.id}">删除</a>
protected void delete(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 封装要删除的Bok Book book = WebUtils.param2bean2(request,new Book()); //删除 bookService.delete(book); // 返回 response.sendRedirect(request.getContextPath()+"/BookManagerServlet?method=list"); }
-
修改图书
- 首先先要在servlet根据id查找图书,将图书信息显示到修改页面
<a href="manage/BookManagerServlet?method=getBook?id=${book.id}">修改</a>
protected void getBook(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 按照id查找图书
Book book = WebUtils.param2bean2(request,new Book());
// 获取详细信息
Book one = bookService.getOne(book);
// 回到编辑界面进行显示,放在域中
request.setAttribute("book",one);
// 转发到界面
request.getRequestDispatcher("/pages/book_edit.jsp");
}
book_edit
修改/添加界面
<form action="/BookManagerServlet" method="post">
<input type="hidden" name="pageNo" value="${add }" />
<tr>
<td><input name="name" type="text" value="${ book.title }"/></td>
<td><input name="price" type="text" value="${ book.price }"/></td>
<td><input name="author" type="text" value="${ book.author }"/></td>
<td><input name="sales" type="text" value="${ book.sales }"/></td>
<td><input name="stock" type="text" value="${ book.stock }"/></td>
<td><input type="submit" value="提交"/></td>
</tr>
问题: 修改和增加公用一个界面book_edit.jsp, 都指向同一个方法add, 点击提交,都调用了add方法,无法动态的更换method显示更改后的图书信息
book_edit
修改value为update 或者 form表单修改为 /BookManagerServlet?method=update
<form action="/BookManagerServlet" method="post">
<input type="hidden" name="pageNo" value="${update }" />
BookManagerServlet
protected void update(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 按照id查找图书
Book book = WebUtils.param2bean2(request,new Book());
// 由于添加和修改操作,封装出的Book id有差别,所以可以通过id直接判别
if(book.getId()==0){
//添加
bookService.add(book);
}else{
//修改
bookService.update(book);
}
response.sendRedirect(request.getContextPath()+"/BookManagerServlet?method=list");
}
6. 图书分页
作用:显示部分信息,减轻服务器负担
分页原理:select * from bs_book limit
起始的索引,要取出多少个数据
要做出分页功能,将参数(起始的索引)设置为动态改变的即可
分页模型Page:
select * from bs_book limit index,size;
当前是第几页 int pageNo;
共多少页 int totalPage;
共多少条记录: int totalCount;
每页显示多少条记录: int pageSize; (=size)
数据库查询的起始索引: int index; (根据当前是第几页算出索引)
使用泛型的目的是因为其他模块也可能需要分页
-
创建Bean层的分页模型
Page
public class Page<T> { // 总共的记录数 查询得到 select count(*) private int totalCount; // 每页显示的记录数 可以设定 private int pageSize = 4; // 总的页数 计算得到 公式:总记录数 / 每页显示记录数 private int totalPage; // 当前页码 传进来的参数 private int pageNo; // 从哪个索引开始查 计算得到 private int index; // 是否有下一页 判断得到 private boolean hasNext; // 是否有下一页 判断得到 private boolean hasPrev; // 封装的当前页的数据集合 查询出来设置进去的 select * from bs_book limit index, size; private List<T> pageData; @Override public String toString() { return "Page{" + "totalCount=" + totalCount + ", pageSize=" + pageSize + ", totalPage=" + totalPage + ", pageNo=" + pageNo + ", index=" + index + ", hasNext=" + hasNext + ", hasPrev=" + hasPrev + ", pageData=" + pageData + '}'; } public Page() { super(); } public Page(int totalCount, int pageSize, int totalPage, int pageNo, int index, boolean hasNext, boolean hasPrev, List<T> pageData) { this.totalCount = totalCount; this.pageSize = pageSize; this.totalPage = totalPage; this.pageNo = pageNo; this.index = index; this.hasNext = hasNext; this.hasPrev = hasPrev; this.pageData = pageData; } public int getTotalCount() { return totalCount; } public void setTotalCount(int totalCount) { this.totalCount = totalCount; } public int getPageSize() { return pageSize; } public void setPageSize(int pageSize) { this.pageSize = pageSize; } //计算总页数,向上取整 public int getTotalPage() { int t =getTotalCount()/getPageSize(); if(!(getTotalCount()%getPageSize() == 0)) t = t+1; return t; } public void setTotalPage(int totalPage) { this.totalPage = totalPage; } public int getPageNo() { return pageNo; } public void setPageNo(int pageNo) { this.pageNo = pageNo; } // 计算索引值 public int getIndex() { // 每页显示4条 // 页码 开始索引 结束索引 // 1 0 3 // 2 4 7 // 3 8 11 int index = (getPageNo()-1) * pageSize; return index; } //不允许修改index 删除setIndex方法 // 是否有下一页 public boolean isHasNext() { return getPageNo()<getTotalPage(); } // 是否有上一页 public boolean isHasPrev() { return getPageNo()>1; } public List<T> getPageData() { return pageData; } public void setPageData(List<T> pageData) { this.pageData = pageData; } }
-
dao层
List getPageList(int index, int pageSize);
(Dao层就先返回List原始数据, 在Service层在进行封装成Book)
获取总记录数的方法:int getTotalCount();
BookDaoImpl
@Override public List<Book> getPageList(int index, int size) { String sql = "select id, name, author, price from book limit ?,?"; return getBeanList(sql, index, size); } @Override public int getTotalCount() { String sql = "select count(*) from book"; Object object = getSingleValue(sql); // object->int int i = Integer.parseInt(object.toString()); return i; }
BaseDao
/** * 查询单个值,用在BookDao获取数据库总记录数 * @param sql * @param params * @return */ public Object getSingleValue(String sql, Object ...params){ Object query = null; Connection connection = JDBCUtils.getConnection(); try { // ScalarHandler封装单个数据 query = queryRunner.query(connection, sql, new ScalarHandler(), params); } catch (SQLException e) { e.printStackTrace(); } finally { JDBCUtils.closeConnection(connection); } return query; }
-
Service层
BookService
/** * 获取分页数据 * @param pageNo 当前是第几页 request传过来的数据是String类型,在函数里面再进行转型 * @param pageSize * @return */ @Override public Page<Book> getPage(String pageNo, String pageSize) { // 1. 将用户传入的数据先封装部分 Page<Book> page = new Page<Book>(); // 将用户传入的数据转型并封装,设置默认值 int pn = 1; int ps = page.getPageSize(); pn = Integer.parseInt(pageNo); ps = Integer.parseInt(pageSize); // 2. 因为要使用当前总记录,所以需要查询数据库 //先要设置页面大小 page.setPageSize(ps); int totalCount = bd.getTotalCount(); // 获取总记录数 // 再设置总记录数(这样才能据此算出总页码) page.setTotalCount(totalCount); page.setPageNo(pn); // 3. 查询数据并封装 List<Book> list = bd.getPageList(page.getIndex(), page.getPageSize()); page.setPageData(list); return page; }
-
Servlet层
第一次请求图书列表应该只显示第一页数据
page()
book_manager.jsp
<c:forEach items="${ requestScope.page.pageData }" var="book">
BookManagerServlet.java
/** * 显示分页数据 * @param request * @param response * @throws ServletException * @throws IOException */ protected void page(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 用户点击图书管理显示部分数据,页码应该是由用户传进来的 // 动态获取页码参数 String pn = request.getParameter("pn"); Page<Book> page = bookService.getPage(pn, "4"); // 将第一页数据放到页面显示 request.setAttribute("page",page); // 交给页面 request.getRequestDispatcher("/pages/book_manager.jsp").forward(request,response); }
-
前端显示分页信息
book_manager.jsp
<div id="page_nav"> <a href="manage/BookManagerServlet?method=page&pn=1">首页</a> <c:if test="${page.hasPrev}"> <a href="manage/BookManagerServlet?method=page&pn=${page.pageNo-1}">上一页</a> </c:if> <%--当前页码--%> <%--显示所有页码--%> <c:forEach begin = "1" end = "${page.totalPage}" var = "pnum"> <%--判断当前遍历的页码是否是当前页码,如果是则不加连接--%> <c:if test = "${pnum == page.pageNo}"> 【${page.pageNo}】 </c:if> <c:if test = "${pnum != page.pageNo}"> <a href="manage/BookManagerServlet?method=page&pn=${pnum}">${pnum}</a> </c:if> </c:forEach> <c:if test="${page.hasNext}"> <a href="manage/BookManagerServlet?method=page&pn=${page.pageNo+1}">下一页</a> </c:if> <a href="manage/BookManagerServlet?method=page&pn=${page.totalPage}">末页</a> 共${page.totalPage}页,${page.totalCount}条记录 到第<input value="${page.pageNo}" name="pn" id="pn_input"/>页 <input type="button" value="确定" id = "gotoPage"> </div>
解决显示页码过多问题
相当于显示出当前页码的前两页和后两页
- 总页码五页以内,全部显示
- begin = 1 ,end = totalPage
- 总页码五页以上
- 当前页码< 3 显示1-5
- 当前页码>=3
- 当前页码+2>总页码
- 总页码五页以内,全部显示
<%--总页码五页以内--%>
<c:if test ="${page.totalPage<=5}">
<!--给begin和end动态赋值-->
<c:set var = "begin" value = "1" scope ="page"></c:set>
<c:set var = "end" value = "${page.totalPage}" scope ="page"></c:set>
</c:if>
<%--总页码五页以外--%>
<c:if test ="${page.totalPage>5}">
<c:if test="${page.pageNo<=3}">
<c:set var = "begin" value = "1" scope ="page"></c:set>
<c:set var = "end" value = "5" scope ="page"></c:set>
</c:if>
<c:if test="${page.pageNo>3}">
<c:set var = "begin" value = "${page.pageNo-2}" scope ="page"></c:set>
<c:set var = "end" value = "${page.pageNo+2}" scope ="page"></c:set>
</c:if>
<c:if test="${page.pageNo+2 >= page.totalPage}">
<c:set var = "begin" value = "${page.totalPage-4}" scope ="page"></c:set>
<c:set var = "end" value = "${page.totalPage}" scope ="page"></c:set>
</c:if>
</c:if>
<c:forEach begin = "${begin}" end = "${end}" var = "pnum">
修改删除优化
修改删除后跳转在当前页面而不是首页
利用Http协议的请求头
修改不能这样用:因为修改请求来源于getBook方法,而不是page方法
protected void delete(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// Http协议 请求头 Referer代表我从哪里来
String string = request.getHeader("Referer");
// 封装要删除的Bok
Book book = WebUtils.param2Bean(request,new Book());
//删除
bookService.delete(book);
// 返回
response.sendRedirect(string);
}
protected void update(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String pn = request.getParameter("pn");
// 按照id查找图书
Book book = WebUtils.param2Bean(request,new Book());
// 由于添加和修改操作,封装出的Book id有差别,所以可以通过id直接判别
if(book.getId()==0){
//添加
bookService.add(book);
}else{
//修改
bookService.update(book);
}
//跳转到请求头为了修改后还停留在此界面而不是跳转到首页
response.sendRedirect(request.getContextPath()+"/manage/BookManagerServlet?method=page&pn="+pn);
}
<%--带上正在修改的页数--%>
<input type="hidden" name="pageNo" value="${param.pn}" />