基於JAVA-MVC技術的顧客管理項目案例總結
作者 白寧超
2016年6月9日22:47:08
閱讀前瞻:本文源於對javaweb相關技術和資料匯總,涉及大量javaweb基礎技術諸如:Servlet運行原理、Get/Post請求的區別、jsp的基本原理和運行框架、jsp的9大隱含對象的使用、MVC開發模式的使用、構建封裝自己dao代碼庫、以及基於MVC的增刪改查操作等;小結最后還有面向接口編程的多數據源配置與存儲,以及工廠模式的使用。除此之外,后續文章會對cookie、session、JavaBean、監聽、權限管理、文件上傳與下載、分頁等諸多技術匯總。本文旨在java-web多技術貫穿於單項目中,逐漸深入的過程,使得大家既學習了java技術路線,也知道其怎么用。最后會附上源碼,最后一節重點對所有實現技術小結與匯總,此過程會使用作者項目技術理解、網絡資源資料、學習視頻和文檔截圖文件等為參考,力求簡單通俗易學。最后,作者文章布局采用:1、實驗准備;2、需求分析;3、模塊化實現;4、實驗優化;5、技術梳理的寫作思路。(本文原創,轉載標明出處:基於JAVA-MVC技術的顧客管理項目案例總結)
一、實驗准備階段:
1 win*系統,一般配置筆記本或者台式機
2 安裝MyEclipse開發平台,本實驗使用MyEclipse2015(點擊下載 訪問密碼 eafa)
3 Mysql數據庫,本實驗采用mysql-installer-community-5.6.14.0.msi(點擊下載 訪問密碼 39bf)
4 關於數據庫連接的3個JAR包
4.1 JDBC鏈接數據庫的jar包,本實驗采用mysql-connector-java-5.1.20.jar(點擊下載 訪問密碼 8bb1)
4.2 dbUtils數據庫JAR包,本實驗采用commons-dbutils-1.6.jar(點擊下載 訪問密碼 535d)
4.3 c3p0數據庫配置JAR包,本實驗采用c3p0-0.9.1.2.jar(點擊下載 訪問密碼 9916)
5 兩個公共文件
5.1 關於編寫Jquery需要的js文件,本實驗使用jquery.min.js(點擊下載 訪問密碼 3357)
5.2 關於c3p0數據庫配置xml源文件c3p0-config.xml(點擊下載 訪問密碼 33a6)
二、需求分析階段
1 對MyEclipse和MySql的正確安裝,並對MyEclipse環境變量配置:(配置參考文檔)
2 要求l使用mysql數據庫去創建數據庫test和表customers(id int 主鍵自增,name String 唯一約束,address String,phone String)
3 采用MVC技術開發,實現M/V/C很好的封裝與解耦,在此基礎完成對顧客表的增刪改查,其中要求數據可以回顯、模糊查詢、容錯等
4 servlet初始化啟動控制多數據源配置
5 其他諸如分頁、cookie、session、JavaBean、監聽、權限管理、文件上傳與下載等后續文章繼續完善優化。
三、數據庫創建階段
# 創建數據庫test create database test; use test; #創建customer表id主鍵自增,name唯一 create table customers( id varchar(11) primary key not null, name varchar(70) not null unique, address varchar(70), phone varchar(70) );
四、基於MVC技術開發階段
1 顧客管理項目環境配置簡介
MVC百度百科:MVC全名是Model View Controller,是模型(model)-視圖(view)-控制器(controller)的縮寫,一種軟件設計典范,用一種業務邏輯、數據、界面顯示分離的方法組織代碼,將業務邏輯聚集到一個部件里面,在改進和個性化定制界面及用戶交互的同時,不需要重新編寫業務邏輯。MVC被獨特的發展起來用於映射傳統的輸入、處理和輸出功能在一個邏輯的圖形化用戶界面的結構中。(注:詳細MVC可以參照官方文檔或者google)
配置簡介:
1 新建java web項目,默認基礎下分別建立MVC對於的包,以及添加需要配置的jar包、js文件、xml文件、imgs等文件,打通整體開發框架。
2 創建需要完成jsp頁面
2 MVC架構搭建
1、配置文件的引用
mysql-connector-java-5.1.20.jar:連接數據庫的jar包,放於./WEB-INF/lib下
commons-dbutils-1.6.jar:dbutils的jar包,放於./WEB-INF/lib下
c3p0-0.9.1.2.jar:c3p0的jar包,放於./WEB-INF/lib下
jquery.min.js:用於編寫js的文件,放於./WebRoot/scripts下
c3p0-config.xml:用於配置數據庫,放於./src下
<?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:///test</property> <property name="acquireIncrement">5</property> <property name="initialPoolSize">10</property> <property name="minPoolSize">10</property> <property name="maxPoolSize">50</property> <!-- intergalactoApp adopts a different approach to configuring statement caching --> <property name="maxStatements">20</property> <property name="maxStatementsPerConnection">5</property> </named-config> </c3p0-config>
2、 數據層配置
com.cuit.mvc.db包:JdbcUtils.java數據庫連接和釋放方法的封裝
package com.cuit.mvc.db; import java.sql.Connection; import java.sql.SQLException; import javax.sql.DataSource; import com.mchange.v2.c3p0.ComboPooledDataSource; /** * JDBC操作工具 * @author 白寧超 http://www.cnblogs.com/baiboy/ */ public class JdbcUtils { /** * 釋放Connection鏈接 * @param connection */ public static void releaseConnection(Connection connection){ try{ if(connection!=null) connection.close(); }catch(Exception e){ e.printStackTrace(); } } private static DataSource dataSource = null; static{ dataSource=new ComboPooledDataSource("mvcapp"); } /** * 返回數據源的一個Connection對象 * @return * @throws SQLException */ public static Connection getConnection() throws SQLException{ return dataSource.getConnection(); } }
com.cuit.mvc.model包:Customer.java實體類的封裝
package com.cuit.mvc.model; public class Customer { private int id; private String name; private String address; private String phone; public int getId() { return id; } public Customer() { } public Customer(String name, String address, String phone) { this.name = name; this.address = address; this.phone = phone; } public void setId(int 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+"]"; } }
com.cuit.mvc.dao包:DAO.java最底層公共方法封裝;CustomerDAO提供公共方法的接口;
DAO源碼:
package com.cuit.mvc.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.cuit.mvc.db.JdbcUtils; /** * 封裝了基本的CRUD的方法,以供子類繼承使用 * 當前DAO直接在方法中獲取數據庫連接 * @param <T> :當前DAO處理實體的類型是什么 * @author 白寧超 http://www.cnblogs.com/baiboy/ * */ public class DAO<T> { //此步驟前需要/lib加入commons-dbutils-xx.jar private QueryRunner queryRunner=new QueryRunner(); private Class<T> clazz; public DAO(){ //Type通過Ctrl+Shift+O進行反射Type選擇 Type superClass=getClass().getGenericSuperclass(); if(superClass instanceof ParameterizedType){ ParameterizedType parameterizedType=(ParameterizedType)superClass; Type[] typeArgs=parameterizedType.getActualTypeArguments(); if(typeArgs!=null && typeArgs.length>0){ if(typeArgs[0] instanceof Class) clazz=(Class<T>)typeArgs[0]; } } } /** * 返回某一個字段的值,或者返回數據表中有多少條記錄等。 * @param sql:SQL語句 * @param args:填充SQL語句的占位符 * @return */ public <E> E getForValue(String sql,Object ... args) { Connection connection=null; try{ connection=JdbcUtils.getConnection(); return (E) queryRunner.query(connection,sql,new ScalarHandler<T>(),args); }catch(Exception e){ e.printStackTrace(); }finally{ JdbcUtils.releaseConnection(connection); } return null; } /** * 返回T所對應的List * @param sql:SQL語句 * @param args:填充SQL語句的占位符 * @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; } /** * 返回對應T的一個實體類對象 * @param sql:SQL語句 * @param args:填充SQL語句的占位符 * @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; } /** * 該方法封裝了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); } } }
CustomerDAO源碼:
package com.cuit.mvc.dao; import java.util.List; import com.cuit.mvc.model.CriteriaCustomer; import com.cuit.mvc.model.Customer; public interface CustomerDAO { public List<Customer> getAll();//獲取Customer列表信息 public void save(Customer customer);//對Customer的添加,通過CTRL+T轉到定義 public void update(Customer customer);//對Customer的更新,通過CTRL+T轉到定義 public Customer get(int id);//獲取Customer實體 public void delete(int id);//根據id進行刪除 public long getCountWithName(String name);//返回name相等的記錄數 //cc封裝了查詢條件,返回查詢條件的list public List<Customer> getForListWithCriteriaCustomer(CriteriaCustomer cc); }
com.cuit.mvc.dao.impl包:CustomerDAOJdbcImpl.java:Customer對CustomerDAO具體方法的實現
package com.cuit.mvc.dao.impl; import java.util.List; import com.cuit.mvc.dao.CustomerDAO; import com.cuit.mvc.dao.DAO; import com.cuit.mvc.model.CriteriaCustomer; import com.cuit.mvc.model.Customer; public class CustomerDAOJdbcImpl extends DAO<Customer> implements CustomerDAO{ public List<Customer> getForListWithCriteriaCustomer(CriteriaCustomer cc) { String sql="select * from customers where name like ? and address like ? " + "and phone like ?"; //修改了CriteriaCustomer的getter方法:使其返回字符串中有%% //若返回值為null返回%%,若不返回null則返回:"%"+字段本身的值+"%" //如上效果如:cc.getName()==null?%%:%+name+% System.out.println(sql); return getForList(sql,cc.getName(),cc.getAddress(),cc.getPhone()); } @Override public List<Customer> getAll() { String sql="select * from customers"; return getForList(sql); } @Override public void save(Customer customer) { String sql="insert customers(name,address,phone) values(?,?,?)"; update(sql, customer.getName(),customer.getAddress(),customer.getPhone()); } @Override public Customer get(int id) { String sql="select * from customers where id=?"; return get(sql,id); } @Override public void delete(int 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 void update(Customer customer) { String sql="update customers set name=?,address=?,phone=? where id=?"; update(sql,customer.getName(),customer.getAddress(),customer.getPhone(),customer.getId()); } }
3 業務邏輯層
com.cuit.mvc.dao.servlet包:CustomerServlet.java對CustomerDAO公共方法具體實現,以及頁面顯示的控制
package com.cuit.mvc.servlet; import java.io.IOException; import java.io.PrintWriter; 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.cuit.mvc.dao.CustomerDAO; import com.cuit.mvc.dao.factory.CustomerDAOFactory; import com.cuit.mvc.dao.impl.CustomerDAOJdbcImpl; import com.cuit.mvc.dao.impl.CustomerDAOXMLImpl; import com.cuit.mvc.model.CriteriaCustomer; import com.cuit.mvc.model.Customer; public class CustomerServlet extends HttpServlet { //private CustomerDAO customerDAO=new CustomerDAOJdbcImpl(); //private CustomerDAO customerDAO=new CustomerDAOXMLImpl(); private CustomerDAO customerDAO=CustomerDAOFactory.getInstance().getCustomerDAO(); public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } /*public 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; default: break; } }*/ @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //1 獲取servlet路徑 諸如:/add.do String servletPath=req.getServletPath().substring(1); //去除/和.do得到類似於add這樣字符串 String methodName=servletPath.substring(0,servletPath.length()-3); //System.out.println(methodName); try { //利用反射獲取獲取methodName對應的方法 Method method = getClass().getDeclaredMethod(methodName, HttpServletRequest.class,HttpServletResponse.class); //利用反射獲取方法 method.invoke(this, req,resp); } catch (Exception e) { //出錯時候響應出來 resp.sendRedirect("error.jsp"); } } private void edit(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{ String forwordPath="/error.jsp"; //1 獲取請求參數id String idstr=request.getParameter("id"); //2 調用CustomeDAO的customerDAO.get(id)獲取和id對應的Customer對象customer try{ Customer customer=customerDAO.get(Integer.parseInt(idstr)); if(customer!=null){ forwordPath="/updatecustomer.jsp"; //3 將customer放在request中 request.setAttribute("customer", customer); } }catch(Exception e){} //4 響應updatecustomer.jsp頁面:轉發 request.getRequestDispatcher(forwordPath).forward(request, response); } private void update(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{ //1 獲取請求參數:id,name,address,phone,oldname String id=request.getParameter("id"); String name=request.getParameter("name"); String oldname=request.getParameter("oldname"); String address=request.getParameter("address"); String phone=request.getParameter("phone"); //2 檢驗name是否被占用 //2.1 比較name和oldname是否相同,若相同name可用,oldname.equals(name)不如equalsIgnoreCase,數據庫默認大小寫一致的,而equals忽略大小寫 if(!oldname.equalsIgnoreCase(name)){ //不相同,調用CustomerDAO的getCountWithName(String name)獲取name在數據庫中是否存在 long count=customerDAO.getCountWithName(name); //大於0, 響應updatecustomer.jsp頁面:通過轉發響應newcustomer.jsp if(count>0){ // 通過request.getAttribute("message")顯示信息,在頁面上request.getAttribute("message")的方式顯示 // 表單據回顯。address,phone顯示提交的新值, name顯示oldname,而不是新值 request.setAttribute("message", "用戶名["+name+"]已經被占用,請重新填寫!"); // 方法結束 request.getRequestDispatcher("/updatecustomer.jsp").forward(request, response); 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"); } //模糊查詢 private void query(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{ String name=request.getParameter("name"); String address=request.getParameter("address"); String phone=request.getParameter("phone"); CriteriaCustomer cc=new CriteriaCustomer(name,address,phone); //1 調用CustomerDAO的getALl方法得到Customer集合 //List<Customer> sustomers=customerDAO.getAll();獲取所有信息列表 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 delete(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{ String idstr=request.getParameter("id").trim(); int id=0; try{ id=Integer.parseInt(idstr); customerDAO.delete(id); }catch(Exception e){} response.sendRedirect("query.do"); } //此方法名稱跟頁面add添加的action中add.do匹配 private void add(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(String name)獲取name在數據庫中是否存在 long count=customerDAO.getCountWithName(name); if(count>0){ //2.2 若返回值大於0,則相應newcustomer.jsp頁面:①在此頁面顯示一個錯誤信息②此表單值可以回顯 // 通過request.getAttribute("message")顯示信息 // 通過value="<%=request.getParameter("name")==null?"":request.getParameter("name")%>"回顯 request.setAttribute("message", "用戶名["+name+"]已經被占用,請重新填寫!"); request.getRequestDispatcher("/newcustomer.jsp").forward(request, response); return; } //3 若驗證通過,把表單參數封裝為一個Customer對象customer Customer customer=new Customer(name,address,phone); //4 調用CustomerDAO的save(Customer customer)執行保存操作 customerDAO.save(customer); //5 重定向到success.jsp頁面 response.sendRedirect("success.jsp"); } }
4 單元測試層
com.cuit.mvc.dao.test包:JdbcUtilsTest.java對CustomerServlet.java各個方法單元測試
package com.cuit.mvc.test; import static org.junit.Assert.*; import java.util.List; import org.junit.Test; import com.cuit.mvc.dao.CustomerDAO; import com.cuit.mvc.dao.impl.CustomerDAOJdbcImpl; import com.cuit.mvc.model.CriteriaCustomer; import com.cuit.mvc.model.Customer; public class CustomerDAOJdbcImplTest { private CustomerDAO customerDAO=new CustomerDAOJdbcImpl(); @Test public void getForListWithCriteriaCustomer(){ CriteriaCustomer cc=new CriteriaCustomer("Tom", null, null); List<Customer> customers=customerDAO.getForListWithCriteriaCustomer(cc); System.out.println(customers); } @Test public void testGetAll() { List<Customer> customers=customerDAO.getAll(); System.out.println(customers); } @Test public void testSaveCustomer() { Customer customer=new Customer("Baijing","Shanghai","134-2345-9086"); customerDAO.save(customer); } @Test public void testGetInt() { Customer cust=customerDAO.get(0); System.out.println(cust); } @Test public void testDelete() { customerDAO.delete(2); } @Test public void testGetCountWithName() { long count=customerDAO.getCountWithName("Tom"); System.out.println(count); } }
5 視圖顯示頁面層
index.jsp:顯示顧客信息,並支持回顯
<%@page import="com.cuit.mvc.model.Customer"%> <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <base href="<%=basePath%>"> <title>My JSP 'index.jsp' starting page</title> <script type="text/javascript" src="scripts/jquery.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"> <table> <tr> <td>CustomerName:</td> <td><input type="text" name="name"/></td> </tr> <tr> <td>CustomerAddress:</td> <td><input type="text" name="address"/></td> </tr> <tr> <td>CustomerPhone:</td> <td><input type="text" name="phone"/></td> </tr> <tr> <td><input type="submit" value="Query"/></td> <td><a href="newcustomer.jsp">Create New Customer</a></td> </tr> </table> </form> <br/><br/> <% List<Customer> customers=(List<Customer>)request.getAttribute("customers"); if(customers!=null && customers.size()>0){ %> <hr> <br/><br/> <table border="1" cellpadding="10" cellspacing="0"> <tr> <th>ID</th> <th>CustomerName</th> <th>CustomerAddress</th> <th>CustomerPhone</th> <th>Update/Delete</th> </tr> <% for(Customer customer:customers){ %> <tr> <td class="id"><%=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="delete.do?id=<%=customer.getId() %>" class="delete">Delete</a> </td> </tr> <% } %> </table> <% } %> </body> </html>
error.jsp:異常或者報錯頁面跳轉
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <base href="<%=basePath%>"> <title>My JSP 'error.jsp' starting page</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> <meta http-equiv="description" content="This is my page"> <!-- <link rel="stylesheet" type="text/css" href="styles.css"> --> </head> <body> <h4>對不起沒有您請求的頁面</h4> <img style=" height:200px; width: 200; margin: 0 auto;" src="imgs/error.jpg"></img><br/><br> <p style="font-size: 25px; color: red;">對不起訪問失敗!</p> </body> </html>
newcustomer.jsp:添加顧客信息頁面,支持回顯,控制name不能重復
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> <% Object mes=request.getAttribute("message"); if(mes!=null){ out.print("<br>"); out.print(mes); out.print("<br>"); out.print("<br>"); } %> <h1>添加一條新的customer信息</h1> <!--此處add.do依賴於CustomerServlet中的add方法名 --> <form action="add.do"> <table> <tr> <td>CustomerName:</td> <td><input type="text" name="name" value="<%=request.getParameter("name")==null?"":request.getParameter("name")%>"/></td> </tr> <tr> <td>CustomerAddress:</td> <td><input type="text" name="address" value="<%=request.getParameter("address")==null?"":request.getParameter("address")%>"/></td> </tr> <tr> <td>CustomerPhone:</td> <td><input type="text" name="phone" value="<%=request.getParameter("phone")==null?"":request.getParameter("phone")%>"/></td> </tr> <tr> <td colspan="2"><input type="submit" value="Submit"/></td> </tr> </table> </form> </body> </html>
success.jsp:添加新信息成功跳轉頁面
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> <h2>成功添加,保存成功!</h2><br/><br/> <h2><a href="index.jsp">Back Index</a></h2> </body> </html>
updatecustomer.jsp:更新信息頁面,支持回顯,回顯顯示的是name舊值
<%@page import="com.cuit.mvc.model.Customer"%> <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> <% Object mes=request.getAttribute("message"); if(mes!=null){ out.print("<br>"); out.print(mes); out.print("<br>"); out.print("<br>"); } String id=null; String name=null; String oldname=null; String address=null; String phone=null; Customer customer=(Customer)request.getAttribute("customer"); if(customer!=null){ id=customer.getId()+""; address=customer.getAddress(); name=customer.getName(); oldname=customer.getName(); phone=customer.getPhone(); }else{ id=request.getParameter("id"); name=request.getParameter("oldname"); oldname=request.getParameter("oldname"); address=request.getParameter("address"); phone=request.getParameter("phone"); } %> <h1>更新一條新的customer信息</h1> <!--此處add.do依賴於CustomerServlet中的add方法名 --> <form action="update.do"> <input type="hidden" name="id" value="<%=customer.getId()%>"/> <input type="hidden" name="oldname" value="<%=oldname%>"/> <table> <tr> <td>CustomerName:</td> <td><input type="text" name="name" value="<%=name%>"/></td> </tr> <tr> <td>CustomerAddress:</td> <td><input type="text" name="address" value="<%=address %>"/></td> </tr> <tr> <td>CustomerPhone:</td> <td><input type="text" name="phone" value="<%=phone%>"/></td> </tr> <tr> <td colspan="2"><input type="submit" value="Submit"/></td> </tr> </table> </form> </body> </html>
3 顧客信息模糊查詢設計與實現
1) 項目設計分析: 實現name,address,phone聯合模糊查詢
1、 調用CustomerDAO的getALl方法得到Customer集合
2、 把customer的集合放入request
3、 轉發頁面index.jsp(不能使用重定向)
4、 index.jsp頁面循環遍歷顯示
2)項目源碼實現
1 DAO數據操作
public List<Customer> getForListWithCriteriaCustomer(CriteriaCustomer cc) {
String sql="select * from customers where name like ? and address like ? "
+ "and phone like ?";
//修改了CriteriaCustomer的getter方法:使其返回字符串中有%%
//若返回值為null返回%%,若不返回null則返回:"%"+字段本身的值+"%"
//如上效果如:cc.getName()==null?%%:%+name+%
System.out.println(sql);
return getForList(sql,cc.getName(),cc.getAddress(),cc.getPhone());
}
2、servlet控制源碼:
//模糊查詢
private void query(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
String name=request.getParameter("name");
String address=request.getParameter("address");
String phone=request.getParameter("phone");
CriteriaCustomer cc=new CriteriaCustomer(name,address,phone);
//1 調用CustomerDAO的getALl方法得到Customer集合
//List<Customer> sustomers=customerDAO.getAll();獲取所有信息列表
List<Customer> customers=customerDAO.getForListWithCriteriaCustomer(cc);
//2 把customer的集合放入request
request.setAttribute("customers", customers);
//3 轉發頁面index.jsp(不能使用重定向)
request.getRequestDispatcher("/index.jsp").forward(request,response);
}
3、index頁面顯示
<%
List<Customer> customers=(List<Customer>)request.getAttribute("customers");
if(customers!=null && customers.size()>0){
%>
<hr>
<br/><br/>
<table border="1" cellpadding="10" cellspacing="0">
<tr>
<th>ID</th>
<th>CustomerName</th>
<th>CustomerAddress</th>
<th>CustomerPhone</th>
<th>Update/Delete</th>
</tr>
<%
for(Customer customer:customers){
%>
<tr>
<td class="id"><%=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="delete.do?id=<%=customer.getId() %>" class="delete">Delete</a>
</td>
</tr>
<%
}
%>
</table>
<%
}
%>
3)項目單元測試
@Test
public void getForListWithCriteriaCustomer(){
CriteriaCustomer cc=new CriteriaCustomer("Tom", null, null);
List<Customer> customers=customerDAO.getForListWithCriteriaCustomer(cc);
System.out.println(customers);
}
4)項目運行效果

4 顧客信息添加設計與實現
1) 項目設計分析:name唯一,新添加信息需要驗證錯誤提示
1、獲取表單參數:name、address、phone
2、 檢驗name是否被占用
3、若驗證通過,把表單參數封裝為一個Customer對象customer
4、調用CustomerDAO的save(Customer customer)執行保存操作
5、重定向到success.jsp頁面
2)項目源碼實現
1、DAO操作源碼
@Override
public void save(Customer customer) {
String sql="insert customers(name,address,phone) values(?,?,?)";
update(sql, customer.getName(),customer.getAddress(),customer.getPhone());
}
2、servlet操作源碼
//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(String name)獲取name在數據庫中是否存在
long count=customerDAO.getCountWithName(name);
if(count>0){
//2.2 若返回值大於0,則相應newcustomer.jsp頁面:①在此頁面顯示一個錯誤信息②此表單值可以回顯
// 通過request.getAttribute("message")顯示信息
// 通過value="<%=request.getParameter("name")==null?"":request.getParameter("name")%>"回顯
request.setAttribute("message", "用戶名["+name+"]已經被占用,請重新填寫!");
request.getRequestDispatcher("/newcustomer.jsp").forward(request, response);
return;
}
//3 若驗證通過,把表單參數封裝為一個Customer對象customer
Customer customer=new Customer(name,address,phone);
//4 調用CustomerDAO的save(Customer customer)執行保存操作
customerDAO.save(customer);
//5 重定向到success.jsp頁面
response.sendRedirect("success.jsp");
3、 視圖頁面顯示源碼
<body>
<%
Object mes=request.getAttribute("message");
if(mes!=null){
out.print("<br>");
out.print(mes);
out.print("<br>");
out.print("<br>");
}
%>
<h1>添加一條新的customer信息</h1>
<!--此處add.do依賴於CustomerServlet中的add方法名 -->
<form action="add.do">
<table>
<tr>
<td>CustomerName:</td>
<td><input type="text" name="name"
value="<%=request.getParameter("name")==null?"":request.getParameter("name")%>"/></td>
</tr>
<tr>
<td>CustomerAddress:</td>
<td><input type="text" name="address"
value="<%=request.getParameter("address")==null?"":request.getParameter("address")%>"/></td>
</tr>
<tr>
<td>CustomerPhone:</td>
<td><input type="text" name="phone"
value="<%=request.getParameter("phone")==null?"":request.getParameter("phone")%>"/></td>
</tr>
<tr>
<td colspan="2"><input type="submit" value="Submit"/></td>
</tr>
</table>
</form>
</body>
3)項目單元測試
@Test
public void testSaveCustomer() {
Customer customer=new Customer("Baijing","Shanghai","134-2345-9086");
customerDAO.save(customer);
}
4)項目運行效果

