import com.google.common.collect.Lists;
import org.springframework.beans.BeansException;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.springframework.stereotype.Component;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
@Component
public class FiledCheckHandlerFactory implements CommandLineRunner, ApplicationContextAware {
private ApplicationContext applicationContext;
private static AbstractFiledCheckHandler handlers;
/**
* 拼接变种责任链
* @param args
*/
@Override
public void run(String... args) {
Collection<AbstractFiledCheckHandler> checkHandlers = this.applicationContext.getBeansOfType(AbstractFiledCheckHandler.class).values();
List<AbstractFiledCheckHandler> list = Lists.newArrayList(checkHandlers);
Collections.sort(list, AnnotationAwareOrderComparator.INSTANCE);
for (int i = 0; i < list.size() - 1; i++) {
list.get(i).setNextHandler(list.get(i + 1));
}
setHandlers(list.get(0));
}
public static void setHandlers(AbstractFiledCheckHandler handlers) {
FiledCheckHandlerFactory.handlers = handlers;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
/**
* 执行方法校验
* @param filedCheckDto
*/
public static void processHandler(FiledCheckDto filedCheckDto) {
handlers.handler(filedCheckDto);
}
}
import lombok.Builder;
import lombok.Data;
import java.util.List;
import java.util.Map;
@Data
@Builder
public class FiledCheckDto {
private List<FiledCheckEnum> checkEnums;
private List<ModelPropertyResultDto> properties;
private Map<String, Object> argument;
private String modelCode;
}
import lombok.Data;
@Data
public abstract class AbstractFiledCheckHandler {
protected AbstractFiledCheckHandler nextHandler = null;
public abstract FiledCheckEnum getType();
/**
* 检测字段是否符合规范
*/
public void handler(FiledCheckDto filedCheckDto) {
//匹配到该类型
if (filedCheckDto.getCheckEnums().contains(getType())) {
checkHandler(filedCheckDto);
}
if (null == nextHandler) {
return;
}
nextHandler.handler(filedCheckDto);
}
/**
* 子类具体校验
*
* @param filedCheckDto
*/
public abstract void checkHandler(FiledCheckDto filedCheckDto);
}
@Getter
@AllArgsConstructor
public enum FiledCheckEnum {
// 检查字段是否存在
CHECK_FILED_EXSIT(0, "存在校验"),
CHECK_FILED_NULL(1, "非空校验"),
CHECK_FILED_SEARCH(2, "搜索校验"),
CHECK_FILED_EDIT(3, "编辑校验"),
CHECK_FILED_IMPORT(4, "导入校验"),
CHECK_FILED_SORT(5, "排序校验"),
CHECK_FILED_TYPE(6,"类型校验"),
CHECK_FILED_UNIQUE(7,"唯一校验"),
CHECK_FILED_DEFAULT(8,"默认值校验"),
;
private Integer code;
private String value;
public static String getValueByCode(Integer code) {
FiledCheckEnum[] values = FiledCheckEnum.values();
for (FiledCheckEnum type : values) {
if (type.code.equals(code)) {
return type.value;
}
}
return null;
}
public static List<Integer> getCodes() {
List<Integer> codes = Lists.newArrayList();
FiledCheckEnum[] values = FiledCheckEnum.values();
for (FiledCheckEnum type : values) {
codes.add(type.getCode());
}
return codes;
}
public static Integer getCodeByValue(String value) {
FiledCheckEnum[] values = FiledCheckEnum.values();
for (FiledCheckEnum type : values) {
if (type.value.equalsIgnoreCase(value)) {
return type.code;
}
}
return null;
}
}
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Order(7)
@Component
@Slf4j
public class FiledCheckDefaultHandler extends AbstractFiledCheckHandler {
@Override
public FiledCheckEnum getType() {
return FiledCheckEnum.CHECK_FILED_DEFAULT;
}
/**
* 如果值为空且有默认值,设置进去
* @param filedCheckDto
*/
@Override
public void checkHandler(FiledCheckDto filedCheckDto) {
// ...
}
}
@Order(1)
@Component
@Slf4j
public class FiledCheckExsitHandler extends AbstractFiledCheckHandler {
@Override
public FiledCheckEnum getType() {
return FiledCheckEnum.CHECK_FILED_EXSIT;
}
/**
* 检测字段是否符合规范
*
* @param filedCheckDto
*/
@Override
public void checkHandler(FiledCheckDto filedCheckDto) {
// ...
}
}
@RestController
@RequestMapping("/a")
public class AController {
@PostMapping("/{modelCode}/add")
@ResourceCheck(value = {FiledCheckEnum.CHECK_FILED_EXSIT, FiledCheckEnum.CHECK_FILED_NULL,
FiledCheckEnum.CHECK_FILED_TYPE, FiledCheckEnum.CHECK_FILED_UNIQUE})
public ApiResponse<String> add(
@PathVariable("modelCode") String modelCode,
@RequestBody Map<String, Object> params) {
// ...
return new ApiResponse<String>().success();
}
}
@Target({ ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ResourceCheck {
FiledCheckEnum[] value() default {};
}
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
@Aspect
@Component
@Order(4)
public class ResourceCheckAspect {
@Autowired
private ModelService modelService;
@Pointcut("@annotation(com.aaa.ResourceCheck)")
public void resourceCheckAspect() {
// 切面位置以及方法定义
}
@Before("resourceCheckAspect()")
public void doBefore(JoinPoint joinPoint) {
// 拿到被注解的方法签名
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
// 拿到被注解的方法
Method method = signature.getMethod();
Method targetMethod = AopUtils.getMostSpecificMethod(method, joinPoint.getTarget().getClass());
// 拿到注解类的参数
Object[] arguments = joinPoint.getArgs();
if (null == arguments || arguments.length <= 0) {
throw new BizException(BaseCode.PARAM_ERROR);
}
ResourceCheck resourceCheck = AnnotationUtils.findAnnotation(targetMethod, ResourceCheck.class);
// 先匹配方法名
String modelCode = (String) arguments[0];
Map<String, Object> argument = (Map<String, Object>) arguments[1];
// 获取了所有字段
List<ModelPropertyResultDto> properties = // ...
if (null == resourceCheck || resourceCheck.value().length <= 0) {
return;
}
FiledCheckDto build = FiledCheckDto.builder()
.argument(argument)
.properties(properties)
.checkEnums(Arrays.asList(resourceCheck.value()))
.modelCode(modelCode)
.build();
FiledCheckHandlerFactory.processHandler(build);
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix