当前位置: 首页 > news >正文

将ResultSet转实体类

将ResultSet转实体类

sqlExecutor.executeQuery的执行结果的返回值是ResultSet:package java.sql;

一般在程序中我们需要把查询结果转为实体类返回给前端,此处可以使用的方法:

ResultSet转实体类方法1 2

1:resultSet.getXXX(columnIndex) 根据列的序号依次取值,并赋值给实体类的具体属性

定义一个实体类比如EntityDefine.class

public class EntityDefine implements Serializable {private static final long serialVersionUID = 3394089767543785764L;// 定义属性private String key;private Integer count;private Date updateTime;...;// get set 方法public String getKey(){return this.key;}public String setKey(String key) {this.key = key;}...;
}

定义一个处理ResultSet的方法handleResultSet

private EntityDefine handleResultSet(ResultSet resultSet) throws SQLException {EntityDefine entity = new EntityDefine();int col = 1;// 字符型entity.setKey(resultSet.getString(col++));// 整型entity.setCount(resultSet.getInt(col++));// 时间戳entity updateTime = resultSet.getTimestamp(col++);entity.setUpdateTime(updateTime);entity.setXXX(resultSet.getString(col++));return entity;
}

以上即可将ResultSet转为实体类。

优点是简单 ;

缺点是需要对ResultSet中的数据提前调试,确定每一列对应的属性(一般和数据库列的顺序一致)

2:实体类+注解+反射

注解是一种在Java中用来提供元数据的工具,它们可以在编译时和运行时为代码添加信息,并且可以被反射机制获取和处理。

(1)首先我们定义一个注解,用在实体类的所有属性上,都加上;

需要在注解中声明对应的数据库字段名;

属性对应的get方法可以编码时直接给出(如果属性值过多则配置会麻烦),或者用方法动态拼接(例子用这种方法);

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface MyResultSetFiled {/** 对应的数据库字段名 */String dbFiled();Class<?> fieldType() default String.class;/** 属性对应的get方法 */String get() default "";/** 是否需要自动补充当前时间 */boolean autoDate() default false;
}

关于注解:

注解按生命周期来划分可分为3类:

1、RetentionPolicy.SOURCE:注解只保留在源文件,当Java文件编译成class文件的时候,注解被遗弃;
2、RetentionPolicy.CLASS:注解被保留到class文件,但jvm加载class文件时候被遗弃,这是默认的生命周期;
3、RetentionPolicy.RUNTIME:注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在;

这3个生命周期分别对应于:Java源文件(.java文件) —> .class文件 —> 内存中的字节码。

那怎么来选择合适的注解生命周期呢?

首先要明确生命周期长度 SOURCE < CLASS < RUNTIME ,所以前者能作用的地方后者一定也能作用。

一般如果需要在运行时去动态获取注解信息,那只能用 RUNTIME 注解;

如果要在编译时进行一些预处理操作,比如生成一些辅助代码(如 ButterKnife),就用 CLASS注解;

如果只是做一些检查性的操作,比如 @Override 和 @SuppressWarnings,则可选用 SOURCE 注解。

@Target 指的是注解的作用目标。
@Target(ElementType.TYPE)——接口、类、枚举、注解
@Target(ElementType.FIELD)——字段、枚举的常量
@Target(ElementType.METHOD)——方法
@Target(ElementType.PARAMETER)——方法参数
@Target(ElementType.CONSTRUCTOR) ——构造函数
@Target(ElementType.LOCAL_VARIABLE)——局部变量
@Target(ElementType.ANNOTATION_TYPE)——注解
@Target(ElementType.PACKAGE)——包

(2)定义一个实体类比如EntityDefine.class

public class EntityDefine implements Serializable {private static final long serialVersionUID = 3394089767543785764L;// 定义属性,并添加注解@MyResultSetFiled(dbFiled = "key")private String key;@MyResultSetFiled(dbFiled = "count")private Integer count;@MyResultSetFiled(dbFiled = "update_time")private Date updateTime;...;// get set 方法public String getKey(){return this.key;}public String setKey(String key) {this.key = key;}...;
}

注意此处dbFiled要是数据库中的字段名,一般是采用下划线命名法,与实体类中定义属性的驼峰命名法有所区别。

可以将dbFiled后面跟的这些值封装成常量,便于维护。

(3)定义一个抽象类,在此方法中直接给类的各种属性封装好对应的值,所以建议做成构造函数的实现形式