5 顧客信息更新設計與實現
1) 項目設計分析
1、 編輯操作:①獲取請求參數id;②調用CustomeDAO的customerDAO.get(id)獲取和id對應的Customer對象customer;③若驗證通過,把表單參數封裝為一個Customer對象customer;④ 調用CustomerDAO的update(Customer customer)執行更新操作;⑤重定向到query.do
2、更新操作:①獲取請求參數:id,name,address,phone,oldname;②檢驗name是否被占用;③若驗證通過,把表單參數封裝為一個Customer對象customer;④調用CustomerDAO的update(Customer customer)執行更新操作;⑤重定向到query.do;
2)項目源碼實現
1、DAO操作源碼:
@Override
public void save(Customer customer) {
String sql="insert customers(name,address,phone) values(?,?,?)";
update(sql, customer.getName(),customer.getAddress(),customer.getPhone());
}
2、servlet操作源碼
private void edit(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
String forwordPath="/error.jsp";
//1 獲取請求參數id
String idstr=request.getParameter("id");
//2 調用CustomeDAO的customerDAO.get(id)獲取和id對應的Customer對象customer
try{
Customer customer=customerDAO.get(Integer.parseInt(idstr));
if(customer!=null){
forwordPath="/updatecustomer.jsp";
//3 將customer放在request中
request.setAttribute("customer", customer);
}
}catch(Exception e){}
//4 響應updatecustomer.jsp頁面:轉發
request.getRequestDispatcher(forwordPath).forward(request, response);
}
private void update(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
//1 獲取請求參數:id,name,address,phone,oldname
String id=request.getParameter("id");
String name=request.getParameter("name");
String oldname=request.getParameter("oldname");
String address=request.getParameter("address");
String phone=request.getParameter("phone");
//2 檢驗name是否被占用
//2.1 比較name和oldname是否相同,若相同name可用,oldname.equals(name)不如equalsIgnoreCase,數據庫默認大小寫一致的,而equals忽略大小寫
if(!oldname.equalsIgnoreCase(name)){
//不相同,調用CustomerDAO的getCountWithName(String name)獲取name在數據庫中是否存在
long count=customerDAO.getCountWithName(name);
//大於0, 響應updatecustomer.jsp頁面:通過轉發響應newcustomer.jsp
if(count>0){
// 通過request.getAttribute("message")顯示信息,在頁面上request.getAttribute("message")的方式顯示
// 表單據回顯。address,phone顯示提交的新值, name顯示oldname,而不是新值
request.setAttribute("message", "用戶名["+name+"]已經被占用,請重新填寫!");
// 方法結束
request.getRequestDispatcher("/updatecustomer.jsp").forward(request, response);
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");
}
3、視圖顯示操作源碼
<body>
<%
Object mes=request.getAttribute("message");
if(mes!=null){
out.print("<br>");
out.print(mes);
out.print("<br>");
out.print("<br>");
}
String id=null;
String name=null;
String oldname=null;
String address=null;
String phone=null;
Customer customer=(Customer)request.getAttribute("customer");
if(customer!=null){
id=customer.getId()+"";
address=customer.getAddress();
name=customer.getName();
oldname=customer.getName();
phone=customer.getPhone();
}else{
id=request.getParameter("id");
name=request.getParameter("oldname");
oldname=request.getParameter("oldname");
address=request.getParameter("address");
phone=request.getParameter("phone");
}
%>
<h1>更新一條新的customer信息</h1>
<!--此處add.do依賴於CustomerServlet中的add方法名 -->
<form action="update.do">
<input type="hidden" name="id" value="<%=customer.getId()%>"/>
<input type="hidden" name="oldname" value="<%=oldname%>"/>
<table>
<tr>
<td>CustomerName:</td>
<td><input type="text" name="name" value="<%=name%>"/></td>
</tr>
<tr>
<td>CustomerAddress:</td>
<td><input type="text" name="address" value="<%=address %>"/></td>
</tr>
<tr>
<td>CustomerPhone:</td>
<td><input type="text" name="phone" value="<%=phone%>"/></td>
</tr>
<tr>
<td colspan="2"><input type="submit" value="Submit"/></td>
</tr>
</table>
</form>
</body>
3)項目單元測試
@Test
public void testSaveCustomer() {
Customer customer=new Customer("Baijing","Shanghai","134-2345-9086");
customerDAO.save(customer);
}
4)項目運行效果


