springboot注解Aspect实现方案

作者:daodfs1 时间:2022-12-17 19:32:06 

目标

本文提供一种自定义注解,来实现业务审批操作的DEMO,不包含审批流程的配置功能。
具体方案是
自定义一个Aspect注解,拦截sevice方法,将拦截的信息持久化,待审批;审批时获取持久化数据,执行目标方法。

实现

POM

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.8</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.proc</groupId>
<artifactId>process-test</artifactId>
<version>1.0.0-SNAPSHOT</version>
<name>process-test</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<!-- 用于主线程给子线程传递数据,支持线程池 -->
<dependency>
   <groupId>com.alibaba</groupId>
   <artifactId>transmittable-thread-local</artifactId>
   <version>2.12.2</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

一些实体类

CheckedParam

用于包装页面传进来的参数

package com.proc.model;
import java.util.List;
public class CheckedParam {
//业务标记,由页面传入,用于审批时页面根据tagPageJs解析data,渲染到页面,审批管理员可看到审批的内容
private String tagPageJs;
//页面传入的原始数据
private List<String> data;
public String getTagPageJs() {
return tagPageJs;
}
public void setTagPageJs(String tagPageJs) {
this.tagPageJs = tagPageJs;
}
public List<String> getData() {
return data;
}
public void setData(List<String> data) {
this.data = data;
}

}

ProcessDbModel

拦截的信息包装类,用于持久化数据

package com.proc.model;
public class ProcessDbModel {
//bean的目标类全限定名
private String targetClassName;

//拦截到的service方法名
private String methodName;
//页面传入的tagPageJs或Checked注解的tag
private String tag;

private String description;

//拦截到的service入参类型,包含泛型信息
private String paramTypes;

//拦截到的service入参值
private String paramArgs;

//拦截到的service入参值或页面传入的原始数据
private String data;
public String getTargetClassName() {
return targetClassName;
}
public void setTargetClassName(String targetClassName) {
this.targetClassName = targetClassName;
}
public String getMethodName() {
return methodName;
}
public void setMethodName(String methodName) {
this.methodName = methodName;
}
public String getTag() {
return tag;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public void setTag(String tag) {
this.tag = tag;
}
public String getParamTypes() {
return paramTypes;
}
public void setParamTypes(String paramTypes) {
this.paramTypes = paramTypes;
}
public String getParamArgs() {
return paramArgs;
}
public void setParamArgs(String paramArgs) {
this.paramArgs = paramArgs;
}
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
@Override
public String toString() {
return "ProcessDbModel [targetClassName=" + targetClassName + ", methodName=" + methodName + ", tag=" + tag
+ ", description=" + description + ", paramTypes=" + paramTypes + ", paramArgs=" + paramArgs + ", data="
+ data + "]";
}

}

测试用的入参对象


package com.proc.model;
import java.math.BigDecimal;
public class Score {
private BigDecimal langue;

private BigDecimal math;

private BigDecimal english;
public BigDecimal getLangue() {
return langue;
}
public void setLangue(BigDecimal langue) {
this.langue = langue;
}
public BigDecimal getMath() {
return math;
}
public void setMath(BigDecimal math) {
this.math = math;
}
public BigDecimal getEnglish() {
return english;
}
public void setEnglish(BigDecimal english) {
this.english = english;
}
@Override
public String toString() {
return "Score [langue=" + langue + ", math=" + math + ", english=" + english + "]";
}
}

package com.proc.model;
import java.util.List;
public class Person<T> {
private String name;

private String age;

private String sex;

private String testName;

private String salary;

private String work;

private List<T> grades;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getSalary() {
return salary;
}
public void setSalary(String salary) {
this.salary = salary;
}
public String getTestName() {
return testName;
}
public void setTestName(String testName) {
this.testName = testName;
}
public String getWork() {
return work;
}
public void setWork(String work) {
this.work = work;
}
public List<T> getGrades() {
return grades;
}
public void setGrades(List<T> grades) {
this.grades = grades;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + ", sex=" + sex + ", testName=" + testName + ", salary="
+ salary + ", work=" + work + ", grades=" + grades + "]";
}

}

一些工具类

JacksonCanonicalUtil

package com.proc.util;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.json.JsonMapper;

public class JacksonCanonicalUtil {

private static final JsonMapper MAPPER = new JsonMapper();

private JacksonCanonicalUtil () {}

public static <T> String toCanonical (Class<T> clazz) {
return MAPPER.getTypeFactory().constructType(clazz).toCanonical();
}

public static <T> String toCanonical (TypeReference<T> tr) {
return MAPPER.getTypeFactory().constructType(tr).toCanonical();
}

//反序列化时从持久数据中获取JavaType
public static JavaType constructFromCanonical (String canonical) {
return MAPPER.getTypeFactory().constructFromCanonical(canonical);
}
}

StringZipUtil

用于压缩和解压字符串,减少持久数据占用空间

package com.proc.util;
import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.zip.DeflaterOutputStream;
import java.util.zip.InflaterOutputStream;
public class StringZipUtil {
private StringZipUtil () {}

public static String zipBase64(String text) {
       try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
           try (OutputStream os = new DeflaterOutputStream(out)) {
           os.write(text.getBytes(StandardCharsets.UTF_8));
           }
           return Base64.getEncoder().encodeToString(out.toByteArray());
       } catch (Exception e) {
throw new RuntimeException("压缩字符串出错", e);
}
   }

public static String unzipBase64(String text) {
       try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
           try (OutputStream os = new InflaterOutputStream(out)) {
           os.write(Base64.getDecoder().decode(text));
           }
           return new String(out.toByteArray(), StandardCharsets.UTF_8);
       } catch (Exception e) {
throw new RuntimeException("解压字符串出错", e);
}
   }
}

