【Jsp+Servlet】实现图书增删改查和分页显示

BaseDaoBaseServlet 见此项目 【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}" />
发布了50 篇原创文章 · 获赞 15 · 访问量 4767

猜你喜欢

转载自blog.csdn.net/qq_41133986/article/details/104571513