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

it2023-06-15  72

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

1.前言2.搭建MVC架构MVC概念JavaBean数据库相关配置lib中的jar包project目录 3.各JSP页面、URI、Servlet的关系4.前后端如何实现数据传递后端传给前端前端传给后端 5.代码JSPmainPage.jspshowAllBestsellers.jspadd.jspdelete.jspupdate.jsp beandaoservicewebFilterSelectServletAddServletDeleteServletUpdateServlet 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包

从上到下,各Jar包的作用依次为:

DruidDruidJSTLJDBCJSTL

project目录

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

src文件夹:

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

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

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

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

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 Bestsellers</h1> <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> <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("<script language='javascript'>alert('您的输入不规范。');" + "window.location.href='mainPage.jsp';</script>"); } 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("<script language='javascript'>alert('您的输入不规范。');" + "window.location.href='mainPage.jsp';</script>"); }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("<script language='javascript'>alert('您的输入不规范。');" + "window.location.href='mainPage.jsp';</script>"); } 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("<script language='javascript'>alert('您的输入不规范。');" + "window.location.href='mainPage.jsp';</script>"); }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("<script language='javascript'>alert('删除产品信息失败。可能的原因:数据库中不存在该产品。');" + "window.location.href='delete.jsp';</script>"); }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("<script language='javascript'>alert('修改产品信息失败。可能的原因:数据库中不存在该产品。');" + "window.location.href='update.jsp';</script>"); }else{ //注意:如果跳转页面的代码不放在else里,该弹弹窗的时候弹不出来!!! //3.跳转页面 //注意:应该写/toSelect,而不是showAllBestsellers.jsp,否则表格是空的 req.getRequestDispatcher("/toSelect").forward(req,resp); } } }

6.测试

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

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

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

最新回复(0)