利用反射和代理简单模拟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 { ...
随机推荐
- JDBC Request 中 Variable names 以及 Result variable name 的使用方法
1.Variable name 的使用方法 设置好JDBC Connection Configuration.JDBC Request 具体配置百度 如果数据库查询的结果不止一列那就在Variabl ...
- Nmap安装
Nmap(Network Mapper,网络映射器)是一款开放源代码的网络探测和安全审核工具.它被设计用来快速扫描大型网络,包括主机探测与发现.开放的端口情况.操作系统与应用服务指纹识别.WAF识别及 ...
- 将xlsx列表文件转为md列表
转换网站: https://tableconvert.com/ 在这篇文章中,我将告诉你如何快速的将Excel转换为markdown表格,以及如何将Google Docs,Numbers,网页中的表格 ...
- 每个Java程序员都必须知道的四种负载均衡算法
前言 一般来说,我们在设计系统的时候,为了系统的高扩展性,会尽可能的创建无状态的系统,这样我们就可以采用集群的方式部署,最终很方便的根据需要动态增减服务器数量.但是,要使系统具有更好的可扩展性,除了无 ...
- 我们来汉化IntelliJ IDEA
(原发于 GitHub Pages,2018-10-13 13:51:09) 两年前我从一名光荣的C++程序员专业为PHP程序员以后,告别了世界第一IDE Visual Studio,改用当时觉得特别 ...
- AspNetCore管道
title: Asp.Net Core底层源码剖析(一)中间件/管道 categories: 后端 tags: - .NET 当我们像下面这样添加一个管道时发生了什么? app.Use(async ( ...
- [C#]从两个例子理解async/await
1 例子1 输出的结果为: 可以看出执行的结果为:A--D--B--C--E. 我们再看下一个例子(注意,我们把代码中D和E的位置交换) 2 例子2 结果: 结果为:A--B--C--E--D 3 理 ...
- 为什么要虚拟化,为什么要容器,为什么要Docker,为什么要K8S?
前言 如标题中的问题所提到的虚拟化,容器,Docker和K8s那样,我们不妨这样问:这些技术到底适用于哪些场景,有没有别的技术可以替代?这些技术的优劣在哪里? 下面我将针对性地从以上几个问题的出发点, ...
- Docker 基础 - 3
Web 服务器与应用 Nginx 我的Nginx Docker镜像 ## 设置继承自己创建的 sshd 镜像 FROM caseycui/ubuntu-sshd ## 维护者 LABEL mainta ...
- 12.ThreadLocal的那点小秘密
大家好,我是王有志.关注王有志,一起聊技术,聊游戏,聊在外漂泊的生活. 好久不见,不知道大家新年过得怎么样?有没有痛痛快快得放松?是不是还能收到很多压岁钱?好了,话不多说,我们开始今天的主题:Thre ...