1.需求
需要针对某些Controller
的返回结果进行统一的处理,类似记录日志或者干嘛,使用注解最为方便,下面使用注解解决这个需求.
2.实现思路
写个注解,在注解内进行业务逻辑处理,所有上面加了这个注解的方法都可以通过这个注解的功能做一些自定义的业务逻辑.
3.代码
3.1.配置文件增加开关
# 注解启用的开关
anno-xxx:
open: true
3.2.配置读取类
package xxx;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* 分级授权配置文件(对应yml)
*/
@ConfigurationProperties(prefix = "anno-xxx")
public class XxxProperties {
/**
* 开启调试模式(或者开关),用于像Swagger这种在线API测试场景
*/
private boolean open;
public boolean isOpen() {
return open;
}
public void setOpen(boolean open) {
this.open = open;
}
}
3.3.定义一个注解
package xxx;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 分级授权注解定义
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Xxx{
}
3.4.启用注解自动配置
package xxx;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
/**
* 分级授权开启注解自动配置
*/
@Configuration
@Component
@EnableAutoConfiguration
@EnableConfigurationProperties(XxxProperties.class)
public class XxxAutoConfiguration {
}
3.5.注解实现类内写业务逻辑
package xxx;
import com.alibaba.fastjson2.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
/**
* 请求响应处理类 对加了@Xxx注解的方法的数据进行分级授权筛选
*/
@Slf4j
@ControllerAdvice
public class ClassifiedAuthResponseBodyAdvice implements ResponseBodyAdvice<Object> {
@Autowired
private ClassifiedAuthProperties properties;
private static ThreadLocal<Boolean> encryptLocal = new ThreadLocal<Boolean>();
public static void setStatus(boolean status){
encryptLocal.set(status);
}
public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {
return true;
}
/**
* 切面主要处理入口,针对响应报文进行处理
*/
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,
Class<? extends HttpMessageConverter<?>> selectedConverterType,
ServerHttpRequest request, ServerHttpResponse response) {
//可以通过调用XxxResponseBodyAdvice.setStatus(false)来动态设置不操作
Boolean status = encryptLocal.get();
if (status != null && status == false){
encryptLocal.remove();
return body;
}
long start = System.currentTimeMillis();
boolean doIt = false;
if (returnType.getMethod().isAnnotationPresent(ClassifiedAuth.class) && properties.isOpen()){
doIt = true;
}
if (doIt){
//开始业务处理
JSONObject jsonObject = JSONObject.from(body);
//TODO 筛选逻辑
jsonObject.replace("data",null);
jsonObject.replace("msg","暂无权限");
body = jsonObject;
}
long end = System.currentTimeMillis();
log.info("Xxx处理耗时={}ms", (end-start));
return body;
}
}
4.注解使用
//...
@ApiOperation("Xxx接口")
@PostMapping("/xxx")
@Xxx //在这里使用Xxx注解,即可完成此类方法的处理
public Object doSth(@RequestBody Vo vo)
{
return xxxService.doSthXxx(vo);
}
//...