AOP Aspect 统一日志、异常处理、数据格式 【转】
package com.gsww.chis.aop;
import java.util.Arrays;
import com.google.common.base.Throwables;
import com.gsww.chis.pojo.pacs.PacswsLog;
import com.gsww.chis.service.pacs.PacswsLogService;
import com.gsww.chis.util.TimeHelper;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* 系统日志
* @author fenglanglang
*
*/
@Aspect
@Component
public class WebServiceLogAspect {
private static final Logger logger = LoggerFactory.getLogger(WebServiceLogAspect.class);
@Autowired
private PacswsLogService pacswsLogService;
@Pointcut("execution(public * com.gsww.chis.webservice.*.*(..)) && @annotation(com.gsww.chis.annotation.WebServiceLog)")
public void Pointcut() {
}
@Around("Pointcut()")
public Object around(ProceedingJoinPoint point) {
PacswsLog log = new PacswsLog();
log.setRst("T");
log.setTime(TimeHelper.getCurrentTime());
MethodSignature signature = (MethodSignature) point.getSignature();
// 请求的方法名
String methodName = signature.getName();
log.setHisMethod(methodName);
// 请求的参数
Object[] args = point.getArgs();
log.setParamsIn(Arrays.toString(args));
// 执行方法
Object result =null;
long beginTime = System.currentTimeMillis();
try {
result = point.proceed();
log.setTimeConsuming(System.currentTimeMillis() - beginTime);
log.setParamsOut(result.toString());
} catch (Throwable e) {
if("RisCheckInfo".equals(methodName)){
result = "<Response><list></list><ResultCode>-1</ResultCode><ResultContent>"+e.getMessage()+"</ResultContent></Response>";
}else{
result = "<Response><ResultCode>-1</ResultCode><ResultContent>"+e.getMessage()+"</ResultContent></Response>";
}
log.setRst("F");
log.setParamsOut(result.toString());
log.setTimeConsuming(0L);
logger.error("请求异常:请求方法:{}, 异常信息:{}",methodName,Throwables.getStackTraceAsString(e));
}
saveWebServiceLog(log);
return result;
}
/**
* 保存接口日志
* @param pacswsLog
*/
private void saveWebServiceLog(PacswsLog pacswsLog){
try{
pacswsLogService.save(pacswsLog);
}catch(Exception e){
logger.error("请求异常:请求方法:{}, 异常信息:{}","saveWebServiceLog",Throwables.getStackTraceAsString(e));
}
}
}
package com.gsww.bhis.common.aop;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.Date;
import javax.servlet.http.HttpServletRequest;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import com.google.common.base.Throwables;
/**
* @author fenglanglang
* @see
*
*/
@Aspect //声明是个切面
@Component
public class LogAspect {
private static final Logger logger = LogManager.getLogger("LogConfig");
//切点
@Pointcut("execution(public * com.gsww.bhis..controller.*.*(..))")
public void Pointcut(){}
/**
*
* doAround:(环绕方法,统一日志处理). <br/>
*
* @author fenglanglang
* @param joinPoint
* @return
* @throws Throwable
*/
@Around("Pointcut()")
public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
long beginTime = System.currentTimeMillis();//1、开始时间
ServletRequestAttributes requestAttr = (ServletRequestAttributes)RequestContextHolder.currentRequestAttributes();
String uri = requestAttr.getRequest().getRequestURI();
logger.info("开始计时: {} URI: {}", new Date(),uri);
//访问目标方法的参数 可动态改变参数值
Object[] args = joinPoint.getArgs();
//方法名获取
String methodName = joinPoint.getSignature().getDeclaringTypeName()+"."+joinPoint.getSignature().getName();
logger.info("请求方法:{}, 请求参数: {}", methodName, Arrays.toString(args));
//可能在反向代理请求进来时,获取的IP存在不正确行 这里直接摘抄一段来自网上获取ip的代码
logger.info("请求ip:{}", getIpAddr(requestAttr.getRequest()));
//调用实际方法
Object object = joinPoint.proceed();
logger.info("请求返回值:{}",object);
long endTime = System.currentTimeMillis();
logger.info("结束计时: {}, URI: {},耗时:{}", new Date(),uri,endTime - beginTime);
return object;
}
/**
*
* afterThrowable:(统一异常处理). <br/>
*
* @author fenglanglang
* @param e
*/
@AfterThrowing(pointcut="Pointcut()",throwing="e")
public void afterThrowable(JoinPoint joinPoint,Throwable e) {
//方法名获取
String methodName = joinPoint.getSignature().getDeclaringTypeName()+"."+joinPoint.getSignature().getName();
logger.error("请求异常:请求方法:{}, 异常信息:{}",methodName,Throwables.getStackTraceAsString(e));
}
/**
*
* getIpAddr:(获取ip). <br/>
*
* @author fenglanglang
* @param request
* @return
*/
public static String getIpAddr(HttpServletRequest request) {
String ipAddress = null;
try {
ipAddress = request.getHeader("x-forwarded-for");
if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
ipAddress = request.getHeader("Proxy-Client-IP");
}
if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
ipAddress = request.getHeader("WL-Proxy-Client-IP");
}
if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
ipAddress = request.getRemoteAddr();
if (ipAddress.equals("127.0.0.1")) {
// 根据网卡取本机配置的IP
InetAddress inet = null;
try {
inet = InetAddress.getLocalHost();
} catch (UnknownHostException e) {
logger.error("获取ip异常:{}" ,Throwables.getStackTraceAsString(e));
}
ipAddress = inet.getHostAddress();
}
}
// 对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割
if (ipAddress != null && ipAddress.length() > 15) { // "***.***.***.***".length()
if (ipAddress.indexOf(",") > 0) {
ipAddress = ipAddress.substring(0, ipAddress.indexOf(","));
}
}
} catch (Exception e) {
ipAddress = "";
}
return ipAddress;
}
}
package com.gsww.bhis.common.aop;
import java.lang.annotation.Annotation;
import java.util.LinkedHashMap;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpStatus;
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.stereotype.Controller;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
import com.alibaba.fastjson.JSON;
import com.google.common.base.Throwables;
import com.gsww.bhis.common.util.GlobalResponse;
/**
*
* 类名: GlobalResponseHandler <br/>
* 功能: 正常请求统一响应数据格式 <br/>
* 创建时间: 2018年9月6日 上午10:33:32 <br/>
*
* @author fenglanglang
* @version
*/
@ControllerAdvice(annotations={RestController.class,Controller.class})
public class GlobalResponseHandler implements ResponseBodyAdvice<Object>{
/**
*
* 拦截没有进行统一数据格式的方法
* @see org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice#supports(org.springframework.core.MethodParameter, java.lang.Class)
*/
@Override
public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
//swagger2 api 数据不进行转换 ,否则api界面会出错
String ngp = returnType.getNestedGenericParameterType().toString();
if(ngp.indexOf("swagger")>=0){
return false;
}
Annotation[] ano = returnType.getMethodAnnotations();
for(Annotation a:ano){
if(a.annotationType().getName().indexOf("ApiIgnore")>=0){
return false;
}
}
//已经是标准格式的数据不进行转换
String returnTypeName = returnType.getParameterType().getName();
return !"com.gsww.bhis.common.util.GlobalResponse".equals(returnTypeName);
}
@SuppressWarnings("unchecked")
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,
Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request,
ServerHttpResponse response) {
if(body == null) {
return JSON.toJSONString(GlobalResponse.success(null));
}
//权限校验特殊处理
if(body instanceof LinkedHashMap){
LinkedHashMap<String, Object> hashMapBody = (LinkedHashMap<String, Object>)body;
Integer status = (Integer)hashMapBody.get("status");
Object message = hashMapBody.get("message");
if(status != null && message != null){
return GlobalResponse.fail(message.toString(),status);
}
}
//防止classCaseExceptiin https://my.oschina.net/u/1757225/blog/1543715
if(body instanceof String) {
return JSON.toJSONString(GlobalResponse.success(body));
}
//不是json类型类型的返回值
if(!selectedContentType.includes(MediaType.APPLICATION_JSON)){
return body;
}
return GlobalResponse.success(body);
}
/**
*
* handlerThrowable:(异常时返回统一格式). <br/>
*
* @author fenglanglang
* @param e
* @return
*/
@ResponseBody
@ResponseStatus(HttpStatus.OK)
@ExceptionHandler({Throwable.class})
public <T> GlobalResponse<T> handlerThrowable(Throwable e){
return GlobalResponse.fail(Throwables.getStackTraceAsString(e), 500);
}
}
package com.gsww.bhis.common.util;
import java.io.Serializable;
/**
*
* @author fenglanglang
* 数据格式
* @param <T>
*/
public class GlobalResponse<T> implements Serializable{
private static final long serialVersionUID = 8696541815421373761L;
private Boolean rst = false;
private T data;
private Integer errorCode;
private String errorMsg;
public GlobalResponse() {
super();
}
public GlobalResponse(T data,Boolean rst) {
super();
this.rst = rst;
this.data = data;
}
public static <T> GlobalResponse<T> success(T data){
return new GlobalResponse<T>(data,true);
}
public static <T> GlobalResponse<T> fail(String errorMsg,Integer errorCode){
GlobalResponse<T> gr = new GlobalResponse<T>();
gr.setErrorCode(errorCode);
gr.setErrorMsg(errorMsg);
gr.setRst(false);
return gr;
}
public Boolean isRst() {
return rst;
}
public void setRst(Boolean rst) {
this.rst = rst;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public Integer getErrorCode() {
return errorCode;
}
public void setErrorCode(Integer errorCode) {
this.errorCode = errorCode;
}
public String getErrorMsg() {
return errorMsg;
}
public void setErrorMsg(String errorMsg) {
this.errorMsg = errorMsg;
}
@Override
public String toString() {
return "GlobalResponse [rst=" + rst + ", data=" + data + ", errorCode=" + errorCode + ", errorMsg=" + errorMsg
+ "]";
}
}
完全参考自
AOP Aspect 统一日志、异常处理、数据格式==》https://my.oschina.net/langgege/blog/3025492
AOP Aspect 统一日志、异常处理、数据格式 【转】的更多相关文章
- Spring MVC 中使用AOP 进行统一日志管理--XML配置实现
1.介绍 上一篇博客写了使用AOP进行统一日志管理的注解版实现,今天写一下使用XML配置实现版本,与上篇不同的是上次我们记录的Controller层日志,这次我们记录的是Service层的日志.使用的 ...
- Spring AOP实现统一日志输出
目的: 统一日志输出格式 思路: 1.针对不同的调用场景定义不同的注解,目前想的是接口层和服务层. 2.我设想的接口层和服务层的区别在于: (1)接口层可以打印客户端IP,而服务层不需要 (2)接口层 ...
- Spring MVC 中使用AOP 进行统一日志管理--注解实现
1.AOP简介 AOP称为面向切面编程 AOP的基本概念 (1)Aspect(切面):通常是一个类,里面可以定义切入点和通知 (2)JointPoint(连接点):程序执行过程中明确的点,一般是方法的 ...
- SpringBoot | 第二十四章:日志管理之AOP统一日志
前言 上一章节,介绍了目前开发中常见的log4j2及logback日志框架的整合知识.在很多时候,我们在开发一个系统时,不管出于何种考虑,比如是审计要求,或者防抵赖,还是保留操作痕迹的角度,一般都会有 ...
- SpringBoot系列(十三)统一日志处理,logback+slf4j AOP+自定义注解,走起!
往期精彩推荐 SpringBoot系列(一)idea新建Springboot项目 SpringBoot系列(二)入门知识 springBoot系列(三)配置文件详解 SpringBoot系列(四)we ...
- 如何优雅地在 Spring Boot 中使用自定义注解,AOP 切面统一打印出入参日志 | 修订版
欢迎关注个人微信公众号: 小哈学Java, 文末分享阿里 P8 资深架构师吐血总结的 <Java 核心知识整理&面试.pdf>资源链接!! 个人网站: https://www.ex ...
- Spring Boot 2.0 教程 | AOP 切面统一打印请求日志
欢迎关注微信公众号: 小哈学Java 文章首发于个人网站 https://www.exception.site/springboot/spring-boot-aop-web-request 本节中,您 ...
- Spring Boot 自定义注解,AOP 切面统一打印出入参请求日志
其实,小哈在之前就出过一篇关于如何使用 AOP 切面统一打印请求日志的文章,那为什么还要再出一篇呢?没东西写了? 哈哈,当然不是!原因是当时的实现方案还是存在缺陷的,原因如下: 不够灵活,由于是以所有 ...
- Java 项目创建 -- 统一结果处理、统一异常处理、统一日志处理
一.IDEA 插件使用 1.说明 此处使用 SpringBoot 2.2.6 .JDK 1.8 .mysql 8.0.18 作为演示. 使用 IDEA 作为开发工具. 2.IDEA 插件 -- Lom ...
随机推荐
- <每日一题>题目7:简单的学生管理系统V1.0
''' # 学生管理系统v1.0 # 添加学生的信息 # 删除学生的信息 # 修改学生的信息 # 查看学生的信息 #遍历学生的信息 #退出系统 ''' import json #1 显示操作功能 de ...
- Vue报错——Unknown custom element: <shop-slide> - did you register the component correctly?
参考: https://blog.csdn.net/jiangyu1013/article/details/85676292 解决:除了import组件外,还要在components中添加 <t ...
- Leetcode937. Reorder Log Files重新排列日志文件
你有一个日志数组 logs.每条日志都是以空格分隔的字串. 对于每条日志,其第一个字为字母数字标识符.然后,要么: 标识符后面的每个字将仅由小写字母组成,或: 标识符后面的每个字将仅由数字组成. 我们 ...
- C语言中结构体的深拷贝和浅拷贝
C++ 的浅拷贝和深拷贝(结构体) 拷贝有两种:深拷贝,浅拷贝 浅拷贝:拷贝过程中是按字节复制的,对于指针型成员变量只复制指针本身,而不复制指针所指向的目标 (1)结构体中不存在指针成员变量时 typ ...
- Django项目:CRM(客户关系管理系统)--73--63PerfectCRM实现CRM讲师下载作业
# teacher_urls.py # ————————62PerfectCRM实现CRM讲师讲课记录———————— from django.conf.urls import url from bp ...
- 留下来做项目经理还是跳槽学Java
毕业两年了,曾经给自己计划工作两年后跳一次槽,去尝试学习更多的东西.2012年7月5日入职,现在整整两年,最近面临这样的一个抉择:是留在公司继续做项目经理,还是跳槽去学习Java. 我的基本情况:本科 ...
- NSIS语法解析
注释.!define.变量.!include.常量 ; Script generated by the HM NIS Edit Script Wizard. ; HM NIS Edit Wizard ...
- 享元模式(Flyweight、FlyweightFactory)(围棋棋子共享)
(使用共享对象可有效地支持大量的细粒度的对象.) 假设开发一个围棋程序,围棋程序的围棋的棋子包含了颜色.大小.位置等信息.在定义一个棋盘容器来存放这些棋子. 我们可以发现,棋盘的成员变量包含了一个棋子 ...
- std::map插入失败会返回什么
总所周知,map不能存在2个相同的key,那么如果是后插入的key,对应的value不会添加上去,也不会覆盖原来的,此时会返回一个std::pair<iterator,bool>,可以根据 ...
- PowerDesigner在修改表的字段Name的时Code不自动跟着变的处理方法以及导入Mysql数据库的表
tools-> GeneralOptions-> Dialog:Operation Modes: 去掉 NameToCodeMirroring 前面的√ 导入数据库中的表到PowerD ...