Spring Data JPA 映射自定义实体 并 自定义sql多条件,灵活排序,分页查询【Oracle数据库】

我一共建立了3个VO, V$sqlarea(其实也是实体,包含rownum)V$sqlareaListCountVo 和 V$sqlareaVo(不包含rownum)java

直接代码:Daosql

@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 v$sqlarea t  									\r\n"+
			"		WHERE												\r\n" + 
			"			t.PARSING_SCHEMA_NAME = :parsingSchemaName 		\r\n" + 
			"			AND t.EXECUTIONS >= :executions 				\r\n" + 
			"			AND t.LAST_ACTIVE_TIME >= :startActiveTime  	\r\n" +
			"			AND t.LAST_ACTIVE_TIME < :lastActiveTime  		\r\n" +
			"			AND t.ELAPSED_TIME >= :elapsedTime  			\r\n" + 
			"			AND t.CPU_TIME >= :cpuTime  						" ,
			countQuery="	SELECT	 									\r\n"+
					"		count(t.SQL_ID) 							\r\n"+
					"		FROM	v$sqlarea t 						\r\n"+
					"		WHERE										\r\n" + 
					"		t.PARSING_SCHEMA_NAME = :parsingSchemaName 	\r\n" + 
					"		AND t.EXECUTIONS >= :executions 			\r\n" + 
					"		AND t.LAST_ACTIVE_TIME >= :startActiveTime  \r\n" +
					"		AND t.LAST_ACTIVE_TIME < :lastActiveTime  	\r\n" +
					"		AND t.ELAPSED_TIME >= :elapsedTime  		\r\n" + 
					"		AND t.CPU_TIME >= :cpuTime  					",nativeQuery = true )
	public Page<Object[]> findTopSQLS2(@Param("parsingSchemaName")String parsingSchemaName,
			  @Param("executions")Number executions,
			  @Param("startActiveTime")Date startActiveTime,
			  @Param("lastActiveTime")Date lastActiveTime,
			  @Param("elapsedTime")Number elapsedTime,
			  @Param("cpuTime")Number cpuTime,
			  Pageable pageable);

 由于是自定义实体因此我使用Object[ ]进行接收数据数据库

下面看下个人service层,多条件是我自定义的,感受比较low,若是不是自定义实体咱们直接能够调用JPA接口,使用example参数进行条件构造了,咱们使用Object[ ]接收参数,而后咱们使用EntityUtils中castEntity()方法进行转换你想要的实体类,数组

而后之因此定义V$sqlareaListCountVo是由于我controller中须要pages.getTotalElements()这个参数,这个参数是数据总数量,分页须要他,sqlareaListCountVo中有三个参数一个是 集合Vo 另外一个就是 里面多了一个rownum属性的集合Vo,还有一个即是数据总数,下面我会讲为何我建两个Vo【主要由于oracle(我使用的是oracle数据库),分页第一次查询的时候,没有rownum这个数据字段,可是第一次以后就会有这个字段,因此我定义了两个Vo一个有rownum,另外一个没有rownum,当第一次进来我就使用没有rownum的那个Vo,第一次以后我就会使用另外一个包含rownum属性的Vo】MySQL应该不会出现这样的状况,oracle

而后就是排序,前台传asc desc,可是后台不能这么写,因此我使用了三元运算符app

order.equals("asc") ? Sort.Direction.ASC : Sort.Direction.DESCide

避免使用if else显得代码累赘 =-= 其实如今我都感受个人代码很累赘。。。。。。。。。函数

 

 

