Spring Data JPA映射自定义实体类操作

2022-01-24 0 664
目录

Spring Data JPA映射自定义实体类

这个问题困扰了我2天=-=,好像也能使用 jpql解决

先说下自己的功能:查询oracle最近sql执行记录

sql很简单:【如果需要分页,需要自己手动分页,因为你使用分页工具他第一页查询不会查询rownum,第二页查询就会查询rownum,然而这个返回的List<Object[]>中的参数必须要和实体类中一一对应,所以这就有一个不可控制的属性rownum,所以我们不能使用Pageable入参接口了,需要自定义pageSize pageNum参数】

SELECT
 t.SQL_ID AS SQL的ID,
 t.SQL_TEXT AS SQL语句,
 t.HASH_VALUE AS 完整SQL哈希值,
 t.ELAPSED_TIME AS 解析执行总共时间微秒,
 t.EXECUTIONS AS 执行总共次数,
 t.LAST_ACTIVE_TIME AS 执行最后时间,
 t.CPU_TIME AS CPU执行时间微秒 
FROM 
 v$sqlarea t 
WHERE 
 t.PARSING_SCHEMA_NAME IN ( \'C##DBAAS\' ) 
 AND t.EXECUTIONS > 10  
 AND t.LAST_ACTIVE_TIME > TO_DATE(\'0001-01-01 01:01:01\', \'yyyy-MM-dd hh24:mi:ss\') 
 AND t.ELAPSED_TIME > 0 
 AND t.CPU_TIME > 0 
ORDER BY 
 t.EXECUTIONS DESC;

但是我用的是Spring Data JPA。。。。这个网上说不能将查询结果自动映射到自定义的实体类。。。。这就比较蛋疼了,在网上就找了个轮子。先上一下自己的Dao层,查出来的是集合数组,所以使用List< Object [ ] >接收【我将sql简化了一下,主要先测试能不能成功】

@Query(value=\"SELECT\\r\\n\" + 
   \" t.SQL_ID,\\r\\n\" + 
   \" t.ELAPSED_TIME,\\r\\n\" + 
   \" t.EXECUTIONS,\\r\\n\" + 
   \" t.LAST_ACTIVE_TIME, \\r\\n\" + 
   \" t.CPU_TIME \\r\\n\" + 
   \"FROM\\r\\n\" + 
   \" v$sqlarea t \\r\\n\" + 
   \"WHERE\\r\\n\" + 
   \" t.PARSING_SCHEMA_NAME IN ( \'C##DBAAS\' )   AND t.EXECUTIONS > 100     \\r\\n\" + 
   \"ORDER BY\\r\\n\" + 
   \" t.EXECUTIONS DESC\",nativeQuery=true)
 public List<Object[]> findTopSQLS4();

然后就是实体类了:注意实体类中 必须包含构造函数,而且构造函数中的参数必须和你SQL中 查询的参数 顺序保持一致

package com.befery.oams.entity; 
import java.io.Serializable;
import java.math.BigInteger;
import java.security.Timestamp;
import java.util.Date;
 
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
 
@Entity
@Table(name = \"v$sqlarea\")
public class V$sqlarea implements Serializable { 
 @Id
 private String sqlId; 
 private Number elapsedTime; // 解析+执行sql 总时间 微秒
 private Number executions; // 执行次数
 private Date lastActiveTime;
 private Number cpuTime;
 public String getSqlId() {
  return sqlId;
 }
 
 public void setSqlId(String sqlId) {
  this.sqlId = sqlId;
 }
 
 public Number getElapsedTime() {
  return elapsedTime;
 }
 
 public void setElapsedTime(Number elapsedTime) {
  this.elapsedTime = elapsedTime;
 }
 
 public Number getExecutions() {
  return executions;
 }
 
 public void setExecutions(Number executions) {
  this.executions = executions;
 }
 
 public Date getLastActiveTime() {
  return lastActiveTime;
 }
 
 public void setLastActiveTime(Date lastActiveTime) {
  this.lastActiveTime = lastActiveTime;
 }
 
 public Number getCpuTime() {
  return cpuTime;
 }
 
 public void setCpuTime(Number cpuTime) {
  this.cpuTime = cpuTime;
 }
 
 public V$sqlarea() {
 }
 
 public V$sqlarea(String sqlId, Number elapsedTime, Number executions, Date lastActiveTime,Number cpuTime) {
  this.sqlId = sqlId;
  this.elapsedTime = elapsedTime;
  this.executions = executions;
  this.lastActiveTime = lastActiveTime;
  this.cpuTime = cpuTime;
 } 
}

然后就是网上的轮子了

package com.befery.oams.util; 
import org.slf4j.Logger;
import org.slf4j.LoggerFactory; 
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
 
public class EntityUtils {
    private static Logger logger = LoggerFactory.getLogger(EntityUtils.class); 
    /**
     * 将数组数据转换为实体类
     * 此处数组元素的顺序必须与实体类构造函数中的属性顺序一致
     *
     * @param list           数组对象集合
     * @param clazz          实体类
     * @param <T>            实体类
     * @param model          实例化的实体类
     * @return 实体类集合
     */
    public static <T> List<T> castEntity(List<Object[]> list, Class<T> clazz, Object model) {
        List<T> returnList = new ArrayList<T>();
        if (list.isEmpty()) {
            return returnList;
        }
        //获取每个数组集合的元素个数
        Object[] co = list.get(0);
 
        //获取当前实体类的属性名、属性值、属性类别
        List<Map> attributeInfoList = getFiledsInfo(model);
        //创建属性类别数组
        Class[] c2 = new Class[attributeInfoList.size()];
        //如果数组集合元素个数与实体类属性个数不一致则发生错误
        if (attributeInfoList.size() != co.length) {
            return returnList;
        }
        //确定构造方法
        for (int i = 0; i < attributeInfoList.size(); i++) {
            c2[i] = (Class) attributeInfoList.get(i).get(\"type\");
        }
        try {
            for (Object[] o : list) {
                Constructor<T> constructor = clazz.getConstructor(c2);
                returnList.add(constructor.newInstance(o));
            }
        } catch (Exception ex) {
            logger.error(\"实体数据转化为实体类发生异常:异常信息:{}\", ex.getMessage());
            return returnList;
        }
        return returnList;
    }
 
    /**
     * 根据属性名获取属性值
     *
     * @param fieldName 属性名
     * @param modle     实体类
     * @return 属性值
     */
    private static Object getFieldValueByName(String fieldName, Object modle) {
        try {
            String firstLetter = fieldName.substring(0, 1).toUpperCase();
            String getter = \"get\" + firstLetter + fieldName.substring(1);
            Method method = modle.getClass().getMethod(getter, new Class[]{});
            Object value = method.invoke(modle, new Object[]{});
            return value;
        } catch (Exception e) {
            return null;
        }
    }
 
    /**
     * 获取属性类型(type),属性名(name),属性值(value)的map组成的list
     *
     * @param model 实体类
     * @return list集合
     */
    private static List<Map> getFiledsInfo(Object model) {
        Field[] fields = model.getClass().getDeclaredFields();
        List<Map> list = new ArrayList(fields.length);
        Map infoMap = null;
        for (int i = 0; i < fields.length; i++) {
            infoMap = new HashMap(3);
            infoMap.put(\"type\", fields[i].getType());
            infoMap.put(\"name\", fields[i].getName());
            infoMap.put(\"value\", getFieldValueByName(fields[i].getName(), model));
            list.add(infoMap);
        }
        return list;
    }
}

最后的操作,调用 castEntity() 方法:

@GetMapping(value = \"/list\")
 @ResponseBody
 public List<V$sqlarea> selectTopSQLUntreated() {
  System.out.println(\"============================TOPSQL       START=================================\");
  List<Object[]> list = v$sqlareaDao.findTopSQLS4();
  List<V$sqlarea> list1 =EntityUtils.castEntity(list, V$sqlarea.class,new V$sqlarea());
  System.out.println(\"============================TOPSQL       END=================================\");
  return list1;
 }

看一下日志的输出

============================TOPSQL START=================================
Hibernate:
SELECT
t.SQL_ID,
t.ELAPSED_TIME,
t.EXECUTIONS,
t.LAST_ACTIVE_TIME,
t.CPU_TIME
FROM
v$sqlarea t
WHERE
t.PARSING_SCHEMA_NAME IN (
\'C##DBAAS\'
)
AND t.EXECUTIONS > 100
ORDER BY
t.EXECUTIONS DESC
============================TOPSQL END=================================
2019-03-12 18:06:57.108 INFO 21076 --- [nio-8081-exec-7] com.befery.oams.config.LogAspectConfig : --------------返回内容----------------
2019-03-12 18:06:57.114 INFO 21076 --- [nio-8081-exec-7] com.befery.oams.config.LogAspectConfig : Response内容:[{\"cpuTime\":84731,\"elapsedTime\":183491,\"executions\":348,\"lastActiveTime\":1552385204000,\"sqlId\":\"f05fn7j6rbcsj\"},{\"cpuTime\":17827,\"elapsedTime\":33036,\"executions\":212,\"lastActiveTime\":1552385203000,\"sqlId\":\"avc1jqzz04wpr\"},{\"cpuTime\":9054,\"elapsedTime\":23874,\"executions\":174,\"lastActiveTime\":1552385204000,\"sqlId\":\"b4xr1nw5vtk2v\"},{\"cpuTime\":102017,\"elapsedTime\":97842,\"executions\":153,\"lastActiveTime\":1552313331000,\"sqlId\":\"711b9thj3s4ug\"},{\"cpuTime\":89011,\"elapsedTime\":90341,\"executions\":153,\"lastActiveTime\":1552313331000,\"sqlId\":\"grqh1qs9ajypn\"},{\"cpuTime\":58984,\"elapsedTime\":81214,\"executions\":135,\"lastActiveTime\":1552385214000,\"sqlId\":\"d442vk7001fvw\"},{\"cpuTime\":17260604818,\"elapsedTime\":41375561059,\"executions\":122,\"lastActiveTime\":1552297847000,\"sqlId\":\"170am4cyckruf\"},{\"cpuTime\":13194,\"elapsedTime\":31267,\"executions\":108,\"lastActiveTime\":1552383540000,\"sqlId\":\"9q00dg3n0748y\"}]
2019-03-12 18:06:57.114 INFO 21076 --- [nio-8081-exec-7] com.befery.oams.config.LogAspectConfig : --------------返回内容----------------

JPA 配置类实体映射示例

A: 两张表示例

/**
 *
 * @author xiaofanku@live.cn
 */
@Entity
@Table(name=\"apo_config\")
public class SiteConfig implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long ID;
    private String caption;
    @ElementCollection(fetch = FetchType.LAZY)
    @MapKeyColumn(name=\"name\")
    @Column(name=\"value\")
    @CollectionTable(name=\"apo_config_attributes\", joinColumns=@JoinColumn(name=\"ca_id\"))
    private Map<String, String> attributes = new HashMap<String, String>(); 
    //GET/SET
}

测试代码

    @Test
    public void test(){
        SiteConfig sc=new SiteConfig();
        sc.setID(1L);
        sc.setCaption(\"全局配置\");
        Map<String, String> data=new HashMap<>();
        data.put(\"site\", \"csdn.net\");
        data.put(\"account\", \"xiaofanku\");
        sc.setAttributes(data);
        siteConfigDao.save(sc);
    }
    @Test
    public void getConfig(){
        SiteConfig config=siteConfigDao.findOne(1L);
        assertEquals(config.getAttributes().get(\"site\"), \"csdn.net\");
    }

apo_config:表结构

apo_config_attributes:表结构

B: 三张表示例

/**
 * 
 * @author xiaofanku@live.cn
 */
@Entity
@Table(name=\"apo_config\")
public class SiteConfig implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long ID;
    private String caption;
    @OneToMany(cascade=CascadeType.ALL, orphanRemoval = true)
    @MapKey(name=\"name\")
    @JoinTable(name = \"apo_config_attributes\")
    private Map<String, ConfigAttribute> attributes=new HashMap<>();
    //GET/SET
}
/**
 *
 * @author xiaofanku@live.cn
 */
@Entity
@Table(name=\"apo_attributes\")
public class ConfigAttribute implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long ID;
    @Column(name=\"name\")
    private String name;
    private String value;
    //GET/SET
}

测试代码

    @Test @Ignore
    public void test(){
        SiteConfig sc=new SiteConfig();
        sc.setID(1L);
        sc.setCaption(\"全局配置\");
        Map<String, ConfigAttribute> data=new HashMap<>();
        ConfigAttribute ca1=new ConfigAttribute();
        ca1.setName(\"site\");ca1.setValue(\"csdn.net\");
        data.put(\"site\", ca1);
        ConfigAttribute ca2=new ConfigAttribute();
        ca2.setName(\"account\");ca2.setValue(\"xiaofanku\");
        data.put(\"account\", ca2);
        sc.setAttributes(data);
        siteConfigDao.save(sc);
    }
    @Test @Ignore
    public void getConfig(){
        SiteConfig config=siteConfigDao.findOne(1L);
        assertEquals(config.getAttributes().get(\"site\").getValue(), \"csdn.net\");
    }

apo_config:表结构

apo_attributes:表结构

apo_config_attributes:中间表结构

C: 使用ASF Commons BeanUtils来构造一个Dynamic Class

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import org.apache.commons.beanutils.BasicDynaClass;
import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.beanutils.DynaBean;
import org.apache.commons.beanutils.DynaProperty;
/**
 * 使用Commons Beanutils实现动态类
 * @author xiaofanku@live.cn
 * @since 20171024
 */
public class DynamicClass{
    private final DynaBean config;
    /**
     * 构造一个运态类型
     * @param attributeMeta key属性名,value为属性名的类型,例:java.lang.Boolean
     * @throws IllegalAccessException
     * @throws InstantiationException
     * @throws ClassNotFoundException 
     */
    public DynamicClass(Map<String,String> attributeMeta) throws IllegalAccessException, InstantiationException, ClassNotFoundException{
        DynaProperty[] props=covert(attributeMeta).toArray(new DynaProperty[]{});
        BasicDynaClass dynaClass = new BasicDynaClass(\"CustomConfig\", null, props);
        this.config = dynaClass.newInstance();
    }
    /**
     * 构造一个运态类型
     * @param attributes
     * @throws ClassNotFoundException
     * @throws IllegalAccessException
     * @throws InstantiationException 
     */
    public DynamicClass(Set<Attribute> attributes) throws ClassNotFoundException, IllegalAccessException, InstantiationException{
        DynaProperty[] props=covert(attributes).toArray(new DynaProperty[]{});
        BasicDynaClass dynaClass = new BasicDynaClass(\"CustomConfig\", null, props);
        this.config = dynaClass.newInstance();
        load(attributes);
    }
    /**
     * 获得属性值
     * @param attributeName 属性名
     * @return
     */
    public Object getValue(String attributeName){
        return config.get(attributeName);
    }
    /**
     * 获得属性值
     * @param attributeName 属性名
     * @param classType 属性类型
     * @param <T>
     * @return
     * @throws java.lang.ClassCastException
     */
    public <T> T getValue(String attributeName, Class<T> classType) throws java.lang.ClassCastException{
        return (T)getValue(attributeName);
    }
    /**
     * 设置属性
     * @param attributeName 属性名
     * @param attributeValue 属性值
     */
    public void setValue(String attributeName, String attributeValue){
        DynaProperty dp = config.getDynaClass().getDynaProperty(attributeName);
        config.set(attributeName, ConvertUtils.convert(attributeValue, dp.getType()));
    }
    /**
     * 设置属性
     * @param attribute 属性实例
     * @throws ClassNotFoundException
     */
    public void setValue(Attribute attribute) throws ClassNotFoundException {
        config.set(attribute.getName(), ConvertUtils.convert(attribute.getValue(), Class.forName(attribute.getClassName())));
    }
    /**
     * 装载属性集合,填充动态类实例
     * @param attributes 
     */
    private void load(Set<Attribute> attributes){
        for(Attribute attr : attributes){
            try{
                config.set(attr.getName(), ConvertUtils.convert(attr.getValue(), Class.forName(attr.getClassName())));
            }catch(ClassNotFoundException e){
            }
        }
    }
    /**
     * 返回一个DynaProperty列表
     * @param attributes
     * @return
     * @throws ClassNotFoundException
     */
    private List<DynaProperty> covert(Set<Attribute> attributes) throws ClassNotFoundException{
        List<DynaProperty> attres=new ArrayList<>();
        for(Attribute attr : attributes){
            attres.add(new DynaProperty(attr.getName(), Class.forName(attr.getClassName())));
        }
        return attres;
    }
    /**
     * 返回一个DynaProperty列表
     * @param attributeMeta key属性名,value为属性名的类型,例:java.lang.Boolean
     * @return
     * @throws ClassNotFoundException
     */
    private List<DynaProperty> covert(Map<String,String> attributeMeta) throws ClassNotFoundException{
        List<DynaProperty> properties=new ArrayList<>();
        Set<String> attrSet=attributeMeta.keySet();
        for(String attrName : attrSet){
            String className=attributeMeta.get(attrName);
            properties.add(new DynaProperty(attrName, Class.forName(className)));
        }
        return properties;
    }
    public static enum Type{
        BOOLEAN(\"java.lang.Boolean\"),
        INTEGER(\"java.lang.Integer\"),
        LONG(\"java.lang.Long\"),
        STRING(\"java.lang.String\"),
        CHAR(\"java.lang.Character\"),
        DOUBLE(\"java.lang.Double\"),
        FLOAT(\"java.lang.Float\");
        private final String name;
        private Type(String className){
            this.name=className;
        }
        public String getName() {
            return name;
        }
    }
    public static class Attribute{
        //属性名,例:show
        private final String name;
        //属性名的值,例:\"true\"
        private final String value;
        //属性名的类型,例:java.lang.Boolean
        private final String className;
        public Attribute(String name, String value, String className) {
            this.name = name;
            this.value = value;
            this.className = className;
        }
        public String getName() {
            return name;
        }
        public String getValue() {
            return value;
        }
        public String getClassName() {
            return className;
        }
        @Override
        public int hashCode() {
            int hash = 5;
            hash = 97 * hash + Objects.hashCode(this.name);
            hash = 97 * hash + Objects.hashCode(this.className);
            return hash;
        }
        @Override
        public boolean equals(Object obj) {
            if (this == obj) {
                return true;
            }
            if (obj == null) {
                return false;
            }
            if (getClass() != obj.getClass()) {
                return false;
            }
            final Attribute other = (Attribute) obj;
            if (!Objects.equals(this.name, other.name)) {
                return false;
            }
            if (!Objects.equals(this.className, other.className)) {
                return false;
            }
            return true;
        }
    }
}

测试代码:

    @Test
    public void test(){
        Set<Attribute> sas=new HashSet<>();
        sas.add(new Attribute(\"logo\", \"logo.png\", DynamicClass.Type.STRING.getName()));
        sas.add(new Attribute(\"pageSize\", \"50\", DynamicClass.Type.INTEGER.getName()));
        sas.add(new Attribute(\"shortcut\", \"true\", DynamicClass.Type.BOOLEAN.getName()));
        try{
            DynamicClass dc=new DynamicClass(sas);
            Integer ps = dc.getValue(\"pageSize\", Integer.class);
            System.out.println(ps);
            dc.setValue(\"pageSize\", \"150\");
            System.out.println(dc.getValue(\"pageSize\"));
        }catch(Exception e){
            e.printStackTrace();
        }
    }
    @Test @Ignore
    public void base() {
        Map<String, String> am = new HashMap<>();
        am.put(\"logo\", DynamicClass.Type.STRING.getName());
        am.put(\"pageSize\", DynamicClass.Type.INTEGER.getName());
        am.put(\"shortcut\", DynamicClass.Type.BOOLEAN.getName());
        try {
            DynamicClass dc = new DynamicClass(am);
            dc.setValue(\"pageSize\", \"150\");
            System.out.println(dc.getValue(\"pageSize\"));
            dc.setValue(new Attribute(\"shortcut\", \"true\", DynamicClass.Type.BOOLEAN.getName()));
            System.out.println(dc.getValue(\"shortcut\"));
        } catch (IllegalAccessException | InstantiationException | ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

最后说明:

  • JPA 2.1 实现 EclipseLink 2.5.2
  • JDK 1.8.x
  • Mysql 5.5.x
  • ASF Commons BeanUtils 1.8.3

以上为个人经验,希望能给大家一个参考,也希望大家多多支持。

:本文采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可, 转载请附上原文出处链接。
1、本站提供的源码不保证资源的完整性以及安全性,不附带任何技术服务!
2、本站提供的模板、软件工具等其他资源,均不包含技术服务,请大家谅解!
3、本站提供的资源仅供下载者参考学习,请勿用于任何商业用途,请24小时内删除!
4、如需商用,请购买正版,由于未及时购买正版发生的侵权行为,与本站无关。
5、本站部分资源存放于百度网盘或其他网盘中,请提前注册好百度网盘账号,下载安装百度网盘客户端或其他网盘客户端进行下载;
6、本站部分资源文件是经压缩后的,请下载后安装解压软件,推荐使用WinRAR和7-Zip解压软件。
7、如果本站提供的资源侵犯到了您的权益,请邮件联系: 442469558@qq.com 进行处理!

猪小侠源码-最新源码下载平台 Java教程 Spring Data JPA映射自定义实体类操作 http://www.20zxx.cn/297580/xuexijiaocheng/javajc.html

猪小侠源码,优质资源分享网

常见问题
  • 本站所有资源版权均属于原作者所有,均只能用于参考学习,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担
查看详情
  • 最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,建议提前注册好百度网盘账号,使用百度网盘客户端下载
查看详情

相关文章

官方客服团队

为您解决烦忧 - 24小时在线 专业服务