JavaWeb笔记--记录完整的JavaWeb案例--增删改查模块设计

1、MVC概念

MVC 全称:Model 模型、 View 视图、 Controller 控制器。

MVC 最早出现在 JavaEE 三层中的 Web 层,它可以有效的指导 Web 层的代码如何有效分离,单独工作。MVC 是一种思想,MVC 的理念是将软件代码拆分成为组件,单独开发,组合使用(目的还是为了降低耦合度)

View 视图:只负责数据和界面的显示,不接受任何与显示数据无关的代码,便于程序员和美工的分工合作——JSP/HTML。

Controller 控制器:只负责接收请求,调用业务层的代码处理请求,然后派发页面,是一个“调度者”的角色——Servlet。转到某个页面。或者是重定向到某个页面。

Model 模型:将与业务逻辑相关的数据封装为具体的 JavaBean类,其中不掺杂任何与数据处理相关的代码——JavaBean/domain/entity/pojo。

在这里插入图片描述

2、编写图书模块

2.1编写图书模块的数据库
2.2编写图书模块的 JavaBean
public class Book {
    private Integer id;//图书id
    private String name;//图书姓名
    private BigDecimal price;//图书价格
    private String author;//图书作者
    private Integer sales;//图书库存
    private Integer stock;//图书销量
    private String imgPath="static/img/default.jpg";//图书封面

    public Book() {
    }

    public Book(Integer id, String name, BigDecimal price, String author, Integer sales, Integer stock, String imgPath) {
        this.id = id;
        this.name = name;
        this.price = price;
        this.author = author;
        this.sales = sales;
        this.stock = stock;
        if(imgPath!=null&&"".equals(imgPath)){
            this.imgPath = imgPath;

        }
    }

