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数据源

论数据库连接池的必要性及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>UPDATE\DELETE</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>UPDATE\DELETE</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>UPDATE\DELETE</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();

JavaWeb(五):MVC案例的更多相关文章

  1. 【JavaWeb】MVC案例之新闻列表

    MVC案例之新闻列表 作者:白宁超 2016年6月6日15:26:30 摘要:本文主要针对javaweb基本开发之MVC案例的简单操作,里面涉及mysql数据库及表的创建,以及jsp页面和servle ...

  2. ASP.NET MVC案例教程(五)

    ASP.NET MVC案例教程(四) 前言 通过前几篇文章,我们已经能比较自如的使用ASP.NET MVC来呈现页面和数据了.但是,有一个大问题没有解决:如何处理表单数据.例如,我们将要实现的公告发布 ...

  3. Flume环境搭建_五种案例

    Flume环境搭建_五种案例 http://flume.apache.org/FlumeUserGuide.html A simple example Here, we give an example ...

  4. ASP.NET MVC案例教程(四)

    ASP.NET MVC案例教程(四) 前言 通过前几篇文章,我们已经能比较自如的使用ASP.NET MVC来呈现页面和数据了.但是,有一个大问题没有解决:如何处理表单数据.例如,我们将要实现的公告发布 ...

  5. SpringBoot系列之三_一个完整的MVC案例

    这一节让我们来做一个完整的案例. 我们将使用MyBatis作为ORM框架,并以非常简单的方式来使用MyBatis,完成一个完整的MVC案例. 此案例承接上一节,请先搭建好上一节案例. 一.数据库准备 ...

  6. ASP.NET MVC案例教程(二)

    ASP.NET MVC案例教程(二) 让第一个页面跑起来 现在,我们来实现公告系统中的第一个页面——首页.它非常简单,只包括所有公告分类的列表,并且每个列表项是一个超链接.其中分类数据是用我们的Moc ...

  7. ASP.NET MVC案例教程(三)

    ASP.NET MVC案例教程(二) 让第一个页面跑起来 现在,我们来实现公告系统中的第一个页面——首页.它非常简单,只包括所有公告分类的列表,并且每个列表项是一个超链接.其中分类数据是用我们的Moc ...

  8. ASP.NET MVC案例教程(一) 准备

    ASP.NET MVC案例教程(一) 前言 ASP.NET MVC作为微软官方的MVC解决方案,推出有一段时间了.可以说自动推出以来,一直广受关注.在经历了漫长的Preview之后,前几天终于推出了其 ...

  9. Flume环境搭建_五种案例(转)

    Flume环境搭建_五种案例 http://flume.apache.org/FlumeUserGuide.html A simple example Here, we give an example ...

  10. javaweb之MVC设计模式

    1.MVC简介 MVC是Model-View-Controller的简称,即模型-视图-控制器.MVC是一种设计模式,它把应用程序分成三个核心模块:模型,视图,控制器,它们各自处理自己的任务. 模型( ...

随机推荐

  1. 575 div 3 C. Robot Breakout

    C. Robot Breakout 题目大意: 一堆机器人,已知他们的初始位置(x,y),本来都可以向四个方向移动,但是一些原因,一个机器人的不能向某些方向移动,该方向能移动用1表示,否则用0 求他们 ...

  2. 学习日记3、投机取巧使两个表的数据同时在一个treeGrid中显示

    不多说了直接上代码, $('#List').treegrid({ url: '@Url.Action("GetList")', width: $(window).width() - ...

  3. LintCode之左填充

    题目描述: 分析:由样例可知,第二个参数表示要返回的字符串的最小长度,所以当给定字符串的长度小于规定字符串最小长度时就在左边填充空格,另外还有一个重载方法leftpad的第三个参数指定左边填充的字符. ...

  4. php面试专题---MySQL分区

    php面试专题---MySQL分区 一.总结 一句话总结: mysql的分区操作还比较简单,好处是也不用自己动手建表进行分区,和水平分表有点像 1.mysql分区简介? 一个表或索引-->N个物 ...

  5. linux常用符号命令

    1.符号: 在linux中,&和&&,|和||介绍如下: & 表示任务在后台执行,如要在后台运行redis-server,则有 redis-server & & ...

  6. Socket错误详解及处理方法

    例如错误代码10061, 说明服务器已经找到,但连接被服务器拒绝, 连接失败原因可能是: 端口号设置错误: 2.服务器没有处于监听状态 (即ServerSocket –>Active=true) ...

  7. Linux——管道与重定向

    参考资料: 极客学院IBMdeveloperWorks 重定向标准I/O Linux shell(比如Bash)接收或发送序列和字符串流形式的输入或输出.每个字符都独立于与之相邻的字符.字符没有被组织 ...

  8. "CoolShell puzzle game" writeup

    地址:http://fun.coolshell.cn/ Fuck your brain 看到一大串符号,还以为是 js 代码,结果放到 Chrome 控制台执行没有任何结果,然后搜了一下发现有一门叫B ...

  9. android handler 调用原理

    1,调度原理 andriod提供了Handler 和 Looper 来满足线程间的通信.Handler先进先出原则.Looper类用来管理特定线程内对象之间的消息交换(MessageExchange) ...

  10. Go错误处理机制及自定义错误

    错误处理机制: 先看一段代码:看看输出什么? package mainimport "fmt" func test() { num1 := 10 num2 := 0 res := ...