MVC是Model-View-Controller的简称,即模型-视图-控制器。
MVC是一种设计模式,它把应用程序分成三个核心模块:模型、视图、控制器,它们各自处理自己的任务。模型是应用程序的主体部分,模型表示业务数据和业务逻辑。一个模型能为多个视图提供数据。由于应用于模型的代码只需写一次就可以被多个视图重用,所以提高了代码的可重用性。视图是用户看到并与之交互的界面,作用如下:视图向用户显示相关的数据,接受用户的输入,不进行任何实际的业务处理。控制器接受用户的输入并调用模型和视图去完成用户的需求。控制器接收请求并决定调用哪个模型组件去处理请求,然后决定调用哪个视图来显示模型处理返回的数据。
把逻辑部分、访问数据库的部分放在Servlet,显示部分放在JSP页面。
发请求到服务器,服务器调用Servlet,Servlet做一个控制器,根据请求的情况取去调用Java类,Java类完成业务逻辑和访问数据库的操作,根据POJO的返回结果转向JSP,JSP进行显示,显示的时候可以使用一些标准标签库。
POJO里包含处理逻辑、业务逻辑,并去访问数据库。
Servlet根据不同的返回结果转向不同的JSP页面,转向的方式包括重定向和转发。
model:
controller:Servlet
view:JSP
一、查询和删除
1.1 查询
需求
点击超链接后在页面显示所有学生考试信息
数据库
字段
- flowId
- type
- idCard
- examCard
- studentName
- location
- grade
数据表截图
Bean
public class Student { private Integer flowId; private int type; private String idCard; private String examCard; private String studentName; private String location; private int grade; public Integer getFlowId() { return flowId; } public void setFlowId(Integer flowId) { this.flowId = flowId; } public int getType() { return type; } public void setType(int type) { this.type = type; } public String getIdCard() { return idCard; } public void setIdCard(String idCard) { this.idCard = idCard; } public String getExamCard() { return examCard; } public void setExamCard(String examCard) { this.examCard = examCard; } public String getStudentName() { return studentName; } public void setStudentName(String studentName) { this.studentName = studentName; } public String getLocation() { return location; } public void setLocation(String location) { this.location = location; } public int getGrade() { return grade; } public void setGrade(int grade) { this.grade = grade; } public Student(Integer flowId, int type, String idCard, String examCard, String studentName, String location, int grade) { this.flowId = flowId; this.type = type; this.idCard = idCard; this.examCard = examCard; this.studentName = studentName; this.location = location; this.grade = grade; } // 反射需要一个无参的构造器 public Student(){ } }
流程
页面
超链接的页面 c.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <a href="listAllStudent">List All Student</a> </body> </html>
c.jsp截图
转发的页面 students.jsp
<%@ page import="java.util.List" %> <%@ page import="com.satguigu.mvc.Student" %><%-- Created by IntelliJ IDEA. User: JieZhao Date: 2019/8/13 Time: 13:38 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <%= request.getAttribute("students") %> <br> <% List<Student> stus = (List<Student>)request.getAttribute("students"); %> <table> <tr> <th>FlowId</th> <th>Type</th> <th>IdCard</th> <th>ExamCard</th> <th>StudentName</th> <th>Location</th> <th>Grade</th> </tr> <% for (Student student: stus){ %> <tr> <td><%= student.getFlowId() %> </td> <td><%= student.getType() %> </td> <td><%= student.getIdCard() %> </td> <td><%= student.getExamCard() %> </td> <td><%= student.getStudentName() %> </td> <td><%= student.getLocation() %> </td> <td><%= student.getGrade() %> </td> </tr> <% }%> </table> </body> </html>
代码
Dao
public class StudentDao { public List<Student> getAll(){ List<Student> students = new ArrayList<>(); Connection connection = null; PreparedStatement preparedStatement = null; ResultSet resultSet = null; try{ String driverClass = "com.mysql.jdbc.Driver"; String url = "jdbc:mysql:///aidata"; String user = "root"; String passward = "root"; Class.forName(driverClass); connection = DriverManager.getConnection(url, user, passward); String sql = "SELECT flow_id, type, id_card, exam_card, sutdent_name, Location, Grade FROM examstudent"; preparedStatement = connection.prepareStatement(sql); resultSet = preparedStatement.executeQuery(); while (resultSet.next()){ int flowId = resultSet.getInt(1); int type = resultSet.getInt(2); String idCard = resultSet.getString(3); String examCard = resultSet.getString(4); String studentName = resultSet.getString(5); String location = resultSet.getString(6); int grade = resultSet.getInt(7); Student student = new Student(flowId, type, idCard, examCard, studentName, location, grade); students.add(student); } }catch (Exception e){ e.printStackTrace(); }finally { try{ if(resultSet != null){ resultSet.close(); } }catch (SQLException e){ e.printStackTrace(); } try{ if(preparedStatement != null){ preparedStatement.close(); } }catch (SQLException e){ e.printStackTrace(); } try{ if(connection != null){ connection.close(); } }catch (SQLException e){ e.printStackTrace(); } } return students; } }
Servlet
public class ListAllStudentsServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { StudentDao studentDao = new StudentDao(); List<Student> students = studentDao.getAll(); request.setAttribute("students", students); //结果添加到students属性里,存到request里 request.getRequestDispatcher("/students.jsp").forward(request, response); // 将request转发到students.jsp页面 } }
配置web.xml
<servlet> <servlet-name>listAllStudent</servlet-name> <servlet-class>com.aidata.mvc.ListAllStudentsServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>listAllStudent</servlet-name> <url-pattern>/listAllStudent</url-pattern> </servlet-mapping>
1.2 删除
students.jsp里添加删除按钮
Dao里添加删除方法
public void deleteByFlowId(Integer flowId){ List<Student> students = new ArrayList<>(); Connection connection = null; PreparedStatement preparedStatement = null; try { String driverClass = "com.mysql.jdbc.Driver"; String url = "jdbc:mysql:///aidata"; String user = "root"; String password = "root"; Class.forName(driverClass); connection = DriverManager.getConnection(url, user, password); String sql = "DELETE FROM examstudent WHERE flow_id = ?"; preparedStatement = connection.prepareStatement(sql); preparedStatement.setInt(1, flowId); preparedStatement.executeUpdate(); }catch (Exception e){ e.printStackTrace(); }finally { try{ if(preparedStatement != null){ preparedStatement.close(); } }catch (SQLException e){ e.printStackTrace(); } try{ if(connection != null){ connection.close(); } }catch (SQLException e){ e.printStackTrace(); } } }
Servlet添加删除的Servlet
public class DeleteStudentServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { String flowId = request.getParameter("flowId"); StudentDao studentDao = new StudentDao(); studentDao.deleteByFlowId(Integer.parseInt(flowId)); List<Student> students = studentDao.getAll(); request.setAttribute("students", students); request.getRequestDispatcher("/listAllStudent").forward(request, response); // 重定向到servlet } }
配置web.xml
<servlet> <servlet-name>deleteStudent</servlet-name> <servlet-class>com.aidata.mvc.DeleteStudentServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>deleteStudent</servlet-name> <url-pattern>/deleteStudent</url-pattern> </servlet-mapping>
二、案例
2.1 架构分析
下面开始做一个小案例:利用MVC模式对数据进行增删改查
没有业务层,直接由Servlet调用DAO,所以也没有事务操作,可以在DAO中直接获取Connection对象
采取MVC设计模式
使用到的技术:
- MVC设计模式:JSP、Servlet
- 数据库使用MySQL
- 连接数据库使用C3P0数据库连接池
- JDBC工具采用DBUtils
- 页面的提示操作采用jQuery
技术难点:
- 多个请求如何使用一个Servlet
- 模糊查询
- 在创建或修改的情况下,验证用户名已经被使用,并给出提示信息
2.2 DAO层
DAO 模式
DAO (DataAccessobjects 数据存取对象)是指位于业务逻辑和持久化数据之间实现对持久化数据的访问。通俗来讲,就是将数据库操作都封装起来。
对外提供相应的接口
在面向对象设计过程中,有一些"套路”用于解决特定问题称为模式。
DAO 模式提供了访问关系型数据库系统所需操作的接口,将数据访问和业务逻辑分离对上层提供面向对象的数据访问接口。
从以上 DAO 模式使用可以看出,DAO 模式的优势就在于它实现了两次隔离。
- 1、隔离了数据访问代码和业务逻辑代码。业务逻辑代码直接调用DAO方法即可,完全感觉不到数据库表的存在。分工明确,数据访问层代码变化不影响业务逻辑代码,这符合单一职能原则,降低了藕合性,提高了可复用性。
- 2、隔离了不同数据库实现。采用面向接口编程,如果底层数据库变化,如由 MySQL 变成 Oracle 只要增加 DAO 接口的新实现类即可,原有 MySQ 实现不用修改。这符合 "开-闭" 原则。该原则降低了代码的藕合性,提高了代码扩展性和系统的可移植性。
一个典型的DAO 模式主要由以下几部分组成。
- 1、DAO接口: 把对数据库的所有操作定义成抽象方法,可以提供多种实现。
- 2、DAO 实现类: 针对不同数据库给出DAO接口定义方法的具体实现。
- 3、实体类:用于存放与传输对象数据。
- 4、数据库连接和关闭工具类: 避免了数据库连接和关闭代码的重复使用,方便修改。
数据库
建立数据表
Create table customers( id int primary key auto_increment, name varchar(30) not null unique, address varchar(30), phone varchar(30) ); # 为 name 字段添加唯一约束 alter table customers add constraint name_uk unique(name);
数据表截图
C3P0数据源
使用eclipse
添加c3p0的jar包和mysql驱动的jar包到根目录的lib目录中
添加commons-dbutils-1.3.jar到根目录的lib目录中
添加c3p0的配置文件到src目录
c3p0-config.xml
<?xml version="1.0" encoding="UTF-8"?> <c3p0-config> <named-config name="mvcapp"> <!-- 指定连接数据源的基本属性 --> <property name="user">root</property> <property name="password">root</property> <property name="driverClass">com.mysql.jdbc.Driver</property> <property name="jdbcUrl">jdbc:mysql:///aidata</property> <!-- 若数据库中连接数不足时, 一次向数据库服务器申请多少个连接 --> <property name="acquireIncrement">5</property> <!-- 初始化数据库连接池时连接的数量 --> <property name="initialPoolSize">5</property> <!-- 数据库连接池中的最小的数据库连接数 --> <property name="minPoolSize">5</property> <!-- 数据库连接池中的最大的数据库连接数 --> <property name="maxPoolSize">10</property> <!-- C3P0 数据库连接池可以维护的 Statement 的个数 --> <property name="maxStatements">20</property> <!-- 每个连接同时可以使用的 Statement 对象的个数 --> <property name="maxStatementsPerConnection">5</property> </named-config> </c3p0-config>
实体类
Customer.java
package com.aidata.mvcapp.domain; public class Customer { private Integer id; private String name; private String address; private String phone; 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 String getAddress() { return address; } public void setAddress(String address) { this.address = address; } public String getPhone() { return phone; } public void setPhone(String phone) { this.phone = phone; } @Override public String toString() { return "Customer [id=" + id + ", name=" + name + ", address=" + address + ", phone=" + phone + "]"; } }
数据库连接和关闭工具类
JdbcUtils.java
package com.aidata.mvcapp.db; import java.sql.Connection; import java.sql.SQLException; import javax.sql.DataSource; import com.mchange.v2.c3p0.ComboPooledDataSource; /** * @ClassName JdbcUtils * @Description JDBC操作的工具类 * @author JZ * @Date * @version 1.0.0 */ public class JdbcUtils { /** * @Description 释放连接 * @param connection */ public static void releaseConnection(Connection connection) { try { if (connection != null) { connection.close(); } } catch (Exception e) { // TODO: handle exception } } private static DataSource dataSource = null; // 数据源只能创建一次,所以用static static { dataSource = new ComboPooledDataSource("mvcapp"); } /** * @Description 返回数据源的一个Connection对象 * @return * @throws SQLException */ public static Connection getConnection() throws SQLException { return dataSource.getConnection(); } }
DAO接口
CustomerDAO.java
该接口定义了和业务相关的功能,操作customer
package com.aidata.mvcapp.dao; import java.util.List; import com.aidata.mvcapp.domain.Customer; public interface CustomerDAO { public List<Customer> getAll(); public void save(Customer customer); public Customer get(Integer id); public void delete(Integer id); /** * * @Description 返回和name相等的记录数 * @param name * @return */ public long getCountWithName(String name); }
DAO 实现类
DAO.java
该类不和业务相关,即和customer不相关,而是关注增删改查的功能
增删改都是update,查
package com.aidata.mvcapp.dao; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.sql.Connection; import java.util.List; import org.apache.commons.dbutils.QueryRunner; import org.apache.commons.dbutils.handlers.BeanHandler; import org.apache.commons.dbutils.handlers.BeanListHandler; import org.apache.commons.dbutils.handlers.ScalarHandler; import com.aidata.mvcapp.db.JdbcUtils; /** * @ClassName DAO * @Description 封装了CRUD的方法,以供子类继承使用 当前DAO没有事务,直接在方法中获取数据库连接 整个DAO采取DBUtils解决方案 * @author JZ * @Date * @version 1.0.0 * @param <T> * 所处理的实体类的类型 */ public class DAO<T> { private QueryRunner queryRunner = new QueryRunner(); private Class<T> clazz; public DAO() { Type superClass = getClass().getGenericSuperclass(); if (superClass instanceof ParameterizedType) { ParameterizedType parameterizedType = (ParameterizedType) superClass; Type[] typeArgs = parameterizedType.getActualTypeArguments(); if (typeArgs != null && typeArgs.length > 0) { clazz = (Class<T>) typeArgs[0]; } } } /** * @Description 返回某一个字段的值,例如某一天记录的customerName或 返回数据表中由多少条记录等 * @param sql * @param args * @return */ public <E> E getForValue(String sql, Object... args) { Connection connection = null; try { connection = JdbcUtils.getConnection(); return (E) queryRunner.query(connection, sql, new ScalarHandler(), args); } catch (Exception e) { e.printStackTrace(); } finally { JdbcUtils.releaseConnection(connection); } return null; } /** * @Description 返回 T 所对应的List * @param sql * @param args * @return */ public List<T> getForList(String sql, Object... args) { Connection connection = null; try { connection = JdbcUtils.getConnection(); return queryRunner.query(connection, sql, new BeanListHandler<>(clazz), args); } catch (Exception e) { e.printStackTrace(); } finally { JdbcUtils.releaseConnection(connection); } return null; } /** * @Description 返回对应T的一个实例类对象 * @param sql * @param args * @return */ public T get(String sql, Object... args) { Connection connection = null; try { connection = JdbcUtils.getConnection(); return queryRunner.query(connection, sql, new BeanHandler<>(clazz), args); } catch (Exception e) { e.printStackTrace(); } finally { JdbcUtils.releaseConnection(connection); } return null; } /** * @Description 封装了INSERT、DELETE、UPDATE操作 * @param sql * SQL语句 * @param args * 填充SQL语句的占位符 */ public void update(String sql, Object... args) { Connection connection = null; try { connection = JdbcUtils.getConnection(); queryRunner.update(connection, sql, args); } catch (Exception e) { e.printStackTrace(); } finally { JdbcUtils.releaseConnection(connection); } } }
CustomerDAOJdbcImpl.java
将业务和功能结合起来,实现了业务操作
package com.aidata.mvcapp.dao.impl; import java.util.List; import com.aidata.mvcapp.dao.CustomerDAO; import com.aidata.mvcapp.dao.DAO; import com.aidata.mvcapp.domain.Customer; public class CustomerDAOJdbcImpl extends DAO<Customer> implements CustomerDAO { @Override public List<Customer> getAll() { String sql = "SELECT id, name, address, phone From customers"; return getForList(sql); } @Override public void save(Customer customer) { String sql = "INSERT INTO customers(name, address, phone) VALUES(?,?,?)"; update(sql, customer.getName(), customer.getAddress(), customer.getPhone()); } @Override public Customer get(Integer id) { String sql = "SELECT id, name, address, phone FROM customers WHERE id = ?"; return get(sql, id); } @Override public void delete(Integer id) { String sql = "DELETE FROM customers WHERE id = ?"; update(sql, id); } @Override public long getCountWithName(String name) { String sql = "SELECT count(id) FROM customers WHERE name = ?"; return getForValue(sql, name); } }
2.3 多个请求对应一个Servlet
第一种方式:url添加参数
jsp
<body> <a href="customerServlet?method=add">Add</a> <br><br> <a href="customerServlet?method=query">Query</a> <br><br> <a href="customerServlet?method=delete">Delete</a> <br><br> </body>
定义Servlet
package com.aidata.mvcapp.servlet; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class CustomerServlet extends HttpServlet { private static final long serialVersionUID = 1L; public CustomerServlet() { } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String method = request.getParameter("method"); switch (method) { case "add": add(request, response); break; case "query": query(request, response); break; case "delete": delete(request, response); break; } } private void add(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("add"); } private void query(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("query"); } private void delete(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("delete"); } }
web.xml
<servlet> <servlet-name>customerServlet</servlet-name> <servlet-class>com.aidata.mvcapp.servlet.CustomerServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>customerServlet</servlet-name> <url-pattern>/customerServlet</url-pattern> </servlet-mapping>
缺点:当添加一个请求时,需要在 Servlet 中修改两处代码:switch、添加方法;url 中使用 method=xxx 暴漏了要调用的方法,不私密,有安全隐患。
第二种方式:反射
jsp
<body> <a href="addCustomer.do">Add</a> <br><br> <a href="query.do">Query</a> <br><br> <a href="deleteCustomer.do">Delete</a> <br><br> </body>
web.xml
<servlet> <servlet-name>customerServlet</servlet-name> <servlet-class>com.aidata.mvcapp.servlet.CustomerServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>customerServlet</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping>
Servlet
package com.aidata.mvcapp.servlet; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class CustomerServlet extends HttpServlet { private static final long serialVersionUID = 1L; public CustomerServlet() { } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String servletPath = request.getServletPath(); String methodName = servletPath.substring(1); methodName = methodName.substring(0, methodName.length() - 3); System.out.println(methodName); Method method; try { method = getClass().getDeclaredMethod(methodName, HttpServletRequest.class, HttpServletResponse.class); method.invoke(this, request, response); } catch (NoSuchMethodException | SecurityException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InvocationTargetException e) { // TODO Auto-generated catch block e.printStackTrace(); } } private void addCustomer(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("add"); } private void query(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("query"); } private void deleteCustomer(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("delete"); } private void edit(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("edit"); } }
流程:
2.4 模糊查询
非模糊查询
JSP
<%@page import="java.util.List"%> <%@page import="com.aidata.mvcapp.domain.Customer"%> <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Insert title here</title> </head> <body> <form action="query.do" method="post"> <table> <tr> <td>CustomerName:</td> <td><input type="text" name="name"></td> </tr> <tr> <td>Address:</td> <td><input type="text" name="address"></td> </tr> <tr> <td>Phone:</td> <td><input type="text" name="phone"></td> </tr> <tr> <td><input type="submit" name="Query"></td> <td><a href="">Add New Customer</a></td> </tr> </table> </form> <br><br> <% List<Customer> customers = (List)request.getAttribute("customers"); if(customers != null && customers.size() > 0){ %> <hr> <br><br> <table border="1" cellpadding="0" cellspacing="10"> <tr> <th>ID</th> <th>CustomerName</th> <th>Address</th> <th>Phone</th> <th>UPDATEDELETE</th> </tr> <% for(Customer customer: customers){ %> <tr> <td><%= customer.getId() %></td> <td><%= customer.getName() %></td> <td><%= customer.getAddress() %></td> <td><%= customer.getPhone() %></td> <td> <a href="">UPDATE</a> <a href="">DELETE</a> </td> </tr> <% } %> </table> <% } %> </body> </html>
Servlet
package com.aidata.mvcapp.servlet; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.List; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.aidata.mvcapp.dao.CustomerDAO; import com.aidata.mvcapp.dao.impl.CustomerDAOJdbcImpl; import com.aidata.mvcapp.domain.Customer; public class CustomerServlet extends HttpServlet { private static final long serialVersionUID = 1L; private CustomerDAO customerDAO = new CustomerDAOJdbcImpl(); public CustomerServlet() { } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String servletPath = request.getServletPath(); String methodName = servletPath.substring(1); methodName = methodName.substring(0, methodName.length() - 3); System.out.println(methodName); Method method; try { method = getClass().getDeclaredMethod(methodName, HttpServletRequest.class, HttpServletResponse.class); method.invoke(this, request, response); } catch (NoSuchMethodException | SecurityException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InvocationTargetException e) { // TODO Auto-generated catch block e.printStackTrace(); } } private void addCustomer(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("add"); } private void query(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 1.调用CustomerDAO的getAll()方法,得到Customer的集合 List<Customer> customers = customerDAO.getAll(); // 2.把customer集合放入request中 request.setAttribute("customers", customers); // 3.转发页面到index.jsp,不能用重定向 request.getRequestDispatcher("/index.jsp").forward(request, response); } private void deleteCustomer(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("delete"); } private void edit(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("edit"); } }
模糊查询
接口添加方法,定义用于查询的类
需要在 CustomerDAO 接口中定义一个 getForListWithCriteriaCustomer(CriteriaCustomer cc)。 其中 CriteriaCustomer 用于封装查询条件:name, address, phone。因为查询条件很多时候和 domain 类并不相同,所以要做成一个单独的类
package com.aidata.mvcapp.dao; import java.util.List; import com.aidata.mvcapp.domain.Customer; public interface CustomerDAO { public List<Customer> getForListWithCriteriaCustomer(CriteriaCustomer cc); public List<Customer> getAll(); public void save(Customer customer); public Customer get(Integer id); public void delete(Integer id); /** * @Description 返回和name相等的记录数 * @param name * @return */ public long getCountWithName(String name); }
CriteriaCustomer
package com.aidata.mvcapp.dao; public class CriteriaCustomer { private String name; private String address; private String phone; public CriteriaCustomer(String name, String address, String phone) { super(); this.name = name; this.address = address; this.phone = phone; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } public String getPhone() { return phone; } public void setPhone(String phone) { this.phone = phone; } }
拼 SQL
SQL: "SELECT id, name, address, phone FROM customers WHERE " +
"name LIKE ? AND address LIKE ? ANDphone LIKE ?";
package com.aidata.mvcapp.dao.impl; import java.util.List; import com.aidata.mvcapp.dao.CriteriaCustomer; import com.aidata.mvcapp.dao.CustomerDAO; import com.aidata.mvcapp.dao.DAO; import com.aidata.mvcapp.domain.Customer; public class CustomerDAOJdbcImpl extends DAO<Customer> implements CustomerDAO { @Override public List<Customer> getAll() { String sql = "SELECT id, name, address, phone From customers"; return getForList(sql); } @Override public void save(Customer customer) { String sql = "INSERT INTO customers(name, address, phone) VALUES(?,?,?)"; update(sql, customer.getName(), customer.getAddress(), customer.getPhone()); } @Override public Customer get(Integer id) { String sql = "SELECT id, name, address, phone FROM customers WHERE id = ?"; return get(sql, id); } @Override public void delete(Integer id) { String sql = "DELETE FROM customers WHERE id = ?"; update(sql, id); } @Override public long getCountWithName(String name) { String sql = "SELECT count(id) FROM customers WHERE name = ?"; return getForValue(sql, name); } @Override public List<Customer> getForListWithCriteriaCustomer(CriteriaCustomer cc) { String sql = "SELECT id, name, address, phone FROM customers WHERE " + "name LIKE ? AND address LIKE ? AND phone LIKE ?"; return getForList(sql, cc.getName(), cc.getAddress(), cc.getPhone()); } }
为了正确的填充占位符时,重写了 CriteriaCustomer 的 getter:
package com.aidata.mvcapp.dao; public class CriteriaCustomer { private String name; private String address; private String phone; public CriteriaCustomer(String name, String address, String phone) { super(); this.name = name; this.address = address; this.phone = phone; } public String getName() { if (name == null) { name = "%%"; } else { name = "%" + name + "%"; } return name; } public void setName(String name) { this.name = name; } public String getAddress() { if (address == null) { address = "%%"; } else { address = "%" + address + "%"; } return address; } public void setAddress(String address) { this.address = address; } public String getPhone() { if (phone == null) { phone = "%%"; } else { phone = "%" + phone + "%"; } return phone; } public void setPhone(String phone) { this.phone = phone; } }
修改 Servlet
获取请求参数,把请求参数封装为CriteriaCustomer 对象,再调用 getForListWithCriteriaCustomer(CriteriaCustomer cc) 方法
package com.aidata.mvcapp.servlet; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.List; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.aidata.mvcapp.dao.CriteriaCustomer; import com.aidata.mvcapp.dao.CustomerDAO; import com.aidata.mvcapp.dao.impl.CustomerDAOJdbcImpl; import com.aidata.mvcapp.domain.Customer; public class CustomerServlet extends HttpServlet { private static final long serialVersionUID = 1L; private CustomerDAO customerDAO = new CustomerDAOJdbcImpl(); public CustomerServlet() { } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String servletPath = request.getServletPath(); String methodName = servletPath.substring(1); methodName = methodName.substring(0, methodName.length() - 3); System.out.println(methodName); Method method; try { method = getClass().getDeclaredMethod(methodName, HttpServletRequest.class, HttpServletResponse.class); method.invoke(this, request, response); } catch (NoSuchMethodException | SecurityException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InvocationTargetException e) { // TODO Auto-generated catch block e.printStackTrace(); } } private void addCustomer(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("add"); } private void query(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String name = request.getParameter("name"); String phone = request.getParameter("phone"); String address = request.getParameter("address"); CriteriaCustomer cc = new CriteriaCustomer(name, address, phone); // 1.调用CustomerDAO的getAll()方法,得到Customer的集合 List<Customer> customers = customerDAO.getForListWithCriteriaCustomer(cc); // 2.把customer集合放入request中 request.setAttribute("customers", customers); // 3.转发页面到index.jsp,不能用重定向 request.getRequestDispatcher("/index.jsp").forward(request, response); } private void deleteCustomer(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("delete"); } private void edit(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("edit"); } }
2.5 删除操作
Servlet
超链接:delete.do?id=<%=customer.getId()%>
Servlet 的 delete 方法
获取 id
调用 DAO 执行删除
重定向到 query.do(若目标页面不需要读取当前请求的 request 属性,就可以使用重定向),将显示删除后的 Customer 的 List
package com.aidata.mvcapp.servlet; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.List; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.aidata.mvcapp.dao.CriteriaCustomer; import com.aidata.mvcapp.dao.CustomerDAO; import com.aidata.mvcapp.dao.impl.CustomerDAOJdbcImpl; import com.aidata.mvcapp.domain.Customer; public class CustomerServlet extends HttpServlet { private static final long serialVersionUID = 1L; private CustomerDAO customerDAO = new CustomerDAOJdbcImpl(); public CustomerServlet() { } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String servletPath = request.getServletPath(); String methodName = servletPath.substring(1); methodName = methodName.substring(0, methodName.length() - 3); System.out.println(methodName); Method method; try { method = getClass().getDeclaredMethod(methodName, HttpServletRequest.class, HttpServletResponse.class); method.invoke(this, request, response); } catch (NoSuchMethodException | SecurityException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InvocationTargetException e) { // TODO Auto-generated catch block e.printStackTrace(); } } private void addCustomer(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("add"); } private void query(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String name = request.getParameter("name"); String phone = request.getParameter("phone"); String address = request.getParameter("address"); CriteriaCustomer cc = new CriteriaCustomer(name, address, phone); // 1.调用CustomerDAO的getAll()方法,得到Customer的集合 List<Customer> customers = customerDAO.getForListWithCriteriaCustomer(cc); // 2.把customer集合放入request中 request.setAttribute("customers", customers); // 3.转发页面到index.jsp,不能用重定向 request.getRequestDispatcher("/index.jsp").forward(request, response); } private void deleteCustomer(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String idStri = request.getParameter("id"); int id = 0; // try...catch... 防止idStri不能转为int类型,若不能转,id=0,不进行任何删除操作 try { id = Integer.parseInt(idStri); customerDAO.delete(id); } catch (Exception e) { } response.sendRedirect("query.do"); System.out.println("delete"); } private void edit(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("edit"); } }
JSP
jQuery 提示:
确定要删除 xx 的信息吗?
<%@page import="java.util.List"%> <%@page import="com.aidata.mvcapp.domain.Customer"%> <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Insert title here</title> <script type="text/javascript" src="scripts/jquery-1.11.3.min.js"></script> <script type="text/javascript"> $(function () { $(".delete").click(function() { var content = $(this).parent().parent().find("td:eq(1)").text(); var flag = confirm("确定要删除"+content+"的信息吗?"); return flag; }); }); </script> </head> <body> <form action="query.do" method="post"> <table> <tr> <td>CustomerName:</td> <td><input type="text" name="name"></td> </tr> <tr> <td>Address:</td> <td><input type="text" name="address"></td> </tr> <tr> <td>Phone:</td> <td><input type="text" name="phone"></td> </tr> <tr> <td><input type="submit" name="Query"></td> <td><a href="">Add New Customer</a></td> </tr> </table> </form> <br><br> <% List<Customer> customers = (List)request.getAttribute("customers"); if(customers != null && customers.size() > 0){ %> <hr> <br><br> <table border="1" cellpadding="0" cellspacing="10"> <tr> <th>ID</th> <th>CustomerName</th> <th>Address</th> <th>Phone</th> <th>UPDATEDELETE</th> </tr> <% for(Customer customer: customers){ %> <tr> <td><%= customer.getId() %></td> <td><%= customer.getName() %></td> <td><%= customer.getAddress() %></td> <td><%= customer.getPhone() %></td> <td> <a href="">UPDATE</a> <a href="deleteCustomer.do?id=<%= customer.getId() %>" class="delete">DELETE</a> </td> </tr> <% } %> </table> <% } %> </body> </html>
request的getParameter(String name)方法获取表单里面的name信息
只有设置了 name 属性的表单元素才能在提交表单时传递它们的值,因为服务端获取表单提交的数据是通过表单元素的 name 属性的值而得到的,没有 name 属性就无法得到表单元素提交给服务端的值
2.6 新增
流程
效果:点击Add New Customer 超链接,连接到 newcustomer.jsp
创建newcustomer.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<form action="addCustomer.do" method="post">
<table>
<tr>
<td>CustomerName:</td>
<td><input type="text" name="name" value="<%= request.getParameter("name") == null?"": request.getParameter("name") %>"></td>
</tr>
<tr>
<td>Address:</td>
<td><input type="text" name="address"></td>
</tr>
<tr>
<td>Phone:</td>
<td><input type="text" name="phone"></td>
</tr>
<tr>
<td colspan="2"><input type="submit" name="Submit"></td>
</tr>
</table>
</form>
</body>
</html>
success.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h4>操作成功!</h4>
<h4><a href="index.jsp">Return...</a></h4>
</body>
</html>
修改addCustomer 方法
CustomerServlet 的 addCustomer 方法
package com.aidata.mvcapp.servlet; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.List; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.aidata.mvcapp.dao.CriteriaCustomer; import com.aidata.mvcapp.dao.CustomerDAO; import com.aidata.mvcapp.dao.impl.CustomerDAOJdbcImpl; import com.aidata.mvcapp.domain.Customer; public class CustomerServlet extends HttpServlet { private static final long serialVersionUID = 1L; private CustomerDAO customerDAO = new CustomerDAOJdbcImpl(); public CustomerServlet() { } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String servletPath = request.getServletPath(); String methodName = servletPath.substring(1); methodName = methodName.substring(0, methodName.length() - 3); System.out.println(methodName); Method method; try { method = getClass().getDeclaredMethod(methodName, HttpServletRequest.class, HttpServletResponse.class); method.invoke(this, request, response); } catch (NoSuchMethodException | SecurityException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InvocationTargetException e) { // TODO Auto-generated catch block e.printStackTrace(); } } private void addCustomer(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 1. 获取表单参数:name,address,phone String name = request.getParameter("name"); String address = request.getParameter("address"); String phone = request.getParameter("phone"); // 2. 检验name是否已经被占用 // 2.1 调用customerDAO的getCountWithName方法获取name是否在数据库中存在 long count = customerDAO.getCountWithName(name); // 2.2 若返回值大于0,则响应newcustomer.jsp页面: // 通过转发的方式响应newcustomer.jsp if (count > 0) { // 2.2.1 要求在newcustomer.jsp页面显示一个错误消息:用户名name已经被占用,请重新选择! // 在request中放入一个属性,比如message:用户名name已经被占用,请重新选择!, // 在页面上通过request.getAttribute("message")的方式显示 request.setAttribute("message", "用户名" + name + "已经被占用,请重新选择!"); // 2.2.2 newcustomer.jsp的表单值可以回显 // jsp中,value="<%= request.getParameter("name") == null?"": request.getParameter("name") %> // 2.2.3 结束方法:return request.getRequestDispatcher("/newcustomer.jsp").forward(request, response); return; } // 3. 若验证通过,则把表单参数封装为一个Customer对象customer Customer customer = new Customer(name, address, phone); // 4. 调用CustomerDAO的save方法,执行保存操作 customerDAO.save(customer); // 5. 重定向到success.jsp页面 response.sendRedirect("success.jsp"); } private void query(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String name = request.getParameter("name"); String phone = request.getParameter("phone"); String address = request.getParameter("address"); CriteriaCustomer cc = new CriteriaCustomer(name, address, phone); // 1.调用CustomerDAO的getAll()方法,得到Customer的集合 List<Customer> customers = customerDAO.getForListWithCriteriaCustomer(cc); // 2.把customer集合放入request中 request.setAttribute("customers", customers); // 3.转发页面到index.jsp,不能用重定向 request.getRequestDispatcher("/index.jsp").forward(request, response); } private void deleteCustomer(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String idStri = request.getParameter("id"); int id = 0; // try...catch... 防止idStri不能转为int类型,若不能转,id=0,不进行任何删除操作 try { id = Integer.parseInt(idStri); customerDAO.delete(id); } catch (Exception e) { } response.sendRedirect("query.do"); } private void edit(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("edit"); } }
执行流程图
2.7 修改
先显示(SELECT 操作)修改的页面,再进行修改(update)
显示修改页面
Update 的超链接:<a href="edit.do?id=<%= customer.getId() %>">UPDATE</a>
index.jsp
<%@page import="java.util.List"%> <%@page import="com.aidata.mvcapp.domain.Customer"%> <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Insert title here</title> <script type="text/javascript" src="scripts/jquery-1.11.3.min.js"></script> <script type="text/javascript"> $(function () { $(".delete").click(function() { var content = $(this).parent().parent().find("td:eq(1)").text(); var flag = confirm("确定要删除"+content+"的信息吗?"); return flag; }); }); </script> </head> <body> <form action="query.do" method="post"> <table> <tr> <td>CustomerName:</td> <td><input type="text" name="name"></td> </tr> <tr> <td>Address:</td> <td><input type="text" name="address"></td> </tr> <tr> <td>Phone:</td> <td><input type="text" name="phone"></td> </tr> <tr> <td><input type="submit" name="Query"></td> <td><a href="newcustomer.jsp">Add New Customer</a></td> </tr> </table> </form> <br><br> <% List<Customer> customers = (List)request.getAttribute("customers"); if(customers != null && customers.size() > 0){ %> <hr> <br><br> <table border="1" cellpadding="0" cellspacing="10"> <tr> <th>ID</th> <th>CustomerName</th> <th>Address</th> <th>Phone</th> <th>UPDATEDELETE</th> </tr> <% for(Customer customer: customers){ %> <tr> <td><%= customer.getId() %></td> <td><%= customer.getName() %></td> <td><%= customer.getAddress() %></td> <td><%= customer.getPhone() %></td> <td> <a href="edit.do?id=<%= customer.getId() %>">UPDATE</a> <a href="deleteCustomer.do?id=<%= customer.getId() %>" class="delete">DELETE</a> </td> </tr> <% } %> </table> <% } %> </body> </html>
edit 方法:
private void edit(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String forwardPath = "/error.jsp"; // 1. 获取请求参数id String idStr = request.getParameter("id"); // 2.调用customerDAO的customerDAO.get(id)获取和id对应的Customer对象 try { Customer customer = customerDAO.get(Integer.parseInt(idStr)); if (customer != null) { forwardPath = "updatecustomer.jsp"; // 3.将customer放入request中 request.setAttribute("customer", customer); } } catch (Exception e) { } // 4.响应updatecustomer.jsp页面:转发 request.getRequestDispatcher(forwardPath).forward(request, response); }
JSP 页面
获取请求域中的 Customer 对象,调用对应的字段的 get 方法来显示值。
使用隐藏域来保存要修改的 Customer 对象的 id:<input type="hidden" name="id" value=“<%= customer.getId() %>"/>。虽然没有修改id,当然也不能改,但依然少不了,id用来判断到底是哪个customer。
使用隐藏域来保存 oldName:<input type="hidden" name=“oldName" value=“<%= customer.getName() %>"/>,oldName保存修改前的名字,name会更新为提交的名字。
关于隐藏域:和其他的表单域一样可以被提交到服务器,只不过在页面上不显示
提交到 update.do
updatecustomer.jsp:
<%@page import="com.aidata.mvcapp.domain.Customer"%> <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Insert title here</title> </head> <body> <% Object msg = request.getAttribute("message"); if(msg != null){ %> <br> <font color="red"><%= msg %></font> <br> <br> <% } String id = null; String oldName = null; String name = null; String address = null; String phone = null; Customer customer = (Customer)request.getAttribute("customer"); if(customer != null){ // 如果没有出错,从edit方法过来的,customer不为空 id = customer.getId() + ""; // 这里name和oldName一样,但是后面提交的时候,name会提交,即更新,而oldName保持不变,从而可以比较 oldName = customer.getName(); name = customer.getName(); address = customer.getAddress(); phone = customer.getPhone(); }else{ // 如果出错,即提交了重复的名字,会出现提示信息,会停留在本页面,没有edit方法了,也就没有customer属性了 // 只能从之前提交的request中得到id等 id = request.getParameter("id"); oldName = request.getParameter("oldName"); // name = request.getParameter("oldname"); address = request.getParameter("address"); phone = request.getParameter("phone"); } %> <form action="update.do" method="post"> <input type="hidden" name="id" value="<%= id %>" /> <input type="hidden" name="oldName" value="<%= oldName %>" /> <table> <tr> <td>CustomerName:</td> <td><input type="text" name="name" value="<%= name %>" /></td> </tr> <tr> <td>Address:</td> <td><input type="text" name="address" value="<%= address %>" /></td> </tr> <tr> <td>Phone:</td> <td><input type="text" name="phone"value="<%= phone %>" /></td> </tr> <tr> <td colspan="2"><input type="submit" name="Submit"></td> </tr> </table> </form> </body> </html>
隐藏域的问题
回显的问题
Newcustomer.jsp 和 updateCustomer.jsp 能汇总到一个页面吗 ?
修改操作
Update 方法:
private void update(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1. 获取表单参数:name,address,phone
String id = request.getParameter("id");
String name = request.getParameter("name");
String phone = request.getParameter("phone");
String address = request.getParameter("address");
String oldName = request.getParameter("oldName");
// 2. 检验name是否已经被占用
// 2.1 比较name和oldName是否相同,若相同说明name可用
// 2.1 若不相同,调用customerDAO的getCountWithName方法获取name是否在数据库中存在
if (!oldName.equalsIgnoreCase(name)) {
// 如你输入了A,以前已经有了a,java的equals会认为两者不同,于是进入该if
// 但是mysql认为A和a相同,于是返回了1,即已经存在了,从而引发message
// 忽略大小写,不进入if,直接进行后面的update
long count = customerDAO.getCountWithName(name);
// 2.2 若返回值大于0,则响应updatecustomer.jsp
if (count > 0) {
// 2.2.1 在updatecustomer.jsp页面显示一个错误信息:用户名name已经被占用,请重新选择!
// 在request中放入一个属性,比如message:用户名name已经被占用,请重新选择!,
// 在页面上通过request.getAttribute("message")的方式显示
request.setAttribute("message", "用户名" + name + "已经被占用,请重新选择!");
// 2.2.2 updatecustomer.jsp的表单值可以回显
// address,phone显示提交表单的新的值,而name显示oldName,而不是新提交的name
// 2.2.3 结束方法:return
return;
}
}
// 3. 若验证通过,则把表单参数封装为一个Customer对象customer
Customer customer = new Customer(name, address, phone);
customer.setId(Integer.parseInt(id));
// 4. 调用CustomerDAO的update(Customer customer)执行更新操作
customerDAO.update(customer);
// 5. 重定向到query.do
response.sendRedirect("query.do");
}
}
完整Servlet
package com.aidata.mvcapp.servlet; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.List; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.aidata.mvcapp.dao.CriteriaCustomer; import com.aidata.mvcapp.dao.CustomerDAO; import com.aidata.mvcapp.dao.impl.CustomerDAOJdbcImpl; import com.aidata.mvcapp.domain.Customer; public class CustomerServlet extends HttpServlet { private static final long serialVersionUID = 1L; private CustomerDAO customerDAO = new CustomerDAOJdbcImpl(); public CustomerServlet() { } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String servletPath = request.getServletPath(); String methodName = servletPath.substring(1); methodName = methodName.substring(0, methodName.length() - 3); System.out.println(methodName); Method method; try { method = getClass().getDeclaredMethod(methodName, HttpServletRequest.class, HttpServletResponse.class); method.invoke(this, request, response); } catch (NoSuchMethodException | SecurityException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InvocationTargetException e) { // TODO Auto-generated catch block e.printStackTrace(); } } private void addCustomer(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 1. 获取表单参数:name,address,phone String name = request.getParameter("name"); String address = request.getParameter("address"); String phone = request.getParameter("phone"); // 2. 检验name是否已经被占用 // 2.1 调用customerDAO的getCountWithName方法获取name是否在数据库中存在 long count = customerDAO.getCountWithName(name); // 2.2 若返回值大于0,则响应newcustomer.jsp页面: // 通过转发的方式响应newcustomer.jsp if (count > 0) { // 2.2.1 要求在newcustomer.jsp页面显示一个错误消息:用户名name已经被占用,请重新选择! // 在request中放入一个属性,比如message:用户名name已经被占用,请重新选择!, // 在页面上通过request.getAttribute("message")的方式显示 request.setAttribute("message", "用户名" + name + "已经被占用,请重新选择!"); // 2.2.2 newcustomer.jsp的表单值可以回显 // jsp中,value="<%= request.getParameter("name") == null?"": request.getParameter("name") %> // 2.2.3 结束方法:return request.getRequestDispatcher("/newcustomer.jsp").forward(request, response); return; } // 3. 若验证通过,则把表单参数封装为一个Customer对象customer Customer customer = new Customer(name, address, phone); // 4. 调用CustomerDAO的save方法,执行保存操作 customerDAO.save(customer); // 5. 重定向到success.jsp页面 response.sendRedirect("success.jsp"); } private void query(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String name = request.getParameter("name"); String phone = request.getParameter("phone"); String address = request.getParameter("address"); CriteriaCustomer cc = new CriteriaCustomer(name, address, phone); // 1.调用CustomerDAO的getAll()方法,得到Customer的集合 List<Customer> customers = customerDAO.getForListWithCriteriaCustomer(cc); // 2.把customer集合放入request中 request.setAttribute("customers", customers); // 3.转发页面到index.jsp,不能用重定向 request.getRequestDispatcher("/index.jsp").forward(request, response); } private void deleteCustomer(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String idStri = request.getParameter("id"); int id = 0; // try...catch... 防止idStri不能转为int类型,若不能转,id=0,不进行任何删除操作 try { id = Integer.parseInt(idStri); customerDAO.delete(id); } catch (Exception e) { } response.sendRedirect("query.do"); } private void edit(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String forwardPath = "/error.jsp"; // 1. 获取请求参数id String idStr = request.getParameter("id"); // 2.调用customerDAO的customerDAO.get(id)获取和id对应的Customer对象 try { Customer customer = customerDAO.get(Integer.parseInt(idStr)); if (customer != null) { forwardPath = "updatecustomer.jsp"; // 3.将customer放入request中 request.setAttribute("customer", customer); } } catch (Exception e) { } // 4.响应updatecustomer.jsp页面:转发 request.getRequestDispatcher(forwardPath).forward(request, response); } private void update(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 1. 获取表单参数:name,address,phone String id = request.getParameter("id"); String name = request.getParameter("name"); String phone = request.getParameter("phone"); String address = request.getParameter("address"); String oldName = request.getParameter("oldName"); // 2. 检验name是否已经被占用 // 2.1 比较name和oldName是否相同,若相同说明name可用 // 2.1 若不相同,调用customerDAO的getCountWithName方法获取name是否在数据库中存在 if (!oldName.equalsIgnoreCase(name)) { // 如你输入了A,以前已经有了a,java的equals会认为两者不同,于是进入该if // 但是mysql认为A和a相同,于是返回了1,即已经存在了,从而引发message // 忽略大小写,不进入if,直接进行后面的update long count = customerDAO.getCountWithName(name); // 2.2 若返回值大于0,则响应updatecustomer.jsp if (count > 0) { // 2.2.1 在updatecustomer.jsp页面显示一个错误信息:用户名name已经被占用,请重新选择! // 在request中放入一个属性,比如message:用户名name已经被占用,请重新选择!, // 在页面上通过request.getAttribute("message")的方式显示 request.setAttribute("message", "用户名" + name + "已经被占用,请重新选择!"); // 2.2.2 updatecustomer.jsp的表单值可以回显 // address,phone显示提交表单的新的值,而name显示oldName,而不是新提交的name
request.getRequestDispatcher("update.jsp").forward(request, response);
// 2.2.3 结束方法:return
return; // 重定向跳转后必须加上return,要不然页面虽然跳转了,但是还会执行跳转后面的语句
} } // 3. 若验证通过,则把表单参数封装为一个Customer对象customer Customer customer = new Customer(name, address, phone); customer.setId(Integer.parseInt(id)); // 4. 调用CustomerDAO的update(Customer customer)执行更新操作 customerDAO.update(customer); // 5. 重定向到query.do response.sendRedirect("query.do"); } }
2.8 更换底层存储源
深入理解面向接口编程:在类中调用接口的方法,而不必关心具体的实现。这将有利于代码的解耦,使程序有更好的可移植性和可扩展性。
需要修改源码
src下新建customes.xml
<?xml version="1.0" encoding="UTF-8"?> <customers> <customer id="1001"> <name>Tom</name> <address>Beijing</address> <phone>123</phone> </customer> </customers>
新建实现类,功能暂时省略
package com.aidata.mvcapp.dao.impl; import java.util.List; import com.aidata.mvcapp.dao.CriteriaCustomer; import com.aidata.mvcapp.dao.CustomerDAO; import com.aidata.mvcapp.domain.Customer; public class CustomerDAOXMLImpl implements CustomerDAO { @Override public List<Customer> getForListWithCriteriaCustomer(CriteriaCustomer cc) { // TODO Auto-generated method stub return null; } @Override public List<Customer> getAll() { // TODO Auto-generated method stub return null; } @Override public void save(Customer customer) { // TODO Auto-generated method stub } @Override public Customer get(Integer id) { // TODO Auto-generated method stub return null; } @Override public void delete(Integer id) { // TODO Auto-generated method stub } @Override public void update(Customer customer) { // TODO Auto-generated method stub } @Override public long getCountWithName(String name) { // TODO Auto-generated method stub return 0; } }
只需要在CustomerServlet中修改一行语句
private CustomerDAO customerDAO = new CustomerDAOXMLImpl();
使用工厂模式,不修改源码
如果一行语句也不用修改怎么做?
使用属性文件
动态修改 Customer 的存储方式:通过修改类路径下的 switch.properties 文件的方式来实现
src下创建switch.properties
#type=xml
type=jdbc
创建Servlet读取配置文件
当Web 应用在启动的时候,InitServlet 被创建,并由 Servlet 容器调用其 init() 方法:
<servlet> <servlet-name>InitServlet</servlet-name> <servlet-class>com.aidata.mvcapp.servlet.InitServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet>
读取类路径下的 switch.properties 文件,获取 switch.properties 的 type 属性值,赋给了 CustomerDAOFactory 的 type 属性值
package com.aidata.mvcapp.servlet; import java.io.IOException; import java.io.InputStream; import java.util.Properties; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.aidata.mvcapp.dao.factory.CustomerDAOFactory; public class InitServlet extends HttpServlet { private static final long serialVersionUID = 1L; @Override public void init() throws ServletException { CustomerDAOFactory.getInstance().setType("jdbc"); InputStream in = getServletContext().getResourceAsStream("/WEB-INF/classes/switch.properties"); Properties properties = new Properties(); try { properties.load(in); String type = properties.getProperty("type"); CustomerDAOFactory.getInstance().setType(type); } catch (IOException e) { e.printStackTrace(); } } }
需要通过一个类的一个方法来获取具体的实现类的对象:
package com.aidata.mvcapp.dao.factory; import java.util.HashMap; import java.util.Map; import com.aidata.mvcapp.dao.CustomerDAO; import com.aidata.mvcapp.dao.impl.CustomerDAOJdbcImpl; import com.aidata.mvcapp.dao.impl.CustomerDAOXMLImpl; public class CustomerDAOFactory { private Map<String, CustomerDAO> daos = new HashMap<String, CustomerDAO>(); private CustomerDAOFactory() { daos.put("jdbc", new CustomerDAOJdbcImpl()); daos.put("xml", new CustomerDAOXMLImpl()); } private static CustomerDAOFactory instance = new CustomerDAOFactory(); public static CustomerDAOFactory getInstance() { return instance; } private static String type = null; public void setType(String type) { this.type = type; } public CustomerDAO getCustomerDAO() { return daos.get(type); } }
创建 CustomerServlet 时,为 customerDAO 属性赋值是通过 CustomerDAOFactory 的 getCustomerDAO() 方法完成的 。此时的 type 已经在 InitServlet 中被赋值了。
private CustomerDAO customerDAO = CustomerDAOFactory.getInstance().getCustomerDAO();