Base64Util

一些参数值转为Base64后持久化

package com.proc.util;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;
import java.util.stream.Collectors;
import com.fasterxml.jackson.databind.json.JsonMapper;
public class Base64Util {
private Base64Util () {}

private static final JsonMapper MAPPER = new JsonMapper();

public static String[] toStrings (Object[] objs) {
List<String> list = new ArrayList<>();
try {
for (Object obj : objs) {
list.add(MAPPER.writeValueAsString(obj));
}
} catch (Exception e) {
throw new RuntimeException("序列化对象出错", e);
}
return list.toArray(new String[0]);
}

public static String encode (String[] strs) {
List<String> list = new ArrayList<>();
for (String str : strs) {
list.add(Base64.getEncoder().encodeToString(str.getBytes(StandardCharsets.UTF_8)));
}
String join = list.stream().collect(Collectors.joining("|"));
return join;
}

public static String[] decode (String text) {
String[] strs = text.split("\\|", -1);
List<String> list = new ArrayList<>();
for (String base64 : strs) {
list.add(new String(Base64.getDecoder().decode(base64), StandardCharsets.UTF_8));
}
return list.toArray(new String[0]);
}

public static String encodeZip (Object[] objs) {
return encodeZip(toStrings(objs));
}

public static String encodeZip (String[] strs) {
List<String> list = new ArrayList<>();
for (String str : strs) {
list.add(StringZipUtil.zipBase64(str));
}
String join = list.stream().collect(Collectors.joining("|"));
return StringZipUtil.zipBase64(join);
}

public static String[] decodeZip (String text) {
String str = StringZipUtil.unzipBase64(text);
String[] strs = str.split("\\|", -1);
List<String> list = new ArrayList<>();
for (String base64 : strs) {
list.add(StringZipUtil.unzipBase64(base64));
}
return list.toArray(new String[0]);
}
}

SpringBootBeanUtil

package com.proc.util;
import java.util.Map;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
@Component
public class SpringBootBeanUtil implements ApplicationContextAware {

private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
SpringBootBeanUtil.applicationContext = applicationContext;
}

public static ApplicationContext getApplicationContext() {
return applicationContext;
}
public static Object getBean(String name) {
return applicationContext.getBean(name);
}

public static <T> T getBean(Class<T> clazz) {
return (T) applicationContext.getBean(clazz);
}

public static <T> T getBean(String name, Class<T> clazz) {
return applicationContext.getBean(name, clazz);
}

public static <T> Map<String, T> getBeansOfType(Class<T> clazz) {
return applicationContext.getBeansOfType(clazz);
}

}

ProcessBeanUtil

用于执行目标方法

