利用反射接口做java数据库操作

今天突发奇想,好像一些基本的CRUD操作路数都是一样的,又想到mybatis中的操作,便想着简单的模拟一下。随便写写,就当练习反射了。

Dao接口类:

这里使用泛型,是为了更好的对数据进行处理

public interface BaseDao<T> {

    // 获取所有信息
List<T> getAll(); // 根据id查询信息
T getById(int id); // 根据id修改信息
int updateById(T t); // 根据id删除信息
int deleteById(int id); // 插入数据
int insert(T t); }

之前一直在犹豫,是否可以对接口创建代理类,后来查阅了一些资料,发现mybatis好像就是对接口的一些代理的处理。

使用JDK自带的代理接口InvocationHandler:

 public class ProxyGen<T> implements InvocationHandler {
// 要代理的接口
private Class<T> aClass;
// 要处理的表名
private String tableName;
// pojo的字节码文件
private Class objClass;
// 完整的构造方法
public ProxyGen(Class<T> interfaceClazz, String tableName, Class objClass) {
this.aClass = interfaceClazz;
this.tableName = tableName;
this.objClass = objClass;
} @Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{
...... // 代码处理
} // 获取代理类
public T getProxy() {
return (T) Proxy.newProxyInstance(aClass.getClassLoader(), new Class[] {aClass}, this);
} }

下面展示一下利用反射做简单的CRUD:

先做一些简单的提前准备:

 // 一些连接信息
Connection connect = null;
ResultSet rs = null;
PreparedStatement ps = null; // 这时候通过反射拿到类的属性信息
try {
// 获取连接
connect = SqlUtil.getConnect();
} catch (Exception e) {
throw new RuntimeException(e);
}

把这些先声明出来,方便后续的管理和使用。

查询全部数据:

// 获取所有的学生信息
if (method.getName().equalsIgnoreCase("getAll")) {
// 存储查询到的所有信息
List list = new ArrayList<>();
// 这里执行结果
ps = connect.prepareStatement("select * from " + tableName);
// 查询结果 进行封装
rs = ps.executeQuery();
// 按照顺序进行赋值
while (rs.next()) {
// 获取到所有的字段 进行反射赋值 必须确保有序 !
List<Field> fields = getClassFileds(objClass);
// 获取类对象
Object objClazz = objClass.getConstructor(null).newInstance(null);
// 赋值完毕
// 利用了反射出来的字符是有序的,这样保证了数据库的字段顺序和反射出来的字段顺序一致
for (int i = 0; i < fields.size(); i++) {
Object object = rs.getObject(i + 1);
fields.get(i).setAccessible(true);
fields.get(i).set(objClazz, object);
} list.add( objClazz); }
// 关闭连接
SqlUtil.close(connect, ps, rs); return list;
}

根据id查询信息:

// 根据id查询信息
if (method.getName().equalsIgnoreCase("getById")) {
// 先查看输入的参数是否获取到
System.out.println("args = " + Arrays.toString(args));
// 获取执行结果
ps = connect.prepareStatement("select * from " + tableName + " where id = " + args[0]);
// 获取执行结果
rs = ps.executeQuery();
// 获取类对象信息
Object obj = objClass.getConstructor(null).newInstance();
// 获取POJO类的字段信息
List<Field> fileds = getClassFileds(objClass);
while (rs.next()) {
// 循环赋值
for (int i = 0; i < fileds.size(); i++) {
// 因为字段是私有的 所以需要加上这一步
fileds.get(i).setAccessible(true);
// 给字段赋值
fileds.get(i).set(obj, rs.getObject(i + 1));
}
}
// 释放资源
SqlUtil.close(connect, ps, rs);
// 返回对象
return obj;
} /**
* 获取类反射字段
*
* @param objClass
* @return
*/
private List<Field> getClassFileds(Class objClass) {
ArrayList<Field> list = new ArrayList<>();
// 获取当前类的所有的字段
Field[] fields = objClass.getDeclaredFields();
for (Field field : fields) {
list.add(field);
}
return list;
}

根据Id修改信息:

既然是反射,那就得把数据写活,如果直接用pojo类的字段和属性,那不是写死了?

