一、创建日志表,表结构如下:
image.png二、添加Maven依赖
<!-- aop日志开始-->
<!--hutool工具-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>[4.1.12,)</version>
</dependency>
<!--获取浏览器信息工具-->
<dependency>
<groupId>eu.bitwalker</groupId>
<artifactId>UserAgentUtils</artifactId>
<version>1.20</version>
</dependency>
<!-- aop日志结束-->
<!--excel操作-->
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-spring-boot-starter</artifactId>
<version>3.3.0</version>
</dependency>
<!--aop-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
三、日志实体类
package io.agilefast.modules.oa.entity;
import cn.afterturn.easypoi.excel.annotation.Excel;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
/**
* 日志表
*/
@Data
@TableName("XT_LOG")
public class XtLogEntity implements Serializable {
private static final long serialVersionUID = 1L;
@TableId
private String id;
/**
* 操作模块
*/
@Excel(name = "操作模块")
private String operMudel;
/**
* 异常详情
*/
@Excel(name = "异常详情")
private String exceptionDetail;
/**
* 操作类型
*/
@Excel(name = "操作类型")
private String logType;
/**
* 操作方法
*/
@Excel(name = "操作方法")
private String method;
/**
* 参数
*/
@Excel(name = "参数")
private String params;
/**
* 请求ip
*/
@Excel(name = "请求ip")
private String requestIp;
/**
* 请求URL
*/
@Excel(name = "请求URL")
private String requestUrl;
/**
* 操作员名称
*/
@Excel(name = "操作员名称")
private String username;
/**
* 地址
*/
private String address;
/**
* 浏览器
*/
@Excel(name = "浏览器")
private String browser;
/**
* 请求耗时
*/
@Excel(name = "请求耗时")
private Long time;
/**
* 操作时间
*/
@Excel(name = "操作时间",format = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
public XtLogEntity() {
super();
}
public XtLogEntity(String logType, Long time) {
this.logType = logType;
this.time = time;
}
}
四、日志注解类
package io.agilefast.modules.oa.annotion;
import java.lang.annotation.*;
/**
* 日志注解类
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Log {
String operModul() default "";
}
五、日志切面类
package io.agilefast.modules.oa.aop;
import cn.hutool.json.JSONObject;
import io.agilefast.common.shiro.ShiroUtils;
import io.agilefast.common.utils.R;
import io.agilefast.modules.oa.entity.XtLogEntity;
import io.agilefast.modules.oa.service.XtLogService;
import io.agilefast.modules.oa.utlils.RequestHolder;
import io.agilefast.modules.oa.utlils.StringUtils;
import io.agilefast.modules.oa.utlils.ThrowableUtil;
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;
@Component
@Aspect
@Slf4j
public class LogAspect {
@Autowired
private XtLogService xtLogService;
private long currentTime = 0L;
@Pointcut("@annotation(io.agilefast.modules.oa.annotion.Log)")
public void logPointcut(){ }
/**
* 配置环绕通知
* @param joinPoint
* @return
* @throws Throwable
*/
@Around("logPointcut()")
public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
Object result;
currentTime = System.currentTimeMillis();
result = joinPoint.proceed();
XtLogEntity log = new XtLogEntity("INFO",System.currentTimeMillis() - currentTime);
HttpServletRequest request = RequestHolder.getHttpServletRequest();
xtLogService.save(getUsername(),StringUtils.getBrowser(request),StringUtils.getIp(request),request.getRequestURI(),joinPoint,log);
// 获取增强方法返回值,并转换为原方法返回值类型
R r = (R) result;
return r;
}
/**
* 配置异常通知
* @param joinPoint
* @param e
*/
@AfterThrowing(pointcut = "logPointcut()",throwing = "e")
public void logAfterThrowing(JoinPoint joinPoint,Throwable e){
XtLogEntity log = new XtLogEntity("ERROR",System.currentTimeMillis() - currentTime);
log.setExceptionDetail(ThrowableUtil.stackTraceToString(e.getClass().getName(),e.getMessage(),e.getStackTrace()));
HttpServletRequest request = RequestHolder.getHttpServletRequest();
xtLogService.save(getUsername(),StringUtils.getBrowser(request),StringUtils.getIp(request),request.getRequestURI(), (ProceedingJoinPoint) joinPoint,log);
}
// 通过shiro获取登录名
private String getUsername(){
try{
return ShiroUtils.getUserEntity().getUserName();
}catch (Exception e){
return "";
}
}
}
六、辅助工具类
1.获取HttpServletRequest
package io.agilefast.modules.oa.utlils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.util.Objects;
public class RequestHolder {
public static HttpServletRequest getHttpServletRequest() {
return ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
}
}
2.获取ip、浏览器
package io.agilefast.modules.oa.utlils;
import cn.hutool.json.JSONObject;
import eu.bitwalker.useragentutils.Browser;
import eu.bitwalker.useragentutils.UserAgent;
import io.agilefast.common.shiro.ShiroUtils;
import javax.servlet.http.HttpServletRequest;
import java.net.InetAddress;
import java.net.UnknownHostException;
/**
* 字符串工具类
*/
public class StringUtils extends org.apache.commons.lang.StringUtils {
/**
* 获取浏览器名称
* @param request
* @return
*/
public static String getBrowser(HttpServletRequest request){
UserAgent userAgent = UserAgent.parseUserAgentString(request.getHeader("User-Agent"));
Browser browser = userAgent.getBrowser();
return browser.getName();
}
/**
* 获取ip
* @param request
* @return
*/
public static String getIp(HttpServletRequest request){
String ip = request.getHeader("x-forwarded-for");
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)){
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)){
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)){
ip = request.getRemoteAddr();
}
if (ip.contains(",")){
ip = ip.split(",")[0];
}
if ("127.0.0.1".equals(ip)){
try{
ip = InetAddress.getLocalHost().getHostAddress();
}catch (UnknownHostException e){
e.printStackTrace();
}
}
return ip;
}
}
3.接口返回工具类
package io.agilefast.common.utils;
import java.util.HashMap;
import java.util.Map;
/**
* 返回数据
*
* @author
* @email
* @date 2016年10月27日 下午9:59:27
*/
public class R extends HashMap<String, Object> {
private static final long serialVersionUID = 1L;
public R() {
put("code", 0);
put("msg", "success");
}
public static R error() {
return error(500, "未知异常,请联系管理员");
}
public static R error(String msg) {
return error(500, msg);
}
public static R error(int code, String msg) {
R r = new R();
r.put("code", code);
r.put("msg", msg);
return r;
}
public static R ok(String msg) {
R r = new R();
r.put("msg", msg);
return r;
}
public static R ok(Map<String, Object> map) {
R r = new R();
r.putAll(map);
return r;
}
public static R ok() {
return new R();
}
@Override
public R put(String key, Object value) {
super.put(key, value);
return this;
}
}
4.异常工具类
package io.agilefast.modules.oa.utlils;
import javax.validation.ConstraintViolationException;
import java.io.PrintWriter;
import java.io.StringWriter;
/**
* 异常工具
*/
public class ThrowableUtil {
/**
* 转换异常信息为字符串
*
* @param exceptionName 异常名称
* @param exceptionMessage 异常信息
* @param elements 堆栈信息
*/
public static String stackTraceToString(String exceptionName, String exceptionMessage, StackTraceElement[] elements) {
StringBuffer strbuff = new StringBuffer();
for (StackTraceElement stet : elements) {
strbuff.append(stet + "\n");
}
String message = exceptionName + ":" + exceptionMessage + "\n\t" + strbuff.toString();
return message;
}
}
七、日志serviceImpl,mybatis-plus作为持久层
package io.agilefast.modules.oa.service.impl;
import cn.hutool.core.util.IdUtil;
import cn.hutool.json.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import io.agilefast.common.utils.PageUtils;
import io.agilefast.common.utils.Query;
import io.agilefast.modules.oa.annotion.Log;
import io.agilefast.modules.oa.dao.XtLogDao;
import io.agilefast.modules.oa.entity.XtLogEntity;
import io.agilefast.modules.oa.service.XtLogService;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.service.impl.*;
import org.springframework.transaction.annotation.Transactional;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.Map;
@Service("xtLogService")
public class XtLogServiceImpl extends ServiceImpl<XtLogDao, XtLogEntity> implements XtLogService{
private final XtLogDao xtLogDao;
public XtLogServiceImpl(XtLogDao xtLogDao) {
this.xtLogDao = xtLogDao;
}
@Override
@Transactional(rollbackFor = Exception.class)
public void save(String username, String browser, String ip, String url, ProceedingJoinPoint joinPoint, XtLogEntity xtLogEntity) {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
Log aopLog = method.getAnnotation(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){
for (int i = 0; i < argValues.length; i++) {
params.append(" ").append(argNames[i]).append(": ").append(argValues[i]);
}
}
// 操作模块
if (xtLogEntity != null){
xtLogEntity.setOperMudel(aopLog.operModul());
}
assert xtLogEntity != null;
xtLogEntity.setRequestIp(ip);
String LOGINPATH = "login";
if (LOGINPATH.equals(signature.getName())){
try{
assert argValues != null;
// hutool json
// username = new JSONObject(argValues[0]).get("username").toString();
}catch (Exception e){
e.printStackTrace();
}
}
xtLogEntity.setAddress("");// 根据ip获取城市地址
xtLogEntity.setMethod(methodName);
xtLogEntity.setUsername(username);
xtLogEntity.setParams(params.toString() + " }");
xtLogEntity.setBrowser(browser);
xtLogEntity.setId(IdUtil.randomUUID());
xtLogEntity.setCreateTime(new Date());
xtLogEntity.setRequestUrl(url);
this.save(xtLogEntity);
}
@Override
public PageUtils getLogList(Map<String, Object> params) {
IPage<XtLogEntity> page = xtLogDao.getLogList(new Query<XtLogEntity>(params).getPage(), params);
return new PageUtils(page);
}
}
八、日志restController方法添加@Log注解
package io.agilefast.modules.oa.controller;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import io.agilefast.common.base.AbstractController;
import io.agilefast.common.config.SiteConfig;
import io.agilefast.common.utils.ModelAndViewFactory;
import io.agilefast.common.utils.PageUtils;
import io.agilefast.common.utils.R;
import io.agilefast.modules.oa.annotion.Log;
import io.agilefast.modules.oa.entity.XtLogEntity;
import io.agilefast.modules.oa.entity.vo.JtScheduleVO;
import io.agilefast.modules.oa.service.XtLogService;
import io.agilefast.util.ExcelUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@RestController
@RequestMapping("/xtLog")
public class XtLogController extends AbstractController {
private final SiteConfig siteConfig;
private final XtLogService xtLogService;
public XtLogController(SiteConfig siteConfig, XtLogService xtLogService) {
this.siteConfig = siteConfig;
this.xtLogService = xtLogService;
}
// 日志列表分页查询
@RequestMapping("/logList/{pageNum}/{pageSize}")
public R logList(@RequestBody Map<String,Object> params, @PathVariable("pageNum") int pageNum, @PathVariable("pageSize") int pageSize){
params.put("Page", String.valueOf(pageNum));
params.put("limit", String.valueOf(pageSize));
PageUtils page = xtLogService.getLogList(params);
return R.ok().put("page",page);
}
// 清空日志
@Log(operModul="日志管理-清空日志")
@RequestMapping("/clearLog/{logType}")
public R logList(@PathVariable("logType") String logType){
List<XtLogEntity> logList = xtLogService.list(new QueryWrapper<XtLogEntity>().eq("LOG_TYPE",logType));
if (logList.size() != 0){
xtLogService.removeByIds(logList.stream().map(log -> log.getId()).collect(Collectors.toList()));
}
return R.ok("清空成功");
}
// 导出日志
@Log(operModul="日志管理-导出日志")
@RequestMapping("/exportLog/{logType}")
public void exportLog( @PathVariable("logType") String logType, HttpServletResponse response){
List<XtLogEntity> logList = xtLogService.list(new QueryWrapper<XtLogEntity>().eq("LOG_TYPE",logType));
String title = "";
if ("INFO".equals(logType)){
title = "操作日志";
}else if("ERROR".equals(logType)){
title = "异常日志";
}
try{
ExcelUtils.exportExcel(logList, title, title, XtLogEntity.class, title, response);
}catch (IOException e){
e.printStackTrace();
}
}
}
九、操作日志、异常日志查询功能
image.pngimage.png
image.png
image.png
image.png
网友评论