MVC设计模式+Servlet+Filter【练习】搭建 MVC 架构,实现数据的增删改查

搭建 MVC 架构,实现数据的增删改查

  • 1.前言
  • 2.搭建MVC架构
    • MVC概念
    • JavaBean
    • 数据库相关配置
    • lib中的jar包
    • project目录
  • 3.各JSP页面、URI、Servlet的关系
  • 4.前后端如何实现数据传递
    • 后端传给前端
    • 前端传给后端
  • 5.代码
    • JSP
      • mainPage.jsp
      • showAllBestsellers.jsp
      • add.jsp
      • delete.jsp
      • update.jsp
    • bean
    • dao
    • service
    • web
      • Filter
      • SelectServlet
      • AddServlet
      • DeleteServlet
      • UpdateServlet
  • 6.测试

1.前言

之前学习了MVC 设计模式、HTML、JSP(EL表达式、JSTL)、JDBC、MySql、Servlet、Filter等,在这个例子中加以巩固练习一下。虽然是一个简单的demo,但由于是初学Java web,写完了代码之后,觉得有必要整理一下思路并记录下来。值得记录的有两个方面:1.如何搭建MVC架构 2.各JSP页面是怎么通过URI、Servlet关联起来的 3.前后端怎么进行数据传递?后端查询得到的数据是怎么传给前端的,用户在前端提交的表单信息怎么传给后端。

该例子实现了数据库中表的增删改查,具体的效果请见测试一节。

2.搭建MVC架构

MVC概念

MVC:Model模型,View视图,Controller控制器

Model模型:负责操作数据库(dao包,bean包)
View视图:给用户呈现的页面,html、JSP页面
Controller控制器:负责前后端的交互(web包,service包)

JavaBean

分为2类(bean和dao),
封装业务逻辑的JavaBean(即dao)
封装数据的JavaBean(即bean,又叫:实体类):对应于数据库中的一张表,即数据库中有个Student表,项目中就有个Student.java类。

  • 表名=类名,列名=属性名
  • public修饰的类,提供public 无参构造方法
  • 所有属性 都是private
  • 提供getter和setter方法

数据库相关配置

为了能够正常使用JDBC操作数据,以及使用Druid连接池,需要做以下工作:
1.创建lib文件夹,在idea里配置其为project library(过程略)
2.在lib里放有关数据库的jar包(Druid的jar包,JDBC的jar包)
3. src文件夹里放druid.properties文件,别放错地方了,里边的配置要改一下(数据库的名字)
4. 创建util包,util里放DruidUtil.java文件,这是一个工具类,方便使用连接池
5. dao的impl实现类要继承DruidUtil类

lib中的jar包

MVC设计模式+Servlet+Filter【练习】搭建 MVC 架构,实现数据的增删改查_第1张图片
从上到下,各Jar包的作用依次为:

  1. Druid
  2. Druid
  3. JSTL
  4. JDBC
  5. JSTL

project目录

创建bean包、dao包、service包、web包,这4个包必须创建。util包放工具类,可要可不要。
对于dao和service而言,都采用接口+实现类的模式,impl包里放实现类。

MVC设计模式+Servlet+Filter【练习】搭建 MVC 架构,实现数据的增删改查_第2张图片

src文件夹:
MVC设计模式+Servlet+Filter【练习】搭建 MVC 架构,实现数据的增删改查_第3张图片

3.各JSP页面、URI、Servlet的关系

将JSP页面、URI、Servlet的关系绘制成下图,清晰明了。在写该例子的代码时,有时候会感到思维混乱,页面被各URI和、Servlet关联着,跳过来跳过去的,在写代码的同时,画出下图可能有助于理清思路。

蓝色方框:JSP页面
绿色框:Servlet
红色字:URI
白色框:form表单
下划线:html中的a标签(链接)

注意:本图省略了Filter,每个URI都会先经过Filter。Filter的作用:1.设置编码方式 2.判断用户填写的form是否合乎规范。

MVC设计模式+Servlet+Filter【练习】搭建 MVC 架构,实现数据的增删改查_第4张图片

4.前后端如何实现数据传递

后端传给前端

后端从数据库里查询出来的数据需要传给前端。

后端:
在SelectServlet.java中,调用Service方法进行数据查询,查询出来的所有产品信息存储在List中,将List存入request域。

req.setAttribute("bestsellers",bsList);//将产品信息存入request域

前端:
在showAllBestsellers.jsp中,通过EL表达式,将存在request域里的数据取出来。

