Java, 原创, 服务器Aop, Aspect, JAVA, Spring Boot
记录Spring boot 项目 AOP Aspect 实现环绕通知,含参数获取,结果处理(统一返回参数),异常抛出
- by chenxue4076
- 4 years ago
业务需要,也不想每次返回的结果都手动整理一次数据,另外 com.alibaba.cola.dto.MultiResponse 的字段不够我们需显示的信息,先说下实际需求
1.针对单条记录或者单个字段返回,我们希望返回格式统一为
{
"data": {
"id": 41,
"status": 1
},
"errCode": 200,
"success": true,
"requestId": "f79f656-bf23-712a-ce55-45a51ba1fa72c",
"errMessage": ""
}
或
{
"data": 20,
"errCode": 200,
"success": true,
"requestId": "f79f656-bf23-712a-ce55-45a51ba1fa72c",
"errMessage": ""
}
对多行数据返回,我们希望 格式如下
{
"total": 4,
"data": [
{
"id": 41,
"status": 1
}
],
"size": 1,
"errCode": 200,
"success": true,
"totalPage": 4,
"requestId": "5e02379-37f4-e678-b716-32a7932d9e7e8",
"page": 1,
"errMessage": ""
}
AOP 获取请求参数中的page, size, 这样就可以在结果中统一添加分页信息, 需要在前置通知或环绕通知中获得,代码如下:
int page = 0;
int size = 0;
//前置通知
//RequestBody中参数使用下面获取方式
Object[] args = proceedingJoinPoint.getArgs();
for ( args != null && Object arg : args) {
System.out.println(arg.toString());
JSONObject jsonObject = new JSONObject(arg);
System.out.println(jsonObject.toString());
if ( jsonObject != null && jsonObject.has("page") ) {
int pageParam = jsonObject.getInt("page");
if (pageParam > 0) {
page = pageParam;
}
}
if ( jsonObject != null && j jsonObject.has("page") ) {
int sizeParam = jsonObject.getInt("size");
if (sizeParam > 0) {
size = sizeParam;
}
}
}
如果需要获取头部信息,可以这样获取
ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = servletRequestAttributes.getRequest();
//获取头部信息
String userAgent = request.getHeader("User-Agent");
System.out.println(userAgent);
如何处理返回的结果,
//方法执行
System.out.println("方法执行");
//proceed 就是 controller 中获取到的返回值 (返回值拼错了 (lll¬ω¬))
processd = proceedingJoinPoint.proceed();
System.out.println("后置通知");
if (processd == null) {
System.out.println("无返回值");
return null;
}
//后置通知
if (processd instanceof MultiResponse) {
MultiResponse multiResponse = (MultiResponse) processd;
String errCode = multiResponse.getErrCode();
map.put("errCode", errCode == null ? 200 : errCode);
String errMessage = multiResponse.getErrMessage();
map.put("errMessage", errMessage == null ? "" : errMessage);
map.put("success", multiResponse.isSuccess());
map.put("data", multiResponse.getData());
int total = multiResponse.getTotal();
map.put("total", total);
if (size > 0) {
map.put("page", page);
map.put("size", size);
double totalPage = Math.ceil((double) total / size);
//System.out.println(total + " / " + size + " totalPage: " + totalPage);
map.put("totalPage", (int) totalPage);
}
System.out.println("多行 " + map.toString());
} else if (processd instanceof Response) {
Response response = (Response) processd;
String errCode = response.getErrCode();
map.put("errCode", errCode == null ? 200 : errCode);
//map.put("errCode", response.getErrCode());
String errMessage = response.getErrMessage();
map.put("errMessage", errMessage == null ? "" : errMessage);
//map.put("errMessage", response.getErrMessage());
map.put("success", response.isSuccess());
System.out.println("单行Response " + map.toString());
} else {
map.put("errCode", 200);
map.put("errMessage", "");
map.put("data", processd);
map.put("success", true);
System.out.println("其他对象 类型" + map.toString());
}
String requestId = buildRequestId();
map.put("requestId", requestId);
//System.out.println(map.toString());
return map;
Controller和 service 应该如何定义返回值
//conroller 中返回值 全部定义为 Object 无论service返回什么类型数据
@PostMapping(value = "/index")
@ResponseBody
public Object findAllSupplier(@RequestBody NameSupplierCO nameSupplierCO) {
//获取到的结果是 MuliResponse<SupplierCO>
Object object = cdSupplierService.findAll(nameSupplierCO);
return object;
}
@PostMapping(value = "/create")
@ResponseBody
public Object addSupplier(@Validated @RequestBody AddSupplierCO addSupplierCO) {
//获取到的结果为 int ,添加记录的自增ID值
return cdSupplierService.addSupplier(addSupplierCO);
}
Service定义的接口
//添加供应商
public int addSupplier(AddSupplierCO addSupplierCO);
//获取列表
public MultiResponse<SupplierCO> findAll(NameSupplierCO nameSupplierCO);
整体AOP代码如下
package com.example.test.aop;
import com.alibaba.cola.dto.MultiResponse;
import com.alibaba.cola.dto.Response;
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.json.JSONObject;
import org.springframework.stereotype.Component;
import org.springframework.util.DigestUtils;
import com.alibaba.cola.logger.Logger;
import com.alibaba.cola.logger.LoggerFactory;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
/**
* Create By cx<chenxue4076@163.com>
* File Name MultiResponseAspect.java
* Created Date 2020/11/24
* Created Time 15:52
*/
@Component
@Aspect
public class MultiResponseAspect {
private static Logger logger = LoggerFactory.getLogger(MultiResponseAspect.class);
//后置通知, 最终结果处理
/*@AfterReturning(pointcut = "execution(* cn.focusmedia.fcs.controller..*.*(..))", returning = "returningValue")
*/
//获取需嵌套的切面,我们劫持所有controller, 如果需要去除指定使用 and !execuion(xxxx)
@Pointcut("execution(* cn.focusmedia.fcs.controller..*.*(..))")
public void aroundResponse() {}
//环绕通知
@Around("aroundResponse()")
public Object myAround(ProceedingJoinPoint proceedingJoinPoint) {
//如果有分页,我们需要给结果添加 page, size, totalPage 等参数
int page = 0;
int size = 0;
//前置通知
System.out.println("前置通知在这里显示");
//ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
//HttpServletRequest request = servletRequestAttributes.getRequest();
//获取头部信息
//String userAgent = request.getHeader("User-Agent");
//System.out.println(userAgent);
//RequestBody中参数使用下面获取方式
Object[] args = proceedingJoinPoint.getArgs();
for ( args != null && Object arg : args) {
System.out.println(arg.toString());
JSONObject jsonObject = new JSONObject(arg);
System.out.println(jsonObject.toString());
if ( jsonObject != null && jsonObject.has("page") ) {
int pageParam = jsonObject.getInt("page");
if (pageParam > 0) {
page = pageParam;
}
}
if ( jsonObject != null && j jsonObject.has("page") ) {
int sizeParam = jsonObject.getInt("size");
if (sizeParam > 0) {
size = sizeParam;
}
}
}
//定义返回值类型
Object processd = null;
Map<String, Object> map = new HashMap<String, Object>();
try{
//方法执行
System.out.println("方法执行");
processd = proceedingJoinPoint.proceed();
System.out.println("后置通知");
if (processd == null) {
System.out.println("无返回值");
return null;
}
//后置通知
if (processd instanceof MultiResponse) {
MultiResponse multiResponse = (MultiResponse) processd;
String errCode = multiResponse.getErrCode();
map.put("errCode", errCode == null ? 200 : errCode);
String errMessage = multiResponse.getErrMessage();
map.put("errMessage", errMessage == null ? "" : errMessage);
map.put("success", multiResponse.isSuccess());
map.put("data", multiResponse.getData());
int total = multiResponse.getTotal();
map.put("total", total);
if (size > 0) {
map.put("page", page);
map.put("size", size);
double totalPage = Math.ceil((double) total / size);
//System.out.println(total + " / " + size + " totalPage: " + totalPage);
map.put("totalPage", (int) totalPage);
}
System.out.println("多行 " + map.toString());
} else if (processd instanceof Response) {
Response response = (Response) processd;
String errCode = response.getErrCode();
map.put("errCode", errCode == null ? 200 : errCode);
//map.put("errCode", response.getErrCode());
String errMessage = response.getErrMessage();
map.put("errMessage", errMessage == null ? "" : errMessage);
//map.put("errMessage", response.getErrMessage());
map.put("success", response.isSuccess());
System.out.println("单行Response " + map.toString());
} else {
map.put("errCode", 200);
map.put("errMessage", "");
map.put("data", processd);
map.put("success", true);
System.out.println("其他对象 类型" + map.toString());
}
String requestId = buildRequestId();
map.put("requestId", requestId);
//System.out.println(map.toString());
return map;
} catch (Throwable e) {
//异常通知
logger.error("异常抛出" + e.getMessage());
System.out.println("异常抛出" + e.getMessage());
System.out.println("异常抛出");
Response response = new Response();
response.setErrCode("500");
response.setErrMessage(e.getMessage().substring(0));
response.setSuccess(false);
processd = response;
} finally {
//最终通知
System.out.println("最终通知");
MethodSignature methodSignature = (MethodSignature) proceedingJoinPoint.getSignature();
Class<?> returnType = methodSignature.getReturnType();
String className = returnType.getName();
if( className.contains("Object") ) {
System.out.println("最终通知 Object");
if (map.isEmpty() == false) {
return (Object) map;
}
} else if( className.contains("Response") || className.contains("MultiResponse")) {
System.out.println("最终通知 Response");
if (processd != null) {
return processd;
}
}
if (processd != null) {
System.out.println("最终通知未知");
return processd;
}
return null;
}
}
public String buildRequestId() throws Exception{
byte[] sourceString = String.valueOf(System.currentTimeMillis()).getBytes();
String md5Code = DigestUtils.md5DigestAsHex(sourceString);
return md5Code.substring(0, 7) + "-" + md5Code.substring(7, 11) + "-"+ md5Code.substring(11,15)+"-"+md5Code.substring(15,19)+"-"+md5Code.substring(19);
}
}
// end MultiResponseAspect.java
//end file
通过添加此 AOP处理, 我们的结果就整体统一了, 而不是我们创建一个自定义返回值的类,每个结果都被处理成该类, 这样不仅麻烦,而且还不容易维护。 而AOP很好的实现了统一。
另一篇 AOP切面Mapper实现读写分离的介绍。
(1599)