既然已经学习了javaBean了,就应该了解DAO模式了。也就步入了MVC高级开发的轨道了。关于DAO我们一起来看一下它是个什么东西。看一下面向企业开发的模式的意义。
DAO设计模式简介
DAO全称是Data Access Object,数据库访问对象,主要的功能就是用于进行数据操作的,在程序的标准开发架构中属于数据层的操作
企业分层架构
客户层:因为现在都采用了B/S开发架构,所以一般都使用浏览器进行访问。
显示层:使用JSP/Servlet进行页面效果的显示
业务层:(Business Object,业务对象):会将多个原子性的DAO操作进行组合,组合成一个完整的业务逻辑。
数据层(DAO):提供多个原子性的DAO操作,例如:增加、修改、删除等,都属于原子性的操作。
资源层主要是数据库的操作层,里面可以进行各种的数据存储,但是这些数据存储操作的时候肯定依靠SQL语句,之前也发现了,如果在一个程序中出现了过多的SQL语句直接操作,则jsp页面变得相当复杂,而且也不便于程序的可重用性。
可以通过一个专门的数据库的操作组件完成,那么这个就是数据层的功能
业务层是整个项目的核心。现在我们要学的是DAO数据层。
DAO组成
在整个DAO中实际上都是以接口为操作标准的,即:客户端依靠DAO实现的接口进行操作,而服务端要将接口进行具体的实现。DAO由以下几个部分组成。
1. DatabaseConnection:专门负责数据库的打开与关闭操作的类
2.VO:主要由属性、setter、getter方法组成,VO类中的属性与表中的字段相对应,每一个VO类的对象都表示表中的每一条记录;
3.DAO:主要定义操作的接口,定义一系列数据库的原子性操作,例如:增加、修改、删除、按ID查询等;
4.Impl : DAO接口的真实实现类,完成具体的数据库操作,但是不负责数据库的打开和关闭;
5 Proxy :代理实现类,主要完成数据库的打开和关闭,并且调用真实实现类对象的操作
6 Factory :工厂类,通过工厂类取得一个DAO的实例化对象
DAO的组成是一个重点,我们以下做的程序就是根据DAO的几种组成来编写的程序。
实例说明DAO设计模式的应用(本程序来自网络,经本人测试确实可用)
一: 数据库(工具:MySQL)
数据库名字: 51ctotest
建立一张用户表如下: 表的名字为 emp
Id为编号 ename为用户名字 job为工作 date为工作日期 sal为工资
二 :编写程序(工具:MyEclipse 8.5)
在做项目之前为了大家能更好的把握全局,要做的javaBean和jsp页面就以如下图片展示:
- Emp.java //定义对应的VO类
- package javaBean01;
- import java.util.Date;
- public class Emp{
- private int id; //id编号
- private String ename; //名字
- private String job; //工作
- private Date date; //时间
- private float sal; //工资
- public int getId(){
- return id;
- }
- public void setId(int id){
- this.id=id;
- }
- public String getEname(){
- return ename;
- }
- public void setEname(String ename){
- this.ename=ename;
- }
- public String getJob(){
- return job;
- }
- public void setJob(String job){
- this.job=job;
- }
- public Date getDate(){
- return date;
- }
- public void setDate(Date date){
- this.date=date;
- }
- public float getSal(){
- return sal;
- }
- public void setSal(float sal){
- this.sal=sal;
- }
- }
- DatebaseConnection.java //数据库连接类
- package javaBean01;
- import java.sql.*;
- public class DatebaseConnection {
- private static final String Driver="com.mysql.jdbc.Driver";
- private static final String URL="jdbc:mysql://localhost:3306/51ctotest";
- private static final String USER="root";
- private static final String PWD="425680992";
- private Connection conn=null;
- public DatebaseConnection()throws Exception{ //在构造方法中进行数据库连接
- try{
- Class.forName(Driver); //加载驱动类
- this.conn=DriverManager.getConnection(URL,USER,PWD);
- }catch(Exception e){
- throw e; //直接抛出异常
- }
- }
- public Connection getConnection(){
- return this.conn; //取得数据库的连接
- }
- public void close()throws Exception{ //数据库关闭
- if(this.conn!=null){ //避免NullPointerException
- try{
- this.conn.close(); //数据库关闭
- }catch(Exception e){
- throw e;
- }
- }
- }
- }
- IEmpDAO.java //定义DAO操作标准
- package javaBean01;
- import java.util.List;
- import javaBean01.Emp;
- public interface IEmpDAO {
- /**
- * 数据库增加操作,一般以doXXX的方式命名;
- *@param emp 要增加的数据对象;
- *@return 是否增加成功的标记
- *@throws Exception 有异常交给被调用处处理
- */
- public boolean doCreate(Emp emp)throws Exception ;
- /**
- * 查询全部的数据,一般以findXX的方式命名;
- *@param keyWord 查询关键字
- *@return 返回全部的查询结果,每一个Emp对象表示表的一行记录
- *@throws Exception 有异常交给被调用处处理
- */
- public List<Emp>findAll(String keyWord)throws Exception;
- /**
- * 根据用户编号查询用户信心
- *@param id 用户编号
- *@return 用户的vo对象
- *@throws Exception 有异常交给被调用处处理
- */
- public Emp findById(int id)throws Exception;
- }
在DAO的操作中定义了doCreate()、findAll()、findById()3个功能。doCreate()方法主要执行数据库的插入操作,在执行插入操作时要传入一个Emp对象,Emp对象中保存了所有增加的用户信息;findAll()方法主要完成数据的查询操作,由于返回的是多条查询结果,所以使用List返回;findById()方法将根据用户的编号返回看一个Emp对象,此Emp对象中将包含一条完整数据信息。
DAO接口定义完成后需要做具体的实现类,但是在这里DAO的实现类有两种,一种是真实主题实现类,另一种是代理操作类
真题主题类主要是负责具体的数据库操作,在操作时为了性能及安全将使用PreparedStatement接口完成。
- EmpDAOImpl.java //真实主题实现类
- package javaBean01;
- import java.sql.*;
- import java.util.*;
- import javaBean01.IEmpDAO;
- import javaBean01.Emp;
- public class EmpDAOImpl implements IEmpDAO {
- private Connection conn=null; //数据库连接对象
- private PreparedStatement pStmt=null; //数据库操作对象
- public EmpDAOImpl(Connection conn){ //通过构造方法取得数据库连接
- this.conn=conn; //取得数据库连接
- }
- public boolean doCreate(Emp emp)throws Exception{
- boolean flag=false; //定义标志位
- String sql="insert into emp(id,ename,job,date,sal) values(?,?,?,?,?)";
- thisthis.pStmt=this.conn.prepareStatement(sql);//实例化PrepareStatement对象
- this.pStmt.setInt(1, emp.getId()); //设置id
- this.pStmt.setString(2, emp.getEname());//设置ename
- this.pStmt.setString(3, emp.getJob()); //设置工作
- this.pStmt.setDate(4,new java.sql.Date(emp.getDate().getTime()));
- this.pStmt.setFloat(5, emp.getSal());
- if(this.pStmt.executeUpdate()>0){ //更新记录的行数大于0
- flag=true; //修改标志位
- }
- this.pStmt.close(); //关闭PreparedStatement操作
- return flag;
- }
- public List<Emp>findAll(String keyWord)throws Exception{
- List<Emp> all=new ArrayList<Emp>();//定义集合,接受全部数据
- String sql="select id,ename,job,date,sal from emp where ename like? or job like?";
- thisthis.pStmt=this.conn.prepareStatement(sql);//实例化PreparedStatement
- this.pStmt.setString(1,"%"+keyWord+"%");//设这查询关键字
- this.pStmt.setString(2,"%"+keyWord+"%");
- ResultSet rs=this.pStmt.executeQuery();//执行查询操作
- Emp emp=null;
- while(rs.next()){
- emp=new Emp();//实例化新的Emp对象
- emp.setId(rs.getInt(1)); //设置id属性
- emp.setEname(rs.getString(2));
- emp.setJob(rs.getString(3));
- emp.setDate(rs.getDate(4));
- emp.setSal(rs.getFloat(5));
- all.add(emp); // 向集合中增加对象
- }
- this.pStmt.close();
- return all; //返回全部结果
- }
- public Emp findById(int id)throws Exception{
- Emp emp=null;
- String sql="select id,ename,job,date,sal from emp where id=?";
- thisthis.pStmt=this.conn.prepareStatement(sql);
- this.pStmt.setInt(1,id); //设置用户编号
- ResultSet rs=this.pStmt.executeQuery();
- if(rs.next()){
- emp=new Emp();
- emp.setId(rs.getInt(1));
- emp.setEname(rs.getString(2));
- emp.setJob(rs.getString(3));
- emp.setDate(rs.getDate(4));
- emp.setSal(rs.getFloat(5));
- }
- this.pStmt.close();
- return emp; //如果查询不到结果则返回null,默认值为null
- }
- }
在DAO的实现类中定义了Connection和PreparedStatement两个接口对象,并在构造方法中接收外部传递过来的Connection的实例化对象
在进行数据增加操作时,首先要实例化PreparedStatement接口,然后将Emp对象中的内容依次设置到PreparedStatement操作中,如果最后更新的记录大于0,则表示插入成功,将标志位修改为true.
在执行查询全部数据时,首先实力哈U了List接口的对象;在定义SQL语句时,将用户姓名和职位定义成了模糊查询的字段,然后分别将查询关键字设置到了PreparedStatement对象中,由于查询出来的是多条记录,所以每一条记录都重新实例化了一个Emp对象,同时会将内容设置到每个Emp对象中,并将这些对象全部加到List集合中
按编号查询时,如果此编号的用户存在,则实例化Emp对象,并将内容取出赋予Emp对象中的属性,如果没有查询到相应的用户,则返回null
可以发现,在真实主题的实现类中,根本就没有处理数据库的打开和连接操作,只是通过构造方法取得了数据库的连接,而真正负责打开和关闭的操作将由代理列完成
- IEmpDAOProxy.java //代理主题实现类
- package javaBean01;
- import java.util.*;
- import javaBean01.IEmpDAO;
- import javaBean01.DatebaseConnection;
- import javaBean01.EmpDAOImpl;
- import javaBean01.Emp;
- public class IEmpDAOProxy implements IEmpDAO {
- private DatebaseConnection dbc=null; //定义数据库连接类
- private IEmpDAO dao=null; //声明DAO对象
- public IEmpDAOProxy()throws Exception{ //在构造方法中实例化连接,同时实例化dao对象
- this.dbc=new DatebaseConnection();
- this.dao=new EmpDAOImpl(this.dbc.getConnection());//实例化真实主题类
- }
- public boolean doCreate(Emp emp)throws Exception{
- boolean flag=false; //定义标志位
- try{
- if(this.dao.findById(emp.getId())==null){//如果要插入的用户编号不存在
- flag=this.dao.doCreate(emp);//调用真实主题操作
- }
- }catch(Exception e){
- throw e;
- }finally{
- this.dbc.close();
- }
- return flag;
- }
- public List<Emp>findAll(String keyWord)throws Exception{
- List<Emp>all=null; //定义返回的集合
- try{
- all=this.dao.findAll(keyWord);//调用真实主题
- }catch(Exception e){
- throw e;
- }finally{
- this.dbc.close();
- }
- return all;
- }
- public Emp findById(int id)throws Exception{
- Emp emp=null;
- try{
- emp=this.dao.findById(id);
- }catch(Exception e){
- throw e;
- }finally{
- this.dbc.close();
- }
- return emp;
- }
- }
可以发现,在代理类的构造方法中实例化了数据库连接类的对象以及真实主题实现类,而在代理中的各个方法也只是调用了真实主题实现类中的相应的方法。
DAO的真实实现类和代理实现类编写完成后就需要编写工厂类,以降低代码间的耦合度
- DAOFactory.java //工厂类
- package javaBean01;
- import javaBean01.IEmpDAOProxy;
- import javaBean01.IEmpDAO;
- public class DAOFactory {
- public static IEmpDAO getIEmpDAOInstance()throws Exception {//取得DAO接口实例
- return new IEmpDAOProxy();//取得代理类的实现类
- }
- }
编写后javaBean后就开始编写jsp,用来调用DAO
- Emp_insert.jsp
- <%@ page language="java" contentType="text/html" pageEncoding="utf-8"%>
- <html>
- <head>
- <title>WEB开发项目</title>
- </head>
- <body>
- <form action="emp_insert_do.jsp" method="post">
- 编号:<input type="text" name="id"><br>
- 姓名:<input type="text" name="ename"><br>
- 职位:<input type="text" name="job"><br>
- 日期:<input type="text" name="date"><br>
- 工资: <input type="text" name="sal"><br>
- <input type="submit" value="注册">
- <input type="reset" value="重置">
- </form>
- </body>
- </html>
- Emp_insert_do.jsp
- <%@ page language="java" contentType="text/html" pageEncoding="utf-8"%>
- <%@ page import="javaBean01.*" %>
- <%@ page import="java.text.*" %>
- <html>
- <head>
- <title>WEB开发项目</title>
- </head>
- <%
- request.setCharacterEncoding("utf-8");
- %>
- <body>
- <%
- Emp emp=new Emp();
- emp.setId(Integer.parseInt(request.getParameter("id")));
- emp.setEname(request.getParameter("ename"));
- emp.setJob(request.getParameter("job"));
- emp.setDate(new SimpleDateFormat("yyyy-MM-dd").parse(request.getParameter("date")));
- emp.setSal(Float.parseFloat(request.getParameter("sal")));
- try{
- if(DAOFactory.getIEmpDAOInstance().doCreate(emp)){
- %>
- <h3>用户信息添加成功!</h3>
- <%
- }else{
- %>
- <h3>用户信息添加失败!</h3>
- <%
- }
- }catch(Exception e){
- e.printStackTrace();
- }
- %>
- </body>
- </html>
- Emp_list.jsp
- <%@ page language="java" contentType="text/html" pageEncoding="utf-8"%>
- <%@ page import="javaBean01.*" %>
- <%@ page import="java.util.*" %>
- <html>
- <head>
- <title>WEB开发项目</title>
- </head>
- <%
- request.setCharacterEncoding("utf-8");
- %>
- <body>
- <%
- try{
- //String keyWord=new String(request.getParameter("kw").getBytes("ISO-8859-1"));
- String keyWord=request.getParameter("kw");
- if(keyWord==null){ //判断是否有传递的参数
- keyWord ="";
- }
- List<Emp>all=DAOFactory.getIEmpDAOInstance().findAll(keyWord);//取得全部记录
- Iterator<Emp>iter=all.iterator();//实例化iterator对象
- %>
- <center>
- <form action="emp_list.jsp" method="post">
- 请输入查询的关键字<input type="text" name="kw">
- <input type="submit" value="查询">
- </form>
- <table border="1" width="80%">
- <tr>
- <td>编号</td>
- <td>姓名</td>
- <td>工作</td>
- <td>工资</td>
- <td>日期</td>
- </tr>
- <%
- while(iter.hasNext()){
- Emp emp=iter.next();//取得每一个Emp对象
- %>
- <tr>
- <td><%=emp.getId() %></td>
- <td><%=emp.getEname() %></td>
- <td><%=emp.getJob() %></td>
- <td><%=emp.getSal() %></td>
- <td><%=emp.getDate() %></td>
- </tr>
- <%
- }
- %>
- </table>
- </center>
- <%
- }catch(Exception e){
- e.printStackTrace();
- }
- %>
- </body>
- </html>
运行结果:
注意: 到此为止学完javaBean后,以上代码应该也必须得看懂了,如果以上代码研究起来很吃力的话,那必须好好学习了,不然之后的servlet、MVC以及SSH等等的模式将会很困难,当然java基础也是很重要的,对于java学了个半吊子的同学,也必须学完java,因为WEB开发是在java语言的基础上。