package com.proc.util;
import java.lang.reflect.Method;
import org.springframework.util.ReflectionUtils;
public class ProcessBeanUtil {
private ProcessBeanUtil () {}

public static Object excuteBeanMethod (String targetClassName, String methodName, Class<?>[] parameterTypes, Object[] args) {
Class<?> targetClass;
try {
targetClass = Class.forName(targetClassName);
} catch (ClassNotFoundException e) {
throw new RuntimeException("未找到类", e);
}
return excuteBeanMethod(targetClass, methodName, parameterTypes, args);
}

public static Object excuteBeanMethod (Class<?> targetClass, String methodName, Class<?>[] parameterTypes, Object[] args) {
Object bean = SpringBootBeanUtil.getBean(targetClass);
Method method = ReflectionUtils.findMethod(targetClass, methodName, parameterTypes);
return ReflectionUtils.invokeMethod(method, bean, args);
}
}

CheckedTransmitableUtil

用于传递业务参数

package com.proc.util;
import com.alibaba.ttl.TransmittableThreadLocal;
import com.proc.model.CheckedParam;
public class CheckedTransmitableUtil {
private static final TransmittableThreadLocal<CheckedParam> threadLocal = new TransmittableThreadLocal<>();

private CheckedTransmitableUtil () {}

public static void set (CheckedParam checkedParam) {
threadLocal.set(checkedParam);
}

public static CheckedParam getAndRemove () {
CheckedParam checkedParam = threadLocal.get();
threadLocal.remove();
return checkedParam;
}
}

PrivateTransmitableUtil

为Aspect判断是否拦截提供依据

package com.proc.util;
import com.alibaba.ttl.TransmittableThreadLocal;
public class PrivateTransmitableUtil {

private static final String CHECKED = "__CHECKED__";
private static final TransmittableThreadLocal<String> threadLocal = new TransmittableThreadLocal<>();

private PrivateTransmitableUtil () {}

public static void set () {
threadLocal.set(CHECKED);
}

//是否执行的审批程序
public static boolean isCheck () {
String checked = threadLocal.get();
threadLocal.remove();
return CHECKED.equals(checked);
}
}

一些Bean

PostProcess

用于拦截方法后做的个性处理

package com.proc.bean;
public interface PostProcess<T> {
//返回说明内容,审批时在页面显示
String description(String tag, Class<?>[] parameterTypes, Object[] args);

//返回代替的返回值
T retObject(String tag, Class<?>[] parameterTypes, Object[] args);
}

TestCheckPostProcess

测试用


package com.proc.bean;
import org.springframework.stereotype.Component;
@Component
public class TestCheckPostProcess implements PostProcess<String> {
@Override
public String description(String tag, Class<?>[] parameterTypes, Object[] args) {
return tag + "测试testCheck";
}
@Override
public String retObject(String tag, Class<?>[] parameterTypes, Object[] args) {
return tag + "返回拦截响应";
}
}

Aspect注解

package com.proc.config;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import com.proc.bean.PostProcess;
@Retention(RUNTIME)
@Target(METHOD)
public @interface Checked {

String tag() default "";
/**
* @see com.proc.util.JacksonCanonicalUtil
* @return
*/
String[] paramCanonical();

Class<? extends PostProcess<?>> postProcess();
}

切面类 CheckedAop