// 根据id修改信息
/**
* 这个比较特殊 传入的对象是一个student对象
*/
if (method.getName().equalsIgnoreCase("updateById")) {
// 拿到传输过来的对象
Object obj = args[0];
// 做一个自适应 如果值为null就不修改
Field[] fields = obj.getClass().getDeclaredFields();
// 拼接字符串
StringBuilder builder = new StringBuilder();
builder.append("update ").append(tableName).append(" ").append("set ");
// 循环获取值
for (Field field : fields) {
field.setAccessible(true);
Object o = field.get(obj); if (o != null && !field.getName().equalsIgnoreCase("id")) {
// 这里需要注意 如果对象为时间 需要转换一下
if (o instanceof Date) {
o = String.format("%tF", (Date) o);
}
// 继续拼接
builder
.append(field.getName())
.append("=")
.append("'")
.append(o)
.append("'")
.append(",");
}
} // 拼接sql 如果拼接完最后一个字符为[,],需要去掉
String sql = builder.toString().endsWith(",") ? builder.deleteCharAt(builder.length() - 1).toString() : builder.toString(); // 主键id单独 处理
for (Field field : fields) {
field.setAccessible(true);
Object o = field.get(obj); if (field.getName().equalsIgnoreCase("id") && o != null) {
sql += " where id = '" + o + "'";
} } System.out.println("sql = " + sql);
// 执行对象
ps = connect.prepareStatement(sql);
// 获取执行结果
int i = ps.executeUpdate(); SqlUtil.close(connect, ps, rs); return i; }

根据id修改对象:

/**
* 根据id删除对象
*/
if (method.getName().equalsIgnoreCase("deleteById")) {
// 获取参数
Integer arg = (Integer) args[0];
// 数据判断 避免空指针异常
if (arg != null) {
// 直接拼接删除sql语句
String sql = "delete from " + tableName + " where id = " + arg;
System.out.println("sql = " + sql);
ps = connect.prepareStatement(sql);
int i = ps.executeUpdate();
SqlUtil.close(connect, ps, rs);
return i;
} else {
return 0;
}
}

插入数据:

 // 插入数据
if (method.getName().equalsIgnoreCase("insert")) {
// 传入的对象
Object obj = args[0];
// 根据传入的对象进行拼接sql
Field[] fields = obj.getClass().getDeclaredFields();
// 拼接字符串
StringBuilder builder = new StringBuilder();
builder.append("insert into ").append(tableName).append(" ").append(" set ");
for (Field field : fields) {
field.setAccessible(true);
Object o = field.get(obj);
if (o != null) {
// 这里需要注意 如果对象为时间 需要转换一下
if (o instanceof Date) {
o = String.format("%tF", (Date) o);
}
builder.append(field.getName()).append("='").append(o).append("',");
} }
// 拼接sql 如果拼接完最后一个字符为[,],需要去掉
String sql = builder.toString().endsWith(",") ? builder.deleteCharAt(builder.length() - 1).toString() : builder.toString(); ps = connect.prepareStatement(sql); int i = ps.executeUpdate();
SqlUtil.close(connect, ps, rs);
return i; }

简单测试了一下,还不错。

