阅读前瞻:本文源于对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、监听、权限管理、文件上传与下载等后续文章继续完善优化。
三、数据库创建阶段
1
2
3
4
5
6
7
8
9
10
|
# 创建数据库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数据操作
1
2
3
4
5
6
7
8
9
|
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控制源码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
//模糊查询
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页面显示
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
<%
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)项目单元测试
1
2
3
4
5
6
|
@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操作源码
1
2
3
4
5
|
@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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
//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、 视图页面显示源码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
<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)项目单元测试
1
2
3
4
5
|
@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操作源码:
1
2
3
4
5
|
@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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
|
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、视图显示操作源码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
|
<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)项目单元测试
1
2
3
4
5
|
@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源码:
1
2
3
4
5
|
@Override
public
void
delete(
int
id) {
String sql=
"delete from customers where id=?"
;
update(sql, id);
}
|
2、servlet源码:
1
2
3
4
5
6
7
8
9
|
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、页面显示源码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
<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)项目单元测试
1
2
3
4
|
@Test
public
void
testDelete() {
customerDAO.delete(2);
}
|
4)项目运行效果
7 面向接口开发的数据源配置
倘若需要操作其他数据库或者xml数据源进行存储,该如何操作呢?下面以jdbc和xml进行设计
1 、不修改DAO底层代码前提下,创建工厂模式,利用tyep类型进行选择实例创建连接模式,
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
//单例工厂
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用于切换,如下是该文件的内容
1
2
|
#type=xml
type=jdbc
|
3、初始化servlet,创建InitServlet.java文件,并控制type值传递CustomerDAOFactory工厂用来切换数据源
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
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在项目启动时即运行
1
2
3
4
5
6
7
8
9
|
<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 表单请求和回显图示