package com.proc.config;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.proc.bean.PostProcess;
import com.proc.model.CheckedParam;
import com.proc.model.ProcessDbModel;
import com.proc.service.ProcessDbService;
import com.proc.util.Base64Util;
import com.proc.util.CheckedTransmitableUtil;
import com.proc.util.PrivateTransmitableUtil;
import com.proc.util.SpringBootBeanUtil;
@Component
@Aspect
public class CheckedAop {

@Autowired
private ProcessDbService processDbService;
//拦截Checked注释的方法
@Pointcut("@annotation(com.proc.config.Checked)")
public void check() {
}

@Around(value = "com.proc.config.CheckedAop.check() && @annotation(checked)")
public Object around(ProceedingJoinPoint joinPoint, Checked checked) throws Throwable {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Class<?>[] parameterTypes = signature.getParameterTypes();
String methodName = signature.getMethod().getName();
Object[] args = joinPoint.getArgs();
if (PrivateTransmitableUtil.isCheck()) {
//审批后,执行业务代码
Object returnVal = joinPoint.proceed();
return returnVal;
} else {
//不是审批操作,拦截
Class<? extends PostProcess<?>> postProcess = checked.postProcess();
PostProcess<?> bean = SpringBootBeanUtil.getBean(postProcess);
//组装持久化数据
ProcessDbModel dbModel = new ProcessDbModel();
dbModel.setTargetClassName(joinPoint.getTarget().getClass().getName());
dbModel.setMethodName(methodName);
String tag = checked.tag();
CheckedParam checkedParam = CheckedTransmitableUtil.getAndRemove();
if (checkedParam == null || checkedParam.getTagPageJs() == null || checkedParam.getTagPageJs().isEmpty()) {
//不是页面调用的业务,使用注解的tag,data保存为service的参数,这时需要页面专门解析渲染
String[] argStrs = Base64Util.toStrings(args);
dbModel.setParamArgs(Base64Util.encodeZip(argStrs));
dbModel.setData(Base64Util.encode(argStrs));
} else {
tag = checkedParam.getTagPageJs();
dbModel.setParamArgs(Base64Util.encodeZip(args));
dbModel.setData(Base64Util.encode(checkedParam.getData().toArray(new String[0])));
}
dbModel.setTag(tag);
dbModel.setParamTypes(Base64Util.encodeZip(checked.paramCanonical()));
dbModel.setDescription(bean.description(tag, parameterTypes, args));
//持久化数据
processDbService.save(dbModel);
return bean.retObject(tag, parameterTypes, args);
}
}
}

线程池配置

测试用

package com.proc.config;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import com.alibaba.ttl.threadpool.TtlExecutors;
@Configuration
public class TaskExecutePoolConfig {
@Bean
public Executor processExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
//核心线程池大小
executor.setCorePoolSize(10);
//最大线程数
executor.setMaxPoolSize(10);
//队列容量
executor.setQueueCapacity(500);
//活跃时间
executor.setKeepAliveSeconds(60);
       //线程名字前缀
executor.setThreadNamePrefix("ProcessExecutor-");

executor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
// 等待所有任务结束后再关闭线程池
executor.setWaitForTasksToCompleteOnShutdown(true);
executor.initialize();
//用transmittable-thread-local包装,才可以正确给线程池中的线程传递数据
return TtlExecutors.getTtlExecutor(executor);
}
}

持久化service

为测试方便,未真正实现持久化


package com.proc.service;

import com.proc.model.ProcessDbModel;

public interface ProcessDbService {

void save (ProcessDbModel model);

ProcessDbModel get ();
}

package com.proc.service.impl;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import com.proc.model.ProcessDbModel;
import com.proc.service.ProcessDbService;

@Component
public class ProcessDbServiceImpl implements ProcessDbService {
private static final Logger log = LoggerFactory.getLogger(ProcessDbService.class);

private volatile ProcessDbModel model;

@Override
public void save(ProcessDbModel model) {
this.model = model;
log.info(model.toString());
}

@Override
public ProcessDbModel get() {
return this.model;
}

}

审批用的service


package com.proc.service;
import com.proc.model.ProcessDbModel;
public interface ProcessCheckService {
void process (ProcessDbModel model);
}

package com.proc.service.impl;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.json.JsonMapper;
import com.proc.model.ProcessDbModel;
import com.proc.service.ProcessCheckService;
import com.proc.util.Base64Util;
import com.proc.util.JacksonCanonicalUtil;
import com.proc.util.PrivateTransmitableUtil;
import com.proc.util.ProcessBeanUtil;
@Service
public class ProcessCheckServiceImpl implements ProcessCheckService {
private static final Logger log = LoggerFactory.getLogger(ProcessCheckServiceImpl.class);

private static final JsonMapper MAPPER = new JsonMapper();
@Override
public void process(ProcessDbModel model) {
PrivateTransmitableUtil.set();
String[] paramArgs = Base64Util.decodeZip(model.getParamArgs());
String[] paramTypes = Base64Util.decodeZip(model.getParamTypes());
List<Class<?>> parameterTypes = new ArrayList<>();
List<Object> args = new ArrayList<>();
try {
for (int i = 0; i < paramTypes.length; i++) {
JavaType javaType = JacksonCanonicalUtil.constructFromCanonical(paramTypes[i]);
parameterTypes.add(javaType.getRawClass());
args.add(MAPPER.readValue(paramArgs[i], javaType));
}
} catch (JsonProcessingException e) {
throw new RuntimeException("反序列化对象出错", e);
}

Object ret = ProcessBeanUtil.excuteBeanMethod(
model.getTargetClassName(),
model.getMethodName(),
parameterTypes.toArray(new Class<?>[0]),
args.toArray(new Object[0])
);
log.info(Objects.toString(ret));
}
}

