之前学习了MVC 设计模式、HTML、JSP(EL表达式、JSTL)、JDBC、MySql、Servlet、Filter等,在这个例子中加以巩固练习一下。虽然是一个简单的demo,但由于是初学Java web,写完了代码之后,觉得有必要整理一下思路并记录下来。值得记录的有两个方面:1.如何搭建MVC架构 2.各JSP页面是怎么通过URI、Servlet关联起来的 3.前后端怎么进行数据传递?后端查询得到的数据是怎么传给前端的,用户在前端提交的表单信息怎么传给后端。
该例子实现了数据库中表的增删改查,具体的效果请见测试一节。
MVC:Model模型,View视图,Controller控制器
Model模型:负责操作数据库(dao包,bean包)
View视图:给用户呈现的页面,html、JSP页面
Controller控制器:负责前后端的交互(web包,service包)
分为2类(bean和dao),
封装业务逻辑的JavaBean(即dao)
封装数据的JavaBean(即bean,又叫:实体类):对应于数据库中的一张表,即数据库中有个Student表,项目中就有个Student.java类。
为了能够正常使用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类
创建bean包、dao包、service包、web包,这4个包必须创建。util包放工具类,可要可不要。
对于dao和service而言,都采用接口+实现类的模式,impl包里放实现类。
将JSP页面、URI、Servlet的关系绘制成下图,清晰明了。在写该例子的代码时,有时候会感到思维混乱,页面被各URI和、Servlet关联着,跳过来跳过去的,在写代码的同时,画出下图可能有助于理清思路。
蓝色方框:JSP页面
绿色框:Servlet
红色字:URI
白色框:form表单
下划线:html中的a标签(链接)
注意:本图省略了Filter,每个URI都会先经过Filter。Filter的作用:1.设置编码方式 2.判断用户填写的form是否合乎规范。
后端从数据库里查询出来的数据需要传给前端。
后端:
在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");
<%@ 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>
<%@ 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>
<%@ 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>
<%@ 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>
<%@ 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>
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;
}
}
接口和实现类
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;
}
}
接口和实现类
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);
}
}
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");
}
}
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);
}
}
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);
}
}
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);
}
}
}
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);
}
}
}
测试1:正常流程的增删改查
测试2:filter过滤掉用户不规范的输入
测试3:删除或更新时,数据库中不存在该数据