PS:最近简单的学了学后台Servlet+JSP.也就只能学到这里了.没那么多精力去学SSH了,毕竟Android还有很多东西都没学完..

学习内容:

1.如何使用反射+泛型构建通用DAO.

1.使用泛型+反射构建通用DAO.

 DAO的概念曾经写过.其实就是数据访问对象,Date Access Object.其实就是数据库中的数据和Java对象里的一种关联关系的一系列操作.由于以前写过这个概念.就不啰嗦了..简单说一说思想.

 比如说:有两张表 User表和Shop表.

 这是User表中需要进行的操作.

public interface UserDao {
void add(User user);
void delete(User user);
void update(User user);
User select(User user);
}

这是Shop表中需要进行的操作.

public interface ShopDao {
void add(Shop shop);
void delete(Shop shop);
void update(Shop shop);
Shop select(Shop shop);
}

不 难发现,二者都有相同的操作.这样使得代码冗余度较高.那么能否将这两个DAO相同的方法封装成一个呢.这是可以的.这样就构建了一个BaseDao里面 封装了二者相同的操作.当我们需要操作表的时候,我们将T换成User或者是Shop就可以了.当我们实际项目面对的表有非常多的时候,如果都具有相同的 方法.那么就可以这样进行抽取.

public interface BaseDao<T> {
void add(T t);
void delete(T t);
void update(T t);
T select(T t);
}

 这样就构建了一个通用的DAO抽象接口.这里我拿User表来说,如果User表还有其他的业务逻辑呢(比如说查询所有信息等等).那么我们只需要这样.

public interface UserDao extends BaseDao<User> {

    //按照行查询,额外的业务逻辑.
List<User>findAll();
}

这样我们只需要定义一个新的UserDao就可以了,它继承了BaseDao中的所有方法,当有额外的业务逻辑的时候,只需要添加额外方法就可以了.这样光有接口当然是不行的.我们需要有具体的实现.

 我们先看BaseDao的实现类BaseDaoImp

 我们来看一下思路.

 先上一张原理图.

 1.首先我们如果想对User表进行操作,那么我们首先需要获取User类型.告诉BaseDaoImp,我们当前是需要对User表进行操作.因此构造函数就是用来干这个的.

 2. 当我们获取了User类型之后,如果想要对其进行操作,那么首先需要知道 sql 语句,因此我们需要对sql语句进行拼接.那么拼接过程中,我们需要知道User表内部到底声明了哪些变量.这样就需要使用反射机制.通过反射机制来获取 User实体类中声明的变量,然后对sql进行相关的拼接.那么getsql函数用来完成sql的拼接过程.

 3. 那么拼接完之后还是不行,因为拼接出来的sql语句是这样的:insert into User(id,username,password,email,grade) values(?,?,?,?,?)我们需要对占位符进行赋值操作.那么首先我们需要获取具体的值,那么setArgs就是来获取属性的具体值的.

 4.当获取了具体的值之后,我们就可以通过sql提供给我们的相关函数来执行sql语句了.

 这里函数其实都非常的简单,只要细看,还是能明白其中的道理的.