测试用的service

package com.proc.service;
import com.proc.model.Person;
import com.proc.model.Score;
public interface TestService {
String testCheck(Person<Score> person, String team);

String testCheck2(Person<Score> person, String team);

String testCheckAsync(Person<Score> person, String team);
}

package com.proc.service.impl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import com.proc.bean.TestCheckPostProcess;
import com.proc.config.Checked;
import com.proc.model.Person;
import com.proc.model.Score;
import com.proc.service.TestService;
@Service
public class TestServiceImpl implements TestService {
private static final Logger log = LoggerFactory.getLogger(TestServiceImpl.class);
//paramCanonical对应testCheck的参数类型
@Checked(
paramCanonical = {"com.proc.model.Person<com.proc.model.Score>", "java.lang.String"},
postProcess = TestCheckPostProcess.class)
@Override
public String testCheck(Person<Score> person, String team) {
log.info(team + ">>>>" + person);
return "target方法";
}

@Checked(
tag = "A1",
paramCanonical = {"com.proc.model.Person<com.proc.model.Score>", "java.lang.String"},
postProcess = TestCheckPostProcess.class)
@Override
public String testCheck2(Person<Score> person, String team) {
log.info(team + ">>2>>" + person);
return "target2方法";
}

@Async("processExecutor")
@Checked(
paramCanonical = {"com.proc.model.Person<com.proc.model.Score>", "java.lang.String"},
postProcess = TestCheckPostProcess.class)
@Override
public String testCheckAsync(Person<Score> person, String team) {
log.info(team + ">>>>" + person);
return "target方法";
}
}

审批用的controller


package com.proc.ctrl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import com.proc.model.ProcessDbModel;
import com.proc.service.ProcessCheckService;
import com.proc.service.ProcessDbService;
@RestController
public class ProcessCheckController {
private static final Logger log = LoggerFactory.getLogger(ProcessCheckController.class);

@Autowired
private ProcessDbService processDbService;
@Autowired
private ProcessCheckService processCheckService;

@GetMapping(value = "process")
public String process() {
ProcessDbModel processDbModel = processDbService.get();
log.info(processDbModel.toString());
processCheckService.process(processDbModel);
return "审批成功";
}
}

测试用的controller


