1.自定义注解
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author LWL
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Log {
String value() default "";
int type() default 0;
}
package com.guangyi.project.entity.system_set;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.Id;
import java.io.Serializable;
import java.util.Date;
/**
* {@code 功能描述 Log实体}
* @author LWL
* @since 2021-07-06 14:12:15
* @version 1.0
*/
@Data
@NoArgsConstructor
public class Log implements Serializable {
private static final long serialVersionUID = 1L;
/**
* {@code 功能描述: id}
*/
@Id
private Long id;
/**
* {@code 功能描述: 用户id}
*/
private Long userId;
/**
* {@code 功能描述: 描述}
*/
private String description;
/**
* {@code 功能描述: 异常详细}
*/
private String exceptionDetail;
/**
* {@code 功能描述: 日志类型}
*/
private String logType;
/**
* {@code 功能描述: 方法名}
*/
private String method;
/**
* {@code 功能描述: 参数}
*/
private String params;
/**
* {@code 功能描述: 请求ip}
*/
private String requestIp;
/**
* {@code 功能描述: 请求耗时}
*/
private Long time;
/**
* {@code 功能描述: 用户名}
*/
private String username;
/**
* {@code 功能描述: 地址}
*/
private String address;
/**
* {@code 功能描述: 浏览器}
*/
private String browser;
/**
* {@code 功能描述: }
*/
private Integer type;
/**
* {@code 功能描述: 是否删除}
*/
private Integer isDel;
/**
* {@code 功能描述: }
*/
private Date createdate;
/**
* {@code 功能描述: }
*/
private String createuser;
/**
* {@code 功能描述: }
*/
private Date changedate;
/**
* {@code 功能描述: }
*/
private String changeuser;
public Log(String logType, Long time) {
this.logType = logType;
this.time = time;
}
}
2.配置环绕通知和异常通知
package com.guangyi.project.aspect;
import com.guangyi.project.entity.system_set.Log;
import com.guangyi.project.security.SecurityUserDetails;
import com.guangyi.project.service.LogService;
import com.guangyi.project.utils.RequestHolder;
import com.guangyi.project.utils.StringUtils;
import com.guangyi.project.utils.ThrowableUtil;
import com.guangyi.project.utils.UserUtil;
import eu.bitwalker.useragentutils.Browser;
import eu.bitwalker.useragentutils.UserAgent;
import lombok.extern.slf4j.Slf4j;
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.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
/**
* @author LWL
*/
@Component
@Aspect
@Slf4j
public class LogAspect {
@Autowired
private LogService logService;
ThreadLocal<Long> currentTime = new ThreadLocal<>();
/**
* 配置切入点
*/
@Pointcut("@annotation(com.guangyi.project.config.Log)")
public void logPointcut() {
// 该方法无方法体,主要为了让同类中其他方法使用此切入点
}
/**
* 配置环绕通知,使用在方法logPointcut()上注册的切入点
*
* @param joinPoint join point for advice
*/
@Around("logPointcut()")
public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
Object result;
currentTime.set(System.currentTimeMillis());
result = joinPoint.proceed();
Log log = new Log("INFO", System.currentTimeMillis() - currentTime.get());
currentTime.remove();
HttpServletRequest request = RequestHolder.getHttpServletRequest();
//获取当前登录用户信息
SecurityUserDetails loginUser = UserUtil.getLoginUser(request);
//获取浏览器信息
String ua = request.getHeader("User-Agent");
//转成UserAgent对象
UserAgent userAgent = UserAgent.parseUserAgentString(ua);
//获取浏览器信息
Browser browser = userAgent.getBrowser();
//浏览器名称
String browserName = browser.getName();
log.setBrowser(browserName);
logService.save(loginUser.getUsername(),
StringUtils.getIp(request), joinPoint,
log, loginUser.getId());
return result;
}
/**
* 配置异常通知
*
* @param joinPoint join point for advice
* @param e exception
*/
@AfterThrowing(pointcut = "logPointcut()", throwing = "e")
public void logAfterThrowing(JoinPoint joinPoint, Throwable e) {
Log log = new Log("ERROR", System.currentTimeMillis() - currentTime.get());
currentTime.remove();
log.setExceptionDetail(ThrowableUtil.getStackTrace(e));
HttpServletRequest request = RequestHolder.getHttpServletRequest();
SecurityUserDetails loginUser = UserUtil.getLoginUser(request);
//获取浏览器信息
String ua = request.getHeader("User-Agent");
//转成UserAgent对象
UserAgent userAgent = UserAgent.parseUserAgentString(ua);
//获取浏览器信息
Browser browser = userAgent.getBrowser();
//浏览器名称
String browserName = browser.getName();
log.setBrowser(browserName);
logService.save(loginUser.getUsername(),
StringUtils.getIp(request),
(ProceedingJoinPoint) joinPoint, log, loginUser.getId());
}
}
RequestHolder
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.util.Objects;
/**
* 获取 HttpServletRequest
* @author LWL
* @date 2018-11-24
*/
public class RequestHolder {
public static HttpServletRequest getHttpServletRequest() {
return ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
}
}
import java.io.PrintWriter;
import java.io.StringWriter;
/**
* 异常工具 2021-07-06
* @author LWL
*/
public class ThrowableUtil {
/**
* 获取堆栈信息
*/
public static String getStackTrace(Throwable throwable) {
StringWriter sw = new StringWriter();
try (PrintWriter pw = new PrintWriter(sw)) {
throwable.printStackTrace(pw);
return sw.toString();
}
}
}
3.service
package com.guangyi.project.service;
import com.guangyi.project.entity.system_set.Log;
import com.guangyi.project.model.system.MessageBean;
import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.scheduling.annotation.Async;
import javax.servlet.http.HttpServletRequest;
import java.util.Map;
/**
* {@code 功能描述: Log的service层}
* @author LWL
* @since 2021-07-02 11:35:38
* @version 1.0
*/
public interface LogService {
/**
* 保存日志数据
* @param username 用户
* @param browser 浏览器
* @param ip 请求IP
* @param joinPoint /
* @param log 日志实体
*/
@Async
void save(String username, String ip, ProceedingJoinPoint joinPoint, Log log, Long uid);
/**
* @description: 操作日志
* @param httpServletRequest
* @param map
* @return: com.guangyi.project.model.system.MessageBean
* @author: LWL
* @time: 2021/7/6 16:25
*/
MessageBean operateLog(HttpServletRequest httpServletRequest, Map<String, Object> map);
}
package com.guangyi.project.service.impl;
import cn.hutool.json.JSONObject;
import com.guangyi.project.config.ErrorEnum;
import com.guangyi.project.entity.system_set.Admin;
import com.guangyi.project.entity.system_set.Log;
import com.guangyi.project.entity.user.Baseuser;
import com.guangyi.project.mapper.system_set.AdminMapper;
import com.guangyi.project.mapper.system_set.LogMapper;
import com.guangyi.project.mapper.user.BaseuserMapper;
import com.guangyi.project.model.querydo.LogDO;
import com.guangyi.project.model.system.MessageBean;
import com.guangyi.project.security.SecurityUserDetails;
import com.guangyi.project.service.LogService;
import com.guangyi.project.service.PkSequenceService;
import com.guangyi.project.utils.ErrorInfoUtil;
import com.guangyi.project.utils.ExceptionFormatUtil;
import com.guangyi.project.utils.StringUtils;
import com.guangyi.project.utils.UserUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.List;
import java.util.Map;
@Service
public class LogServiceImpl extends BaseService implements LogService {
private Logger logger = LoggerFactory.getLogger(this.getClass());
@Resource
private LogMapper logMapper;
@Resource
private PkSequenceService pkSequenceService;
@Resource
private AdminMapper adminMapper;
@Resource
private BaseuserMapper baseuserMapper;
@Override
@Transactional(rollbackFor = Exception.class)
public void save(String username, String ip, ProceedingJoinPoint joinPoint, Log log, Long uid) {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
com.guangyi.project.config.Log aopLog = method.getAnnotation(com.guangyi.project.config.Log.class);
// 方法路径
String methodName = joinPoint.getTarget().getClass().getName() + "." + signature.getName() + "()";
StringBuilder params = new StringBuilder("{");
//参数值
Object[] argValues = joinPoint.getArgs();
//参数名称
String[] argNames = ((MethodSignature) joinPoint.getSignature()).getParameterNames();
if (argValues != null && argValues.length>1) {
for (int i = 1; i < argValues.length; i++) {
params.append(" ").append(argNames[i]).append(": ").append(argValues[i]);
}
}else {
params.append("无参数");
}
// 描述
if (log != null) {
log.setDescription(aopLog.value());
}
//类型 0-后台 1-APP
log.setType(aopLog.type());
if (uid != null) {
log.setUserId(uid);
}
assert log != null;
log.setRequestIp(ip);
String loginPath = "login";
if (loginPath.equals(signature.getName())) {
try {
assert argValues != null;
username = new JSONObject(argValues[0]).get("username").toString();
} catch (Exception e) {
e.printStackTrace();
}
}
log.setAddress(StringUtils.getCityInfo(log.getRequestIp()));
log.setMethod(methodName);
log.setUsername(username);
log.setParams(params.toString() + " }");
Long maxId = pkSequenceService.getMaxIdByTableName("log");
log.setId(maxId);
log.setChangedate(new Date());
log.setCreatedate(new Date());
log.setChangeuser(username);
log.setCreateuser(username);
log.setIsDel(0);
logMapper.save(log);
}
@Override
public MessageBean operateLog(HttpServletRequest httpServletRequest, Map<String, Object> map) {
MessageBean result = new MessageBean();
SecurityUserDetails loginUser = UserUtil.getLoginUser(httpServletRequest);
try {
long count = logMapper.count(map);
List<LogDO> list = logMapper.list(map);
if (!CollectionUtils.isEmpty(list)){
list.forEach(x->{
if (x.getType()==0){
Admin admin = adminMapper.selectByPrimaryKey(x.getUserId());
x.setRealName(admin.getRealName());
x.setUsername(admin.getMobile());
}else {
Baseuser baseuser = baseuserMapper.selectByPrimaryKey(x.getUserId());
x.setRealName(baseuser.getNickname());
x.setUsername(baseuser.getMobile());
}
});
}
result.setData(list);
result.setTotal(count);
result.setToken(loginUser.getToken());
}catch (Exception e){
logger.error(ErrorInfoUtil.getErrorInfo(e));
throw ExceptionFormatUtil.formatException(e, ErrorEnum.GETINFO_ERROR);
}
return result;
}
}
4.在接口上使用定义的注解
5.表结构
CREATE TABLE `log` (
`id` bigint(20) NOT NULL COMMENT 'id',
`user_id` bigint(20) DEFAULT NULL COMMENT '用户id',
`description` varchar(255) DEFAULT NULL COMMENT '描述',
`exception_detail` text COMMENT '异常详细',
`log_type` varchar(255) DEFAULT '' COMMENT '日志类型',
`method` varchar(255) DEFAULT NULL COMMENT '方法名',
`params` text COMMENT '参数',
`request_ip` varchar(255) DEFAULT NULL COMMENT '请求ip',
`time` bigint(20) DEFAULT NULL COMMENT '请求耗时',
`username` varchar(255) DEFAULT NULL COMMENT '用户名',
`address` varchar(255) DEFAULT NULL COMMENT '地址',
`browser` varchar(255) DEFAULT NULL COMMENT '浏览器',
`type` smallint(6) DEFAULT '0',
`is_del` smallint(1) DEFAULT '0' COMMENT '是否删除',
`createdate` datetime NOT NULL,
`createuser` varchar(100) NOT NULL,
`changedate` datetime NOT NULL,
`changeuser` varchar(100) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
查看操作日志
查看异常日志
查看报错信息