public abstract class ResultSetWrapper implements Serializable{private static final long serialVersionUID = -2088813051606973972L;/*** 给给定的类的属性赋值,根据注解获取数据库的字段,从ResultSet中获取对应的值value* 动态拼接对应属性的Set方法* 利用反射,执行Set方法,将value赋值给对应的属性* 此方法没有返回值,给定的对象在该方法中执行一遍set后返回* @param resultSet 数据库查询结果集* @param clazz 要转化的实体类*/public void setData(ResultSet resultSet, Class<?> clazz) {try {// 获取类中所有定义的属性Field[] fields = clazz.getDeclaredFields();// 遍历for(Field field : fields) {// 获取属性上的注解信息MyResultSetFiled resultSetFiled = field.getAnnotation(AuditField.class);if(resultSetFiled==null) continue;// resultSet.getObject(列名),// 此方法可以配合我们获取注解中的数据库字段名使用,来获取对应的列的值Object value = resultSet.getObject(resultSetFiled.dbFiled());// 动态凭借对应属性的Set方法String fieldSetName = parSetName(field.getName());// 反射获取方法Method fieldSetMet = clazz.getMethod(fieldSetName, field.getType());if (null != value && !"".equals(value)) {String fieldType = value.getClass().getSimpleName();// 根据value的不同:String, Int, Data等,执行不同的set方法,即invoke(this, value)if ("String".equals(fieldType)) {fieldSetMet.invoke(this, value);} else if ("CLOB".equals(fieldType)) {// Clob转String,见第三部分《Clob转String》介绍String strClob = ClobToString((Clob) value);fieldSetMet.invoke(this, strClob);} else if ("Date".equals(fieldType) || "TIMESTAMP".equals(fieldType)) {Date temp = parseDate(value.toString());fieldSetMet.invoke(this, temp);} else if ("Integer".equals(fieldType)|| "int".equals(fieldType)) {Integer intval = Integer.parseInt(value.toString());fieldSetMet.invoke(this, intval);} else if ("Long".equalsIgnoreCase(fieldType)) {Long temp = Long.parseLong(value.toString());fieldSetMet.invoke(this, temp);} else if ("Double".equalsIgnoreCase(fieldType)) {Double temp = Double.parseDouble(value.toString());fieldSetMet.invoke(this, temp);} else if ("Boolean".equalsIgnoreCase(fieldType)) {Boolean temp = Boolean.parseBoolean(value.toString());fieldSetMet.invoke(this, temp);} else {System.out.println("not supper type" + fieldType);}}}}catch(NoSuchMethodException|SecurityException|IllegalAccessException|IllegalArgumentException|InvocationTargetException|SQLException e) {}}/*** 拼接在某属性的 set方法* @param fieldName 字段名* @return String setXXX*/private String parSetName(String fieldName) {if (null == fieldName || "".equals(fieldName)) {return null;}return "set" + fieldName.substring(0, 1).toUpperCase()+ fieldName.substring(1);}}

实体类EntityDefine.class完善,继承上述抽象类,并在构造方法中,声明:

public class EntityDefine extends ResultItem {...;public EntityDefine() {}// 构造方法public EntityDefine (ResultSet resultSet){super();this.setData(resultSet, EntityDefine.class);}...;}

(4)程序中处理:

new EntityDefine(resultSet);

即可获取到一个被完整赋值的对象实例;

优点:定义好了注解、构造函数之后,在使用时,直接new 即可,非常方便

缺点:配置复杂

Clob转String

在ResultSet转实体类中,存在Clob类型转换问题,需要转为String

 /*** CLOB转String* @param clob clob* @return 字符串*/
public static String ClobToString(Clob clob) {String reString = "";try {// 得到流Reader is = clob.getCharacterStream();BufferedReader br = new BufferedReader(is);String s = br.readLine();StringBuilder sb = new StringBuilder();// 执行循环将字符串全部取出付值给StringBuilder,由StringBuilder转成STRINGwhile (s != null) {sb.append(s).append("\n");s = br.readLine();}reString = sb.toString();} catch (SQLException|IOException e) {e.printStackTrace();}return reString;
}
http://www.lryc.cn/news/280678.html

相关文章:

  • Web后端开发
  • CAN201 计网概念收集
  • 【占用网络】FlashOcc:快速、易部署的占用预测模型
  • 239.【2023年华为OD机试真题(C卷)】求幸存者之和(模拟跳数-JavaPythonC++JS实现)
  • Pytorch中的标准维度顺序
  • Nginx的安装配置和使用
  • P1643 完美数 题解
  • docker一键安装
  • 模板管理支持批量操作,DataEase开源数据可视化分析平台v2.2.0发布
  • 阿里云实时计算企业级状态存储引擎 Gemini 技术解读
  • web缓存之nginx缓存
  • 【用法总结】无障碍AccessibilityService
  • AI绘画风格化实战
  • 008定点小数、奇偶校验码
  • 一、二进制方式 安装部署K8S
  • 【simple-admin】FMS模块如何快速接入阿里云oss 腾讯云cos 服务 实现快速上传文件功能落地
  • 数据结构.线性表(2)
  • 【计算机网络】TCP原理 | 可靠性机制分析(三)
  • 【昕宝爸爸小模块】线程的几种状态,状态之间怎样流转
  • ChatGPT网站小蜜蜂AI更新了
  • 瑞_Java开发手册_(二)异常日志
  • Elasticsearch:Search tutorial - 使用 Python 进行搜索 (四)
  • Python之Matplotlib绘图调节清晰度
  • pygame.error: video system not initialized
  • java面试题2024
  • 配置git服务器
  • vue3环境下,三方组件中使用echarts,无法显示问题
  • FAST OS DOCKER 可视化Docker管理工具
  • MOJO基础语法
  • java基础之IO流之字符流