利用反射和代理简单模拟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 { ...
随机推荐
- TS编写发布订阅模式
interface PubSubType { events: { [key: string]: { name: string, once: boolean, cb: Function }[] } on ...
- 关键字break和continue
关键字:break 和continue提供了另一种控制循环的方式. break 是直接退出循环体 如: continue 是退出当前循环迭代 如: 需要注意的是:使用过多的break和continu ...
- 【leetcode】剑指offer04二维数组查找
很巧妙地把矩阵转化为二叉搜索树(不过好像没什用) class Solution { public: bool findNumberIn2DArray(vector<vector<int&g ...
- docker-compose + mysql8.x 主从数据库配置
0.准备 (略过docker的安装与镜像拉取) docker / docker-compose 安装 拉取 mysql 8.x 1. master和slave的mysql配置 master: [mys ...
- Jmeter 模拟http发送zip文件
发送zip文件的接口配置如下: 1. 在不知参数情况下使用fidder进行抓包操作,查看参数与MiME类型 2. 新建http取样器,并设置接口地址,进入文件上传设置参数与MIME类型 appli ...
- 重学c#系列—— 反射深入一点点[三十三]
前言 在上一章中介绍了什么是反射: https://www.cnblogs.com/aoximin/p/16440966.html 正文 上一节讲述反射的基本原理和为什么要用反射,还用反射的优缺点这些 ...
- CONDITION EVALUATION DELTA热部署启动失效
1.问题描述 我在启动一个SpringBoot项目的时候,在启动中控制台不停的打印日志(如下图所示) 2.产生原因 当时我是看了这篇文章后CONDITION EVALUATION DELTA_苦逼码农 ...
- 学习.NET MAUI Blazor(五)、修改Window窗口标题
由于Blazor属于SPA(single-page application),所以页面标题需要使用PageTitle组件来实现.但是在MAUI Blazor中,Blazor所在的位置是WebView, ...
- 如何理解scanf(“%d %d”,a,b)==2和scanf(“%d”,a)=1【摘抄笔记ψ(._. )>】
scanf 函数有一个返回值,0表示接受输入失败,1表示接受输入成功. while(scanf("%d",&x)==1) 的意思就是: 当接收输入变量x的值成功的时候,继续 ...
- java 进阶P-3.3+P-3.4
Array list的操作 ArrayList 类是一个可以动态修改的数组,与普通数组的区别就是它是没有固定大小的限制,我们可以添加或删除元素.ArrayList 继承了 AbstractList , ...