<c:forEach items="${bestsellers}" var="bs">

前端传给后端

用户在前端填写的form表单里的信息,需要传递给后端,后端利用这些信息来做增、删、改。

前端:
用户点击表单的提交按钮,表单中的元素就会自动存储在request域,以键值对的形式,键:元素的name属性,值:用户填写的内容。

后端:
从request域里取数据,通过request对象的getParameter方法,传入参数:键。

String name = req.getParameter("name");

5.代码

JSP

mainPage.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>主页title>
head>
<body>
    <h1 style="color: coral">Nana Cosmetics Bestsellersh1>
    <h2>Menu:h2>
    <h2><a href="/toSelect">查看所有热销产品a>h2>
    <h2><a href="add.jsp">添加产品信息a>h2>
    <h2><a href="delete.jsp">删除产品信息a>h2>
    <h2><a href="update.jsp">修改产品信息a>h2>
body>
html>

showAllBestsellers.jsp

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>所有热销产品title>
head>
<body>
    <h1 style="color: coral">所有热销产品:h1>
    <table border="1" cellspacing="0" width="500px">

        <tr>
            
            <td>产品名称td>
            <td>价格td>
        tr>
        <%--使用JSTL和EL表达式来获取存入request域里的数据,是个List,存有所有产品的信息--%>
        <%--bs就是获取的单个的Bestseller对象,通过对象.属性名获取属性值--%>
        <c:forEach items="${bestsellers}" var="bs">
        <tr>
            <%--<td>${bs.id}td>--%>
            <td>${bs.brand}${bs.name}td><%--牌子和产品名连在一起,作为产品名称--%>
            <td>${bs.price}td>
        tr>
        c:forEach>

    table>
    <br><h4><a href="mainPage.jsp">点击返回主页a>h4>
body>
html>

add.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>添加产品信息title>
head>
<body>
    <h2>请输入需要添加的产品信息:h2>
    <form action="/toAdd" method="get">
        产品名:<input type="text" name="name"><br><br>
        品牌:<input type="text" name="brand"><br><br>
        价格:<input type="text" name="price"><br><br>
        <input type="submit" value="提交">
    form>
    <br><h4><a href="mainPage.jsp">点击返回主页a>h4>
body>
html>

delete.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>删除产品信息title>
head>
<body>
    <h2>请输入需要删除的产品信息:h2>
    <form action="/toDelete" method="get">
        产品名:<input type="text" name="name"><br><br>
        品牌:<input type="text" name="brand"><br><br>
        价格:<input type="text" name="price"><br><br>
        <input type="submit" value="提交">
    form>
    <br><h4><a href="mainPage.jsp">点击返回主页a>h4>
body>
html>

update.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>修改产品信息title>
head>
<body>

    <form action="/toUpdate" method="get">
        <h2>请输入修改前的产品信息,用于检索:h2>
        产品名:<input type="text" name="oldName"><br><br>
        品牌:<input type="text" name="oldBrand"><br><br>
        价格:<input type="text" name="oldPrice"><br><br>

        <h2>请输入新的产品信息:h2>
        产品名:<input type="text" name="newName"><br><br>
        品牌:<input type="text" name="newBrand"><br><br>
        价格:<input type="text" name="newPrice"><br><br>

        <input type="submit" value="提交">
    form>
    <br><h4><a href="mainPage.jsp">点击返回主页a>h4>

body>
html>

bean

package com.czn.bean;

//实体类(javabean)
//类名=表名  列名=属性名
//a. public修饰的类,提供public 无参构造方法
//b. 所有属性 都是private
//C. 提供getter和setter方法
public class Bestseller {
    private Integer id = null;//id在数据库里自动生成,递增
    private String name;
    private String brand;
    private Integer price;

    public Bestseller() {
    }

    public Bestseller(String name, String brand, int price) {
        this.name = name;
        this.brand = brand;
        this.price = price;
    }

    public String getName() {
        return name;
    }

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

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }

    public Integer getPrice() {
        return price;
    }

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

    public Integer getId() {
        return id;
    }

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

dao

接口和实现类

package com.czn.dao;

import com.czn.bean.Bestseller;

import java.util.List;

//定义操作数据库的方法:增删查改
//接口,都是抽象方法
public interface BestsellerDao {
    //查
    public List<Bestseller> selectAll();
    //增
    public boolean add(Bestseller bs);
    //改
    public boolean update(Bestseller oldBS,Bestseller newBS);
    //删
    public boolean delete(Bestseller bs );
}
package com.czn.dao.impl;