package com.proc.ctrl;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import com.proc.model.CheckedParam;
import com.proc.model.Person;
import com.proc.model.Score;
import com.proc.service.TestService;
import com.proc.util.CheckedTransmitableUtil;
@RestController
public class TestController {
@Autowired
private TestService testService;

//模拟页面调用
@GetMapping(value = "index")
public String testCheck() {
CheckedParam checkedParam = new CheckedParam();
checkedParam.setTagPageJs("01");
List<String> data = new ArrayList<>();
data.add("前端传进来的数据1");
data.add("前端传进来的数据2");
checkedParam.setData(data);
CheckedTransmitableUtil.set(checkedParam);
Person<Score> person = new Person<>();
person.setName("一个人");
person.setAge("18");
person.setSex("1");
person.setSalary("20000.00");
person.setTestName("测试人");
person.setWork("工作");

Score score1 = new Score();
score1.setEnglish(new BigDecimal("12.4"));
score1.setLangue(new BigDecimal("764"));
score1.setMath(new BigDecimal("87.4"));
Score score2 = new Score();
score2.setEnglish(new BigDecimal("12.4"));
score2.setLangue(new BigDecimal("764"));
score2.setMath(new BigDecimal("87.4"));
List<Score> list = new ArrayList<>();
list.add(score1);
list.add(score2);
person.setGrades(list);

testService.testCheck(person, "team>>>>>>>>");
return "12345";
}

//模拟其他渠道调用
@GetMapping(value = "index2")
public String testCheck2() {
Person<Score> person = new Person<>();
person.setName("一个人");
person.setAge("18");
person.setSex("1");
person.setSalary("20000.00");
person.setTestName("测试人");
person.setWork("工作");

Score score1 = new Score();
score1.setEnglish(new BigDecimal("12.4"));
score1.setLangue(new BigDecimal("764"));
score1.setMath(new BigDecimal("87.4"));
Score score2 = new Score();
score2.setEnglish(new BigDecimal("12.4"));
score2.setLangue(new BigDecimal("764"));
score2.setMath(new BigDecimal("87.4"));
List<Score> list = new ArrayList<>();
list.add(score1);
list.add(score2);
person.setGrades(list);

testService.testCheck2(person, "team>>>2>>>>>");
return "12345";
}

//模拟调用异步方法
@GetMapping(value = "index3")
public String testCheckAsync() {
CheckedParam checkedParam = new CheckedParam();
checkedParam.setTagPageJs("01");
List<String> data = new ArrayList<>();
data.add("前端传进来的数据1");
data.add("前端传进来的数据2");
checkedParam.setData(data);
CheckedTransmitableUtil.set(checkedParam);
Person<Score> person = new Person<>();
person.setName("一个人");
person.setAge("18");
person.setSex("1");
person.setSalary("20000.00");
person.setTestName("测试人");
person.setWork("工作");

Score score1 = new Score();
score1.setEnglish(new BigDecimal("12.4"));
score1.setLangue(new BigDecimal("764"));
score1.setMath(new BigDecimal("87.4"));
Score score2 = new Score();
score2.setEnglish(new BigDecimal("12.4"));
score2.setLangue(new BigDecimal("764"));
score2.setMath(new BigDecimal("87.4"));
List<Score> list = new ArrayList<>();
list.add(score1);
list.add(score2);
person.setGrades(list);

testService.testCheckAsync(person, "team>>>3>>>>>");
return "12345";
}
}

开启异步功能

package com.proc;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;
@SpringBootApplication
@EnableAsync
public class ProcessTestApplication {
public static void main(String[] args) {
SpringApplication.run(ProcessTestApplication.class, args);
}
}

测试

http://localhost:8080/indexhttp://localhost:8080/index2http://localhost:8080/index3
浏览器访问上面其中一个路径一次,再访问http://localhost:8080/process一次即可

来源:https://blog.csdn.net/daodfs111/article/details/122386232

标签:springboot,注解,Aspect
0
投稿

猜你喜欢

  • 获取Android手机中所有短信的实现代码

    2023-08-04 16:55:30
  • java二维码生成的方法

    2022-08-02 22:07:28
  • c#动态加载卸载DLL的方法

    2023-06-08 08:18:08
  • 一篇文章带你入门Java变量

    2021-09-21 07:46:02
  • Android自定义可标记日历效果

    2022-09-06 04:11:22
  • 基于WPF实现代码查看器控件

    2022-10-06 03:32:11
  • java集合Collection实现类解析ArrayList LinkedList及Vector

    2022-05-01 05:44:12
  • Java中List使用stream流转成map的几种方式详解

    2022-07-31 21:46:12
  • C#自定义函数NetxtString生成随机字符串

    2022-06-18 20:43:39
  • 如何解决SpringBoot集成百度UEditor图片上传后直接访问404

    2022-03-03 19:27:13
  • Android使用ScrollView实现滚动效果

    2023-05-01 13:25:16
  • C#比较时间大小的方法总结

    2023-09-02 04:38:06
  • springboot整合solr的方法详解

    2023-01-20 17:54:37
  • SpringCloud超详细讲解微服务网关Gateway

    2021-09-11 14:54:49
  • 关于C#委托三种调用的分享使用

    2022-10-29 03:24:35
  • Unity3d实现无限循环滚动背景

    2022-11-02 05:04:22
  • 详解IDEA启动多个微服务的配置方法

    2023-11-24 09:22:24
  • Java TreeSet实现学生按年龄大小和姓名排序的方法示例

    2023-01-09 15:25:18
  • Java的SPI机制实例详解

    2021-08-15 08:47:41
  • Android监听Home键和Back键的区别介绍

    2022-09-11 11:21:03
  • asp之家 软件编程 m.aspxhome.com