package com.example.daoimp;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import com.example.dao.BaseDao;
import com.example.helper.JdbcDaoHelper; //通用DAO public class BaseDaoImp<T> implements BaseDao<T> { /** 操作常量 */
public static final String SQL_INSERT = "insert";
public static final String SQL_UPDATE = "update";
public static final String SQL_DELETE = "delete";
public static final String SQL_SELECT = "select"; private Class<T> EntityClass; // 获取实体类 private PreparedStatement statement; private String sql; private Object argType[]; private ResultSet rs; @SuppressWarnings("unchecked")
public BaseDaoImp() { /**
* 传递User就是 com.example.daoimp.BaseDaoImp<com.example.bean.User>
* 传递Shop就是 com.example.daoimp.BaseDaoImp<com.example.bean.Shop>
* */
ParameterizedType type = (ParameterizedType) getClass()
.getGenericSuperclass(); /**
* 这里如果传递的是User.那么就是class com.example.bean.User
* 如果传递的是Shop. 那么就是class com.example.bean.Shop
* */
EntityClass = (Class<T>) type.getActualTypeArguments()[0];
} @Override
public void add(T t) {
// TODO Auto-generated method stub
sql = this.getSql(SQL_INSERT); //获取sql.
// 赋值.
try {
argType = setArgs(t, SQL_INSERT);
statement = JdbcDaoHelper.getPreparedStatement(sql); //实例化PreparedStatement.
//为sql语句赋值.
statement = JdbcDaoHelper.setPreparedStatementParam(statement,
argType);
statement.executeUpdate(); //执行语句.
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
JdbcDaoHelper.release(statement, null); //释放资源.
}
} @Override
public void delete(T t) {
// TODO Auto-generated method stub
sql = this.getSql(SQL_DELETE);
try {
argType = this.setArgs(t, SQL_DELETE);
statement = JdbcDaoHelper.getPreparedStatement(sql);
statement = JdbcDaoHelper.setPreparedStatementParam(statement,
argType);
statement.executeUpdate();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
JdbcDaoHelper.release(statement, null);
}
} @Override
public void update(T t) {
// TODO Auto-generated method stub
sql = this.getSql(SQL_UPDATE);
try {
argType = setArgs(t, SQL_UPDATE);
statement = JdbcDaoHelper.getPreparedStatement(sql);
statement = JdbcDaoHelper.setPreparedStatementParam(statement,
argType);
statement.executeUpdate();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
JdbcDaoHelper.release(statement, null);
}
} @Override
public T select(T t) {
// TODO Auto-generated method stub
sql = this.getSql(SQL_SELECT);
T obj = null;
try {
argType = setArgs(t, SQL_SELECT);
statement = JdbcDaoHelper.getPreparedStatement(sql);
statement = JdbcDaoHelper.setPreparedStatementParam(statement,
argType);
rs = statement.executeQuery();
Field fields[] = EntityClass.getDeclaredFields();
while (rs.next()) {
obj = EntityClass.newInstance();
for (int i = 0; i < fields.length; i++) {
fields[i].setAccessible(true);
fields[i].set(obj, rs.getObject(fields[i].getName()));
}
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return obj; } // sql拼接函数 形如 : insert into User(id,username,password,email,grade) values(?,?,?,?,?)
private String getSql(String operator) { StringBuffer sql = new StringBuffer();
// 通过反射获取实体类中的所有变量
Field fields[] = EntityClass.getDeclaredFields(); // 插入操作
if (operator.equals(SQL_INSERT)) {
sql.append("insert into " + EntityClass.getSimpleName());
sql.append("(");
for (int i = 0; fields != null && i < fields.length; i++) {
fields[i].setAccessible(true); //这句话必须要有,否则会抛出异常.
String column = fields[i].getName();
sql.append(column).append(",");
}
sql = sql.deleteCharAt(sql.length() - 1);
sql.append(") values (");
for (int i = 0; fields != null && i < fields.length; i++) {
sql.append("?,");
}
sql.deleteCharAt(sql.length() - 1);
// 是否需要添加分号
sql.append(")");
} else if (operator.equals(SQL_UPDATE)) {
sql.append("update " + EntityClass.getSimpleName() + " set ");
for (int i = 0; fields != null && i < fields.length; i++) {
fields[i].setAccessible(true);
String column = fields[i].getName();
if (column.equals("id")) {
continue;
}
sql.append(column).append("=").append("?,");
}
sql.deleteCharAt(sql.length() - 1);
sql.append(" where id=?");
} else if (operator.equals(SQL_DELETE)) {
sql.append("delete from " + EntityClass.getSimpleName()
+ " where id=?");
} else if (operator.equals(SQL_SELECT)) {
sql.append("select * from " + EntityClass.getSimpleName()
+ " where id=?");
}
return sql.toString();
} // 获取参数.
private Object[] setArgs(T entity, String operator)
throws IllegalArgumentException, IllegalAccessException { Field fields[] = EntityClass.getDeclaredFields();
if (operator.equals(SQL_INSERT)) { Object obj[] = new Object[fields.length];
for (int i = 0; obj != null && i < fields.length; i++) {
fields[i].setAccessible(true);
obj[i] = fields[i].get(entity);
}
return obj; } else if (operator.equals(SQL_UPDATE)) { Object Tempobj[] = new Object[fields.length];
for (int i = 0; Tempobj != null && i < fields.length; i++) {
fields[i].setAccessible(true);
Tempobj[i] = fields[i].get(entity);
} Object obj[] = new Object[fields.length];
System.arraycopy(Tempobj, 1, obj, 0, Tempobj.length - 1);
obj[obj.length - 1] = Tempobj[0];
return obj; } else if (operator.equals(SQL_DELETE)) { Object obj[] = new Object[1];
fields[0].setAccessible(true);
obj[0] = fields[0].get(entity);
return obj;
} else if (operator.equals(SQL_SELECT)) { Object obj[] = new Object[1];
fields[0].setAccessible(true);
obj[0] = fields[0].get(entity);
return obj;
}
return null;
} }

这样就对BaseDao进行了具体的实现.因为我们的User表还有其他额外的操作,那么我们只需要这样.它通过继承BaseDaoImp,然后实现UserDao接口,那么UserDaoImp就即具有了BaseDaoImp的通用方法,还具有了自己其他的额外方法.

package com.example.daoimp;

import java.lang.reflect.ParameterizedType;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List; import com.example.bean.User;
import com.example.dao.UserDao;
import com.example.helper.JdbcDaoHelper; public class UserDaoImp extends BaseDaoImp<User> implements UserDao { private Class<?> EntityClass; private String sql; private PreparedStatement statement; private ResultSet rs; private List<User> list; public UserDaoImp() { ParameterizedType type = (ParameterizedType) getClass()
.getGenericSuperclass();
EntityClass = (Class<?>) type.getActualTypeArguments()[0];
} @Override
public List<User> findAll() {
// TODO Auto-generated method stub
StringBuffer b = new StringBuffer();
list = new ArrayList<User>();
sql = b.append("select * from " + EntityClass.getSimpleName())
.toString();
try {
statement = JdbcDaoHelper.getPreparedStatement(sql);
rs = statement.executeQuery();
while (rs.next()) {
User user = new User();
user.setId(rs.getInt("id"));
user.setPassword(rs.getString("password"));
user.setEmail(rs.getString("email"));
user.setUsername(rs.getString("username"));
user.setGrade(rs.getInt("grade"));
list.add(user);
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return list;
} }

有 了他们,我们就可以进行具体的操作了,如果还有Shop表,那么同理我们可以去创建一个ShopDao去继承BaseDao,然后在自己的ShopDao 定义其他的额外方法就可以了.当表非常多的时候,我们就可以采用这种思想进行封装.这样写出的代码质量就显得非常的高,耦合度也非常的松散.

 在添加上工具类.

package com.example.helper;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException; public class JdbcDaoHelper { private static final String USER = "root"; private static final String PASSWORD = ""; private static final String URL = "jdbc:mysql://localhost:3306/usermanager"; private static Connection con; // 获取数据库连接对象
public static Connection getConnection() { if (con == null) {
try {
Class.forName("com.mysql.jdbc.Driver");
con = DriverManager.getConnection(URL, USER, PASSWORD);
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} else {
return con;
}
return con;
} public static PreparedStatement getPreparedStatement(String sql)
throws SQLException { return getConnection().prepareStatement(sql);
} public static PreparedStatement setPreparedStatementParam(
PreparedStatement statement, Object obj[]) throws SQLException { for (int i = 0; i < obj.length; i++) {
statement.setObject(i + 1, obj[i]);
}
return statement;
} // 释放资源
public static void release(PreparedStatement ps, ResultSet rs) {
try {
if (con != null) {
con.close();
con = null;
}
if (ps != null) {
ps.close();
ps = null;
}
if (rs != null) {
rs.close();
rs = null;
}
} catch (Exception e) {
// TODO: handle exception
}
} }

最后加上UserBean.

package com.example.bean;

public class User {

    private int id;
private String username;
private String password;
private String email;
private int grade; public User(){ } public User(int id,String username,String password,String email,int grade){
this.id = id;
this.username = username;
this.password = password;
this.email = email;
this.grade = grade;
} public int getId() {
return id;
} public void setId(int id) {
this.id = id;
} public String getUsername() {
return username;
} public void setUsername(String username) {
this.username = username;
} public String getPassword() {
return password;
} public void setPassword(String password) {
this.password = password;
} public String getEmail() {
return email;
} public void setEmail(String email) {
this.email = email;
} public int getGrade() {
return grade;
} public void setGrade(int grade) {
this.grade = grade;
} }

测试类.

package com.example.jdbc;

import java.util.List;

import com.example.bean.User;
import com.example.daoimp.UserDaoImp; public class Main { /**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub List<User>list = null;
UserDaoImp imp = new UserDaoImp();
list = imp.findAll();
for(User user:list){
System.out.println(user.getId()+" "+user.getUsername()+" "+user.getPassword()+" "+user.getEmail()+" "+user.getGrade());
}
//insert操作.
User user = new User();
user.setId(1);
user.setUsername("代码如风");
user.setPassword("123456");
user.setEmail("123");
user.setGrade(5);
imp.add(user);
//update操作.
User user_1 = new User();
user.setId(1);
user.setUsername("心静如水");
user.setPassword("123456");
user.setEmail("123");
user.setGrade(5);
imp.update(user_1);
} }

 注意(别忘了引入mysql.jar包.)

 最后放上一个源代码:files.cnblogs.com/files/RGogoing/JDBCDao.rar

Java学习笔记之使用反射+泛型构建通用DAO的更多相关文章

  1. Java学习笔记54(反射详解)

    反射概念: java反射机制是在运行状态中,对于任意一个类,都能知道所有属性和方法 对于任意一个对象都能调用它的任意一个方法和属性,这种动态获取和调用的功能称为java的反射机制 实际作用: 已经完成 ...

  2. Java学习笔记--注解和反射

    注解和反射 1. 注解 注解作用: 对程序做出解释 被其他程序读取 注解格式: @注释名,还可以添加一些参数值,例如@SuppressWarnings(value="unchecked&qu ...

  3. Java学习笔记八(反射)

    1.介绍 反射为Java程序在执行时提供了动态的能力.利用反射能够在执行时对程序进行动态的控制.本篇博客着重解说一下Java中的反射. 2.Class类的使用 在Java执行过程中,每一个类被载入后都 ...

  4. Java学习笔记【十、泛型】

    简介 Java 泛型(generics)是 JDK 5 中引入的一个新特性, 泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型. 泛型的本质是参数化类型,也就是说所操作的数据 ...

  5. Java学习笔记【一、环境搭建】

    今天把java的学习重新拾起来,一方面是因为公司的项目需要用到大数据方面的东西,需要用java做语言 另一方面是原先使用的C#公司也在慢慢替换为java,为了以后路宽一些吧,技多不压身 此次的学习目标 ...

  6. 20145330第八周《Java学习笔记》

    20145330第八周<Java学习笔记> 第十五章 通用API 通用API 日志:日志对信息安全意义重大,审计.取证.入侵检验等都会用到日志信息 日志API Logger:注意无法使用构 ...

  7. JAVA学习笔记—review基本知识[反射与异常]

    JAVA学习笔记—review基本知识[反射与异常] 1.异常: 1.1异常的分类: Java会将所有的异常封装成对象,其根本父类为Throwable. Throwable有两个子类:Error 和E ...

  8. 《Java学习笔记(第8版)》学习指导

    <Java学习笔记(第8版)>学习指导 目录 图书简况 学习指导 第一章 Java平台概论 第二章 从JDK到IDE 第三章 基础语法 第四章 认识对象 第五章 对象封装 第六章 继承与多 ...

  9. Java学习笔记4

    Java学习笔记4 1. JDK.JRE和JVM分别是什么,区别是什么? 答: ①.JDK 是整个Java的核心,包括了Java运行环境.Java工具和Java基础类库. ②.JRE(Java Run ...

随机推荐

  1. ABP框架详解(二)AbpKernelModule

    AbpKernelModule类是Abp框架自己的Module,它也跟所有其他的Module一样继承自AbpModule,重写PreInitialize,Initialize,PostInitiali ...

  2. Mac OS X 常用快捷键

       

  3. Java多线程10:ThreadLocal的作用及使用

    ThreadLocal的作用 从上一篇对于ThreadLocal的分析来看,可以得出结论:ThreadLocal不是用来解决共享对象的多线程访问问题的,通过ThreadLocal的set()方法设置到 ...

  4. kali linux 2016.1 滚动更新源

    修改 /etc/apt/sources.list  #kali官方源 deb http://http.kali.org/kali kali-rolling main non-free contrib ...

  5. DeviceOne 竟然做出来如此复杂的App

    分享来自DeviceOne论坛 此文章分享自DeviceOne的论坛,论坛上的用户分享,下面有二维码扫描,可以进行安装和试用.支持android和ios两个 操作系统. 这个还没做完,目前已经完成了初 ...

  6. java 堆栈分析

    再次,研究了一个下午的jhat好jmap.从一开始惊呆.懵懂于那样大量而无聊乏味的数据,到现在有那么一点点收货.赶紧记录下来.没办法,悟性太低... C:\Users\Administrator> ...

  7. flex 阅读器

    遇到很多的困难 首先是 pdf2swf 而后又下载swftools 而后有swfcombine.exe 让制作的swf 文字可选? —— 这应该是很常见的需求啊! 可是我搜索来搜索去都找不到... 搜 ...

  8. Yii 框架学习--01 框架入门

    Yii 是一个高性能的,适用于开发 WEB2.0 应用的 PHP 框架. Yii目前有两个主要的版本: 2.0 和 1.1.本文以YII 2.0.7为例. 环境需求 Yii2.0 框架有一些系统上的需 ...

  9. sql基础知识:日期的常用用法

    日期操作 select sysdate,add_months(sysdate,12) from dual; -- + 1 year select sysdate,add_months(sysdate, ...

  10. Eclipse 工程迁移到 Android Studio

    目标:迁移成功,并成功正常运行! 附加:同步视频在文章后面! 两种方式: 1. 用Gradle导出,在Android Studio中用Gradle导入 (不推荐) 2. 用Android Studio ...