利用反射和代理简单模拟mybatis实现简单的CRUD的更多相关文章

  1. 静态代理和利用反射形成的动态代理(JDK动态代理)

    代理模式 代理模式的定义:为其他对象提供一种代理以控制对这个对象的访问.在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用. 静态代理 1.新建 ...

  2. 利用链式队列(带头节点)解决银行业务队列简单模拟问题(c++)-- 数据结构

    题目: 7-1 银行业务队列简单模拟 (30 分)   设某银行有A.B两个业务窗口,且处理业务的速度不一样,其中A窗口处理速度是B窗口的2倍 —— 即当A窗口每处理完2个顾客时,B窗口处理完1个顾客 ...

  3. [.net 面向对象程序设计进阶] (21) 反射(Reflection)(下)设计模式中利用反射解耦

    [.net 面向对象程序设计进阶] (21) 反射(Reflection)(下)设计模式中利用反射解耦 本节导读:上篇文章简单介绍了.NET面向对象中一个重要的技术反射的基本应用,它可以让我们动态的调 ...

  4. 利用Java的反射与代理机制实现AOP

    在上一篇文章中,我们讲述了利用Java的反射机制中实现Spring中的IOC,在本文中,我们将更进一步,讲述用Java的反射和动态代理机制来实现Spring的AOP. 一.AOP概述 AOP(Aspe ...

  5. Java反射机制详解(3) -java的反射和代理实现IOC模式 模拟spring

    IOC(Inverse of Control) 可翻译为“控制反转”,但大多数人都习惯将它称为“依赖注入”.在Spring中,通过IOC可以将实现类.参数信息等配置在其对应的配置文件中,那么当 需要更 ...

  6. 利用反射生成JDK动态代理

    利用反射生成JDK动态代理 在Java的java.lang.reflect包下提供了一个Proxy类和一个InvocationHandler接口,通过使用这个类和接口可以生成JDK动态代理类和动态代理 ...

  7. 通过模拟Mybatis动态代理生成Mapper代理类,讲解Mybatis核心原理

    本文将通过模拟Mybatis动态代理生成Mapper代理类,讲解Mybatis原理 1.平常我们是如何使用Mapper的 先写一个简单的UserMapper,它包含一个全表查询的方法,代码如下 pub ...

  8. 简单模拟Java中反射的应用场景

    有人说Java是一门静态语言.那么何为静态语言,动态语言又是什么? 1.动态语言 是一类在运行时可以改变其结构的语言:例如新的函数.对象.甚至代码可以 被引进,已有的函数可以被删除或是其他结构上的变化 ...

  9. 利用JDK动态代理机制实现简单拦截器

    利用JDK动态代理机制实现简单的多层拦截器 首先JDK动态代理是基于接口实现的,所以我们先定义一个接口 public interface Executer { public Object execut ...

  10. (反射+内省机制的运用)简单模拟spring IoC容器的操作

    简单模拟spring IoC容器的操作[管理对象的创建.管理对象的依赖关系,例如属性设置] 实体类Hello package com.shan.hello; public class Hello { ...

随机推荐

  1. ajax 获取json值

    请求后台获取json: {"success":true,"datamap":{"rebackName":"振勋"}} a ...

  2. HashMap为何线程不安全?HashMap,HashTable,ConcurrentHashMap对比

    这两天写爬虫帮组里收集网上数据做训练,需要进一步对收集到的json数据做数据清洗,结果就用到了多线程下的哈希表数据结构,猛地回想起自己看<Java并发编程的艺术>框架篇的时候,在Concu ...

  3. http 缓存 笔记

    http 缓存,有时候静态资源没更新的情况下,不需要每次都去服务器获取,减少资源的请求. Http 报文中与缓存相关的首部字段 1. 通用首部字段(就是请求报文和响应报文都能用上的字段) 2. 请求首 ...

  4. ATM购物车项目总结

    目录 项目实现思路 ATM项目 优先实现功能 拆分函数 项目路径展示 项目启动文件 start.py 配置文件 setting.py 日志配置字典 日志函数 展示层 src.py 用户注册 获取用户输 ...

  5. error: expected ‘)’ before ‘PRIx64’

    打印uint64时编译报错 printf("prefix:0x%"PRIx64"\n",ipv6Prefix); 解决办法:添加头文件 #include < ...

  6. HNCTF的pyjail做题过程详解

    简述: 因为本人对python的内置函数理解也不是深入,在做题过程中也是靠着出题人的hint和google大法才做出来几题,详细的解题过程和知识点讲解可以看一下春哥的知乎,[PyJail] pytho ...

  7. [深度学习] tf.keras入门4-过拟合和欠拟合

    过拟合和欠拟合 简单来说过拟合就是模型训练集精度高,测试集训练精度低:欠拟合则是模型训练集和测试集训练精度都低. 官方文档地址为 https://tensorflow.google.cn/tutori ...

  8. Shiro-721反序列化漏洞

    漏洞名称 Shiro-721(Apache Shiro Padding Oracle Attack)反序列化 利用条件 Apache Shiro < 1.4.2 漏洞原理 Apache Shir ...

  9. VS2019注册码

    Visual Studio 2019 Enterprise BF8Y8-GN2QH-T84XB-QVY3B-RC4DF Visual Studio 2019 Professional NYWVH-HT ...

  10. Codeforces Gym 104059B - Breeding Bugs

    简要题意 Virtual Judge 传送门 | Codeforces Gym 传送门 给出一个长度为 \(n\) 的序列 \(a\),你需要从中选出一些数,使其两两相加不为质数.输出最大可以选择多少 ...