可正常启动
This commit is contained in:
parent
c913ab3cc5
commit
1afd981805
@ -4,7 +4,6 @@ import com.qqchen.deploy.backend.dto.TenantDTO;
|
|||||||
import com.qqchen.deploy.backend.framework.controller.BaseController;
|
import com.qqchen.deploy.backend.framework.controller.BaseController;
|
||||||
import com.qqchen.deploy.backend.dto.query.TenantQuery;
|
import com.qqchen.deploy.backend.dto.query.TenantQuery;
|
||||||
import com.qqchen.deploy.backend.entity.Tenant;
|
import com.qqchen.deploy.backend.entity.Tenant;
|
||||||
import com.qqchen.deploy.backend.service.ITenantService;
|
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
@ -15,13 +14,6 @@ import java.util.List;
|
|||||||
@RequestMapping("/api/v1/tenant")
|
@RequestMapping("/api/v1/tenant")
|
||||||
public class TenantApiController extends BaseController<Tenant, TenantDTO, Long, TenantQuery> {
|
public class TenantApiController extends BaseController<Tenant, TenantDTO, Long, TenantQuery> {
|
||||||
|
|
||||||
protected final ITenantService service;
|
|
||||||
|
|
||||||
public TenantApiController(ITenantService service) {
|
|
||||||
super(service);
|
|
||||||
this.service = service;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void exportData(HttpServletResponse response, List<TenantDTO> data) {
|
protected void exportData(HttpServletResponse response, List<TenantDTO> data) {
|
||||||
|
|
||||||
|
|||||||
@ -11,6 +11,7 @@ import com.qqchen.deploy.backend.dto.request.LoginRequest;
|
|||||||
import com.qqchen.deploy.backend.dto.response.LoginResponse;
|
import com.qqchen.deploy.backend.dto.response.LoginResponse;
|
||||||
import com.qqchen.deploy.backend.service.IUserService;
|
import com.qqchen.deploy.backend.service.IUserService;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
@ -23,12 +24,9 @@ import java.util.List;
|
|||||||
@RequestMapping("/api/v1/users")
|
@RequestMapping("/api/v1/users")
|
||||||
public class UserApiController extends BaseController<User, UserDTO, Long, UserQuery> {
|
public class UserApiController extends BaseController<User, UserDTO, Long, UserQuery> {
|
||||||
|
|
||||||
private final IUserService userService;
|
@Resource
|
||||||
|
private IUserService userService;
|
||||||
|
|
||||||
public UserApiController(IUserService userService) {
|
|
||||||
super(userService);
|
|
||||||
this.userService = userService;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Operation(summary = "用户登录")
|
@Operation(summary = "用户登录")
|
||||||
@PostMapping("/login")
|
@PostMapping("/login")
|
||||||
@ -46,7 +44,7 @@ public class UserApiController extends BaseController<User, UserDTO, Long, UserQ
|
|||||||
protected void exportData(HttpServletResponse response, List<UserDTO> data) {
|
protected void exportData(HttpServletResponse response, List<UserDTO> data) {
|
||||||
response.setContentType("application/vnd.ms-excel");
|
response.setContentType("application/vnd.ms-excel");
|
||||||
response.setHeader("Content-Disposition", "attachment;filename=users.xlsx");
|
response.setHeader("Content-Disposition", "attachment;filename=users.xlsx");
|
||||||
|
|
||||||
try (OutputStream out = response.getOutputStream()) {
|
try (OutputStream out = response.getOutputStream()) {
|
||||||
// ExcelUtils.export(data, out);
|
// ExcelUtils.export(data, out);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
|||||||
@ -3,7 +3,6 @@ package com.qqchen.deploy.backend.controller;
|
|||||||
import com.qqchen.deploy.backend.dto.query.TenantQuery;
|
import com.qqchen.deploy.backend.dto.query.TenantQuery;
|
||||||
import com.qqchen.deploy.backend.entity.Tenant;
|
import com.qqchen.deploy.backend.entity.Tenant;
|
||||||
import com.qqchen.deploy.backend.framework.controller.BaseController;
|
import com.qqchen.deploy.backend.framework.controller.BaseController;
|
||||||
import com.qqchen.deploy.backend.service.ITenantService;
|
|
||||||
import com.qqchen.deploy.backend.dto.TenantDTO;
|
import com.qqchen.deploy.backend.dto.TenantDTO;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
@ -14,13 +13,9 @@ import java.io.OutputStream;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/tenants")
|
@RequestMapping("/tenant")
|
||||||
public class TenantController extends BaseController<Tenant, TenantDTO, Long, TenantQuery> {
|
public class TenantController extends BaseController<Tenant, TenantDTO, Long, TenantQuery> {
|
||||||
|
|
||||||
public TenantController(ITenantService service) {
|
|
||||||
super(service);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void exportData(HttpServletResponse response, List<TenantDTO> data) {
|
protected void exportData(HttpServletResponse response, List<TenantDTO> data) {
|
||||||
response.setContentType("application/vnd.ms-excel");
|
response.setContentType("application/vnd.ms-excel");
|
||||||
|
|||||||
@ -1,32 +1,19 @@
|
|||||||
//package com.qqchen.deploy.backend.controller;
|
package com.qqchen.deploy.backend.controller;
|
||||||
//
|
|
||||||
//import com.qqchen.deploy.backend.api.UserApiController;
|
import com.qqchen.deploy.backend.api.UserApiController;
|
||||||
//import com.qqchen.deploy.backend.framework.api.Response;
|
import com.qqchen.deploy.backend.dto.UserDTO;
|
||||||
//import com.qqchen.deploy.backend.converter.UserConverter;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
//import com.qqchen.deploy.backend.service.IUserService;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
//import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
//import org.springframework.web.bind.annotation.RequestMapping;
|
|
||||||
//import org.springframework.web.bind.annotation.RequestParam;
|
import java.util.List;
|
||||||
//import org.springframework.web.bind.annotation.RestController;
|
|
||||||
//
|
@RestController
|
||||||
//@RestController
|
@RequestMapping("/mgmt/users")
|
||||||
//@RequestMapping("/mgmt/users")
|
public class UserController extends UserApiController {
|
||||||
//public class UserController extends UserApiController {
|
|
||||||
//
|
@Override
|
||||||
// protected final IUserService userService;
|
protected void exportData(HttpServletResponse response, List<UserDTO> data) {
|
||||||
//
|
|
||||||
// public UserController(IUserService userService, UserConverter converter) {
|
}
|
||||||
// super(userService, converter);
|
}
|
||||||
// this.userService = userService;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// @GetMapping("/check-username")
|
|
||||||
// public Response<Boolean> checkUsername(@RequestParam String username) {
|
|
||||||
// return Response.success(userService.checkUsernameExists(username));
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// @GetMapping("/check-email")
|
|
||||||
// public Response<Boolean> checkEmail(@RequestParam String email) {
|
|
||||||
// return Response.success(userService.checkEmailExists(email));
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
@ -7,8 +7,12 @@ import lombok.EqualsAndHashCode;
|
|||||||
@Data
|
@Data
|
||||||
@EqualsAndHashCode(callSuper = true)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
public class RoleDTO extends BaseDTO {
|
public class RoleDTO extends BaseDTO {
|
||||||
|
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
private String code;
|
private String code;
|
||||||
|
|
||||||
private String description;
|
private String description;
|
||||||
|
|
||||||
private Integer sort;
|
private Integer sort;
|
||||||
}
|
}
|
||||||
@ -8,12 +8,20 @@ import lombok.EqualsAndHashCode;
|
|||||||
@EqualsAndHashCode(callSuper = true)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
public class TenantDTO extends BaseDTO {
|
public class TenantDTO extends BaseDTO {
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
private String code;
|
private String code;
|
||||||
|
|
||||||
private String description;
|
private String description;
|
||||||
|
|
||||||
private Boolean enabled;
|
private Boolean enabled;
|
||||||
|
|
||||||
private String contactName;
|
private String contactName;
|
||||||
|
|
||||||
private String contactPhone;
|
private String contactPhone;
|
||||||
|
|
||||||
private String contactEmail;
|
private String contactEmail;
|
||||||
|
|
||||||
private String address;
|
private String address;
|
||||||
|
|
||||||
private String remark;
|
private String remark;
|
||||||
}
|
}
|
||||||
@ -3,15 +3,21 @@ package com.qqchen.deploy.backend.dto;
|
|||||||
import com.qqchen.deploy.backend.framework.dto.BaseDTO;
|
import com.qqchen.deploy.backend.framework.dto.BaseDTO;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@EqualsAndHashCode(callSuper = true)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
public class UserDTO extends BaseDTO {
|
public class UserDTO extends BaseDTO {
|
||||||
private String username;
|
private String username;
|
||||||
|
|
||||||
private String nickname;
|
private String nickname;
|
||||||
|
|
||||||
private String email;
|
private String email;
|
||||||
|
|
||||||
private String phone;
|
private String phone;
|
||||||
|
|
||||||
private Boolean enabled;
|
private Boolean enabled;
|
||||||
|
|
||||||
private Set<RoleDTO> roles;
|
private Set<RoleDTO> roles;
|
||||||
}
|
}
|
||||||
@ -0,0 +1,27 @@
|
|||||||
|
package com.qqchen.deploy.backend.framework.annotation;
|
||||||
|
|
||||||
|
import java.lang.annotation.*;
|
||||||
|
|
||||||
|
@Target(ElementType.TYPE)
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Documented
|
||||||
|
public @interface ServiceType {
|
||||||
|
Type value() default Type.DATABASE;
|
||||||
|
|
||||||
|
enum Type {
|
||||||
|
/**
|
||||||
|
* 数据库服务,需要注入Repository和Converter
|
||||||
|
*/
|
||||||
|
DATABASE,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 集成服务,不需要数据库操作
|
||||||
|
*/
|
||||||
|
INTEGRATION,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 混合服务,可以选择性注入
|
||||||
|
*/
|
||||||
|
HYBRID
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,165 @@
|
|||||||
|
package com.qqchen.deploy.backend.framework.config;
|
||||||
|
|
||||||
|
import com.qqchen.deploy.backend.framework.controller.BaseController;
|
||||||
|
import com.qqchen.deploy.backend.framework.domain.Entity;
|
||||||
|
import com.qqchen.deploy.backend.framework.dto.BaseDTO;
|
||||||
|
import com.qqchen.deploy.backend.framework.service.IBaseService;
|
||||||
|
import com.qqchen.deploy.backend.framework.utils.PackageScanner;
|
||||||
|
import com.qqchen.deploy.backend.framework.utils.ReflectionUtils;
|
||||||
|
import com.qqchen.deploy.backend.framework.utils.SpringUtils;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.BeansException;
|
||||||
|
import org.springframework.beans.factory.BeanCreationException;
|
||||||
|
import org.springframework.beans.factory.DisposableBean;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
|
import org.springframework.core.GenericTypeResolver;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
@Slf4j
|
||||||
|
public class ControllerBeanPostProcessor implements BeanPostProcessor, DisposableBean {
|
||||||
|
|
||||||
|
private final ApplicationContext applicationContext;
|
||||||
|
private final Map<Class<?>, IBaseService<?, ?, ?>> serviceCache = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
public ControllerBeanPostProcessor(ApplicationContext applicationContext) {
|
||||||
|
this.applicationContext = applicationContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
||||||
|
if (!(bean instanceof BaseController<?, ?, ?, ?> controller)) {
|
||||||
|
return bean;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return injectService(controller, beanName);
|
||||||
|
} catch (ServiceInjectionException e) {
|
||||||
|
log.error("Service injection failed for controller: {}", beanName, e);
|
||||||
|
throw e;
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Unexpected error during service injection for controller: {}", beanName, e);
|
||||||
|
throw new BeanCreationException("Failed to inject service for controller: " + beanName, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private <T extends Entity<ID>, D extends BaseDTO, ID extends Serializable>
|
||||||
|
Object injectService(BaseController<T, D, ID, ?> controller, String beanName) {
|
||||||
|
Class<T> entityClass = resolveEntityClass(controller);
|
||||||
|
if (entityClass == null) {
|
||||||
|
return controller;
|
||||||
|
}
|
||||||
|
|
||||||
|
IBaseService<?, ?, ?> cachedService = serviceCache.computeIfAbsent(
|
||||||
|
entityClass,
|
||||||
|
key -> findServiceForEntity(entityClass, beanName)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (cachedService == null) {
|
||||||
|
throw new ServiceInjectionException("No service found for entity: " + entityClass.getSimpleName());
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
IBaseService<T, D, ID> service = (IBaseService<T, D, ID>) cachedService;
|
||||||
|
ReflectionUtils.setField("service", controller, service);
|
||||||
|
log.debug("Successfully injected service {} for controller {}",
|
||||||
|
service.getClass().getSimpleName(),
|
||||||
|
controller.getClass().getSimpleName());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ServiceInjectionException("Failed to inject service field", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return controller;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private <T extends Entity<ID>, D extends BaseDTO, ID extends Serializable>
|
||||||
|
Class<T> resolveEntityClass(BaseController<T, D, ID, ?> controller) {
|
||||||
|
Class<?>[] genericTypes = GenericTypeResolver.resolveTypeArguments(
|
||||||
|
controller.getClass(), BaseController.class);
|
||||||
|
|
||||||
|
if (genericTypes == null || genericTypes.length < 3) {
|
||||||
|
log.warn("Could not resolve entity type for controller: {}",
|
||||||
|
controller.getClass().getSimpleName());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (Class<T>) genericTypes[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private <T extends Entity<ID>, ID extends Serializable>
|
||||||
|
IBaseService<?, ?, ?> findServiceForEntity(Class<T> entityClass, String controllerName) {
|
||||||
|
// 先尝试通过命名约定查找
|
||||||
|
String serviceBeanName = "i" + entityClass.getSimpleName() + "Service";
|
||||||
|
log.debug("Looking for service bean: {}", serviceBeanName);
|
||||||
|
|
||||||
|
if (applicationContext.containsBean(serviceBeanName)) {
|
||||||
|
return (IBaseService<?, ?, ?>) applicationContext.getBean(serviceBeanName);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果找不到,再通过类型匹配查找
|
||||||
|
log.debug("Service not found by name, trying to find by type matching");
|
||||||
|
return Arrays.stream(applicationContext.getBeanNamesForType(IBaseService.class))
|
||||||
|
.map(name -> tryGetService(name, entityClass, controllerName))
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.findFirst()
|
||||||
|
.orElseThrow(() -> new ServiceInjectionException(
|
||||||
|
"No service found for entity: " + entityClass.getSimpleName() +
|
||||||
|
" (tried bean name: " + serviceBeanName + " and type matching)"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private <T extends Entity<ID>, ID extends Serializable>
|
||||||
|
IBaseService<?, ?, ?> tryGetService(String beanName, Class<T> entityClass, String controllerName) {
|
||||||
|
try {
|
||||||
|
Class<?> serviceClass = applicationContext.getType(beanName);
|
||||||
|
if (serviceClass == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Class<?>[] serviceGenericTypes = GenericTypeResolver.resolveTypeArguments(
|
||||||
|
serviceClass, IBaseService.class);
|
||||||
|
|
||||||
|
if (serviceGenericTypes != null &&
|
||||||
|
serviceGenericTypes.length > 0 &&
|
||||||
|
entityClass.equals(serviceGenericTypes[0])) {
|
||||||
|
log.debug("Found matching service: {} for entity: {}", beanName, entityClass.getSimpleName());
|
||||||
|
return (IBaseService<?, ?, ?>) applicationContext.getBean(beanName);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("Failed to analyze service bean: {} for controller: {}", beanName, controllerName, e);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void destroy() {
|
||||||
|
serviceCache.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ServiceInjectionException extends BeanCreationException {
|
||||||
|
public ServiceInjectionException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ServiceInjectionException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,114 @@
|
|||||||
|
package com.qqchen.deploy.backend.framework.config;
|
||||||
|
|
||||||
|
import com.qqchen.deploy.backend.framework.domain.Entity;
|
||||||
|
import com.qqchen.deploy.backend.framework.dto.BaseDTO;
|
||||||
|
import com.qqchen.deploy.backend.framework.service.impl.BaseServiceImpl;
|
||||||
|
import com.qqchen.deploy.backend.framework.repository.IBaseRepository;
|
||||||
|
import com.qqchen.deploy.backend.framework.converter.BaseConverter;
|
||||||
|
import com.qqchen.deploy.backend.framework.utils.ReflectionUtils;
|
||||||
|
import com.querydsl.core.types.EntityPath;
|
||||||
|
import org.springframework.beans.BeansException;
|
||||||
|
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
|
import org.springframework.core.GenericTypeResolver;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.beans.factory.BeanCreationException;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
@Slf4j
|
||||||
|
public class ServiceBeanPostProcessor implements BeanPostProcessor {
|
||||||
|
|
||||||
|
private final ApplicationContext applicationContext;
|
||||||
|
|
||||||
|
public ServiceBeanPostProcessor(ApplicationContext applicationContext) {
|
||||||
|
this.applicationContext = applicationContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
||||||
|
if (!(bean instanceof BaseServiceImpl<?, ?, ?> service)) {
|
||||||
|
return bean;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return injectDependencies(service, beanName);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Failed to inject dependencies for service: {}", beanName, e);
|
||||||
|
throw new BeanCreationException("Failed to inject dependencies for service: " + beanName, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private <T extends Entity<ID>, D extends BaseDTO, ID extends Serializable>
|
||||||
|
Object injectDependencies(BaseServiceImpl<T, D, ID> service, String beanName) {
|
||||||
|
Class<T> entityClass = resolveEntityClass(service);
|
||||||
|
log.debug("Resolving dependencies for entity: {}", entityClass.getSimpleName());
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 注入 Repository
|
||||||
|
String repositoryBeanName = "I" + entityClass.getSimpleName() + "Repository";
|
||||||
|
log.debug("Looking for repository bean: {}", repositoryBeanName);
|
||||||
|
if (!applicationContext.containsBean(repositoryBeanName)) {
|
||||||
|
throw new ControllerBeanPostProcessor.ServiceInjectionException("Repository not found: " + repositoryBeanName);
|
||||||
|
}
|
||||||
|
IBaseRepository<T, ID> repository = (IBaseRepository<T, ID>) applicationContext.getBean(repositoryBeanName);
|
||||||
|
ReflectionUtils.setField("repository", service, repository);
|
||||||
|
|
||||||
|
// 注入 Converter
|
||||||
|
String converterBeanName = entityClass.getSimpleName().substring(0, 1).toLowerCase()
|
||||||
|
+ entityClass.getSimpleName().substring(1) + "ConverterImpl";
|
||||||
|
log.debug("Looking for converter bean: {}", converterBeanName);
|
||||||
|
if (!applicationContext.containsBean(converterBeanName)) {
|
||||||
|
throw new ControllerBeanPostProcessor.ServiceInjectionException("Converter not found: " + converterBeanName);
|
||||||
|
}
|
||||||
|
BaseConverter<T, D> converter = (BaseConverter<T, D>) applicationContext.getBean(converterBeanName);
|
||||||
|
ReflectionUtils.setField("converter", service, converter);
|
||||||
|
|
||||||
|
// 初始化 EntityPath
|
||||||
|
try {
|
||||||
|
EntityPath<T> entityPath = initEntityPath(entityClass);
|
||||||
|
ReflectionUtils.setField("entityPath", service, entityPath);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Failed to initialize EntityPath for {}", entityClass.getSimpleName(), e);
|
||||||
|
throw new ControllerBeanPostProcessor.ServiceInjectionException("Failed to initialize EntityPath: " + e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
log.debug("Successfully injected all dependencies for service: {}", beanName);
|
||||||
|
return service;
|
||||||
|
} catch (ControllerBeanPostProcessor.ServiceInjectionException e) {
|
||||||
|
throw e;
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Unexpected error while injecting dependencies for {}", entityClass.getSimpleName(), e);
|
||||||
|
throw new ControllerBeanPostProcessor.ServiceInjectionException("Failed to inject dependencies: " + e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private <T extends Entity<ID>, ID extends Serializable> Class<T> resolveEntityClass(BaseServiceImpl<T, ?, ID> service) {
|
||||||
|
Class<?>[] genericTypes = GenericTypeResolver.resolveTypeArguments(
|
||||||
|
service.getClass(), BaseServiceImpl.class);
|
||||||
|
|
||||||
|
if (genericTypes == null || genericTypes.length < 3) {
|
||||||
|
throw new IllegalStateException("Could not resolve entity type for service: "
|
||||||
|
+ service.getClass().getSimpleName());
|
||||||
|
}
|
||||||
|
|
||||||
|
return (Class<T>) genericTypes[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private <T extends Entity<ID>, ID extends Serializable> EntityPath<T> initEntityPath(Class<T> entityClass) {
|
||||||
|
try {
|
||||||
|
String qClassName = entityClass.getPackageName() + ".Q" + entityClass.getSimpleName();
|
||||||
|
Class<?> qClass = Class.forName(qClassName);
|
||||||
|
Field instanceField = qClass.getDeclaredField(entityClass.getSimpleName().toLowerCase());
|
||||||
|
return (EntityPath<T>) instanceField.get(null);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new IllegalStateException("Failed to get Q class for " + entityClass.getName(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -6,7 +6,6 @@ import com.qqchen.deploy.backend.framework.query.BaseQuery;
|
|||||||
import com.qqchen.deploy.backend.framework.api.Response;
|
import com.qqchen.deploy.backend.framework.api.Response;
|
||||||
import com.qqchen.deploy.backend.framework.service.IBaseService;
|
import com.qqchen.deploy.backend.framework.service.IBaseService;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
import org.springframework.core.GenericTypeResolver;
|
|
||||||
import org.springframework.data.domain.Page;
|
import org.springframework.data.domain.Page;
|
||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
@ -21,11 +20,7 @@ import java.util.concurrent.CompletableFuture;
|
|||||||
@Validated
|
@Validated
|
||||||
public abstract class BaseController<T extends Entity<ID>, D extends BaseDTO, ID extends Serializable, Q extends BaseQuery> {
|
public abstract class BaseController<T extends Entity<ID>, D extends BaseDTO, ID extends Serializable, Q extends BaseQuery> {
|
||||||
|
|
||||||
protected final IBaseService<T, D, ID> service;
|
protected IBaseService<T, D, ID> service;
|
||||||
|
|
||||||
protected BaseController(IBaseService<T, D, ID> service) {
|
|
||||||
this.service = service;
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping
|
@PostMapping
|
||||||
public Response<D> create(@Validated @RequestBody D dto) {
|
public Response<D> create(@Validated @RequestBody D dto) {
|
||||||
@ -78,8 +73,9 @@ public abstract class BaseController<T extends Entity<ID>, D extends BaseDTO, ID
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 导出数据的具体实现
|
* 导出数据的具体实现
|
||||||
|
*
|
||||||
* @param response HTTP响应
|
* @param response HTTP响应
|
||||||
* @param data 要导出的数据
|
* @param data 要导出的数据
|
||||||
*/
|
*/
|
||||||
protected abstract void exportData(HttpServletResponse response, List<D> data);
|
protected abstract void exportData(HttpServletResponse response, List<D> data);
|
||||||
|
|
||||||
|
|||||||
@ -1,20 +1,28 @@
|
|||||||
package com.qqchen.deploy.backend.framework.dto;
|
package com.qqchen.deploy.backend.framework.dto;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public class BaseDTO implements Serializable {
|
public class BaseDTO implements Serializable {
|
||||||
|
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
private LocalDateTime createTime;
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
private String createBy;
|
private String createBy;
|
||||||
|
|
||||||
private LocalDateTime updateTime;
|
private LocalDateTime updateTime;
|
||||||
|
|
||||||
private String updateBy;
|
private String updateBy;
|
||||||
|
|
||||||
private Integer version;
|
private Integer version;
|
||||||
|
|
||||||
private Boolean deleted;
|
private Boolean deleted;
|
||||||
|
|
||||||
// 扩展字段,用于存储额外的属性
|
// 扩展字段,用于存储额外的属性
|
||||||
private Map<String, Object> extraData;
|
private Map<String, Object> extraData;
|
||||||
}
|
}
|
||||||
@ -43,45 +43,29 @@ import jakarta.persistence.PersistenceContext;
|
|||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
|
|
||||||
|
import org.springframework.beans.BeansException;
|
||||||
|
import org.springframework.beans.factory.BeanFactory;
|
||||||
|
import org.springframework.beans.factory.BeanFactoryAware;
|
||||||
|
|
||||||
|
import com.qqchen.deploy.backend.framework.annotation.ServiceType;
|
||||||
|
|
||||||
|
|
||||||
@Transactional(readOnly = true)
|
@Transactional(readOnly = true)
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public abstract class BaseServiceImpl<T extends Entity<ID>, D extends BaseDTO, ID extends Serializable>
|
public abstract class BaseServiceImpl<T extends Entity<ID>, D extends BaseDTO, ID extends Serializable>
|
||||||
implements IBaseService<T, D, ID> {
|
implements IBaseService<T, D, ID> {
|
||||||
|
|
||||||
protected final IBaseRepository<T, ID> repository;
|
protected IBaseRepository<T, ID> repository;
|
||||||
protected final BaseConverter<T, D> converter;
|
protected BaseConverter<T, D> converter;
|
||||||
protected final EntityPath<T> entityPath;
|
protected EntityPath<T> entityPath;
|
||||||
|
|
||||||
@PersistenceContext
|
@PersistenceContext
|
||||||
protected EntityManager entityManager;
|
protected EntityManager entityManager;
|
||||||
|
|
||||||
protected BaseServiceImpl(IBaseRepository<T, ID> repository, BaseConverter<T, D> converter) {
|
|
||||||
this.repository = repository;
|
|
||||||
this.converter = converter;
|
|
||||||
this.entityPath = getEntityPath();
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
private EntityPath<T> getEntityPath() {
|
|
||||||
Class<?>[] genericTypes = GenericTypeResolver.resolveTypeArguments(getClass(), BaseServiceImpl.class);
|
|
||||||
if (genericTypes == null || genericTypes.length < 2) {
|
|
||||||
throw new IllegalStateException("Could not resolve generic type arguments");
|
|
||||||
}
|
|
||||||
|
|
||||||
Class<T> entityClass = (Class<T>) genericTypes[0];
|
|
||||||
try {
|
|
||||||
String qClassName = entityClass.getPackageName() + ".Q" + entityClass.getSimpleName();
|
|
||||||
Class<?> qClass = Class.forName(qClassName);
|
|
||||||
Field instanceField = qClass.getDeclaredField(entityClass.getSimpleName().toLowerCase());
|
|
||||||
return (EntityPath<T>) instanceField.get(null);
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new RuntimeException("Failed to get Q class for " + entityClass.getName(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional
|
@Transactional
|
||||||
public D create(D dto) {
|
public D create(D dto) {
|
||||||
|
validateDatabaseOperation("create");
|
||||||
T entity = converter.toEntity(dto);
|
T entity = converter.toEntity(dto);
|
||||||
T savedEntity = repository.save(entity);
|
T savedEntity = repository.save(entity);
|
||||||
return converter.toDto(savedEntity);
|
return converter.toDto(savedEntity);
|
||||||
@ -90,6 +74,7 @@ public abstract class BaseServiceImpl<T extends Entity<ID>, D extends BaseDTO, I
|
|||||||
@Override
|
@Override
|
||||||
@Transactional
|
@Transactional
|
||||||
public D update(ID id, D dto) {
|
public D update(ID id, D dto) {
|
||||||
|
validateDatabaseOperation("update");
|
||||||
T entity = findEntityById(id);
|
T entity = findEntityById(id);
|
||||||
converter.updateEntity(entity, dto);
|
converter.updateEntity(entity, dto);
|
||||||
T updatedEntity = repository.save(entity);
|
T updatedEntity = repository.save(entity);
|
||||||
@ -99,25 +84,29 @@ public abstract class BaseServiceImpl<T extends Entity<ID>, D extends BaseDTO, I
|
|||||||
@Override
|
@Override
|
||||||
@Transactional
|
@Transactional
|
||||||
public void delete(ID id) {
|
public void delete(ID id) {
|
||||||
|
validateDatabaseOperation("delete");
|
||||||
repository.deleteById(id);
|
repository.deleteById(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public D findById(ID id) {
|
public D findById(ID id) {
|
||||||
|
validateDatabaseOperation("findById");
|
||||||
T entity = findEntityById(id);
|
T entity = findEntityById(id);
|
||||||
return converter.toDto(entity);
|
return converter.toDto(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<D> findAll() {
|
public List<D> findAll() {
|
||||||
|
validateDatabaseOperation("findAll");
|
||||||
List<T> entities = repository.findAll();
|
List<T> entities = repository.findAll();
|
||||||
return converter.toDtoList(entities);
|
return converter.toDtoList(entities);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<D> findAll(BaseQuery query) {
|
public List<D> findAll(BaseQuery query) {
|
||||||
|
validateDatabaseOperation("findAll");
|
||||||
if (query == null) {
|
if (query == null) {
|
||||||
return findAll(); // 如果查询参数为空,返回所有数据
|
return findAll();
|
||||||
}
|
}
|
||||||
BooleanBuilder builder = createQueryPredicate(query);
|
BooleanBuilder builder = createQueryPredicate(query);
|
||||||
Sort sort = createSort(query);
|
Sort sort = createSort(query);
|
||||||
@ -127,6 +116,7 @@ public abstract class BaseServiceImpl<T extends Entity<ID>, D extends BaseDTO, I
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Page<D> page(BaseQuery query) {
|
public Page<D> page(BaseQuery query) {
|
||||||
|
validateDatabaseOperation("page");
|
||||||
Page<T> page = repository.findAll(createQueryPredicate(query), createPageRequest(query));
|
Page<T> page = repository.findAll(createQueryPredicate(query), createPageRequest(query));
|
||||||
return converter.toDtoPage(page);
|
return converter.toDtoPage(page);
|
||||||
}
|
}
|
||||||
@ -344,7 +334,7 @@ public abstract class BaseServiceImpl<T extends Entity<ID>, D extends BaseDTO, I
|
|||||||
public void batchProcess(List<D> dtos) {
|
public void batchProcess(List<D> dtos) {
|
||||||
LocalDateTime now = LocalDateTime.now();
|
LocalDateTime now = LocalDateTime.now();
|
||||||
String operator = SecurityUtils.getCurrentUsername();
|
String operator = SecurityUtils.getCurrentUsername();
|
||||||
|
|
||||||
List<T> entities = converter.toEntityList(dtos);
|
List<T> entities = converter.toEntityList(dtos);
|
||||||
Lists.partition(entities, 500).forEach(batch -> {
|
Lists.partition(entities, 500).forEach(batch -> {
|
||||||
try {
|
try {
|
||||||
@ -353,17 +343,17 @@ public abstract class BaseServiceImpl<T extends Entity<ID>, D extends BaseDTO, I
|
|||||||
.map(e -> repository.findById(e.getId())
|
.map(e -> repository.findById(e.getId())
|
||||||
.orElseThrow(() -> new EntityNotFoundException(getEntityClass().getSimpleName(), e.getId())))
|
.orElseThrow(() -> new EntityNotFoundException(getEntityClass().getSimpleName(), e.getId())))
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
// 版本检查
|
// 版本检查
|
||||||
for (int i = 0; i < batch.size(); i++) {
|
for (int i = 0; i < batch.size(); i++) {
|
||||||
currentEntities.get(i).checkVersion(batch.get(i).getVersion());
|
currentEntities.get(i).checkVersion(batch.get(i).getVersion());
|
||||||
}
|
}
|
||||||
|
|
||||||
// 批量更新
|
// 批量更新
|
||||||
List<ID> ids = currentEntities.stream()
|
List<ID> ids = currentEntities.stream()
|
||||||
.map(Entity::getId)
|
.map(Entity::getId)
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
repository.batchUpdate(ids, now, operator);
|
repository.batchUpdate(ids, now, operator);
|
||||||
repository.flush();
|
repository.flush();
|
||||||
entityManager.clear();
|
entityManager.clear();
|
||||||
@ -384,19 +374,20 @@ public abstract class BaseServiceImpl<T extends Entity<ID>, D extends BaseDTO, I
|
|||||||
try {
|
try {
|
||||||
return update(id, dto);
|
return update(id, dto);
|
||||||
} catch (OptimisticLockException e) {
|
} catch (OptimisticLockException e) {
|
||||||
// 重试前先刷新实体
|
|
||||||
entityManager.refresh(findEntityById(id));
|
entityManager.refresh(findEntityById(id));
|
||||||
throw e; // 抛出异常触发重试
|
throw e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 添加悲观锁查询方法
|
@Override
|
||||||
@Transactional
|
@Transactional
|
||||||
public T findByIdWithLock(ID id) {
|
public T findByIdWithLock(ID id) {
|
||||||
|
validateDatabaseOperation("findByIdWithLock");
|
||||||
return repository.findByIdWithLock(id)
|
return repository.findByIdWithLock(id)
|
||||||
.orElseThrow(() -> new EntityNotFoundException(getEntityClass().getSimpleName(), id));
|
.orElseThrow(() -> new EntityNotFoundException(getEntityClass().getSimpleName(), id));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public Class<T> getEntityClass() {
|
public Class<T> getEntityClass() {
|
||||||
Class<?>[] genericTypes = GenericTypeResolver.resolveTypeArguments(getClass(), BaseServiceImpl.class);
|
Class<?>[] genericTypes = GenericTypeResolver.resolveTypeArguments(getClass(), BaseServiceImpl.class);
|
||||||
@ -406,10 +397,18 @@ public abstract class BaseServiceImpl<T extends Entity<ID>, D extends BaseDTO, I
|
|||||||
throw new IllegalStateException("Could not resolve entity class");
|
throw new IllegalStateException("Could not resolve entity class");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 内部实体操作方法
|
|
||||||
@Override
|
@Override
|
||||||
public T findEntityById(ID id) {
|
public T findEntityById(ID id) {
|
||||||
|
validateDatabaseOperation("findEntityById");
|
||||||
return repository.findById(id)
|
return repository.findById(id)
|
||||||
.orElseThrow(() -> new EntityNotFoundException(getEntityClass().getSimpleName(), id));
|
.orElseThrow(() -> new EntityNotFoundException(getEntityClass().getSimpleName(), id));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void validateDatabaseOperation(String operation) {
|
||||||
|
ServiceType serviceType = getClass().getAnnotation(ServiceType.class);
|
||||||
|
if (serviceType != null && serviceType.value() == ServiceType.Type.INTEGRATION) {
|
||||||
|
throw new UnsupportedOperationException(
|
||||||
|
"Database operation '" + operation + "' is not supported in integration service");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -0,0 +1,37 @@
|
|||||||
|
package com.qqchen.deploy.backend.framework.utils;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.config.BeanDefinition;
|
||||||
|
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
|
||||||
|
import org.springframework.core.type.filter.AnnotationTypeFilter;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
public class PackageScanner {
|
||||||
|
|
||||||
|
public static Set<String> scanControllerPackages(String basePackage) {
|
||||||
|
Set<String> packages = new HashSet<>();
|
||||||
|
|
||||||
|
ClassPathScanningCandidateComponentProvider scanner =
|
||||||
|
new ClassPathScanningCandidateComponentProvider(false);
|
||||||
|
scanner.addIncludeFilter(new AnnotationTypeFilter(RestController.class));
|
||||||
|
|
||||||
|
Set<BeanDefinition> components = scanner.findCandidateComponents(basePackage);
|
||||||
|
for (BeanDefinition component : components) {
|
||||||
|
String className = component.getBeanClassName();
|
||||||
|
if (className != null) {
|
||||||
|
try {
|
||||||
|
Class<?> clazz = Class.forName(className);
|
||||||
|
packages.add(clazz.getPackage().getName());
|
||||||
|
} catch (ClassNotFoundException e) {
|
||||||
|
log.warn("Failed to load class: {}", className, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return packages;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,86 @@
|
|||||||
|
package com.qqchen.deploy.backend.framework.utils;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
public class ReflectionUtils {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置字段值
|
||||||
|
*
|
||||||
|
* @param fieldName 字段名
|
||||||
|
* @param target 目标对象
|
||||||
|
* @param value 值
|
||||||
|
*/
|
||||||
|
public static void setField(String fieldName, Object target, Object value) {
|
||||||
|
Assert.notNull(fieldName, "Field name must not be null");
|
||||||
|
Assert.notNull(target, "Target object must not be null");
|
||||||
|
|
||||||
|
try {
|
||||||
|
Field field = findField(target.getClass(), fieldName);
|
||||||
|
if (field == null) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"Could not find field [" + fieldName + "] on target [" + target.getClass().getName() + "]");
|
||||||
|
}
|
||||||
|
|
||||||
|
makeAccessible(field);
|
||||||
|
field.set(target, value);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Failed to set field [{}] on target [{}]", fieldName, target.getClass().getName(), e);
|
||||||
|
throw new IllegalStateException("Failed to set field: " + fieldName, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取字段值
|
||||||
|
*
|
||||||
|
* @param fieldName 字段名
|
||||||
|
* @param target 目标对象
|
||||||
|
* @return 字段值
|
||||||
|
*/
|
||||||
|
public static Object getField(String fieldName, Object target) {
|
||||||
|
Assert.notNull(fieldName, "Field name must not be null");
|
||||||
|
Assert.notNull(target, "Target object must not be null");
|
||||||
|
|
||||||
|
try {
|
||||||
|
Field field = findField(target.getClass(), fieldName);
|
||||||
|
if (field == null) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"Could not find field [" + fieldName + "] on target [" + target.getClass().getName() + "]");
|
||||||
|
}
|
||||||
|
|
||||||
|
makeAccessible(field);
|
||||||
|
return field.get(target);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Failed to get field [{}] on target [{}]", fieldName, target.getClass().getName(), e);
|
||||||
|
throw new IllegalStateException("Failed to get field: " + fieldName, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查找字段(包括父类)
|
||||||
|
*/
|
||||||
|
private static Field findField(Class<?> clazz, String fieldName) {
|
||||||
|
Class<?> searchType = clazz;
|
||||||
|
while (searchType != null && !Object.class.equals(searchType)) {
|
||||||
|
try {
|
||||||
|
return searchType.getDeclaredField(fieldName);
|
||||||
|
} catch (NoSuchFieldException e) {
|
||||||
|
searchType = searchType.getSuperclass();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使字段可访问
|
||||||
|
*/
|
||||||
|
private static void makeAccessible(Field field) {
|
||||||
|
if (!field.isAccessible()) {
|
||||||
|
field.setAccessible(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,47 @@
|
|||||||
|
package com.qqchen.deploy.backend.framework.utils;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.BeansException;
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
|
import org.springframework.context.ApplicationContextAware;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class SpringUtils implements ApplicationContextAware {
|
||||||
|
private static ApplicationContext applicationContext;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||||
|
SpringUtils.applicationContext = applicationContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public static <T> T getBean(String name) {
|
||||||
|
if (applicationContext == null) {
|
||||||
|
throw new IllegalStateException("ApplicationContext has not been initialized");
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return (T) applicationContext.getBean(name);
|
||||||
|
} catch (BeansException e) {
|
||||||
|
log.error("Failed to get bean by name: {}", name, e);
|
||||||
|
throw new IllegalStateException("Could not find bean: " + name, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> T getBean(Class<T> clazz) {
|
||||||
|
if (applicationContext == null) {
|
||||||
|
throw new IllegalStateException("ApplicationContext has not been initialized");
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return applicationContext.getBean(clazz);
|
||||||
|
} catch (BeansException e) {
|
||||||
|
log.error("Failed to get bean by class: {}", clazz.getName(), e);
|
||||||
|
throw new IllegalStateException("Could not find bean of type: " + clazz.getName(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ApplicationContext getApplicationContext() {
|
||||||
|
return applicationContext;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -14,9 +14,9 @@ import java.util.List;
|
|||||||
@Service
|
@Service
|
||||||
public class TenantServiceImpl extends BaseServiceImpl<Tenant, TenantDTO, Long> implements ITenantService {
|
public class TenantServiceImpl extends BaseServiceImpl<Tenant, TenantDTO, Long> implements ITenantService {
|
||||||
|
|
||||||
public TenantServiceImpl(ITenantRepository repository, TenantConverter converter) {
|
// public TenantServiceImpl(ITenantRepository repository, TenantConverter converter) {
|
||||||
super(repository, converter);
|
// super(repository, converter);
|
||||||
}
|
// }
|
||||||
|
|
||||||
// @Override
|
// @Override
|
||||||
// public List<TenantDTO> findAll(BaseQuery query) {
|
// public List<TenantDTO> findAll(BaseQuery query) {
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
package com.qqchen.deploy.backend.service.impl;
|
package com.qqchen.deploy.backend.service.impl;
|
||||||
|
|
||||||
|
import com.qqchen.deploy.backend.framework.annotation.ServiceType;
|
||||||
import com.qqchen.deploy.backend.framework.audit.annotation.Audited;
|
import com.qqchen.deploy.backend.framework.audit.annotation.Audited;
|
||||||
import com.qqchen.deploy.backend.framework.enums.ResponseCode;
|
import com.qqchen.deploy.backend.framework.enums.ResponseCode;
|
||||||
import com.qqchen.deploy.backend.framework.exception.BusinessException;
|
import com.qqchen.deploy.backend.framework.exception.BusinessException;
|
||||||
@ -28,28 +29,22 @@ import org.springframework.transaction.annotation.Transactional;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import static com.qqchen.deploy.backend.framework.annotation.ServiceType.Type.DATABASE;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
|
@ServiceType(DATABASE)
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class UserServiceImpl extends BaseServiceImpl<User, UserDTO, Long> implements IUserService {
|
public class UserServiceImpl extends BaseServiceImpl<User, UserDTO, Long> implements IUserService {
|
||||||
|
|
||||||
private final UserConverter converter;
|
@Resource
|
||||||
private final RoleConverter roleConverter;
|
private RoleConverter roleConverter;
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private AuthenticationManager authenticationManager;
|
private AuthenticationManager authenticationManager;
|
||||||
|
|
||||||
@Resource
|
|
||||||
private IUserRepository userRepository;
|
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private JwtTokenUtil jwtTokenUtil;
|
private JwtTokenUtil jwtTokenUtil;
|
||||||
|
|
||||||
public UserServiceImpl(IUserRepository repository, UserConverter converter, RoleConverter roleConverter) {
|
|
||||||
super(repository, converter);
|
|
||||||
this.converter = converter;
|
|
||||||
this.roleConverter = roleConverter;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional(readOnly = false)
|
@Transactional(readOnly = false)
|
||||||
@Audited(action = "REGISTER", detail = "用户注册")
|
@Audited(action = "REGISTER", detail = "用户注册")
|
||||||
@ -83,26 +78,27 @@ public class UserServiceImpl extends BaseServiceImpl<User, UserDTO, Long> implem
|
|||||||
@Transactional(readOnly = true)
|
@Transactional(readOnly = true)
|
||||||
@Audited(action = "USER_LOGIN", detail = "登录")
|
@Audited(action = "USER_LOGIN", detail = "登录")
|
||||||
public LoginResponse login(LoginRequest request) {
|
public LoginResponse login(LoginRequest request) {
|
||||||
Authentication authentication = authenticationManager.authenticate(
|
// Authentication authentication = authenticationManager.authenticate(
|
||||||
new UsernamePasswordAuthenticationToken(request.getUsername(), request.getPassword())
|
// new UsernamePasswordAuthenticationToken(request.getUsername(), request.getPassword())
|
||||||
);
|
// );
|
||||||
|
//
|
||||||
UserDetails userDetails = (UserDetails) authentication.getPrincipal();
|
// UserDetails userDetails = (UserDetails) authentication.getPrincipal();
|
||||||
String token = jwtTokenUtil.generateToken(userDetails);
|
// String token = jwtTokenUtil.generateToken(userDetails);
|
||||||
|
//
|
||||||
User user = userRepository.findByUsernameAndDeletedFalse(userDetails.getUsername())
|
// User user = userRepository.findByUsernameAndDeletedFalse(userDetails.getUsername())
|
||||||
.orElseThrow(() -> new BusinessException(ResponseCode.USER_NOT_FOUND));
|
// .orElseThrow(() -> new BusinessException(ResponseCode.USER_NOT_FOUND));
|
||||||
|
//
|
||||||
LoginResponse response = new LoginResponse();
|
// LoginResponse response = new LoginResponse();
|
||||||
response.setId(user.getId());
|
// response.setId(user.getId());
|
||||||
response.setUsername(user.getUsername());
|
// response.setUsername(user.getUsername());
|
||||||
response.setNickname(user.getNickname());
|
// response.setNickname(user.getNickname());
|
||||||
response.setEmail(user.getEmail());
|
// response.setEmail(user.getEmail());
|
||||||
response.setPhone(user.getPhone());
|
// response.setPhone(user.getPhone());
|
||||||
response.setToken(token);
|
// response.setToken(token);
|
||||||
|
//
|
||||||
log.info("用户 {} ({}) 登录成功", user.getUsername(), user.getNickname());
|
// log.info("用户 {} ({}) 登录成功", user.getUsername(), user.getNickname());
|
||||||
return response;
|
// return response;
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
server:
|
server:
|
||||||
port: 8080
|
port: 8080
|
||||||
|
|
||||||
spring:
|
spring:
|
||||||
datasource:
|
datasource:
|
||||||
url: jdbc:mysql://127.0.0.1:3306/deploy-ease-platform?useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true
|
url: jdbc:mysql://127.0.0.1:3306/deploy-ease-platform?useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user