JAVA基于MVC架构Java技术荟萃案例演练

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JAVA基于MVC架构Java技术荟萃案例演练相关的知识,希望对你有一定的参考价值。

基于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>
View Code

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();
    }

}
View Code

 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+"]";
    }
}
View Code

 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);
        }
    }
}
View Code

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);
    
}
View Code

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());
    }

}
View Code

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");
    }

}
View Code

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);
    }

}
View Code

5 视图显示页面层 

index.jsp:显示顾客信息,并支持回显