import com.alibaba.fastjson.JSON;
import com.google.common.base.Strings;
import com.ziku.mall.entity.MallSysLogWithBLOBs;
import com.ziku.mall.enums.ErrorCodeEnum;
import com.ziku.mall.exception.BizException;
import com.ziku.mall.interceptor.UncheckAuth;
import com.ziku.mall.model.user.UserResult;
import com.ziku.mall.util.ProjectUtil;
import com.ziku.mall.util.SpringContextUtil;
import com.ziku.msb.common.base.BusinessException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
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.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.StopWatch;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.lang.annotation.Annotation;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
/**
* @Description:
* @Author: wangxuqiang
* @Date: Created in 2018/9/27
* @Version: 1.0
*/
@Aspect
@Slf4j
@Component
public class LogAspect {
@Autowired
private LogService logService;
@Pointcut("execution(* com.ziku.mall.service..*.*Impl.add*(..)) ||" +
"execution(* com.ziku.mall.service..*.*Impl.insert*(..)) ||" +
"execution(* com.ziku.mall.service..*.*Impl.save*(..))")
public void saveCell() {}
@Pointcut("execution(* com.ziku.mall.service..*.*Impl.update*(..)) &&" +
"!execution(* com.ziku.mall.service..*.*Impl.updateOrder(..)) ||" +
"execution(* com.ziku.mall.service..*.*Impl.edit*(..)) ||" +
"execution(* com.ziku.mall.service..*.*Impl.send*(..)) ||" +
"execution(* com.ziku.mall.service..*.*Impl.pay*(..))")
public void updateCell() {}
@Pointcut("execution(* com.ziku.mall.service..*.*Impl.delete*(..)) ||" +
"execution(* com.ziku.mall.service..*.*Impl.cancel*(..)) &&" +
"!execution(* com.ziku.mall.service..*.*Impl.cancelCoupon(..))")
public void deleteCell() {}
@Around("saveCell()")
public Object saveLog(final ProceedingJoinPoint joinPoint) throws Throwable {
return doLog(joinPoint);
}
@Around("updateCell()")
public Object updateLog(final ProceedingJoinPoint joinPoint) throws Throwable {
return doLog(joinPoint);
}
@Around("deleteCell()")
public Object deleteLog(final ProceedingJoinPoint joinPoint) throws Throwable {
return doLog(joinPoint);
}
private Object doLog(final ProceedingJoinPoint joinPoint) throws Throwable {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
MallSysLogWithBLOBs sysLog=new MallSysLogWithBLOBs();
String errorStr="";
try {
sysLog.setGmtCreate(new Date());
sysLog.setIp(getIP(request));
sysLog.setMethod(getMethod(joinPoint));
sysLog.setParams(getParams(joinPoint));
sysLog.setResponseResult("SUCCESS");
sysLog.setOperation(getOperation(request));
sysLog.setUserId(getUserId(request,joinPoint));
} catch (Exception e) {
if (log.isErrorEnabled()) {
log.error("[小程序]日志信息转换异常:{}",ExceptionUtils.getStackTrace(e));
}
errorStr=errorMsg(e);
sysLog.setResponseResult(errorStr);
}
StopWatch sw = new StopWatch(System.currentTimeMillis()+""+Math.random());
sw.start();
Object object=null;
try {
object=joinPoint.proceed();
} catch (Throwable throwable) {
if (log.isErrorEnabled()) {
log.error("[小程序]日志方法执行异常:{}",ExceptionUtils.getStackTrace(throwable));
}
errorStr=errorStr+" --- "+errorMsg(throwable);
sysLog.setResponseResult(errorStr);
if (throwable instanceof BizException) {
sw.stop();
sysLog.setResponseTime(sw.getTotalTimeMillis());
sysLog.setResponseResult(errorStr);
logService.asyncSaveSysLog(sysLog);
throw throwable;
}
}
sw.stop();
sysLog.setResponseTime(sw.getTotalTimeMillis());
logService.asyncSaveSysLog(sysLog);
return object;
}
private String getIP(HttpServletRequest request){
return ProjectUtil.getRemoteHost(request);
}
private String getOperation(HttpServletRequest request) {
String url=request.getRequestURL().toString();
return String.format("[小程序]请求路径:%s;HTTP_METHOD:%s",url,request.getMethod());
}
private String getMethod(ProceedingJoinPoint joinPoint) {
return joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName();
}
private String getParams(final ProceedingJoinPoint joinPoint) {
Object[] args = joinPoint.getArgs();
Signature signature = joinPoint.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
String[] strings = methodSignature.getParameterNames();
Map<Object,Object> map=new HashMap();
String param = null;
if(args!=null&& args.length>0 ){
if (strings != null) {
for (int i = 0; i < strings.length; i++) {
if (strings[i]!=null&&args[i]!=null) {
map.put(strings[i], args[i]);
}
}
param = JSON.toJSONString(map);
} else {
param = JSON.toJSONString(args);
}
}
return param;
}
private String getUserId(HttpServletRequest request,ProceedingJoinPoint joinPoint){
Signature signature = joinPoint.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
// RequiresAuthentication 注解的方法需要用户登录认证
Annotation an = methodSignature.getMethod().getAnnotation(UncheckAuth.class);
UserResult member = getCacheUser(request.getHeader("token"));
if (an == null) {
if (member == null) {
throw new BusinessException(ErrorCodeEnum.USER_TOKEN_EXPIRE.getErrorCode(),ErrorCodeEnum.USER_TOKEN_EXPIRE.getErrorMsg());
}
}
return member != null ? String.valueOf(member.getUserId()) : null;
}
private UserResult getCacheUser(String token) {
UserResult userInfo = null;
if (Strings.isNullOrEmpty(token)) {
return null;
}
StringRedisTemplate redisTemplate = (StringRedisTemplate) SpringContextUtil.getBean("stringRedisTemplate");
String userId = redisTemplate.opsForValue().get("JWT_TOKEN:" + token);
if (Strings.isNullOrEmpty(userId)) {
return null;
}
String userJson = redisTemplate.opsForValue().get("USER-ID:" + userId);
if (Strings.isNullOrEmpty(userJson)) {
return null;
}
userInfo = JSON.parseObject(userJson, UserResult.class);
return userInfo;
}
private String errorMsg(Exception e) {
return String.format("转换异常信息:%s --- %s",e.toString(),e.getStackTrace()[0]);
}
private String errorMsg(Throwable e) {
return String.format("执行方法异常信息:%s --- %s",e.toString(),e.getStackTrace()[0]);
}
}
package com.ziku.mall.aspect;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.validation.BindingResult;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
/**
* @Description:
* @Author: wangxuqiang
* @Date: Created in 2018/12/18
* @Version: 1.0
*/
@Aspect
@Slf4j
@Component
public class LogConsole {
private static final String START_TIME = "request-start";
/**
* 切入点
*/
@Pointcut("execution(public * com.ziku.mall.web.*Controller.*(..))")
public void log() {
}
/**
* 前置操作
*
* @param point 切入点
*/
@Before("log()")
public void beforeLog(JoinPoint point) {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = Objects.requireNonNull(attributes).getRequest();
log.info("【请求 URL】:{}\n【请求 IP】:{}\n【请求类名】:{},【请求方法名】:{}\n【请求参数】:{},", request.getRequestURL(),
request.getRemoteAddr(),point.getSignature().getDeclaringTypeName(), point.getSignature().getName(),
getParams(point));
//log.info("【请求 IP】:{}", request.getRemoteAddr());
//log.info("【请求类名】:{},【请求方法名】:{}", point.getSignature().getDeclaringTypeName(), point.getSignature().getName());
//log.info("【请求参数】:{},", getParams(point));
Long start = System.currentTimeMillis();
request.setAttribute(START_TIME, start);
}
/**
* 环绕操作
*
* @param point 切入点
* @return 原方法返回值
* @throws Throwable 异常信息
*/
@Around("log()")
public Object aroundLog(ProceedingJoinPoint point) throws Throwable {
Object result = point.proceed();
log.info("【返回值】:{}", JSON.toJSONString((result)));
return result;
}
/**
* 后置操作
*/
@AfterReturning("log()")
public void afterReturning() {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = Objects.requireNonNull(attributes).getRequest();
Long start = (Long) request.getAttribute(START_TIME);
Long end = System.currentTimeMillis();
log.info("【请求耗时】:{}毫秒", end - start);
}
private String getParams(final JoinPoint joinPoint) {
String param = null;
try {
Object[] args = joinPoint.getArgs();
Signature signature = joinPoint.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
String[] strings = methodSignature.getParameterNames();
Map<Object,Object> map=new HashMap();
param = null;
if(args!=null&& args.length>0 ){
if (strings != null) {
for (int i = 0; i < strings.length; i++) {
if (args[i] instanceof ServletRequest || args[i] instanceof ServletResponse || args[i] instanceof MultipartFile ||
args[i] instanceof BindingResult) {
//ServletRequest不能序列化,从入参里排除,否则报异常:java.lang.IllegalStateException: It is illegal to call this method if the current request is not in asynchronous mode (i.e. isAsyncStarted() returns false)
//ServletResponse不能序列化 从入参里排除,否则报异常:java.lang.IllegalStateException: getOutputStream() has already been called for this response
continue;
}
if (strings[i]!=null&&args[i]!=null) {
map.put(strings[i], args[i]);
}
}
param = JSON.toJSONString(map);
} else {
param = JSON.toJSONString(args);
}
}
} catch (Exception e) {
log.info("参数无法序列化为JSON");
return "参数无法序列化为JSON";
}
return param;
}
}
package com.ziku.mall.aspect;
import com.ziku.mall.entity.MallSysLogWithBLOBs;
import com.ziku.mall.mapper.MallSysLogMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
/**
* @Description:
* @Author: wangxuqiang
* @Date: Created in 2018/9/29
* @Version: 1.0
*/
@Slf4j
@Component
public class LogService {
@Autowired
private MallSysLogMapper mallSysLogMapper;
@Async
public void asyncSaveSysLog(MallSysLogWithBLOBs sysLog) {
try {
mallSysLogMapper.insertSelective(sysLog);
} catch (Exception e) {
log.error("[小程序]日志保存失败:{}",e.getMessage());
}
}
}