import com.czn.bean.Bestseller;
import com.czn.dao.BestsellerDao;
import com.czn.util.DruidUtil;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

//为了使用DruidUtil,需要继承它
public class BestsellerDaoImpl extends DruidUtil implements BestsellerDao {
    @Override
    public List<Bestseller> selectAll() {
        List list = new ArrayList();
        Connection conn = null;
        PreparedStatement state = null;
        ResultSet rs = null;

        try{
            conn = getConnection();//DruidUtil里的方法
            String sql = "select * from bestsellers";
            state = conn.prepareStatement(sql);
            rs = state.executeQuery();
            while(rs.next()){
                //创建Bestseller对象
                Bestseller bs = new Bestseller();
                bs.setId(rs.getInt("id"));
                bs.setBrand(rs.getString("brand"));
                bs.setName(rs.getString("name"));
                bs.setPrice(rs.getInt("price"));

                //将对象添加到list
                list.add(bs);
            }
        }catch (SQLException e){
            System.out.println("从数据库中取数据时出错。");
            e.printStackTrace();
        }finally {
            //关闭资源
            close(conn,state,rs);//DruidUtil里的方法
        }

        return list;
    }

    @Override
    public boolean add(Bestseller bs) {
        Connection conn = null;
        PreparedStatement state = null;
        int rowNumAffected = 0;

        try{
            conn = getConnection();//DruidUtil里的方法
            String sql = "insert into bestsellers(name,brand,price) value(?,?,?)";
            state = conn.prepareStatement(sql);

            state.setString(1,bs.getName());
            state.setString(2,bs.getBrand());
            state.setInt(3,bs.getPrice());

            rowNumAffected = state.executeUpdate();
        }catch (SQLException e){
            System.out.println("从数据库中取数据时出错。");
            e.printStackTrace();
        }finally {
            //关闭资源
            close(conn,state,null);
        }

        if(rowNumAffected > 0){
            return true;
        }
        return false;
    }

    @Override
    public boolean update(Bestseller oldBS,Bestseller newBS) {
        Connection conn = null;
        PreparedStatement state = null;
        int rowNumAffected = 0;

        try{
            conn = getConnection();//DruidUtil里的方法
            String sql = "update bestsellers set name=?,brand=?,price=? where name=? and brand=? and price=?";
            state = conn.prepareStatement(sql);

            state.setString(1,newBS.getName());
            state.setString(2,newBS.getBrand());
            state.setInt(3,newBS.getPrice());

            state.setString(4,oldBS.getName());
            state.setString(5,oldBS.getBrand());
            state.setInt(6,oldBS.getPrice());
            rowNumAffected = state.executeUpdate();
            System.out.println("更新数据库的数据时,影响表的行数:"+rowNumAffected);
        }catch (SQLException e){
            System.out.println("在数据库中更新数据时出错。");
            e.printStackTrace();
        }finally {
            //关闭资源
            close(conn,state,null);
        }

        if(rowNumAffected > 0){
            return true;
        }
        return false;
    }

    @Override
    public boolean delete(Bestseller bs ) {
        Connection conn = null;
        PreparedStatement state = null;
        int rowNumAffected = 0;

        try{
            conn = getConnection();//DruidUtil里的方法
            String sql = "delete from bestsellers where name=? and brand=? and price=?";
            state = conn.prepareStatement(sql);

            state.setString(1,bs.getName());
            state.setString(2,bs.getBrand());
            state.setInt(3,bs.getPrice());

            rowNumAffected = state.executeUpdate();
            System.out.println("删除数据库的数据时,影响表的行数:"+rowNumAffected);
        }catch (SQLException e){
            System.out.println("在数据库中删除数据时出错。");
            e.printStackTrace();
        }finally {
            //关闭资源
            close(conn,state,null);
        }

        if(rowNumAffected > 0){
            return true;
        }
        return false;
    }
}

service

接口和实现类

package com.czn.service;

import com.czn.bean.Bestseller;

import java.util.List;

//跟BestsellerDao接口一模一样
public interface BestsellerService {
    //查
    public List<Bestseller> selectAll();
    //增
    public boolean add(Bestseller bs);
    //改
    public boolean update(Bestseller oldBS,Bestseller newBS);
    //删
    public boolean delete(Bestseller bs);
}

import com.czn.service.BestsellerService;

import java.util.List;

public class BestsellerServiceImpl implements BestsellerService {
    //创建dao对象
    private BestsellerDao dao = new BestsellerDaoImpl();

