提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
前言 springBoot 开发
提示:这里可以添加本文要记录的大概内容:
参考了论坛大神的代码,写的不好请见谅,废话不多说,直接上代码
提示:以下是本篇文章正文内容,下面案例可供参考
一、AOP
先加入依赖
<!--全局请求日志处理-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
启动配置:@ComponentScan({“com.test”}),改成自己项目的包名
@SpringBootApplication
@EnableScheduling
@ComponentScan({"com.github.jackpanz.json","com.test"})
public class DingApplication {
public static void main(String[] args) {
TimeZone.setDefault(TimeZone.getTimeZone("Asia/Shanghai"));
SpringApplication.run(DingApplication.class, args);
}
/*自定义过滤字段*/
@Order(0)
@Bean
public JFilterHttpMessageConverter jFilterHttpMessageConverter(ObjectMapper objectMapper) {
JFilterHttpMessageConverter messageConverter = new JFilterHttpMessageConverter(objectMapper);
return messageConverter;
}
}
aop工具
/**
* 日志切面
*/
@Aspect
@Component
public class LogAspect {
private Logger logger = LoggerFactory.getLogger(LogAspect.class);
//日志记录
@Autowired
RequestLogService requestLogService;
/*事物回滚*/
@Autowired
PlatformTransactionManager platformTransactionManager;
@Autowired
TransactionDefinition transactionDefinition;
//统计请求的处理时间
Long startTime = null;
//controller包的路径
@Pointcut("execution(public * com.test.controller.*.*(..))")
public void webLog() {
}
@Before("webLog()")
public void deBefore(JoinPoint joinPoint) throws Throwable {
// System.out.println("方法的开始执行.....");
}
@AfterReturning(returning = "ret", pointcut = "webLog()")
public void doAfterReturning(JoinPoint joinPoint, Object ret) throws Throwable {
// 处理完请求,返回内容
// System.out.println("方法的返回值 : " + ret.toString());
}
//后置异常通知,有@Around无法执行这个方法,
@AfterThrowing(pointcut = "webLog()", throwing = "e")
public void throwing(JoinPoint joinPoint, Exception e) {
// System.out.println("方法异常时执行.....");
}
//后置最终通知,final增强,不管是抛出异常或者正常退出都会执行
@After("webLog()")
public void after(JoinPoint joinPoint) {
// System.out.println("方法最后执行.....");
}
//环绕通知,环绕增强,相当于MethodInterceptor
@Around("webLog()")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
// System.out.println("方法环绕start.....");
startTime = System.currentTimeMillis();
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
HttpServletResponse response = attributes.getResponse();
//从切面织入点处通过反射机制获取织入点处的方法
MethodSignature methodSignature = (MethodSignature) pjp.getSignature();
//开启事务
TransactionStatus transactionStatus = platformTransactionManager.getTransaction(transactionDefinition);
Object o = null;
Exception exception = null;
try {
//获取token并验证token
validToken(request.getHeader("Authorization"), methodSignature.getMethod());
//请求过程
o = pjp.proceed();
// System.out.println("方法环绕proceed,结果是 :" + o!=null?o.toString():"");
} catch (Exception e) {
//错误,事物回滚
platformTransactionManager.rollback(transactionStatus);
//抛出到全局统一异常,GlobalExceptionHandler
exception = e;
throw e;
} finally {
//保存请求日志
RequestLogUtil.saveLog(request, response, pjp, startTime, exception);
}
//成功,提交事务
platformTransactionManager.commit(transactionStatus);
return o;
}
/**
* 获取token并验证token
*/
private void validToken(String token, Method method) {
// 判断接口是否是token验证
if (method.isAnnotationPresent(StaffLoginToken.class)) {
StaffLoginToken staffLoginToken = method.getAnnotation(StaffLoginToken.class);
if (staffLoginToken.required()) {
// 执行认证
if (token == null || token.length() != 32) {
throw new JwtException(401, "无token,请重新登录");
}
// 验证方法自己定义....
if (验证失败就throw) {
throw new JwtException(401, "用户不存在,请重新登录");
}
}
}
}
}
二、统一异常处理
1.针对controller层的异常
2.还有一些错误是不进入aop处理的,这块我用的是Advice捕获异常,异常类型可以自己补充
/**
* 统一异常处理
*/
@RestControllerAdvice
public class GlobalExceptionHandler {
/**
* aop抛出的异常,判断错误是否是已定义的已知错误,不是则由未知错误代替
*/
@ExceptionHandler(value = Exception.class)
public ResultJson<Object> exceptionController(Exception e) {
// System.out.println("exceptionGet系统异常:" + e);
ResultJson<Object> resultJson = new ResultJson<>();
if (e instanceof JwtException) {
JwtException exception = (JwtException) e;
resultJson = resultJson.diy(exception.getStatusCode(), exception.getMessage());
} else if (e instanceof DescribeException) {
DescribeException exception = (DescribeException) e;
resultJson = resultJson.diy(exception.getStatusCode(), exception.getMessage());
} else if (e instanceof SocketException) {
resultJson = resultJson.diy(500, "无网络连接");
} else if (e instanceof SocketTimeoutException) {
resultJson = resultJson.diy(500, "连接网络超时");
} else if (e instanceof HttpException) {
resultJson = resultJson.diy(500, "http错误");
} else if (e instanceof NullPointerException) {
resultJson = resultJson.diy(500, "空指针异常");
} else if (e instanceof JsonSyntaxException) {
resultJson = resultJson.diy(500, "Json数据解析异常");
} else if (e instanceof ArrayIndexOutOfBoundsException) {
resultJson = resultJson.diy(500, "数组下标越界");
} else if (e instanceof ClassCastException) {
resultJson = resultJson.diy(500, "数据类型转换错误");
} else if (e instanceof ClientException) {
resultJson = resultJson.diy(500, "人脸识别失败");
} else if (e instanceof ArithmeticException) {
resultJson = resultJson.diy(500, "算术运算异常");
} else if (e instanceof ConstraintViolationException) {
ConstraintViolationException exception = (ConstraintViolationException) e;
Set<ConstraintViolation<?>> constraintViolations = exception.getConstraintViolations();
List<String> list = new ArrayList<>();
for (ConstraintViolation<?> constraintViolation : constraintViolations) {
String messageTemplate = constraintViolation.getMessageTemplate();
list.add(messageTemplate);
}
String message = list.stream().collect(Collectors.joining(","));
resultJson = resultJson.diy(500, message);
} else {
resultJson = resultJson.diy(500, "系统错误");
}
return resultJson;
}
/**
* 不进入controller层的异常捕获,保存记录,这里保存的记录信息没有aop详细
*/
@ExceptionHandler({MethodArgumentTypeMismatchException.class, MissingServletRequestParameterException.class, IllegalArgumentException.class})
public ResultJson<Object> exceptionExceptController(Exception e) {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
HttpServletResponse response = attributes.getResponse();
//保存请求日志
RequestLogUtil.saveLog2(request, response, e);
ResultJson<Object> resultJson = new ResultJson<>();
String errmsg = "";
String message = "";
if (e instanceof MethodArgumentTypeMismatchException) {
MethodArgumentTypeMismatchException exception = (MethodArgumentTypeMismatchException) e;
// MethodParameter parameter = exception.getParameter();
// errmsg = "参数转换失败,方法:"+ Objects.requireNonNull(exception.getParameter().getMethod()).getName()
// +",期望参数类型:"+exception.getParameter().getParameterType()
// +",参数:"+exception.getName()
// +",信息:"+exception.getMessage();
message = "参数类型转换异常";
} else if (e instanceof MissingServletRequestParameterException) {
message = "参数信息异常";
} else if (e instanceof IllegalArgumentException) {
message = "不合法的参数异常";
} else {
message = "未知错误";
}
// System.out.println("errmsg = " + errmsg);
return resultJson.diy(400, message);
}
}
三、请求接口
注意
1.接口要加public修饰,否则不能进入aop
2.不用加try…catch…
3.回滚不用加注解@Transactional
这些在aop里都已处理好了
@ApiOperation(value = "测试异常回滚后保存日志")
@PostMapping(value = "/test", produces = "application/json; charset=UTF-8")
public ResultJson<Object> test() {
ResultJson<Object> result = new ResultJson<>();
Appellation log = new Appellation();
log.setAppellationName("测试");
log.setAddTime(DateUtil.getNowDatetime());
appellationService.save(log);
int s = 3/0;
return result.success();
}
四、日志保存
@Component
public class RequestLogUtil {
public static RequestLogUtil util;
@PostConstruct
public void init() {
util = this;
}
@Autowired
private RequestLogService requestLogService;
/**
* aop-保存请求日志
*/
public static void saveLog(HttpServletRequest request, HttpServletResponse response, ProceedingJoinPoint joinPoint, Long startTime, Exception e) {
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
//获取切入点所在的方法
Method method = methodSignature.getMethod();
String requestUrl = request.getRequestURL().toString();
String requestMethod = request.getMethod();
String ip = WxPayBusiness.self().getIpAddr(request);
String path = methodSignature.getDeclaringTypeName() + "." + methodSignature.getName();
// 记录下请求内容
// System.out.println("请求URL = " + requestUrl);
// System.out.println("请求方法 = " + requestMethod);
// System.out.println("请求的IP = " + ip);
// System.out.println("请求的包和方法名 = " + path);
// 输出请求参数
Map<String, String[]> parameterMap = request.getParameterMap();
Map<String, String> stringMap = new HashMap<>();
for (Map.Entry<String, String[]> stringEntry : parameterMap.entrySet()) {
String key = stringEntry.getKey();
String[] value = stringEntry.getValue();
String valueStr = "";
if (value != null && value.length > 0) {
ArrayList<String> strings = Lists.newArrayList(value);
valueStr = StringUtils.strip(strings.toString(), "[]");
}
stringMap.put(key, valueStr);
}
RequestLog log = new RequestLog();
//获取操作
ApiOperation requestMapping = method.getAnnotation(ApiOperation.class);
//获取请求的类名
String className = joinPoint.getTarget().getClass().getName();
//获取请求的方法名
String methodName = method.getName();
if (requestMapping != null) {
String value = requestMapping.value();
log.setName(value);
}
log.setIp(ip);
log.setMethod(requestMethod);
log.setRequestUrl(requestUrl);
log.setRequestPath(className + "-" + methodName);
// log.setJsonResponse(JSONObject.toJSONString(ret));
log.setJsonRequest(JSONObject.toJSONString(stringMap));
if (startTime != null) {
double l = System.currentTimeMillis() - startTime;
log.setUserTime(DoubleUtil.div(l, 1000, 2));
} else {
log.setUserTime(0d);
}
if (e != null) {
if (e instanceof JwtException) {
JwtException jwtException = (JwtException) e;
log.setHttpStatus(jwtException.getStatusCode());
} else {
log.setHttpStatus(500);
}
log.setThrowException(e.toString());
} else {
log.setHttpStatus(response != null ? response.getStatus() : 0);
}
log.setAddTime(DateUtil.getNowDatetime());
util.requestLogService.save(log);
}
/**
* ControllerAdvice-保存请求日志
*/
public static void saveLog2(HttpServletRequest request, HttpServletResponse response, Exception e) {
//获取切入点所在的方法
String requestUrl = request.getRequestURL().toString();
String requestMethod = request.getMethod();
String pathInfo = request.getPathInfo();
String ip = WxPayBusiness.self().getIpAddr(request);
// 记录下请求内容
// System.out.println("请求URL = " + requestUrl);
// System.out.println("请求方法 = " + requestMethod);
// System.out.println("请求的IP = " + ip);
// System.out.println("请求的包和方法名 = " + path);
// 输出请求参数
Map<String, String[]> parameterMap = request.getParameterMap();
Map<String, String> stringMap = new HashMap<>();
for (Map.Entry<String, String[]> stringEntry : parameterMap.entrySet()) {
String key = stringEntry.getKey();
String[] value = stringEntry.getValue();
String valueStr = "";
if (value != null && value.length > 0) {
ArrayList<String> strings = Lists.newArrayList(value);
valueStr = StringUtils.strip(strings.toString(), "[]");
}
stringMap.put(key, valueStr);
}
RequestLog log = new RequestLog();
//获取操作
log.setName(null);
log.setIp(ip);
log.setMethod(requestMethod);
log.setRequestUrl(requestUrl);
log.setRequestPath(null);
// log.setJsonResponse(JSONObject.toJSONString(ret));
log.setJsonRequest(JSONObject.toJSONString(stringMap));
log.setHttpStatus(400);
log.setUserTime(0d);
if (e != null) {
log.setThrowException(e.toString());
}
log.setAddTime(DateUtil.getNowDatetime());
util.requestLogService.save(log);
}
}
总结
1.非controller异常开始没有思路搞了好久
2.回滚后的日志保存,看了好多文章还是没搞定,最后瞎搞搞出来了,哈哈哈…
这些基本就够用了,验证方法和统一返回类可以改成自己的