利用反射和代理简单模拟mybatis实现简单的CRUD
利用反射接口做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的更多相关文章
- 静态代理和利用反射形成的动态代理(JDK动态代理)
代理模式 代理模式的定义:为其他对象提供一种代理以控制对这个对象的访问.在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用. 静态代理 1.新建 ...
- 利用链式队列(带头节点)解决银行业务队列简单模拟问题(c++)-- 数据结构
题目: 7-1 银行业务队列简单模拟 (30 分) 设某银行有A.B两个业务窗口,且处理业务的速度不一样,其中A窗口处理速度是B窗口的2倍 —— 即当A窗口每处理完2个顾客时,B窗口处理完1个顾客 ...
- [.net 面向对象程序设计进阶] (21) 反射(Reflection)(下)设计模式中利用反射解耦
[.net 面向对象程序设计进阶] (21) 反射(Reflection)(下)设计模式中利用反射解耦 本节导读:上篇文章简单介绍了.NET面向对象中一个重要的技术反射的基本应用,它可以让我们动态的调 ...
- 利用Java的反射与代理机制实现AOP
在上一篇文章中,我们讲述了利用Java的反射机制中实现Spring中的IOC,在本文中,我们将更进一步,讲述用Java的反射和动态代理机制来实现Spring的AOP. 一.AOP概述 AOP(Aspe ...
- Java反射机制详解(3) -java的反射和代理实现IOC模式 模拟spring
IOC(Inverse of Control) 可翻译为“控制反转”,但大多数人都习惯将它称为“依赖注入”.在Spring中,通过IOC可以将实现类.参数信息等配置在其对应的配置文件中,那么当 需要更 ...
- 利用反射生成JDK动态代理
利用反射生成JDK动态代理 在Java的java.lang.reflect包下提供了一个Proxy类和一个InvocationHandler接口,通过使用这个类和接口可以生成JDK动态代理类和动态代理 ...
- 通过模拟Mybatis动态代理生成Mapper代理类,讲解Mybatis核心原理
本文将通过模拟Mybatis动态代理生成Mapper代理类,讲解Mybatis原理 1.平常我们是如何使用Mapper的 先写一个简单的UserMapper,它包含一个全表查询的方法,代码如下 pub ...
- 简单模拟Java中反射的应用场景
有人说Java是一门静态语言.那么何为静态语言,动态语言又是什么? 1.动态语言 是一类在运行时可以改变其结构的语言:例如新的函数.对象.甚至代码可以 被引进,已有的函数可以被删除或是其他结构上的变化 ...
- 利用JDK动态代理机制实现简单拦截器
利用JDK动态代理机制实现简单的多层拦截器 首先JDK动态代理是基于接口实现的,所以我们先定义一个接口 public interface Executer { public Object execut ...
- (反射+内省机制的运用)简单模拟spring IoC容器的操作
简单模拟spring IoC容器的操作[管理对象的创建.管理对象的依赖关系,例如属性设置] 实体类Hello package com.shan.hello; public class Hello { ...
随机推荐
- ajax 获取json值
请求后台获取json: {"success":true,"datamap":{"rebackName":"振勋"}} a ...
- HashMap为何线程不安全?HashMap,HashTable,ConcurrentHashMap对比
这两天写爬虫帮组里收集网上数据做训练,需要进一步对收集到的json数据做数据清洗,结果就用到了多线程下的哈希表数据结构,猛地回想起自己看<Java并发编程的艺术>框架篇的时候,在Concu ...
- http 缓存 笔记
http 缓存,有时候静态资源没更新的情况下,不需要每次都去服务器获取,减少资源的请求. Http 报文中与缓存相关的首部字段 1. 通用首部字段(就是请求报文和响应报文都能用上的字段) 2. 请求首 ...
- ATM购物车项目总结
目录 项目实现思路 ATM项目 优先实现功能 拆分函数 项目路径展示 项目启动文件 start.py 配置文件 setting.py 日志配置字典 日志函数 展示层 src.py 用户注册 获取用户输 ...
- error: expected ‘)’ before ‘PRIx64’
打印uint64时编译报错 printf("prefix:0x%"PRIx64"\n",ipv6Prefix); 解决办法:添加头文件 #include < ...
- HNCTF的pyjail做题过程详解
简述: 因为本人对python的内置函数理解也不是深入,在做题过程中也是靠着出题人的hint和google大法才做出来几题,详细的解题过程和知识点讲解可以看一下春哥的知乎,[PyJail] pytho ...
- [深度学习] tf.keras入门4-过拟合和欠拟合
过拟合和欠拟合 简单来说过拟合就是模型训练集精度高,测试集训练精度低:欠拟合则是模型训练集和测试集训练精度都低. 官方文档地址为 https://tensorflow.google.cn/tutori ...
- Shiro-721反序列化漏洞
漏洞名称 Shiro-721(Apache Shiro Padding Oracle Attack)反序列化 利用条件 Apache Shiro < 1.4.2 漏洞原理 Apache Shir ...
- VS2019注册码
Visual Studio 2019 Enterprise BF8Y8-GN2QH-T84XB-QVY3B-RC4DF Visual Studio 2019 Professional NYWVH-HT ...
- Codeforces Gym 104059B - Breeding Bugs
简要题意 Virtual Judge 传送门 | Codeforces Gym 传送门 给出一个长度为 \(n\) 的序列 \(a\),你需要从中选出一些数,使其两两相加不为质数.输出最大可以选择多少 ...