    @Override
    public List<Bestseller> selectAll() {
        return dao.selectAll();
    }

    @Override
    public boolean add(Bestseller bs) {
        return dao.add(bs);
    }

    @Override
    public boolean update(Bestseller oldBS,Bestseller newBS) {
        return dao.update(oldBS,newBS);
    }

    @Override
    public boolean delete(Bestseller bs) {
        return dao.delete(bs);
    }
}

web

Filter

package com.czn.web.filters;


import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

//对所有请求、响应的编码方式进行设置
//判断用户输入是否符合规范:产品价格不能为非数/负数,产品名称不能为空,品牌名称不能为空
public class EncodingFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("初始化过滤器EncodingFilter");
    }

    @Override
    public void destroy() {
        System.out.println("销毁过滤器EncodingFilter");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("开始执行过滤器EncodingFilter");

        //强转类型
        HttpServletRequest req = (HttpServletRequest)servletRequest;
        HttpServletResponse resp = (HttpServletResponse)servletResponse;
        //设置编码方式
        req.setCharacterEncoding("utf-8");
        //设置服务器端编码
        resp.setCharacterEncoding("utf-8");
        //设置浏览器端解码,通知浏览器服务器发送的数据格式
        //踩坑:如果不写这句,提示登录失败的弹窗里的文字是乱码!
        resp.setContentType("text/html;charset=utf-8");

        //获得请求地址
        //这一句很有用!!!可以看到每次请求是什么
        String requestURI = req.getRequestURI();
        System.out.println("requestURI="+requestURI);//注意:第一次打印 requestURI=/

        //判断用户输入的价格是否符合规范
        //注意:这里的逻辑容易出错!!
        //碰到输入不规范的情况,就不要调用filterChain.doFilter(req,resp)了!不然会继续调用servlet的!
        //不是/toDelete或者/toAdd或者/toUpdate的请求的话,记着要调用filterChain.doFilter(req,resp)
        //以上两种情况,涉及到把filterChain.doFilter(req,resp)放在else里还是不放在else里,易错
        if(requestURI.endsWith("/toDelete")||requestURI.endsWith("/toAdd")){
            String price = req.getParameter("price");
            String name = req.getParameter("name");
            String brand = req.getParameter("brand");
            try {
                Integer.parseInt(price);
            }catch (NumberFormatException e){
                //如果进入了catch,后边的代码都不会执行了,不会调用filterChain.doFilter(req,resp),即不调用Servlet
                System.out.println("用户输入的价格不规范。");
                PrintWriter out = resp.getWriter();
                out.print("");
            }

            if(Integer.parseInt(price)<0||name == null||brand == null||price == null
                    ||name.length()==0||brand.length()==0||price.length()==0){
                System.out.println("用户输入不规范。");
                PrintWriter out = resp.getWriter();
                out.print("");
            }else{
                //将请求、响应传给下一个filter或者servlet
                filterChain.doFilter(req,resp);
            }
        }else if (requestURI.endsWith("/toUpdate")){
            String oldPrice = req.getParameter("oldPrice");
            String newPrice = req.getParameter("newPrice");
            String oldName = req.getParameter("oldName");
            String newName = req.getParameter("newName");
            String oldBrand =req.getParameter("oldBrand");
            String newBrand = req.getParameter("newBrand");
            try {
                Integer.parseInt(oldPrice);
                Integer.parseInt(newPrice);
            }catch (NumberFormatException e){
                //如果进入了catch,后边的代码都不会执行了,不会调用filterChain.doFilter(req,resp),即不调用Servlet
                System.out.println("用户输入的价格不规范。");
                PrintWriter out = resp.getWriter();
                out.print("");
            }
            if(oldPrice == null||Integer.parseInt(oldPrice)<0||oldName == null||oldBrand == null
                ||newPrice == null||Integer.parseInt(newPrice)<0||newName == null||newBrand == null
                    ||oldPrice .length()==0||oldName.length()==0||oldBrand.length()==0
                    ||newPrice.length()==0||newName.length()==0|| newBrand.length()==0){
                System.out.println("用户输入不规范。");
                PrintWriter out = resp.getWriter();
                out.print("");
            }else{
                //将请求、响应传给下一个filter或者servlet
                filterChain.doFilter(req,resp);
            }
        }else {
            //将请求、响应传给下一个filter或者servlet
            filterChain.doFilter(req,resp);
        }

        System.out.println("结束执行过滤器EncodingFilter");
    }
}

SelectServlet

package com.czn.web.servlets;

