一. 程序分层设计模式
1.1 代码分层
1. 开发项目最终目的是让客户从浏览器端或者APP端操作数据,要实现这个功能就需要访问数据库,业务算法处理,请求的分发处理。
2. 访问数据库,业务算法处理,请求的分发处理这三个功能可以放在一起实现,但是全部放在一起代码会显得臃肿,不方便维护,于是就出现代码分层的概念。
3. 代码分层:把代码按照功能分为不同的层。
4. 最常见的代码分层组合模式:MVC模式
1.2 MVC模式
MVC模式:按照程序功能将代码分为三层,Model层(模型层),View层(显示层),Controller层(控制层)
详细说明:
Modle层:Modle层又分为dao层(数据访问层),
1. serveice层(业务层)
(1)sercice层:主要负责一些业务处理,比如取得连接,关闭数据库连接,事务回滚或者一些复杂的逻辑业务处理.........
(2)dao层: 负责访问数据库,进行数据操作,取的结果集ResultSet,将结果集ResultSet中的数据取出来封装到VO对象中返回给service层
2. Controller层:控制层,负责处理用户发送的请求。
3. View层:限制层,负责显示数据(渲染数据)。
分层的直接体现是将不同功能的代码保存到不同的包中。如下图所示:
1. 定义接口:
需要为每一层定义标准,不能让上层代码对下层代码依赖程度过高,也就是高耦合。
2. MVC模式中代码的调用顺序:
view-->Controller-->Service-->dao
二. DAO层基础设计模型
现在为emp数据表设计数据操作的DAO层
实际开发中DAO层需要先定义出自己的操作标准(接口),防止耦合过高。
再定义接口实现类
2.1 创建包结构
创建出包的结构,必须按照标准来
2.2 创建Emp对象
1. Emp对象,放到vo实体对象包
2. 简单java类中的基本数据类型必须使用基本数据类型包装类
3. 此简单java类必须实现Serializable接口,方便以后程序的扩展(比如序列化该类对象需要用到Serializable接口)
public class Emp implements Serializable {
private Integer empno;
private String ename;
private String job;
private double sal;
private Date hiredate;
public Emp() {
}
public Emp(Integer empno, String ename, String job, double sal, Date hiredate) {
this.empno = empno;
this.ename = ename;
this.job = job;
this.sal = sal;
this.hiredate = hiredate;
}
public void setEmpno(Integer empno) {
this.empno = empno;
}
public void setEname(String ename) {
this.ename = ename;
}
public void setJob(String job) {
this.job = job;
}
public void setSal(double sal) {
this.sal = sal;
}
public void setHiredate(Date hiredate) {
this.hiredate = hiredate;
}
public Integer getEmpno() {
return empno;
}
public String getEname() {
return ename;
}
public String getJob() {
return job;
}
public double getSal() {
return sal;
}
public Date getHiredate() {
return hiredate;
}
@Override
public String toString() {
return "Emp{" +
"empno=" + empno +
", ename='" + ename + '\'' +
", job='" + job + '\'' +
", sal=" + sal +
", hiredate=" + hiredate +
'}';
}
}
2.3 创建dao层接口(操作标准)
操作emp数据表的接口
import java.util.List;
public interface IEmpDAO {
int seletCount(String kw);
List<Emp> selectSplitALL(String kw,int start,int ls);
Emp selectById(Integer id);
int delectById(Integer id);
int update(Emp emp);
int insert(Emp emp);
}
2.4 定义DAO层接口实现类
public class IEmpDAOImpl implements IEmpDAO {
private Connection conn;
public IEmpDAOImpl(){
}
public IEmpDAOImpl(Connection conn){
this.conn = conn;
}
@Override
public int seletCount(String kw) throws Exception {
PreparedStatement pst =null;
String str = "SELECT empno,ename,job,sal,hiredate FROM emp WHERE ename LIKE ? ";
try{
pst = conn.prepareStatement(str);
pst.setString(1,"%"+kw+"%");
ResultSet rst = pst.executeQuery();
if(rst.next()){
return rst.getInt(1);
}
}catch(Exception e) {
e.printStackTrace();
}finally{
ConnectionUtil.close(conn,pst);
}
return 0;
}
@Override
public List<Emp> selectSplitALL(String kw, int start, int ls) throws Exception {
ArrayList<Emp> emps = new ArrayList<Emp>();
PreparedStatement pst = null;
String str1 = "SELECT empno,ename,job,sal,hiredate FROM emp WHERE ename LIKE '%?%' "+" LIMIT ?,?";
try {
pst = conn.prepareStatement(str1);
pst.setString(1,kw);
pst.setInt(2,start);
pst.setInt(3,ls);
ResultSet rst = pst.executeQuery();
while (rst.next()) {
emps.add( new Emp(rst.getInt(1), rst.getString(2), rst.getString(3), rst.getDouble(4), rst.getDate(5)));
}
return emps;
} catch (Exception e) {
e.printStackTrace();
}finally {
ConnectionUtil.close(conn,pst);
}
return null;
}
@Override
public Emp selectById(Integer id) throws Exception {
PreparedStatement pst =null;
String str = "SELECT empno,ename,job,sal,hiredate FROM emp WHERE empno=?";
try{
pst = conn.prepareStatement(str);
pst.setInt(1,id);
ResultSet rst = pst.executeQuery();
if(rst.next()){
return new Emp(rst.getInt(1),rst.getString(2),rst.getString(3),rst.getDouble(4),rst.getDate(5));
}
}catch(Exception e) {
e.printStackTrace();
}finally{
ConnectionUtil.close(conn,pst);
}
return null;
}
@Override
public int delectById(Integer id) throws Exception {
PreparedStatement pst=null;
try {
conn = com.ConnectionUtil.ConnectionUtil.getConnection();
String sql = "DELETE FROM emp WHERE empno=?";
pst = conn.prepareStatement(sql);
pst.setInt(1,id);
return pst.executeUpdate();
}catch (Exception e){
e.printStackTrace();
}finally{
ConnectionUtil.close(conn,pst);
}
return 0;
}
@Override
public int update(Emp emp) throws Exception {
String sql = "Update emp SET ename=?,sal=? WHERE empno=?";
PreparedStatement pst=null;
try {
conn = com.ConnectionUtil.ConnectionUtil.getConnection();
pst = conn.prepareStatement(sql);
pst.setString(1,emp.getEname());
pst.setDouble(2,emp.getSal());
pst.setInt(3,emp.getEmpno());
return pst.executeUpdate();
}catch (Exception e){
e.printStackTrace();
}finally{
ConnectionUtil.close(conn,pst);
}
return 0;
}
@Override
public int insert(Emp emp) throws Exception {
String sql = "insert INTO emp (ename,job,sal)" + "VALUES(?,?,?)";
PreparedStatement pst=null;
try {
conn = com.ConnectionUtil.ConnectionUtil.getConnection();
pst = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
pst.setString(1,emp.getEname());
pst.setString(2,emp.getJob());
pst.setDouble(3,emp.getSal());
pst.executeUpdate();
ResultSet key = pst.getGeneratedKeys();
if(key.next()){
System.out.println("主键自增长的值为"+key.getInt(1));
}
}catch (Exception e){
e.printStackTrace();
}finally{
ConnectionUtil.close(conn,pst);
}
return 0;
}
}
2.5 测试程序
import java.sql.Connection;
public class Test {
public static void main(String[] args) throws Exception {
Connection conn = ConnectionUtil.getConnection();
IEmpDAOImpl iEmpDAO = new IEmpDAOImpl(conn);
System.out.println(iEmpDAO.selectById(7369));
}
}
三. DAO层父接口定义
3.1 定义DAO层父接口的意义
1.背景:前面在DAO层只是定义了操作Emp表的接口,但是在实际开发中,不仅仅只有一张数据表,那么就需要为每一张数据表定义一个操作接口,就会发现每个接口中的方法都是基本相同,仅仅是参数不一样,就会有很多重复代码
2. 此时可以
---->定义一个父接口,将形式相同的方法抽象到父接口
---->父接口使用泛型,子接口继承父接口时指定出泛型类型
---->子接口不需要再编写公共方法,可以定义自己特有的方法。
3.2 定义公共父接口
import java.util.List;
public interface IDAO<V> {
int seletCount(String kw) throws Exception;
List<V> selectSplitALL(String kw, int start, int ls) throws Exception;
V selectById(Integer id) throws Exception;
int delectById(Integer id) throws Exception;
int update(V v) throws Exception;
int insert(V v) throws Exception;
}
1.创建Dept类,IDeptDAOImpl
import java.io.Serializable;
public class Dept implements Serializable {
private Integer deptno;
private String dname;
private String loc;
public Dept() {
}
public Dept(Integer deptno, String dname, String loc) {
this.deptno = deptno;
this.dname = dname;
this.loc = loc;
}
public Integer getDeptno() {
return deptno;
}
public String getDname() {
return dname;
}
public String getLoc() {
return loc;
}
public void setDeptno(Integer deptno) {
this.deptno = deptno;
}
public void setDname(String dname) {
this.dname = dname;
}
public void setLoc(String loc) {
this.loc = loc;
}
@Override
public String toString() {
return "Dept{" +
"deptno=" + deptno +
", dname='" + dname + '\'' +
", loc='" + loc + '\'' +
'}';
}
}
-------------------------------------------------------
public interface IDeptDAO extends IDAO<Dept> {
}
---------------
public class IDeptDAOImpl extends DAOAdapter<Dept> implements IDeptDAO {
private Connection conn;
public IDeptDAOImpl(){
}
public IDeptDAOImpl(Connection conn){
this.conn = conn;
}
@Override
public int seletCount(String kw) throws Exception {
PreparedStatement pst =null;
String str = "SELECT deptno,dname,loc FROM emp WHERE dept LIKE ? ";
try{
pst = conn.prepareStatement(str);
pst.setString(1,"%"+kw+"%");
ResultSet rst = pst.executeQuery();
if(rst.next()){
return rst.getInt(1);
}
}catch(Exception e) {
e.printStackTrace();
}
return 0;
}
@Override
public List<Dept> selectSplitALL(String kw, int start, int ls) throws Exception {
ArrayList<Dept> depts = new ArrayList<Dept>();
PreparedStatement pst = null;
String str1 = "SELECT deptno,dname,loc FROM dept WHERE dname LIKE '%?%' "+" LIMIT ?,?";
try {
pst = conn.prepareStatement(str1);
pst.setString(1,kw);
pst.setInt(2,start);
pst.setInt(3,ls);
ResultSet rst = pst.executeQuery();
while (rst.next()) {
depts.add( new Dept(rst.getInt(1), rst.getString(2), rst.getString(3)));
}
return depts;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
@Override
public Dept selectById(Serializable id) throws Exception {
PreparedStatement pst =null;
String str = "SELECT deptno,dname,loc FROM dept WHERE deptno=?";
try{
pst = conn.prepareStatement(str);
pst.setObject(1,id);
ResultSet rst = pst.executeQuery();
if(rst.next()){
return new Dept(rst.getInt(1),rst.getString(2),rst.getString(3));
}
}catch(Exception e) {
e.printStackTrace();
}
return null;
}
@Override
public int delectById(Serializable id) throws Exception {
PreparedStatement pst=null;
try {
String sql = "DELETE FROM dept WHERE deptno=?";
pst.setObject(1,id);
pst = conn.prepareStatement(sql);
return pst.executeUpdate();
}catch (Exception e){
e.printStackTrace();
}
return 0;
}
@Override
public int update(Dept dept) throws Exception {
String sql = "Update emp SET dname=?,loc=? WHERE deptno=?";
PreparedStatement pst=null;
try {
pst = conn.prepareStatement(sql);
pst.setString(1,dept.getDname());
pst.setString(2,dept.getLoc());
pst.setInt(3,dept.getDeptno());
return pst.executeUpdate();
}catch (Exception e){
e.printStackTrace();
}
return 0;
}
@Override
public int insert(Dept dept) throws Exception {
String sql = "insert INTO dept (deptno,dname,loc)" + "VALUES(?,?,?)";
PreparedStatement pst=null;
try {
pst = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
pst.setInt(1,dept.getDeptno());
pst.setString(2,dept.getDname());
pst.setString(3,dept.getLoc());
pst.executeUpdate();
ResultSet key = pst.getGeneratedKeys();
if(key.next()){
System.out.println("主键自增长的值为"+key.getInt(1));
}
}catch (Exception e){
e.printStackTrace();
}
return 0;
}
}
2. 定义操作dept数据表的接口,继承父接口IDAO,泛型为Dept
public interface IDeptDAO extends IDAO<Dept> {
}
3. 让操作Emp数据表的接口,继承父接口IDAO,泛型为Emp
public interface IEmpDAO extends IDAO<Emp> {
}
3.3 测试程序
public class Test {
public static void main(String[] args) throws Exception {
Connection conn = ConnectionUtil.getConnection();
IDAO iEmpDAO = new IEmpDAOImpl(conn);
System.out.println(iEmpDAO.selectById(7369));
}
}
四. 适配器模式
4.1 使用适配器的意义
1. 在DAO层开发中所有实现类都要覆写父接口中的所有方法,但是父接口中的某些方法对于某些实现类是不需要的
2. 此时就可以使用适配器设计模式让实现类可以自由选择覆写父接口中的方法。
3. 就是定义一个类去实现父接口,然后让子接口在实现对应接口的同时继承适配器类(继承又实现)
4.2 定义适配器类
import java.util.List;
public class DAOAdapter<T> implements IDAO<T> {
@Override
public int seletCount(String kw) throws Exception {
return 0;
}
@Override
public List<T> selectSplitALL(String kw, int start, int ls) throws Exception {
return null;
}
@Override
public T selectById(Integer id) throws Exception {
return null;
}
@Override
public int delectById(Integer id) throws Exception {
return 0;
}
@Override
public int update(T t) throws Exception {
return 0;
}
@Override
public int insert(T t) throws Exception {
return 0;
}
}
4.3 改变子接口实现类继承结构
public class IEmpDAOImpl extends DAOAdapter<Emp> implements IEmpDAO {
private Connection conn;
-------------------------------------------------------------
public class IDeptDAOImpl extends DAOAdapter<Dept> implements IDeptDAO {
private Connection conn;
此时,子接口实现类不需要强制性覆写所有父接口中的方法,可以自由选择覆写自己需要的方法,使代码变得灵活
4.4 完善父接口
把参数的Integer类型变成Serializable类型
而实现类中为占位符赋值时使用setObject()方法
public interface IDAO<V> {
int seletCount(String kw) throws Exception;
List<V> selectSplitALL(String kw, int start, int ls) throws Exception;
V selectById(Serializable id) throws Exception;
int delectById(Serializable id) throws Exception;
int update(V v) throws Exception;
int insert(V v) throws Exception;
}