利用反射和代理简单模拟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 { ...
随机推荐
- Blender修改视野范围
首先,我不是专门的建模人员.但是有时候会拿到建模人员的制作的模型导入进行修改. 比如简单的删除某个模型,调整模型的尺寸. 还有就是调整模型的建模中心点,这点有时候显得特别重要,模型的中心点偏离较大会给 ...
- Android 内存缓存框架 LruCache 的实现原理,手写试试?
本文已收录到 AndroidFamily,技术和职场问题,请关注公众号 [彭旭锐] 提问. 前言 大家好,我是小彭. 在之前的文章里,我们聊到了 LRU 缓存淘汰算法,并且分析 Java 标准库中支持 ...
- JavaEE Day11 BootStrap
之前:前端知识 HTML+CSS+JavaScript 不好写 今日内容:前端的开发框架,内部定义了丰富的CSS样式和JS代码,只需要拿来用就行 会用即可 一.BootStrap ...
- 【每日一题】【(双端)队列初始化&工具类&层次遍历】2022年1月29日-NC14 按之字形顺序打印二叉树
描述给定一个二叉树,返回该二叉树的之字形层序遍历,(第一层从左向右,下一层从右向左,一直这样交替) 注意:树的初始化 public class TreeNode { int val = 0; Tree ...
- 使用sanic框架实现分布式爬虫
bee_server.py from sanic import Sanic from sanic import response from urlpool import UrlPool #初始化url ...
- Vue中关于数组与对象修改触发页面更新的机制与原理简析
Vue中关于数组与对象修改触发页面更新的机制与原理简析 相关问题 数组 使用索引直接赋值与直接修改数组length时,不会触发页面更新. 例如: <script> export defau ...
- ArcObjects SDK开发 014 MapSurround和普通Element
1.如何获取MapSurround 和获取MapFrame类似,如果你已经获取指北针.比例尺等对象,可以通过IGraphicsContainer的FindFrame函数获取.如果没有,则通过IGrap ...
- Django静态文件配置(from表单-request对象方法-get请求与post请求-视图函数书写)
目录 一:静态文件配置 1.静态文件配置 2.什么是静态文件? 3.静态文件的创建 4.解决使用django后端代码修改前端不显示(缓存问题) 5.settings.py 静态文件配置 6.静态文接口 ...
- 从稍微懂一点开始的C++学习之路1: 智能指针
从稍微懂一点开始的C++学习之路1 智能指针 因为之前一直是搞qt的,没有搞过纯c++,所以现在算得上是刚开始学纯C++.C++的大部分语法其实我都懂,主要的是一些规范,还有内存回收等一些细节地方纯C ...
- Spring IOC官方文档学习笔记(二)之Bean概述
1.Bean概述 (1) Spring IoC容器管理一个或多个bean,这些bean是根据我们所提供的配置元数据来创建的,在容器内部,BeanDefinition对象就代表了bean的配置元数据,它 ...