import com.czn.bean.Bestseller;
import com.czn.service.BestsellerService;
import com.czn.service.impl.BestsellerServiceImpl;

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 java.io.IOException;
import java.util.List;

@WebServlet(value = "/toSelect")
public class SelectServlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //1.接受参数

        //2.调取service方法
        BestsellerService bsService = new BestsellerServiceImpl();
        List<Bestseller> bsList = bsService.selectAll();
        //3.跳转页面
        req.setAttribute("bestsellers",bsList);//将产品信息存入request域
        req.getRequestDispatcher("showAllBestsellers.jsp").forward(req,resp);
    }
}

AddServlet

package com.czn.web.servlets;

import com.czn.bean.Bestseller;
import com.czn.service.BestsellerService;
import com.czn.service.impl.BestsellerServiceImpl;

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 java.io.IOException;


@WebServlet(value = "/toAdd")
public class AddServlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //1.接受参数
        String name = req.getParameter("name");
        String brand = req.getParameter("brand");
        String price = req.getParameter("price");

        Bestseller bs = new Bestseller();
        bs.setName(name);
        bs.setBrand(brand);
        bs.setPrice(Integer.parseInt(price));
        //2.调取service方法
        BestsellerService bsService = new BestsellerServiceImpl();
        boolean result = bsService.add(bs);
        //3.跳转页面
        //注意:应该写/toSelect,而不是showAllBestsellers.jsp,否则表格是空的
        req.getRequestDispatcher("/toSelect").forward(req,resp);
    }
}

DeleteServlet

package com.czn.web.servlets;

import com.czn.bean.Bestseller;
import com.czn.service.BestsellerService;
import com.czn.service.impl.BestsellerServiceImpl;

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 java.io.IOException;
import java.io.PrintWriter;

@WebServlet(value = "/toDelete")
public class DeleteServlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //1.接受参数
        String name = req.getParameter("name");
        String brand = req.getParameter("brand");
        String price = req.getParameter("price");

        Bestseller bs = new Bestseller();
        bs.setName(name);
        bs.setBrand(brand);
        bs.setPrice(Integer.parseInt(price));
        //2.调取service方法
        BestsellerService bsService = new BestsellerServiceImpl();
        boolean result = bsService.delete(bs);
        System.out.println("result:"+result);
        if(result == false){
            PrintWriter out = resp.getWriter();
            out.print("");
        }else{
            //注意:如果跳转页面的代码不放在else里,该弹弹窗的时候弹不出来!!!
            //3.跳转页面
            //注意:应该写/toSelect,而不是showAllBestsellers.jsp,否则表格是空的
            req.getRequestDispatcher("/toSelect").forward(req,resp);
        }

    }
}

UpdateServlet

package com.czn.web.servlets;

import com.czn.bean.Bestseller;
import com.czn.service.BestsellerService;
import com.czn.service.impl.BestsellerServiceImpl;

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 java.io.IOException;
import java.io.PrintWriter;

@WebServlet(value = "/toUpdate")
public class UpdateServlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //1.接受参数
        String oldName = req.getParameter("oldName");
        String oldBrand = req.getParameter("oldBrand");
        String oldPrice = req.getParameter("oldPrice");

        String newName = req.getParameter("newName");
        String newBrand = req.getParameter("newBrand");
        String newPrice = req.getParameter("newPrice");

        Bestseller oldBS = new Bestseller();
        oldBS.setName(oldName);
        oldBS.setBrand(oldBrand);
        oldBS.setPrice(Integer.parseInt(oldPrice));

        Bestseller newBS = new Bestseller();
        newBS.setName(newName);
        newBS.setBrand(newBrand);
        newBS.setPrice(Integer.parseInt(newPrice));
        //2.调取service方法
        BestsellerService bsService = new BestsellerServiceImpl();
        boolean result = bsService.update(oldBS,newBS);
        System.out.println("result:"+result);
        if(result == false){

            PrintWriter out = resp.getWriter();
            out.print("");
        }else{
            //注意:如果跳转页面的代码不放在else里,该弹弹窗的时候弹不出来!!!
            //3.跳转页面
            //注意:应该写/toSelect,而不是showAllBestsellers.jsp,否则表格是空的
            req.getRequestDispatcher("/toSelect").forward(req,resp);
        }
    }
}

6.测试

测试1:正常流程的增删改查

测试2:filter过滤掉用户不规范的输入

测试3:删除或更新时,数据库中不存在该数据

你可能感兴趣的:(java,servlet,jsp,web,数据库)