/**
	 * 查询topSQL
	 */
	@Override
	public V$sqlareaListCountVo findTopSQL(Integer pageNum, Integer pageSize, ReqV$sqlarea sql) throws ParseException {
		V$sqlarea v$sqlarea = new V$sqlarea();
		ExampleMatcher matcher = ExampleMatcher.matching().withMatcher("indicatorsName",
				ExampleMatcher.GenericPropertyMatchers.contains());
		Example<V$sqlarea> example = Example.of(v$sqlarea, matcher);

		// 表空间名称
		String tableSpaseName = "C##DBAAS";

		// sql执行次数
		Number executions = sql.getExecutions();

		// 最新执行时间
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		Date startActiveTime = sql.getStartActiveTime();
		Date lastActiveTime = sql.getLastActiveTime();

		// 执行总时间(微秒)
		Number elapsedTime = sql.getElapsedTime();

		// sql执行所占用cpu的时间(微秒)
		Number cpuTime = sql.getCpuTime();

//		if (null == tableSpaseName) {
//			throw new CustomerException(1001, "表空间名称不能为空");
//		}
		if (null == executions) {
			executions = 0;
		} else if (executions.intValue() < 0) {
			throw new CustomerException(1001, "执行次数不能为负数");
		}
		if (null == lastActiveTime) {
			lastActiveTime = new Date();
		}
		if (null == startActiveTime) {
			startActiveTime = sdf.parse("0001-01-01 01:01:01");
		}
		if (null == elapsedTime) {
			elapsedTime = 0;
		} else if (elapsedTime.intValue() < 0) {
			throw new CustomerException(1001, "执行次数不能为负数");
		}
		if (null == cpuTime) {
			cpuTime = 0;
		} else if (cpuTime.intValue() < 0) {
			throw new CustomerException(1001, "执行次数不能为负数");
		}
		String order = sql.getOrder();
		Pageable pageable = PageRequest.of(pageNum, pageSize, order.equals("asc") ? Sort.Direction.ASC : Sort.Direction.DESC, sql.getSortName());
		Page<Object[]> pages = v$sqlareaDao.findTopSQLS2(tableSpaseName, executions, startActiveTime, lastActiveTime,elapsedTime, cpuTime, pageable);
		System.out.println(pages.getTotalElements());
		List<V$sqlarea> list1 = null;
		List<V$sqlareaVo> list2 = null;
		V$sqlareaListCountVo v$sqlareaListCountVo = new V$sqlareaListCountVo();

		if (pageNum != 0) {
			list1 = EntityUtils.castEntity(pages.getContent(), V$sqlarea.class, new V$sqlarea());
			v$sqlareaListCountVo.setCount(pages.getTotalElements());
			v$sqlareaListCountVo.setList(list1);
			return v$sqlareaListCountVo;
		} else {
			list2 = EntityUtils.castEntity(pages.getContent(), V$sqlareaVo.class, new V$sqlareaVo());
			v$sqlareaListCountVo.setCount(pages.getTotalElements());
			v$sqlareaListCountVo.setListVo(list2);
			return v$sqlareaListCountVo;
		}
	}

下面是个人EntityUtils类code

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;
/**
 * 用来将查询到的集合数组 转换成 集合对象
 * 注意:对象(实体)中必须包含构造函数,并且构造函数中的参数 要与数组中的参数顺序 一一对应,
 * 而且对象(实体)中的属性 必须和数据库中的字段 类型同样,不然转换不成功。
 * @author zhangxuewei
 *
 */
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;
    }
}

 注意:映射自定义实体类中,必须有构造函数,而且构造函数中的参数要 和 你sql中查询的字段顺序必须保持一致,这样才不会出错,orm

 而后看下个人controller层,在这里我也是没有办法,进行判断两个Vo中哪一个有值我便返回哪个

/**
	 * 查询TopSQL
	 * @author zhangxuewei
	 * @param pageNum
	 * @param pageSize
	 * @param sql
	 * @return
	 * @throws ParseException
	 */
	@GetMapping(value = "/list")
	@ResponseBody
	public PageResult selectTopSQLUntreated(@RequestParam(value = "pageNumber", defaultValue = "0")Integer pageNum,@RequestParam(value = "pageSize", defaultValue = "2") Integer pageSize,ReqV$sqlarea sql) throws ParseException {
		V$sqlareaListCountVo vo = topSQLService.findTopSQL(pageNum-1, pageSize, sql);
		PageResult page = new PageResult();
		page.setTotal(vo.getCount());
		if(null == vo.getList()) {
			page.setRows(vo.getListVo());
			return page;
		}else {
			page.setRows(vo.getList());
			return page;
		}
	}