6 顧客信息刪除設計與實現
1) 項目設計分析
1、獲取id的值
2、調用DAO的刪除方法
3、執行提示是否刪除
4、刪除成功跳轉刷新
2)項目源碼實現
1、DAO源碼:
@Override
public void delete(int id) {
String sql="delete from customers where id=?";
update(sql, id);
}
2、servlet源碼:
private void delete(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
String idstr=request.getParameter("id").trim();
int id=0;
try{
id=Integer.parseInt(idstr);
customerDAO.delete(id);
}catch(Exception e){}
response.sendRedirect("query.do");
}
3、頁面顯示源碼:
<script type="text/javascript" src="scripts/jquery.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>
<td>
<a href="edit.do?id=<%=customer.getId() %>">Update</a>
<a href="delete.do?id=<%=customer.getId() %>" class="delete">Delete</a>
</td>
3)項目單元測試
@Test
public void testDelete() {
customerDAO.delete(2);
}
4)項目運行效果

7 面向接口開發的數據源配置
倘若需要操作其他數據庫或者xml數據源進行存儲,該如何操作呢?下面以jdbc和xml進行設計
1 、不修改DAO底層代碼前提下,創建工廠模式,利用tyep類型進行選擇實例創建連接模式,
//單例工廠
public class CustomerDAOFactory {
private Map<String,CustomerDAO> daos=new HashMap<String,CustomerDAO>();
private static CustomerDAOFactory instance=new CustomerDAOFactory();
public static CustomerDAOFactory getInstance(){
return instance;
}
private String type=null;
public void setType(String type) {
this.type=type;
}
private CustomerDAOFactory() {
daos.put("jdbc", new CustomerDAOJdbcImpl());
daos.put("xml", new CustomerDAOXMLImpl());
}
public CustomerDAO getCustomerDAO(){
return daos.get(type);
}
}
2、type值放在switch.properties用於切換,如下是該文件的內容
#type=xml type=jdbc
3、初始化servlet,創建InitServlet.java文件,並控制type值傳遞CustomerDAOFactory工廠用來切換數據源
public class InitServlet extends HttpServlet {
@Override
public void init() throws ServletException {
CustomerDAOFactory.getInstance().setType("jdbc");
//讀取類路徑switch.properties文件
InputStream in=getServletContext().getResourceAsStream("/WEB-INF/classes/switch.properties");
Properties properties=new Properties();
try {
properties.load(in);
//獲取switch.properties的type值
String type=properties.getProperty("type");
//賦給了CustomerDAOFactory的type屬性
CustomerDAOFactory.getInstance().setType(type);
} catch (Exception e) {
e.printStackTrace();
}
}
}
4、配置web.xml文件,使InitServlet.java在項目啟動時即運行
<servlet>
<servlet-name>CustomerServlet</servlet-name>
<servlet-class>com.cuit.mvc.servlet.CustomerServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>InitServlet</servlet-name>
<servlet-class>com.cuit.mvc.servlet.InitServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
五、顧客管理項目完整源碼
本項目完整源碼:(點擊下載 訪問密碼 16cf)
六、顧客管理項目技術總結
1 Tomcat目錄結構圖

2 Tomcat配置,MyEclipse2015默認集成了,不需要配置

3 web程序結構圖

4 Servlet簡介

5 servlet運行交互圖


6 servlet運行原理

7 jsp運行原理

8 jsp的9大隱含對象


9 jsp注釋與聲明


10 jsp和屬性相關的方法

11 頁面請求重定向與請求轉發




12 page指令

12 errorPage和isErrorPage


13 關於中文亂碼的解決方案

14 MVC簡介

15 MVC原理圖

16 多頁面向單個servlet發送請求控制:方法1

17 多頁面向單個servlet發送請求控制:方法2


18 更新操作原理示意圖

19 查詢設計思路




20 MVC案例需求設計

21 jsp頁面請求遍歷數據

22 修改更新設計思路

23 面向接口編程


24 表單請求和回顯圖示