    @Override
    public String toString() {
        return "Book{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", price=" + price +
                ", author='" + author + '\'' +
                ", sales=" + sales +
                ", stock=" + stock +
                ", imgPath='" + imgPath + '\'' +
                '}';
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public BigDecimal getPrice() {
        return price;
    }

    public void setPrice(BigDecimal price) {
        this.price = price;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    public Integer getSales() {
        return sales;
    }

    public void setSales(Integer sales) {
        this.sales = sales;
    }

    public Integer getStock() {
        return stock;
    }

    public void setStock(Integer stock) {
        this.stock = stock;
    }

    public String getImgPath() {
        return imgPath;
    }

    public void setImgPath(String imgPath) {
        if(imgPath!=null&&"".equals(imgPath)){
            this.imgPath = imgPath;

        }
    }
}
2.3编写图书模块的Dao接口 和Dao的实现类及测试 Dao
  • BookDao
public interface BookDao {
    //增加图书
    public int addBook(Book book);
    //删除图书
    public int deleteBookById(Integer id);
    //修改图书
    public int updateBook(Book book);
    //查询单种图书
    public Book queryBookById(Integer id);
    //查询多种图书
    public List<Book> queryBooks();
}
  • BookDaoImpl
public class BookDaoImpl extends BaseDao implements BookDao {
    @Override
    public int addBook(Book book) {
        String sql="INSERT INTO t_book(`name` , `author` , `price` , `sales` , `stock` , `img_path`)values(?,?,?,?,?,?)";
        return update(sql,book.getName(),book.getAuthor(),book.getPrice(),book.getSales(),book.getStock(),book.getImgPath());
    }

    @Override
    public int deleteBookById(Integer id) {
        String sql="delete from t_book where id=?";
        return update(sql,id);
    }

    @Override
    public int updateBook(Book book) {
        String sql="update t_book set `name`=? , `author`=? , `price`=? , `sales`=? , `stock`=? , `img_path`=? where id=?";
        return update(sql,book.getName(),book.getAuthor(),book.getPrice(),book.getSales(),book.getStock(),book.getImgPath(),book.getId());
    }

    @Override
    public Book queryBookById(Integer id) {
        String sql="select `id` , `name` , `author` , `price` , `sales` , `stock` , `img_path` imgPath from t_book where id=?";
        return queryForOne(Book.class,sql,id);
    }

    @Override
    public List<Book> queryBooks() {
        String sql="select `id` , `name` , `author` , `price` , `sales` , `stock` , `img_path` imgPath from t_book";
        return queryForList(Book.class,sql);
    }
    }
  • 一定要测试!一定要测试!一定要测试!
2.4编写图书模块的Service接口和Service的实现类及测试 Service
  • 编写BookService
public interface BookService {
    //添加
    public void addBook(Book book);
    //删除
    public void deleteBookById(Integer id);
    //修改
    public void updateBook(Book book);
    //查询
    public Book queryBookById(Integer id);
    //查询
    public List<Book> queryBooks();

    Page<Book> page(int pageNo, int pageSize);
}
  • 编写BookServiceImpl
public class BookServiceImpl implements BookService {
    //service一般都是依赖于dao,去操作访问数据库
    private BookDao bookDao=new BookDaoImpl();
    @Override
    public void addBook(Book book) {
        bookDao.addBook(book);
    }

    @Override
    public void deleteBookById(Integer id) {
        bookDao.deleteBookById(id);
    }

    @Override
    public void updateBook(Book book) {
        bookDao.updateBook(book);
    }

    @Override
    public Book queryBookById(Integer id) {
        return bookDao.queryBookById(id);
    }

    @Override
    public List<Book> queryBooks() {
        return bookDao.queryBooks();
    }

    @Override
    public Page<Book> page(int pageNo, int pageSize) {
        Page<Book> page = new Page<>();
        //设置当前页码
        page.setPageNo(pageNo);
        //设置每页显示的数量
        page.setPageSize(pageSize);
        //设置总记录数
        Integer pageTotalCount=bookDao.queryForPageTotalCount();
        page.setPageTotalCount(pageTotalCount);
        //求总页码
        Integer pageTotal=pageTotalCount/pageSize;
        if(pageTotalCount%pageSize>0){
            pageTotal+=1;
        }
        //设置总页码
        page.setPageTotal(pageTotal);
        //设置当前页数据
        //球当前页数据的开始索引
        int begin=(page.getPageNo()-1)*pageSize;
        List<Book> items=bookDao.queryForPageItems(begin,pageSize);
        page.setItems(items);

        return page;
    }
}

  • 一定要测试!一定要测试!一定要测试!只有测试才能检查自己的代码有没有错误

3、编写图书模块的 Web 层,和页面联调测试

3.1查找图书
  • 分析

JSP页面不可以直接访问到持久层,必须由web层控制service层去访问持久层

在这里插入图片描述

  • 1、通过Servlet程序访问bookService.queryBooks()查询全部图书,把全部图书保存到Request域中
protected void list(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    //通过bookService查询全部图书
    List<Book> books = bookService.queryBooks();
    //把全部图书保存到Request域中
    req.setAttribute("books",books);
    //请求转发到/pages/manager/book_manager.jsp
    req.getRequestDispatcher("/pages/manager/book_manager.jsp").forward(req,resp);
}
  • 2、从Request域中获取全部图书信息,通过JSTL标签库遍历输出
<c:forEach items="${requestScope.books}" 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="manager/bookServlet?action=getBook&id=${book.id}&method=update">修改</a></td>
		<td><a class="deleteClass" href="manager/bookServlet?action=delete&id=${book.id}">删除</a></td>
	</tr>
</c:forEach>
  • 3、修改请求地址
<a href="manager/bookServlet?action=list">图书管理</a>
  • 关于manager的解释
    在这里插入图片描述

为了更好地区分地址,在配置web.xml时,给servlet添加上相应的标志

3.2添加图书
  • 分析
    在这里插入图片描述
    protected void add(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //1、获取请求的参数==封装成为book对象
        Book book= WebUtils.copyParamToBean(req.getParameterMap(),new Book());
        //2、调用BookService.addBook保存图书
        bookService.addBook(book);
        //3、跳到图书列表页面
        //问题----->表单重复提交:当用户提交完请求,浏览器惠济路最后一次请求的全部信息,当用户按下功能键F5后,就会发起浏览器记录的最后一次请求
//        req.getRequestDispatcher("/");所以此时不可以使用请求转发,请求转发是一次请求
        resp.sendRedirect(req.getContextPath()+"/manager/bookServlet?action=list");
        /**
         * 2.那么一个完整的url地址,基本格式如下:
         * https://host:port/path?xxx=aaa&ooo=bbb
         * --http/https:这个是协议类型,如图中1所示
         * --host:服务器的IP地址或者域名,如图中2所示
         * --port:HTTP服务器的默认端口是80,这种情况下端口号可以省略。
         * 如果使用了别的端口,必须指明,例如:192.168.3.111:8080,这里的8080就是端口
         * --path:访问资源的路径,如图中3所示/s (图中3是把path和请求参数放一起了)
         * --?:url里面的?这个符号是个分割线,用来区分问号前面的是path,问号后面的是参数
         * --url-params:问号后面的是请求参数,格式:xxx=aaa,如图4区域就是请求参数
         * --&:多个参数用&符号连接
         */
    }
  • 表单重复提交问题

当用户提交完请求,浏览器会记录最后一次请求的全部信息,当用户按下功能键F5后,就会发起浏览器记录的最后一次请求

  • 隐藏域的引入

作用:
1 、隐藏域在页面中对于用户是不可见的,在表单中插入隐藏域的目的在于收集或发送信息,以利于被处理表单的程序所使用。浏览者单击发送按钮发送表单的时候,隐藏域的信息也被一起发送到服务器。

2、有些时候我们要给用户一信息,让他在提交表单时提交上来以确定用户身份,如sessionkey,等等.当然这些东西也能用cookie实现,但使用隐藏域就简单的多了.而且不会有浏览器不支持,用户禁用cookie的烦恼。
3、有些时候一个form里有多个提交按钮,怎样使程序能够分清楚到底用户是按那一个按钮提交上来的呢?我们就可以写一个隐藏域,然后在每一个按钮处加上οnclick=”document.form.command.value=”xx”“然后我们接到数据后先检查command的值就会知道用户是按的那个按钮提交上来的。
4 、有时候一个网页中有多个form,我们知道多个form是不能同时提交的,但有时这些form确实相互作用,我们就可以在form中添加隐藏域来使它们联系起来。
5 、javascript不支持全局变量,但有时我们必须用全局变量,我们就可以把值先存在隐藏域里,它的值就不会丢失了

  • 修改访问地址
		<table>
			<c:forEach items="${requestScope.page.items}" 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="manager/bookServlet?action=getBook&id=${book.id}&method=update">修改</a></td>
					<td><a class="deleteClass" href="manager/bookServlet?action=delete&id=${book.id}">删除</a></td>
				</tr>
			</c:forEach>
			<tr>
				<td></td>
				<td></td>
				<td></td>
				<td></td>
				<td></td>
				<td></td>
				<td><a href="pages/manager/book_edit.jsp?method=add">添加图书</a></td>
			</tr>	
		</table>	
			<form action="manager/bookServlet" method="get">
<%--				隐藏域,告诉服务器调用哪个方法--%>
				<input type="hidden" name="action" value="${param.method}">
<%--														 方法二	${ empty param.id ?"add" : "update"}       --%>
<%--														 方法三	${ empty requestScope.book ?"add" : "update"}       --%>
				<input type="hidden" name="id" value="${requestScope.book.id}">

				<table>
					<tr>
						<td>名称</td>
						<td>价格</td>
						<td>作者</td>
						<td>销量</td>
						<td>库存</td>
						<td colspan="2">操作</td>
					</tr>		
					<tr>
						<td><input name="name" type="text" value="${requestScope.book.name}"/></td>
						<td><input name="price" type="text" value="${requestScope.book.price}"/></td>
						<td><input name="author" type="text" value="${requestScope.book.author}"/></td>
						<td><input name="sales" type="text" value="${requestScope.book.sales}"/></td>
						<td><input name="stock" type="text" value="${requestScope.book.stock}"/></td>
						<td><input type="submit" value="提交"/></td>
					</tr>	
				</table>
			</form>

由于有时候一个网页中有多个form,我们知道多个form是不能同时提交的,但有时这些form确实相互作用,我们就可以在form中添加隐藏域来使它们联系起来。

3.3修改图书
  • 分析
    在这里插入图片描述
  • 得到要修改的图书的信息,并保存到Request域中
    /**
     * 得到要修改的图书的信息
     * @param req
     * @param resp
     * @return void
     * @author 许宝华
     * @creed: Talk is cheap,show me the code
     * @date 2021/4/24 16:30
     */
    protected void getBook(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //获取请求的参数
        int id = WebUtils.parseInt(req.getParameter("id"), 0);
        //调用bookService.queryById查询图书
        Book book = bookService.queryBookById(id);
        //保存到图书到request域中
        req.setAttribute("book",book);
        //请求转发到 pages/manager/book_edit.jsp页面
        req.getRequestDispatcher("/pages/manager/book_edit.jsp").forward(req,resp);
    }
  • 在页面显示要修改的数据
<table>
					<tr>
						<td>名称</td>
						<td>价格</td>
						<td>作者</td>
						<td>销量</td>
						<td>库存</td>
						<td colspan="2">操作</td>
					</tr>		
					<tr>
						<td><input name="name" type="text" value="${requestScope.book.name}"/></td>
						<td><input name="price" type="text" value="${requestScope.book.price}"/></td>
						<td><input name="author" type="text" value="${requestScope.book.author}"/></td>
						<td><input name="sales" type="text" value="${requestScope.book.sales}"/></td>
						<td><input name="stock" type="text" value="${requestScope.book.stock}"/></td>
						<td><input type="submit" value="提交"/></td>
					</tr>	
</table>
  • 实现update方法
    protected void update(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //获取请求的参数,封装成为book对象
        Book book = WebUtils.copyParamToBean(req.getParameterMap(), new Book());
        //调用bookService.updateBook(book)方法
        bookService.updateBook(book);
        //重定向回到图书管理页面
        resp.sendRedirect(req.getContextPath()+"/manager/bookServlet?action=list");

    }

req.getContextPath()+"/manager/bookServlet?action=list",在地址的前边加req.getContextPath()的原因是getContextPath()能解决相对路径的问题,可返回站点的根路径。

  • 解决 book_edit.jsp 页面,即要实现添加,又要实现修改操作。
			<c:forEach items="${requestScope.page.items}" 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="manager/bookServlet?action=getBook&id=${book.id}&method=update">修改</a></td>
					<td><a class="deleteClass" href="manager/bookServlet?action=delete&id=${book.id}">删除</a></td>
				</tr>
			</c:forEach>
			<tr>
				<td></td>
				<td></td>
				<td></td>
				<td></td>
				<td></td>
				<td></td>
				<td><a href="pages/manager/book_edit.jsp?method=add">添加图书</a></td>
			</tr>	
  • 分别给add、update添加一个method属性

方法一:<input type="hidden" name="action" value="${param.method}">

  • 判断id值是否为空

方法二:<input type="hidden" name="action" value="${ empty param.id ?"add" : "update"} ">

方法一:<input type="hidden" name="action" value="${ empty requestScope.book?"add" : "update"}">

3.4删除图书
  • 分析
    在这里插入图片描述
  • 在BookServlet中实现delete方法
    protected void delete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //获取请求的参数
        int id = WebUtils.parseInt(req.getParameter("id"), 0);
        //调用bookService
        bookService.deleteBookById(id);
        //重定向返回图书管理页面
        resp.sendRedirect(req.getContextPath()+"/manager/bookServlet?action=list");

    }
  • 由于req.getParameter(“id”)的返回值是一个字符串类型,每次都需要类型转换,大大增加了代码的冗余量,所以把类型转换写进工具类之中
    /**
     * 将字符串类型转换成为int类型
     * @param strInt
     * @param defaultValue 默认值
     * @return void
     * @author 许宝华
     * @creed: Talk is cheap,show me the code
     * @date 2021/4/22 10:07
            */
    public static int parseInt(String strInt,int defaultValue){
        try {
            return Integer.parseInt(strInt);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return defaultValue;
    }
  • 修改删除地址
			<c:forEach items="${requestScope.page.items}" 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="manager/bookServlet?action=getBook&id=${book.id}&method=update">修改</a></td>
					<td><a class="deleteClass" href="manager/bookServlet?action=delete&id=${book.id}">删除</a></td>
				</tr>
			</c:forEach>
  • 与用户界面进行交互
<script type="text/javascript">
	$(function (){
		//在事件的function函数中,有一个this对象,这个this对象,是正在响应事件的dom对象
		//给删除的a标签绑定单击事件,用于删除的确认提示操作
		$("a.deleteClass").click(function () {
			return confirm("你确定删除["+$(this).parent().parent().find("td:first").text()+"]么?");
		});
	})
</script>

3、心得和遇到的问题

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值