(未经允许,请勿转载,谢谢。)
本案例的处理过程:
客户端发送一个请求给服务器,服务器把这个请求给Servlet,Servlet 获取请求信息,根据请求信息的情况去调用 model (在这里是一个普通的 Java 类),然后把返回结果给 Servlet ,然后Servlet 根据返回结果 转向一个 JSP,JSP是用来呈现数据的 (这里用的是Java 代码),生成一个HTML 页面显给客户。
使用到的技术:
MVC 设计模式:JSP、Servlet、POJO
数据库:MySQL
连接数据库使用 c3p0 数据库连接池
JDBC 工具使用 DBUtils
页面上的提示操作使用 jQuery
具体实现步骤:
1、建立数据表
代码:
Create table customer(
id int(10) 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);
2、底层实现
①、加入c3p0 数据源:导入两个 jar 包(c3p0 和 数据库驱动),在 src 下新建配置文件:c3p0-config.xml ,修改一下要有连接数据库的基本信息(driverClass、jdbcUrl、user、password)。
c3p0-config.xml 代码:
1 <?xml version="1.0" encoding="UTF-8" ?> 2 <c3p0-config> 3 4 <named-config name="mvcapp"> 5 6 <!--指定连接数据源的基本信息 --> 7 <property name="driverClass">com.mysql.jdbc.Driver</property> 8 <property name="jdbcUrl">jdbc:mysql:///javawebdb</property> 9 <property name="user">root</property> 10 <property name="password">root</property> 11 12 <!-- 若数据库中连接不足时,一次性向数据库服务器申请多少个连接--> 13 <property name="acquireIncrement">5</property> 14 <!-- 初始化数据库连接池时连接的数量--> 15 <property name="initialPoolSize">10</property> 16 <!-- 数据库连接池中的最小的数据库连接数--> 17 <property name="minPoolSize">10</property> 18 <!-- 数据库连接池中的最大的数据库连接数--> 19 <property name="maxPoolSize">50</property> 20 21 <!-- c3p0 数据库连接池可以维护的 Statement 的个数--> 22 <property name="maxStatements">20</property> 23 <!-- 每个连接同时可以使用的Statement 对象的个数--> 24 <property name="maxStatementsPerConnection">5</property> 25 26 27 </named-config> 28 </c3p0-config>
②、编写DAO 工具类、JdbcUtils 工具类和 CustomerDao 接口(以下有具体说明和代码)
DAO 工具类:封装了基本的增删改查的方法,以供子类继承使用。当前DAO 没有事务,直接在方法中获取数据库连接。导入了DBUtils 的 jar 包,整个 DAO 采取 DBUtils 的解决方案。
实现方法:
update(封装了insert、delete、update)操作:public void update(String sql, Object...args){ }
查询 返回 T 对应的实体类的对象:public T get(String sql, Object...args){ }
查询 返回 T 对应的List :public List<T> getForList(String sql, Object...args){ }
查询 返回一个字段的值: public <E> E getForValue(String sql, Object...args){ }
DAO.java 代码:
1 package com.hnust.mvcapp.dao; 2 3 import java.lang.reflect.ParameterizedType; 4 import java.lang.reflect.Type; 5 import java.sql.Connection; 6 import java.sql.SQLException; 7 import java.util.List; 8 9 import org.apache.commons.dbutils.QueryRunner; 10 import org.apache.commons.dbutils.handlers.BeanHandler; 11 import org.apache.commons.dbutils.handlers.BeanListHandler; 12 import org.apache.commons.dbutils.handlers.ScalarHandler; 13 14 import com.hnust.mvcapp.utils.JdbcUtils; 15 16 /** 17 * 封装了基本的增删改查的方法,以供子类继承使用。 18 * 当前DAO 直接在方法中获取数据库连接。 19 * 整个DAO 采取DBUtils 解决方案。 20 * @author User 21 * 22 * @param <T> 当前 DAO 处理的实体类的类型是什么 23 */ 24 public class Dao<T> { 25 26 private QueryRunner queryRunner = new QueryRunner(); 27 28 private Class<T> clazz; 29 30 /** 31 * 需要确定 clazz 32 */ 33 public Dao(){ 34 //由得到子类的 Class得到父类 带泛型的那个类型。 35 Type superClass = getClass().getGenericSuperclass(); 36 //先判断是不是那个类型 37 if(superClass instanceof ParameterizedType){ 38 //是的话,强转一下 39 ParameterizedType parameterizedType = (ParameterizedType) superClass; 40 //获取真正的泛型的参数 41 Type[] typeArgs = parameterizedType.getActualTypeArguments(); 42 if(typeArgs != null && typeArgs.length >0){ 43 if(typeArgs[0] instanceof Class){ 44 clazz = (Class<T>) typeArgs[0]; 45 } 46 } 47 } 48 } 49 50 51 /** 52 * 查询,返回某一个字段的值 53 */ 54 public <E> E getForValue(String sql, Object...args){ 55 Connection connection = null; 56 try { 57 connection = JdbcUtils.getConnection(); 58 return (E) queryRunner.query(connection, sql, new ScalarHandler(), args); 59 } catch (SQLException e) { 60 e.printStackTrace(); 61 }finally{ 62 JdbcUtils.releaseConnection(connection); 63 } 64 return null; 65 } 66 67 /** 68 * 查询,返回T 所对应的 List 69 */ 70 public List<T> getForList(String sql, Object...args){ 71 Connection connection = null; 72 try { 73 connection = JdbcUtils.getConnection(); 74 return queryRunner.query(connection, sql, new BeanListHandler<>(clazz), args); 75 } catch (SQLException e) { 76 e.printStackTrace(); 77 }finally{ 78 JdbcUtils.releaseConnection(connection); 79 } 80 return null; 81 } 82 83 /** 84 * 查询,返回一个T 的实体类对象 85 */ 86 public T get(String sql, Object...args){ 87 Connection connection = null; 88 89 try { 90 connection = JdbcUtils.getConnection(); 91 return queryRunner.query(connection, sql, new BeanHandler<>(clazz), args); 92 } catch (SQLException e) { 93 e.printStackTrace(); 94 }finally{ 95 JdbcUtils.releaseConnection(connection); 96 } 97 return null; 98 } 99 100 /** 101 * 通用的 insert 、delete、update 方法 102 */ 103 public void update(String sql, Object...args){ 104 Connection connection = null; 105 try { 106 connection = JdbcUtils.getConnection(); 107 queryRunner.update(connection, sql, args); 108 } catch (Exception e) { 109 e.printStackTrace(); 110 }finally{ 111 JdbcUtils.releaseConnection(connection); 112 } 113 } 114 }
JdbcUtils 工具类:JDBC 操作的工具类。
实现方法:
返回数据源的一个 Connection 对象:public static Connection getConnection(){ }
释放 Connection 的连接:public static void releaseConnection(Connection connection){ }
注意:数据源的初始化一定要放在静态代码块中,数据源被创建一次就够了。写完一个可以用单元测试检验以下。
JdbcUtils.java 代码:
1 package com.hnust.mvcapp.utils; 2 3 import java.sql.Connection; 4 import java.sql.SQLException; 5 6 import javax.sql.DataSource; 7 8 import com.mchange.v2.c3p0.ComboPooledDataSource; 9 10 /** 11 * JDBC 操作的工具类 12 * @author User 13 * 14 */ 15 public class JdbcUtils { 16 17 /** 18 * 释放连接 19 */ 20 public static void releaseConnection(Connection connection){ 21 22 try { 23 if(connection != null){ 24 connection.close(); 25 } 26 } catch (Exception e) { 27 e.printStackTrace(); 28 } 29 } 30 31 private static DataSource dataSource = null; 32 static{ 33 dataSource = new ComboPooledDataSource("mvcapp"); //传入的是 configName 34 } 35 /** 36 * 获取连接 37 * @throws SQLException 38 */ 39 public static Connection getConnection() throws SQLException{ 40 41 return dataSource.getConnection(); 42 } 43 }
CustomerDao 接口:
实现的方法:
模糊查询 返回满足条件的List :public List<Customer> getForListWithCriteriaCustomer(CriteriaCustomer cc);
查询 返回List:public List<Customer> getAll();
添加:poublic void save(Customer customer);
修改时要根据id 的查询显示:public Customer get(Inreger id);
删除(根据 id):public void delete(Integer id);
查询 和这个名字一样的 记录数(根据 name):public long getCountWithName(String name);
CustomerDao.java 代码:
1 package com.hnust.mvcapp.dao; 2 3 import java.util.List; 4 5 import com.hnuct.mvcapp.entity.Customer; 6 7 public interface CustomerDao { 8 9 /** 10 * 模糊查询 返回满足条件的List 11 * @param cc :封装了查询条件 12 * @return 13 */ 14 public List<Customer> getForListWithCriteriaCustomer(CriteriaCustomer cc); 15 16 /** 17 * 查询 返回 List 18 */ 19 public List<Customer> getAll(); 20 21 /** 22 * 增加 23 */ 24 public void save(Customer customer); 25 26 /** 27 * 修改 更新时候的查询(根据id)显示 28 */ 29 public Customer get(Integer id); 30 31 /** 32 * 删除 33 */ 34 public void delete(Integer id); 35 36 /** 37 * 返回和name 相同的记录数 38 */ 39 public long getCountWithName(String name); 40 }
实体类 Customer:
Customer.java 代码:
1 package com.hnuct.mvcapp.entity; 2 3 public class Customer { 4 5 private Integer id; 6 private String name; 7 private String address; 8 private String phone; 9 public Integer getId() { 10 return id; 11 } 12 public void setId(Integer id) { 13 this.id = id; 14 } 15 public String getName() { 16 return name; 17 } 18 public void setName(String name) { 19 this.name = name; 20 } 21 public String getAddress() { 22 return address; 23 } 24 public void setAddress(String address) { 25 this.address = address; 26 } 27 public String getPhone() { 28 return phone; 29 } 30 public void setPhone(String phone) { 31 this.phone = phone; 32 } 33 public Customer(Integer id, String name, String address, String phone) { 34 super(); 35 this.id = id; 36 this.name = name; 37 this.address = address; 38 this.phone = phone; 39 } 40 public Customer() { 41 super(); 42 } 43 44 @Override 45 public String toString() { 46 return "Customers [id=" + id + ", name=" + name + ", address=" 47 + address + ", phone=" + phone + "]"; 48 } 49 50 51 }
Dao 接口的实现:
CustomerDaoJdbcImpl.java 代码:
1 package com.hnuct.mvcapp.dao.impl; 2 3 import java.util.List; 4 5 import com.hnuct.mvcapp.entity.Customer; 6 import com.hnust.mvcapp.dao.CriteriaCustomer; 7 import com.hnust.mvcapp.dao.CustomerDao; 8 import com.hnust.mvcapp.dao.Dao; 9 10 public class CustomerDaoJdbcImpl extends Dao<Customer> implements CustomerDao{ 11 12 @Override 13 public List<Customer> getAll() { 14 String sql = "select * from customer"; 15 return getForList(sql); 16 } 17 18 @Override 19 public void save(Customer customer) { 20 String sql = "insert into customer(name,address,phone) values (?,?,?)"; 21 update(sql, customer.getName(), customer.getAddress(), customer.getPhone()); 22 } 23 24 @Override 25 public Customer get(Integer id) { 26 String sql = "select * from customer where id = ?"; 27 return get(sql, id); 28 } 29 30 @Override 31 public void delete(Integer id) { 32 String sql = "delete from customer where id = ? "; 33 update(sql, id); 34 } 35 36 @Override 37 public long getCountWithName(String name) { 38 String sql = "select count(id) from customer where name = ?"; 39 return getForValue(sql, name); 40 } 41 42 @Override 43 public List<Customer> getForListWithCriteriaCustomer(CriteriaCustomer cc) { 44 String sql = "SELECT id,name,address,phone FROM customer WHERE name LIKE ? AND " 45 + "address LIKE ? AND phone LIKE ?"; 46 //注意:修改了 CriteriaCustomer 的 getter 方法,使其返回的字符串中有 "%%", 47 //若返回值为 null 则返回 "%%" ,若不为 null, 则返回 "% " + 字段本身的值 + " %" 48 return getForList(sql, cc.getName(), cc.getAddress(), cc.getPhone()); 49 } 50 51 }
ps:注意因为查询条件很多时候 和 实体类 并不相同,所以要做成一个单独的类,这里是 CriteriaCustomer 类,其中里面的getter 方法做了修改,是为了正确的填充占位符。
CriteriaCustomer.java 代码:
1 package com.hnust.mvcapp.dao; 2 3 public class CriteriaCustomer { 4 5 private String name; 6 private String address; 7 private String phone; 8 public String getName() { 9 if(name == null) 10 name = "%%"; 11 else 12 name = "%" + name + "%"; 13 return name; 14 } 15 public void setName(String name) { 16 this.name = name; 17 } 18 public String getAddress() { 19 if(address == null) 20 address = "%%"; 21 else 22 address = "%" + address + "%"; 23 return address; 24 } 25 public void setAddress(String address) { 26 this.address = address; 27 } 28 public String getPhone() { 29 if(phone == null) 30 phone = "%%"; 31 else 32 phone = "%" + phone + "%"; 33 return phone; 34 } 35 public void setPhone(String phone) { 36 this.phone = phone; 37 } 38 39 40 41 public CriteriaCustomer() { 42 super(); 43 } 44 public CriteriaCustomer(String name, String address, String phone) { 45 super(); 46 this.name = name; 47 this.address = address; 48 this.phone = phone; 49 } 50 51 52 }
3、Servlet 的实现:获取请求信息的参数,根据请求信息调用 DAO 的对应的方法。
先写了一个 test.jsp 页面 放了三个超链接。
test.jsp 代码:
1 <%@ page language="java" contentType="text/html; charset=UTF-8" 2 pageEncoding="UTF-8"%> 3 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> 4 <html> 5 <head> 6 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> 7 <title>Insert title here</title> 8 </head> 9 <body> 10 <%-- 11 <a href="customerServlet?method=add">add</a> 12 <br><br> 13 <a href="customerServlet?method=query">query</a> 14 <br><br> 15 <a href="customerServlet?method=delete">delete</a> 16 --%> 17 18 <a href="addCustomer.do">add</a> 19 <br><br> 20 <a href="query.do">query</a> 21 <br><br> 22 <a href="delete.do">delete</a> 23 <br><br> 24 25 26 27 </body> 28 </html>
注意你的 web.xml 里的 url-pattern:<url-pattern>*.do</url-pattern>
然后 创建了CustomerServlet :去响应服务器的请求,调用对应的model,返回结果(我这里暂时实现了 模糊查询和 删除的功能)。
CustomerServlet.java 代码:
1 package com.hnust.mvcapp.servlet; 2 3 import java.io.IOException; 4 import java.lang.reflect.InvocationTargetException; 5 import java.lang.reflect.Method; 6 import java.util.List; 7 8 import javax.servlet.ServletException; 9 import javax.servlet.http.HttpServlet; 10 import javax.servlet.http.HttpServletRequest; 11 import javax.servlet.http.HttpServletResponse; 12 13 import com.hnuct.mvcapp.dao.impl.CustomerDaoJdbcImpl; 14 import com.hnuct.mvcapp.entity.Customer; 15 import com.hnust.mvcapp.dao.CriteriaCustomer; 16 import com.hnust.mvcapp.dao.CustomerDao; 17 18 19 public class CustomerServlet extends HttpServlet { 20 private static final long serialVersionUID = 1L; 21 22 private CustomerDao customerDao = new CustomerDaoJdbcImpl(); 23 24 protected void doGet(HttpServletRequest request, HttpServletResponse response) 25 throws ServletException, IOException { 26 27 this.doPost(request, response); 28 } 29 30 @Override 31 protected void doPost(HttpServletRequest req, HttpServletResponse resp) 32 throws ServletException, IOException { 33 34 //1、获取servletPath 35 String servletPath = req.getServletPath(); 36 //System.out.println(servletPath); //得到的是 /addCustomer.do 37 38 //2、去除 / 和 .do ,得到 addCustomer 这样的字符串 39 String methodName = servletPath.substring(1); 40 methodName = methodName.substring(0, methodName.length() - 3); 41 //System.out.println(methodName); // 得到的是 addCustomer 42 43 try { 44 //3、利用反射,根据获取的 方法名,获取对应的方法。 45 Method method = getClass().getDeclaredMethod(methodName, HttpServletRequest.class, 46 HttpServletResponse.class); 47 //4、利用反射调用对应的方法 48 method.invoke(this, req, resp); 49 50 } catch (Exception e) { 51 e.printStackTrace(); 52 //可以有一些响应 53 resp.sendRedirect("error.jsp"); 54 } 55 56 } 57 58 private void delete(HttpServletRequest request, HttpServletResponse response) 59 throws ServletException, IOException { 60 //1、获取 id 61 String idStr = request.getParameter("id"); 62 int id = 0; 63 //为了避免输入的 id 是不 合法的。 idStr 不能转为 int 类型。若不能转,则 id 为0,无法执行任何的操作。 64 try { 65 id = Integer.parseInt(idStr); 66 //2、调用 CustomerDAO 的 delete 方法 67 customerDao.delete(id); 68 //3、页面的重定向 69 response.sendRedirect("query.do"); 70 } catch (Exception e) { 71 e.printStackTrace(); 72 } 73 } 74 75 private void query(HttpServletRequest request, HttpServletResponse response) 76 throws ServletException, IOException { 77 //1、获取模糊查询的请求参数 78 String name = request.getParameter("name"); 79 String address = request.getParameter("address"); 80 String phone = request.getParameter("phone"); 81 82 //2、把请求参数封装为 CriteriaCustomer 对象 83 CriteriaCustomer cc = new CriteriaCustomer(name, address, phone); 84 85 //3、再调用CustomerDao 的 getForListWithCriteriaCustomer() 方法 86 List<Customer> customers = customerDao.getForListWithCriteriaCustomer(cc); 87 88 //调用CustomerDao 的 getAll() 方法 查询。 89 //List<Customer> customers = customerDao.getAll(); 90 91 //4、把查询到的结果集放入 request 中 92 request.setAttribute("customers", customers); 93 //5、请求的转发 94 request.getRequestDispatcher("/index.jsp").forward(request, response); 95 96 } 97 98 private void addCustomer(HttpServletRequest request, HttpServletResponse response) 99 throws ServletException, IOException { 100 101 System.out.println("add"); 102 } 103 104 }
4、返回结果 的 JSP 页面:获取返回结果,遍历显示。
index.jsp 代码:
1 <%@page import="com.hnuct.mvcapp.entity.Customer"%> 2 <%@page import="java.util.List"%> 3 <%@ page language="java" contentType="text/html; charset=UTF-8" 4 pageEncoding="UTF-8"%> 5 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> 6 <html> 7 <head> 8 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> 9 <title>Insert title here</title> 10 <script type="text/javascript" src="Scripts/jquery-1.7.2.js"></script> 11 <script type="text/javascript"> 12 $(function(){ 13 $(".delete").click(function(){ 14 var content = $(this).parent().parent().find("td:eq(1)").text(); 15 var flag = confirm("确定要删除 " + content + " 的信息吗?"); 16 return flag; 17 }); 18 }) 19 </script> 20 </head> 21 <body> 22 <form action="query.do" method="post"> 23 <table> 24 <tr> 25 <td>name:</td> 26 <td><input type="text" name="name"/></td> 27 </tr> 28 <tr> 29 <td>address:</td> 30 <td><input type="text" name="address"/></td> 31 </tr> 32 <tr> 33 <td>phone:</td> 34 <td><input type="text" name="phone"/></td> 35 36 <tr> 37 <td><input type="submit" value="Query"/></td> 38 <td><a href="">Add new Customer</a></td> 39 </tr> 40 </table> 41 </form> 42 <br><br> 43 44 <% 45 List<Customer> customers = (List<Customer>) request.getAttribute("customers"); 46 if(customers != null && customers.size() > 0){ 47 %> 48 <hr> 49 <br><br> 50 <table border="1" cellpadding="10" cellspacing="0"> 51 <tr> 52 <th>ID</th> 53 <th>NAME</th> 54 <th>ADDRESS</th> 55 <th>PHONE</th> 56 <th>UPDATE/DELETE</th> 57 </tr> 58 <% for(Customer cust : customers){ 59 60 %> 61 <tr> 62 <td><%= cust.getId() %></td> 63 <td><%= cust.getName() %></td> 64 <td><%= cust.getAddress() %></td> 65 <td><%= cust.getPhone() %></td> 66 <td> 67 <a href="">Update</a> 68 <a href="delete.do?id=<%=cust.getId() %>" class="delete">Delete</a> 69 </td> 70 </tr> 71 <% 72 } 73 %> 74 </table> 75 <% 76 } 77 %> 78 </body> 79 </html>
最后结果:
点击query
可以实现模糊查询,和删除的功能。
这是今天的学习内容。