This commit is contained in:
parent
bf7167e818
commit
d5c7ab0f53
|
@ -1,102 +0,0 @@
|
|||
package com.guwan.backend.MergeStrategy;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.invoke.SerializedLambda;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.function.Function;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Lambda表达式和方法引用解析工具类
|
||||
*/
|
||||
public class LambdaUtils {
|
||||
|
||||
/**
|
||||
* 从Lambda表达式或方法引用中提取属性名
|
||||
* @param getter Lambda方法引用
|
||||
* @return 属性名
|
||||
*/
|
||||
public static <T, R> String getPropertyName(PropertyFunction<T, R> getter) {
|
||||
try {
|
||||
// 1. 获取SerializedLambda
|
||||
Method writeReplace = getter.getClass().getDeclaredMethod("writeReplace");
|
||||
writeReplace.setAccessible(true);
|
||||
SerializedLambda serializedLambda = (SerializedLambda) writeReplace.invoke(getter);
|
||||
|
||||
// 2. 从SerializedLambda获取实现方法名
|
||||
String implMethodName = serializedLambda.getImplMethodName();
|
||||
|
||||
// 3. 转换方法名为属性名
|
||||
if (implMethodName.startsWith("get") && implMethodName.length() > 3) {
|
||||
String propertyName = implMethodName.substring(3);
|
||||
return propertyName.substring(0, 1).toLowerCase() + propertyName.substring(1);
|
||||
} else if (implMethodName.startsWith("is") && implMethodName.length() > 2) {
|
||||
String propertyName = implMethodName.substring(2);
|
||||
return propertyName.substring(0, 1).toLowerCase() + propertyName.substring(1);
|
||||
}
|
||||
|
||||
return implMethodName;
|
||||
} catch (Exception e) {
|
||||
// 降级到常规正则表达式解析
|
||||
return parsePropertyNameByRegex(getter);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用正则表达式解析属性名(备选方案)
|
||||
*/
|
||||
private static <T, R> String parsePropertyNameByRegex(Function<T, R> getter) {
|
||||
// 尝试从Lambda toString()解析
|
||||
String methodRef = getter.toString();
|
||||
|
||||
// 处理方法引用格式: com.example.Entity::getName
|
||||
if (methodRef.contains("::")) {
|
||||
Pattern pattern = Pattern.compile("::get(\\w+)|::is(\\w+)");
|
||||
Matcher matcher = pattern.matcher(methodRef);
|
||||
if (matcher.find()) {
|
||||
String fieldName = matcher.group(1) != null ? matcher.group(1) : matcher.group(2);
|
||||
return fieldName.substring(0, 1).toLowerCase() + fieldName.substring(1);
|
||||
}
|
||||
|
||||
// 直接从方法名截取
|
||||
String methodName = methodRef.substring(methodRef.lastIndexOf("::") + 2);
|
||||
return extractFieldNameFromMethod(methodName);
|
||||
}
|
||||
// 处理Lambda表达式格式: (Entity e) -> e.getName() 或 e -> e.getName()
|
||||
else if (methodRef.contains("->")) {
|
||||
Pattern pattern = Pattern.compile("->\\s*\\w+\\.get(\\w+)\\(\\)|->\\s*\\w+\\.is(\\w+)\\(\\)");
|
||||
Matcher matcher = pattern.matcher(methodRef);
|
||||
if (matcher.find()) {
|
||||
String fieldName = matcher.group(1) != null ? matcher.group(1) : matcher.group(2);
|
||||
return fieldName.substring(0, 1).toLowerCase() + fieldName.substring(1);
|
||||
}
|
||||
}
|
||||
|
||||
// 处理其他情况 - 也许是已经是字段名
|
||||
return methodRef;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从方法名中提取字段名
|
||||
*/
|
||||
private static String extractFieldNameFromMethod(String methodName) {
|
||||
if (methodName.startsWith("get") && methodName.length() > 3) {
|
||||
// getName -> name (首字母小写)
|
||||
String fieldName = methodName.substring(3);
|
||||
return fieldName.substring(0, 1).toLowerCase() + fieldName.substring(1);
|
||||
} else if (methodName.startsWith("is") && methodName.length() > 2) {
|
||||
// isActive -> active (首字母小写)
|
||||
String fieldName = methodName.substring(2);
|
||||
return fieldName.substring(0, 1).toLowerCase() + fieldName.substring(1);
|
||||
}
|
||||
return methodName;
|
||||
}
|
||||
|
||||
/**
|
||||
* 可序列化的函数接口 - 用于支持方法引用解析
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface PropertyFunction<T, R> extends Function<T, R>, Serializable {
|
||||
}
|
||||
}
|
|
@ -1,16 +1,11 @@
|
|||
package com.guwan.backend.MergeStrategy;
|
||||
package com.guwan.backend.builder;
|
||||
|
||||
import jakarta.persistence.EntityManager;
|
||||
import jakarta.persistence.criteria.*;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
import org.springframework.data.jpa.repository.query.QueryUtils;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import com.guwan.backend.MergeStrategy.LambdaUtils.PropertyFunction;
|
||||
|
||||
/**
|
||||
* 自定义连表查询构建器
|
||||
|
@ -42,19 +37,6 @@ public class JoinBuilder<T> {
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加连接表(使用增强的方法引用)
|
||||
* @param joinClass 要连接的表实体类
|
||||
* @param sourceFieldGetter 主表外键字段的getter方法引用
|
||||
* @param targetFieldGetter 连接表目标字段的getter方法引用
|
||||
*/
|
||||
public <J, V> JoinBuilder<T> join(Class<J> joinClass,
|
||||
PropertyFunction<T, V> sourceFieldGetter,
|
||||
PropertyFunction<J, V> targetFieldGetter) {
|
||||
String sourceField = LambdaUtils.getPropertyName(sourceFieldGetter);
|
||||
String targetField = LambdaUtils.getPropertyName(targetFieldGetter);
|
||||
return join(joinClass, sourceField, targetField);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加等值条件
|
||||
|
@ -70,64 +52,6 @@ public class JoinBuilder<T> {
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加等值条件(使用增强的方法引用)
|
||||
* @param entityClass 实体类
|
||||
* @param fieldGetter 字段的getter方法引用
|
||||
* @param value 字段值
|
||||
*/
|
||||
public <E, V> JoinBuilder<T> equal(Class<E> entityClass, PropertyFunction<E, V> fieldGetter, V value) {
|
||||
String fieldName = LambdaUtils.getPropertyName(fieldGetter);
|
||||
return equal(entityClass, fieldName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 选择返回的字段
|
||||
* @param selectedFields 每个实体类需要返回的字段映射
|
||||
*/
|
||||
public JoinBuilder<T> selectFields(Map<Class<?>, String[]> selectedFields) {
|
||||
this.selectedFields = selectedFields;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 选择返回的字段(使用增强的方法引用)
|
||||
* @param fieldGetters 方法引用列表
|
||||
*/
|
||||
@SafeVarargs
|
||||
public final <E> JoinBuilder<T> select(Class<E> entityClass, PropertyFunction<E, ?>... fieldGetters) {
|
||||
if (selectedFields == null) {
|
||||
selectedFields = new HashMap<>();
|
||||
}
|
||||
|
||||
String[] fieldNames = Arrays.stream(fieldGetters)
|
||||
.map(LambdaUtils::getPropertyName)
|
||||
.toArray(String[]::new);
|
||||
|
||||
selectedFields.put(entityClass, fieldNames);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加一个具有别名的字段选择(使用增强的方法引用)
|
||||
* @param alias 字段别名
|
||||
* @param entityClass 实体类
|
||||
* @param fieldGetter 字段的getter方法引用
|
||||
*/
|
||||
public <E, V> JoinBuilder<T> selectAs(String alias, Class<E> entityClass, PropertyFunction<E, V> fieldGetter) {
|
||||
String fieldName = LambdaUtils.getPropertyName(fieldGetter);
|
||||
|
||||
// 存储字段信息,稍后在configureSelections处理
|
||||
if (selectedFields == null) {
|
||||
selectedFields = new HashMap<>();
|
||||
}
|
||||
if (!selectedFields.containsKey(entityClass)) {
|
||||
selectedFields.put(entityClass, new String[0]);
|
||||
}
|
||||
namedSelections.put(alias, new SelectionInfo(entityClass, fieldName));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加一个具有别名的字段选择(字符串版本)
|
||||
|
@ -147,50 +71,75 @@ public class JoinBuilder<T> {
|
|||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置实体间字段映射关系的别名,以便对应DTO字段
|
||||
* @param dtoClass DTO类
|
||||
* @param mappings 字段映射
|
||||
*/
|
||||
@SafeVarargs
|
||||
public final <R> JoinBuilder<T> selectDto(Class<R> dtoClass, FieldMapping<R, ?>... mappings) {
|
||||
for (FieldMapping<R, ?> mapping : mappings) {
|
||||
String dtoFieldName = mapping.getDtoFieldName();
|
||||
String entityFieldName = mapping.getEntityFieldName();
|
||||
Class<?> entityClass = mapping.getEntityClass();
|
||||
|
||||
// 存储字段信息,稍后在configureSelections处理
|
||||
if (selectedFields == null) {
|
||||
selectedFields = new HashMap<>();
|
||||
}
|
||||
if (!selectedFields.containsKey(entityClass)) {
|
||||
selectedFields.put(entityClass, new String[0]);
|
||||
}
|
||||
namedSelections.put(dtoFieldName, new SelectionInfo(entityClass, entityFieldName));
|
||||
|
||||
|
||||
|
||||
public long count(EntityManager entityManager) {
|
||||
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
|
||||
CriteriaQuery<Long> countQuery = criteriaBuilder.createQuery(Long.class);
|
||||
Root<T> root = countQuery.from(rootClass);
|
||||
|
||||
// 创建连接关系
|
||||
Map<Class<?>, From<?, ?>> fromMap = createJoins(root, countQuery);
|
||||
|
||||
// 应用条件,包括表之间的连接条件和额外查询条件
|
||||
List<Predicate> predicates = applyAllConditions(root, fromMap, criteriaBuilder);
|
||||
|
||||
// 添加条件到查询
|
||||
if (!predicates.isEmpty()) {
|
||||
countQuery.where(criteriaBuilder.and(predicates.toArray(new Predicate[0])));
|
||||
}
|
||||
return this;
|
||||
|
||||
// 设置count查询
|
||||
countQuery.select(criteriaBuilder.count(root));
|
||||
|
||||
// 执行查询并返回结果
|
||||
return entityManager.createQuery(countQuery).getSingleResult();
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建规范查询
|
||||
* @return Specification<T> 查询规范
|
||||
*/
|
||||
public Specification<T> build() {
|
||||
return (root, query, criteriaBuilder) -> {
|
||||
// 创建连接关系
|
||||
Map<Class<?>, From<?, ?>> joinMap = createJoins(root, query);
|
||||
|
||||
// 应用连表条件和其他条件
|
||||
List<Predicate> predicates = applyAllConditions(root, joinMap, criteriaBuilder);
|
||||
|
||||
// 设置查询结果投影
|
||||
configureSelections(root, joinMap, query);
|
||||
|
||||
return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
|
||||
};
|
||||
public <R> List<R> executeAndMapWithPaging(EntityManager entityManager,
|
||||
Class<R> dtoClass,
|
||||
int page,
|
||||
int size) {
|
||||
List<Object[]> results = executeWithPaging(entityManager, page, size);
|
||||
return mapToDto(results, dtoClass);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public List<Object[]> executeWithPaging(EntityManager entityManager, int page, int size) {
|
||||
// 创建CriteriaBuilder
|
||||
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
|
||||
|
||||
// 创建CriteriaQuery
|
||||
CriteriaQuery<Object[]> criteriaQuery = criteriaBuilder.createQuery(Object[].class);
|
||||
|
||||
// 设置根实体
|
||||
Root<T> root = criteriaQuery.from(rootClass);
|
||||
|
||||
// 创建连接关系
|
||||
Map<Class<?>, From<?, ?>> fromMap = createJoins(root, criteriaQuery);
|
||||
|
||||
// 应用所有条件
|
||||
List<Predicate> predicates = applyAllConditions(root, fromMap, criteriaBuilder);
|
||||
|
||||
// 添加条件到查询
|
||||
if (!predicates.isEmpty()) {
|
||||
criteriaQuery.where(criteriaBuilder.and(predicates.toArray(new Predicate[0])));
|
||||
}
|
||||
|
||||
// 设置查询结果投影
|
||||
configureSelections(root, fromMap, criteriaQuery);
|
||||
|
||||
// 创建查询并设置分页
|
||||
jakarta.persistence.Query query = entityManager.createQuery(criteriaQuery);
|
||||
query.setFirstResult(page * size);
|
||||
query.setMaxResults(size);
|
||||
|
||||
// 执行查询并返回结果
|
||||
return query.getResultList();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 执行查询并返回结果
|
||||
* @param entityManager EntityManager实例
|
||||
|
@ -274,18 +223,7 @@ public class JoinBuilder<T> {
|
|||
|
||||
return predicates;
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行查询并直接映射到DTO对象
|
||||
* @param entityManager EntityManager实例
|
||||
* @param dtoClass DTO类
|
||||
* @param <R> DTO类型
|
||||
* @return DTO对象列表
|
||||
*/
|
||||
public <R> List<R> executeAndMap(EntityManager entityManager, Class<R> dtoClass) {
|
||||
List<Object[]> results = execute(entityManager);
|
||||
return mapToDto(results, dtoClass);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 将查询结果映射到DTO对象
|
||||
|
@ -384,54 +322,7 @@ public class JoinBuilder<T> {
|
|||
throw new UnsupportedOperationException("Unsupported operator: " + condition.operator);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 字段映射定义,用于DTO映射
|
||||
*/
|
||||
public static class FieldMapping<D, E> {
|
||||
private final String dtoFieldName;
|
||||
private final String entityFieldName;
|
||||
private final Class<E> entityClass;
|
||||
|
||||
private FieldMapping(String dtoFieldName, String entityFieldName, Class<E> entityClass) {
|
||||
this.dtoFieldName = dtoFieldName;
|
||||
this.entityFieldName = entityFieldName;
|
||||
this.entityClass = entityClass;
|
||||
}
|
||||
|
||||
public static <D, E, V> FieldMapping<D, E> of(PropertyFunction<D, V> dtoFieldGetter, PropertyFunction<E, V> entityFieldGetter) {
|
||||
String dtoFieldName = LambdaUtils.getPropertyName(dtoFieldGetter);
|
||||
String entityFieldName = LambdaUtils.getPropertyName(entityFieldGetter);
|
||||
|
||||
// 通过反射获取entityClass
|
||||
Class<E> entityClass = null;
|
||||
try {
|
||||
// 尝试从方法引用中提取类信息
|
||||
Method writeReplace = entityFieldGetter.getClass().getDeclaredMethod("writeReplace");
|
||||
writeReplace.setAccessible(true);
|
||||
Object serializedLambda = writeReplace.invoke(entityFieldGetter);
|
||||
String implClass = (String) serializedLambda.getClass().getMethod("getImplClass").invoke(serializedLambda);
|
||||
implClass = implClass.replace('/', '.');
|
||||
entityClass = (Class<E>) Class.forName(implClass);
|
||||
} catch (Exception e) {
|
||||
// 忽略异常,entityClass将在运行时确定
|
||||
}
|
||||
|
||||
return new FieldMapping<>(dtoFieldName, entityFieldName, entityClass);
|
||||
}
|
||||
|
||||
public String getDtoFieldName() {
|
||||
return dtoFieldName;
|
||||
}
|
||||
|
||||
public String getEntityFieldName() {
|
||||
return entityFieldName;
|
||||
}
|
||||
|
||||
public Class<?> getEntityClass() {
|
||||
return entityClass;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 连接信息
|
|
@ -1,18 +1,16 @@
|
|||
package com.guwan.backend.jpaTest;
|
||||
|
||||
import com.guwan.backend.jpaTest.domain.EmployeeDTO;
|
||||
import jakarta.persistence.EntityManager;
|
||||
import jakarta.persistence.PersistenceContext;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.util.List;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/employees")
|
||||
public class EmployeeController {
|
||||
|
@ -35,23 +33,12 @@ public class EmployeeController {
|
|||
* @return 员工DTO列表
|
||||
*/
|
||||
@GetMapping("/details")
|
||||
public List<EmployeeDTO> getEmployeeDetails(
|
||||
public Page<EmployeeDTO> getEmployeeDetails(
|
||||
@RequestParam(required = false) String departmentName,
|
||||
@RequestParam(required = false, defaultValue = "false") boolean projectDeleted) {
|
||||
return employeeService.getEmployeeDetails(departmentName, projectDeleted);
|
||||
return employeeService.getEmployeeDetails(departmentName, projectDeleted, 0, 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据条件查询员工信息
|
||||
*
|
||||
* @param employeeName 员工名称过滤条件,可选
|
||||
* @param departmentName 部门名称过滤条件,可选
|
||||
* @return 员工DTO列表
|
||||
*/
|
||||
@GetMapping("/search")
|
||||
public List<EmployeeDTO> searchEmployees(
|
||||
@RequestParam(required = false) String employeeName,
|
||||
@RequestParam(required = false) String departmentName) {
|
||||
return employeeService.findEmployees(employeeName, departmentName);
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
package com.guwan.backend.jpaTest;
|
||||
|
||||
import com.guwan.backend.jpaTest.domain.Employee;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
|
|
@ -1,11 +1,16 @@
|
|||
package com.guwan.backend.jpaTest;
|
||||
|
||||
import com.guwan.backend.MergeStrategy.JoinBuilder;
|
||||
import com.guwan.backend.MergeStrategy.JoinBuilder.FieldMapping;
|
||||
import com.guwan.backend.MergeStrategy.LambdaUtils.PropertyFunction;
|
||||
import com.guwan.backend.builder.JoinBuilder;
|
||||
import com.guwan.backend.jpaTest.domain.Department;
|
||||
import com.guwan.backend.jpaTest.domain.Employee;
|
||||
import com.guwan.backend.jpaTest.domain.EmployeeDTO;
|
||||
import com.guwan.backend.jpaTest.domain.Project;
|
||||
import jakarta.persistence.EntityManager;
|
||||
import jakarta.persistence.PersistenceContext;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageImpl;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
|
@ -27,7 +32,8 @@ public class EmployeeService {
|
|||
* @param projectDeleted 项目是否已删除的过滤条件
|
||||
* @return 员工DTO列表
|
||||
*/
|
||||
public List<EmployeeDTO> getEmployeeDetails(String departmentName, boolean projectDeleted) {
|
||||
public Page<EmployeeDTO> getEmployeeDetails(String departmentName, boolean projectDeleted,
|
||||
int page, int size) {
|
||||
// 创建查询构建器,从Employee实体开始
|
||||
JoinBuilder<Employee> builder = JoinBuilder.from(Employee.class);
|
||||
|
||||
|
@ -47,77 +53,19 @@ public class EmployeeService {
|
|||
builder.selectAs("departmentName", Department.class, "name");
|
||||
builder.selectAs("projectName", Project.class, "name");
|
||||
|
||||
// 直接执行查询并映射到DTO
|
||||
return builder.executeAndMap(entityManager, EmployeeDTO.class);
|
||||
// 先获取总记录数
|
||||
long total = builder.count(entityManager);
|
||||
|
||||
// 执行分页查询并映射到DTO
|
||||
List<EmployeeDTO> content = builder.executeAndMapWithPaging(
|
||||
entityManager,
|
||||
EmployeeDTO.class,
|
||||
page,
|
||||
size
|
||||
);
|
||||
|
||||
// 返回分页结果
|
||||
return new PageImpl<>(content, PageRequest.of(page, size), total);
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用自定义条件查询员工信息
|
||||
* 使用新的方法引用方式
|
||||
*
|
||||
* @param employeeName 员工名称过滤条件,可选
|
||||
* @param departmentName 部门名称过滤条件,可选
|
||||
* @return 员工DTO列表
|
||||
*/
|
||||
public List<EmployeeDTO> findEmployees(String employeeName, String departmentName) {
|
||||
JoinBuilder<Employee> builder = JoinBuilder.from(Employee.class);
|
||||
|
||||
// 尝试使用增强的方法引用
|
||||
try {
|
||||
// 添加关联,使用增强的方法引用
|
||||
builder.join(Department.class,
|
||||
(PropertyFunction<Employee, Long>) Employee::getDepartmentId,
|
||||
(PropertyFunction<Department, Long>) Department::getId);
|
||||
builder.join(Project.class,
|
||||
(PropertyFunction<Employee, Long>) Employee::getProjectId,
|
||||
(PropertyFunction<Project, Long>) Project::getId);
|
||||
|
||||
// 添加查询条件,使用增强的方法引用
|
||||
if (employeeName != null && !employeeName.isEmpty()) {
|
||||
builder.equal(Employee.class,
|
||||
(PropertyFunction<Employee, String>) Employee::getName,
|
||||
employeeName);
|
||||
}
|
||||
|
||||
if (departmentName != null && !departmentName.isEmpty()) {
|
||||
builder.equal(Department.class,
|
||||
(PropertyFunction<Department, String>) Department::getName,
|
||||
departmentName);
|
||||
}
|
||||
|
||||
// 使用selectAs配合增强的方法引用
|
||||
builder.selectAs("employeeId", Employee.class,
|
||||
(PropertyFunction<Employee, Long>) Employee::getId);
|
||||
builder.selectAs("employeeName", Employee.class,
|
||||
(PropertyFunction<Employee, String>) Employee::getName);
|
||||
builder.selectAs("departmentName", Department.class,
|
||||
(PropertyFunction<Department, String>) Department::getName);
|
||||
builder.selectAs("projectName", Project.class,
|
||||
(PropertyFunction<Project, String>) Project::getName);
|
||||
}
|
||||
catch (Exception e) {
|
||||
/* // 如果增强方法引用失败,回退到字符串方式
|
||||
builder = JoinBuilder.from(Employee.class);
|
||||
|
||||
// 使用字符串作为回退方案
|
||||
builder.join(Department.class, "departmentId", "id");
|
||||
builder.join(Project.class, "projectId", "id");
|
||||
|
||||
if (employeeName != null && !employeeName.isEmpty()) {
|
||||
builder.equal(Employee.class, "name", employeeName);
|
||||
}
|
||||
|
||||
if (departmentName != null && !departmentName.isEmpty()) {
|
||||
builder.equal(Department.class, "name", departmentName);
|
||||
}
|
||||
|
||||
builder.selectAs("employeeId", Employee.class, "id");
|
||||
builder.selectAs("employeeName", Employee.class, "name");
|
||||
builder.selectAs("departmentName", Department.class, "name");
|
||||
builder.selectAs("projectName", Project.class, "name");*/
|
||||
}
|
||||
|
||||
// 直接执行查询并映射到DTO
|
||||
return builder.executeAndMap(entityManager, EmployeeDTO.class);
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package com.guwan.backend.jpaTest;
|
||||
package com.guwan.backend.jpaTest.domain;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Id;
|
|
@ -1,4 +1,4 @@
|
|||
package com.guwan.backend.jpaTest;
|
||||
package com.guwan.backend.jpaTest.domain;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Id;
|
|
@ -1,4 +1,4 @@
|
|||
package com.guwan.backend.jpaTest;
|
||||
package com.guwan.backend.jpaTest.domain;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
|
@ -1,4 +1,4 @@
|
|||
package com.guwan.backend.jpaTest;
|
||||
package com.guwan.backend.jpaTest.domain;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Id;
|
|
@ -1,140 +0,0 @@
|
|||
package com.guwan.backend.jpaTest.mapper;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 查询结果映射工具类
|
||||
* 用于将原始查询结果转换为更有意义的对象
|
||||
*/
|
||||
public class QueryResultMapper {
|
||||
|
||||
/**
|
||||
* 将Object[]结果列表映射为指定类型的对象列表
|
||||
* @param results 查询结果
|
||||
* @param mapper 映射函数
|
||||
* @return 映射后的对象列表
|
||||
*/
|
||||
public static <T> List<T> mapToList(List<Object[]> results, Function<ResultRow, T> mapper) {
|
||||
return results.stream()
|
||||
.map(row -> mapper.apply(new ResultRow(row)))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 将Object[]结果列表使用命名方式映射为指定类型的对象列表
|
||||
* @param results 查询结果
|
||||
* @param columnMap 列名到索引的映射
|
||||
* @param mapper 映射函数
|
||||
* @return 映射后的对象列表
|
||||
*/
|
||||
public static <T> List<T> mapToListWithNames(List<Object[]> results,
|
||||
Map<String, Integer> columnMap,
|
||||
Function<NamedResultRow, T> mapper) {
|
||||
return results.stream()
|
||||
.map(row -> mapper.apply(new NamedResultRow(row, columnMap)))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 结果行封装,提供类型安全的访问方法
|
||||
*/
|
||||
public static class ResultRow {
|
||||
private final Object[] row;
|
||||
|
||||
public ResultRow(Object[] row) {
|
||||
this.row = row;
|
||||
}
|
||||
|
||||
public Long getLong(int index) {
|
||||
Object value = getValue(index);
|
||||
if (value == null) return null;
|
||||
if (value instanceof Long) return (Long) value;
|
||||
if (value instanceof Number) return ((Number) value).longValue();
|
||||
return Long.valueOf(value.toString());
|
||||
}
|
||||
|
||||
public Integer getInteger(int index) {
|
||||
Object value = getValue(index);
|
||||
if (value == null) return null;
|
||||
if (value instanceof Integer) return (Integer) value;
|
||||
if (value instanceof Number) return ((Number) value).intValue();
|
||||
return Integer.valueOf(value.toString());
|
||||
}
|
||||
|
||||
public String getString(int index) {
|
||||
Object value = getValue(index);
|
||||
return value == null ? null : value.toString();
|
||||
}
|
||||
|
||||
public Boolean getBoolean(int index) {
|
||||
Object value = getValue(index);
|
||||
if (value == null) return null;
|
||||
if (value instanceof Boolean) return (Boolean) value;
|
||||
if (value instanceof Number) return ((Number) value).intValue() != 0;
|
||||
return Boolean.valueOf(value.toString());
|
||||
}
|
||||
|
||||
public Object getValue(int index) {
|
||||
if (index < 0 || index >= row.length) {
|
||||
throw new IndexOutOfBoundsException("索引超出范围: " + index);
|
||||
}
|
||||
return row[index];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 命名结果行封装,通过列名访问数据
|
||||
*/
|
||||
public static class NamedResultRow {
|
||||
private final Object[] row;
|
||||
private final Map<String, Integer> columnMap;
|
||||
|
||||
public NamedResultRow(Object[] row, Map<String, Integer> columnMap) {
|
||||
this.row = row;
|
||||
this.columnMap = columnMap;
|
||||
}
|
||||
|
||||
public Long getLong(String columnName) {
|
||||
Object value = getValue(columnName);
|
||||
if (value == null) return null;
|
||||
if (value instanceof Long) return (Long) value;
|
||||
if (value instanceof Number) return ((Number) value).longValue();
|
||||
return Long.valueOf(value.toString());
|
||||
}
|
||||
|
||||
public Integer getInteger(String columnName) {
|
||||
Object value = getValue(columnName);
|
||||
if (value == null) return null;
|
||||
if (value instanceof Integer) return (Integer) value;
|
||||
if (value instanceof Number) return ((Number) value).intValue();
|
||||
return Integer.valueOf(value.toString());
|
||||
}
|
||||
|
||||
public String getString(String columnName) {
|
||||
Object value = getValue(columnName);
|
||||
return value == null ? null : value.toString();
|
||||
}
|
||||
|
||||
public Boolean getBoolean(String columnName) {
|
||||
Object value = getValue(columnName);
|
||||
if (value == null) return null;
|
||||
if (value instanceof Boolean) return (Boolean) value;
|
||||
if (value instanceof Number) return ((Number) value).intValue() != 0;
|
||||
return Boolean.valueOf(value.toString());
|
||||
}
|
||||
|
||||
public Object getValue(String columnName) {
|
||||
Integer index = columnMap.get(columnName);
|
||||
if (index == null) {
|
||||
throw new IllegalArgumentException("列名不存在: " + columnName);
|
||||
}
|
||||
if (index < 0 || index >= row.length) {
|
||||
throw new IndexOutOfBoundsException("索引超出范围: " + index);
|
||||
}
|
||||
return row[index];
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package com.guwan.backend.util;
|
||||
|
||||
import com.guwan.backend.jpaTest.domain.EmployeeDTO;
|
||||
|
||||
// 示例用法
|
||||
public class DtoGeneratorExample {
|
||||
public static void main(String[] args) {
|
||||
// 为EmployeeDTO生成构造函数
|
||||
String constructor = DtoGeneratorUtil.generateDtoConstructor(EmployeeDTO.class);
|
||||
System.out.println(constructor);
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
package com.guwan.backend.util;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
public class DtoGeneratorUtil {
|
||||
|
||||
public static String generateDtoConstructor(Class<?> dtoClass) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
Field[] fields = dtoClass.getDeclaredFields();
|
||||
|
||||
// 构造函数参数
|
||||
sb.append("public ").append(dtoClass.getSimpleName())
|
||||
.append("(");
|
||||
for (int i = 0; i < fields.length; i++) {
|
||||
if (i > 0) sb.append(", ");
|
||||
sb.append("Object ").append(fields[i].getName());
|
||||
}
|
||||
sb.append(") {\n");
|
||||
|
||||
// 构造函数体
|
||||
for (Field field : fields) {
|
||||
String fieldName = field.getName();
|
||||
String conversion = getConversion(field.getType(), fieldName);
|
||||
sb.append(" this.").append(fieldName)
|
||||
.append(" = ").append(fieldName).append(" != null ? ")
|
||||
.append(conversion).append(" : null;\n");
|
||||
}
|
||||
|
||||
sb.append("}");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private static String getConversion(Class<?> type, String fieldName) {
|
||||
if (type == String.class) {
|
||||
return "String.valueOf(" + fieldName + ")";
|
||||
} else if (type == Long.class || type == long.class) {
|
||||
return "Long.valueOf(" + fieldName + ".toString())";
|
||||
} else if (type == Integer.class || type == int.class) {
|
||||
return "Integer.valueOf(" + fieldName + ".toString())";
|
||||
} else if (type == Double.class || type == double.class) {
|
||||
return "Double.valueOf(" + fieldName + ".toString())";
|
||||
} else if (type == Boolean.class || type == boolean.class) {
|
||||
return "Boolean.valueOf(" + fieldName + ".toString())";
|
||||
} else if (type == java.util.Date.class) {
|
||||
return "(" + fieldName + " instanceof java.util.Date) ? (" +
|
||||
"java.util.Date) " + fieldName + " : new java.text.SimpleDateFormat(\"yyyy-MM-dd\").parse(" +
|
||||
fieldName + ".toString())";
|
||||
} else if (type == java.time.LocalDate.class) {
|
||||
return "java.time.LocalDate.parse(" + fieldName + ".toString())";
|
||||
} else if (type == java.time.LocalDateTime.class) {
|
||||
return "java.time.LocalDateTime.parse(" + fieldName + ".toString())";
|
||||
} else {
|
||||
// 对于其它复杂类型,可能需要更特殊的处理
|
||||
return "(" + type.getSimpleName() + ") " + fieldName;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue