新增操作日志

This commit is contained in:
马超 2021-02-08 12:15:32 +08:00
parent 67bfc145df
commit 6725ec2d79
13 changed files with 426 additions and 1 deletions

View File

@ -0,0 +1,61 @@
package com.qiwenshare.common.cbb;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.http.HttpServletRequest;
import java.net.InetAddress;
import java.net.UnknownHostException;
/**
* 通信工具类
*
* @author ma116
*/
public class CollectUtil {
private static final Logger LOG = LoggerFactory.getLogger(CollectUtil.class);
/**
* java 后台获取访问客户端ip地址
*
* @param request HttpServletRequest请求
* @return IP地址
*/
public String getClientIpAddress(HttpServletRequest request) {
String clientIp = request.getHeader("x-forwarded-for");
if (clientIp == null || clientIp.length() == 0
|| "unknown".equalsIgnoreCase(clientIp)) {
clientIp = request.getHeader("Proxy-Client-IP");
}
if (clientIp == null || clientIp.length() == 0
|| "unknown".equalsIgnoreCase(clientIp)) {
clientIp = request.getHeader("WL-Proxy-Client-IP");
}
if (clientIp == null || clientIp.length() == 0
|| "unknown".equalsIgnoreCase(clientIp)) {
clientIp = request.getRemoteAddr();
}
return clientIp;
}
/**
* 获取本地IP
*
* @return IP地址
*/
public String getLocalIp() {
InetAddress addr = null;
String ip = "";
try {
addr = InetAddress.getLocalHost();
} catch (UnknownHostException e) {
LOG.error("获取本地IP失败");
}
if (addr != null) {
ip = addr.getHostAddress().toString();
}
return ip;
}
}

View File

@ -0,0 +1,19 @@
package com.qiwenshare.file.anno;
import java.lang.annotation.*;
/**
* 自定义注解类
*/
@Target(ElementType.METHOD) //注解放置的目标位置,METHOD是可注解在方法级别上
@Retention(RetentionPolicy.RUNTIME) //注解在哪个阶段执行
@Documented //生成文档
public @interface MyLog {
String module() default "";
String operation() default "";
String type() default "operation";
String level() default "0"; //0-1-2-
}

View File

@ -0,0 +1,116 @@
package com.qiwenshare.file.aop;
import com.qiwenshare.common.cbb.RestResult;
import com.qiwenshare.file.anno.MyLog;
import com.qiwenshare.file.api.IOperationLogService;
import com.qiwenshare.file.api.IUserService;
import com.qiwenshare.file.domain.UserBean;
import com.qiwenshare.file.util.OperationLogUtil;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.CodeSignature;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
/**
* 操作日志切面
*/
@Aspect
@Component
public class WebLogAcpect {
@Resource
IOperationLogService operationLogService;
@Resource
IUserService userService;
private String operation = "";
private String module = "";
private String token = "";
private HttpServletRequest request;
private Logger logger = LoggerFactory.getLogger(WebLogAcpect.class);
/**
* 定义切入点切入点为com.example.aop下的所有函数
*/
@Pointcut("@annotation(com.qiwenshare.file.anno.MyLog)")
public void webLog() {
}
/**
* 前置通知在连接点之前执行的通知
*
* @param joinPoint 切入点
*/
@Before("webLog()")
public void doBefore(JoinPoint joinPoint) {
//从切面织入点处通过反射机制获取织入点处的方法
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
//获取切入点所在的方法
Method method = signature.getMethod();
Map<String, Object> map = getNameAndValue(joinPoint);
//获取操作
MyLog myLog = method.getAnnotation(MyLog.class);
if (myLog != null) {
operation = myLog.operation();
module = myLog.module();
token = (String) map.get("token");
}
// 接收到请求记录请求内容
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
request = attributes.getRequest();
}
@AfterReturning(returning = "ret", pointcut = "webLog()")
public void doAfterReturning(Object ret) throws Throwable {
if (ret instanceof RestResult) {
boolean isSuccess = ((RestResult) ret).getSuccess();
String errorMessage = ((RestResult) ret).getMessage();
UserBean sessionUserBean = userService.getUserBeanByToken(token);
if (isSuccess) {
operationLogService.insertOperationLog(
OperationLogUtil.getOperationLogObj(request,sessionUserBean, "成功", module, operation, "操作成功"));
} else {
operationLogService.insertOperationLog(
OperationLogUtil.getOperationLogObj(request,sessionUserBean, "失败", module, operation, errorMessage));
}
}
}
/**
* 获取参数Map集合
* @param joinPoint
* @return
*/
Map<String, Object> getNameAndValue(JoinPoint joinPoint) {
Map<String, Object> param = new HashMap<>();
Object[] paramValues = joinPoint.getArgs();
String[] paramNames = ((CodeSignature)joinPoint.getSignature()).getParameterNames();
for (int i = 0; i < paramNames.length; i++) {
param.put(paramNames[i], paramValues[i]);
}
return param;
}
}

View File

@ -0,0 +1,17 @@
package com.qiwenshare.file.api;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.IService;
import com.qiwenshare.file.domain.OperationLogBean;
import java.util.List;
public interface IOperationLogService extends IService<OperationLogBean> {
IPage<OperationLogBean> selectOperationLogPage(Integer current, Integer size);
List<OperationLogBean> selectOperationLog();
void insertOperationLog(OperationLogBean operationlogBean);
}

View File

@ -10,6 +10,7 @@ import com.qiwenshare.common.operation.FileOperation;
import com.qiwenshare.common.oss.AliyunOSSRename;
import com.qiwenshare.common.util.FileUtil;
import com.qiwenshare.common.util.PathUtil;
import com.qiwenshare.file.anno.MyLog;
import com.qiwenshare.file.api.IFileService;
import com.qiwenshare.file.api.IRecoveryFileService;
import com.qiwenshare.file.api.IUserFileService;
@ -50,6 +51,8 @@ public class FileController {
QiwenFileConfig qiwenFileConfig;
public static Executor executor = Executors.newFixedThreadPool(20);
public static final String CURRENT_MODULE = "文件接口";
public static int COMPLETE_COUNT = 0;
public static long treeid = 0;
@ -57,6 +60,7 @@ public class FileController {
@Operation(summary = "创建文件", description = "目录(文件夹)的创建", tags = {"file"})
@RequestMapping(value = "/createfile", method = RequestMethod.POST)
@MyLog(operation = "创建文件", module = CURRENT_MODULE)
@ResponseBody
public RestResult<String> createFile(@RequestBody CreateFileDTO createFileDto, @RequestHeader("token") String token) {
if (!operationCheck(token).getSuccess()){
@ -84,6 +88,7 @@ public class FileController {
@Operation(summary = "文件重命名", description = "文件重命名", tags = {"file"})
@RequestMapping(value = "/renamefile", method = RequestMethod.POST)
@MyLog(operation = "文件重命名", module = CURRENT_MODULE)
@ResponseBody
public RestResult<String> renameFile(@RequestBody RenameFileDTO renameFileDto, @RequestHeader("token") String token) {
RestResult<String> restResult = new RestResult<>();
@ -190,6 +195,7 @@ public class FileController {
@Operation(summary = "批量删除文件", description = "批量删除文件", tags = {"file"})
@RequestMapping(value = "/batchdeletefile", method = RequestMethod.POST)
@MyLog(operation = "批量删除文件", module = CURRENT_MODULE)
@ResponseBody
public RestResult<String> deleteImageByIds(@RequestBody BatchDeleteFileDTO batchDeleteFileDto, @RequestHeader("token") String token) {
@ -216,6 +222,7 @@ public class FileController {
@Operation(summary = "删除文件", description = "可以删除文件或者目录", tags = {"file"})
@RequestMapping(value = "/deletefile", method = RequestMethod.POST)
@MyLog(operation = "删除文件", module = CURRENT_MODULE)
@ResponseBody
public RestResult deleteFile(@RequestBody DeleteFileDTO deleteFileDto, @RequestHeader("token") String token) {
@ -243,6 +250,7 @@ public class FileController {
@Operation(summary = "解压文件", description = "压缩功能为体验功能,目前持续优化中。", tags = {"file"})
@RequestMapping(value = "/unzipfile", method = RequestMethod.POST)
@MyLog(operation = "解压文件", module = CURRENT_MODULE)
@ResponseBody
public RestResult<String> unzipFile(@RequestBody UnzipFileDTO unzipFileDto, @RequestHeader("token") String token) {
@ -326,6 +334,7 @@ public class FileController {
@Operation(summary = "文件移动", description = "可以移动文件或者目录", tags = {"file"})
@RequestMapping(value = "/movefile", method = RequestMethod.POST)
@MyLog(operation = "文件移动", module = CURRENT_MODULE)
@ResponseBody
public RestResult<String> moveFile(@RequestBody MoveFileDTO moveFileDto, @RequestHeader("token") String token) {
@ -344,6 +353,7 @@ public class FileController {
@Operation(summary = "批量移动文件", description = "可以同时选择移动多个文件或者目录", tags = {"file"})
@RequestMapping(value = "/batchmovefile", method = RequestMethod.POST)
@MyLog(operation = "批量移动文件", module = CURRENT_MODULE)
@ResponseBody
public RestResult<String> batchMoveFile(@RequestBody BatchMoveFileDTO batchMoveFileDto, @RequestHeader("token") String token) {

View File

@ -3,6 +3,7 @@ package com.qiwenshare.file.controller;
import com.qiwenshare.common.cbb.DateUtil;
import com.qiwenshare.common.util.FileUtil;
import com.qiwenshare.common.cbb.RestResult;
import com.qiwenshare.file.anno.MyLog;
import com.qiwenshare.file.api.IFileService;
import com.qiwenshare.file.api.IFiletransferService;
import com.qiwenshare.file.api.IUserFileService;
@ -44,9 +45,11 @@ public class FiletransferController {
IUserService userService;
@Resource
IUserFileService userFileService;
public static final String CURRENT_MODULE = "文件传输接口";
@Operation(summary = "极速上传", description = "校验文件MD5判断文件是否存在如果存在直接上传成功并返回skipUpload=true如果不存在返回skipUpload=false需要再次调用该接口的POST方法", tags = {"filetransfer"})
@RequestMapping(value = "/uploadfile", method = RequestMethod.GET)
@MyLog(operation = "极速上传", module = CURRENT_MODULE)
@ResponseBody
public RestResult<UploadFileVo> uploadFileSpeed(HttpServletRequest request, UploadFileDTO uploadFileDto, @RequestHeader("token") String token) {
RestResult<UploadFileVo> restResult = new RestResult<UploadFileVo>();
@ -103,6 +106,7 @@ public class FiletransferController {
*/
@Operation(summary = "上传文件", description = "真正的上次文件接口", tags = {"filetransfer"})
@RequestMapping(value = "/uploadfile", method = RequestMethod.POST)
@MyLog(operation = "上传文件", module = CURRENT_MODULE)
@ResponseBody
public RestResult<UploadFileVo> uploadFile(HttpServletRequest request, UploadFileDTO uploadFileDto, @RequestHeader("token") String token) {
RestResult<UploadFileVo> restResult = new RestResult<>();

View File

@ -6,6 +6,7 @@ import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.qiwenshare.common.cbb.DateUtil;
import com.qiwenshare.common.cbb.RestResult;
import com.qiwenshare.common.util.PathUtil;
import com.qiwenshare.file.anno.MyLog;
import com.qiwenshare.file.api.IRecoveryFileService;
import com.qiwenshare.file.api.IUserFileService;
import com.qiwenshare.file.api.IUserService;
@ -35,9 +36,10 @@ public class RecoveryFileController {
IUserFileService userFileService;
@Resource
IUserService userService;
public static final String CURRENT_MODULE = "回收站文件接口";
@Operation(summary = "删除回收文件", description = "删除回收文件", tags = {"recoveryfile"})
@MyLog(operation = "删除回收文件", module = CURRENT_MODULE)
@RequestMapping(value = "/deleterecoveryfile", method = RequestMethod.POST)
@ResponseBody
public RestResult<String> deleteRecoveryFile(@RequestBody DeleteRecoveryFileDTO deleteRecoveryFileDTO, @RequestHeader("token") String token) {
@ -55,6 +57,7 @@ public class RecoveryFileController {
@Operation(summary = "批量删除回收文件", description = "批量删除回收文件", tags = {"recoveryfile"})
@RequestMapping(value = "/batchdelete", method = RequestMethod.POST)
@MyLog(operation = "批量删除回收文件", module = CURRENT_MODULE)
@ResponseBody
public RestResult<String> batchDeleteRecoveryFile(@RequestBody BatchDeleteRecoveryFileDTO batchDeleteRecoveryFileDTO, @RequestHeader("token") String token) {
RestResult<String> restResult = new RestResult<String>();
@ -86,6 +89,7 @@ public class RecoveryFileController {
@Operation(summary = "还原文件", description = "还原文件", tags = {"recoveryfile"})
@RequestMapping(value = "/restorefile", method = RequestMethod.POST)
@MyLog(operation = "还原文件", module = CURRENT_MODULE)
@ResponseBody
public RestResult restoreFile(RestoreFileDto restoreFileDto, @RequestHeader("token") String token) {
UserBean sessionUserBean = userService.getUserBeanByToken(token);

View File

@ -5,6 +5,7 @@ import com.alibaba.fastjson.JSON;
import com.qiwenshare.common.cbb.RestResult;
import com.qiwenshare.common.domain.AliyunOSS;
import com.qiwenshare.common.util.JjwtUtil;
import com.qiwenshare.file.anno.MyLog;
import com.qiwenshare.file.api.IUserService;
import com.qiwenshare.file.config.QiwenFileConfig;
import com.qiwenshare.file.domain.UserBean;
@ -52,6 +53,7 @@ public class UserController {
@Operation(summary = "用户注册", description = "注册账号", tags = {"user"})
@PostMapping(value = "/register")
@MyLog(operation = "用户注册", module = CURRENT_MODULE)
@ResponseBody
public RestResult<String> addUser(@RequestBody RegisterDTO registerDTO) {
RestResult<String> restResult = null;
@ -64,6 +66,7 @@ public class UserController {
@Operation(summary = "用户登录", description = "用户登录认证后才能进入系统", tags = {"user"})
@GetMapping("/login")
@MyLog(operation = "用户登录", module = CURRENT_MODULE)
@ResponseBody
public RestResult<UserLoginVo> userLogin(
@Parameter(description = "登录用户名") String username,

View File

@ -0,0 +1,73 @@
package com.qiwenshare.file.domain;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import javax.persistence.*;
/**
* 操作日志基础信息类
*
* @author ma116
*/
@Data
@Table(name = "operationlog")
@Entity
@TableName("operationlog")
public class OperationLogBean {
/**
* 操作日志id
*/
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@TableId(type = IdType.AUTO)
private long operationLogId;
/**
* 用户id
*/
private long userId;
/**
* 操作
*/
private String operation;
/**
* 操作对象
*/
private String operationObj;
/**
* 终端IP
*/
private String terminal;
/**
* 操作结果
*/
private String result;
/**
* 操作详情
*/
private String detail;
/**
* 操作源
*/
private String source;
/**
* 时间
*/
private String time;
/**
* 日志级别
*/
private String logLevel;
}

View File

@ -0,0 +1,14 @@
package com.qiwenshare.file.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.qiwenshare.file.domain.OperationLogBean;
import java.util.List;
public interface OperationLogMapper extends BaseMapper<OperationLogBean> {
List<OperationLogBean> selectOperationLog();
void insertOperationLog(OperationLogBean operationlogBean);
}

View File

@ -0,0 +1,42 @@
package com.qiwenshare.file.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qiwenshare.file.api.IOperationLogService;
import com.qiwenshare.file.domain.OperationLogBean;
import com.qiwenshare.file.mapper.OperationLogMapper;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
@Service
public class OperationLogService extends ServiceImpl<OperationLogMapper, OperationLogBean> implements IOperationLogService {
@Resource
OperationLogMapper operationLogMapper;
@Override
public IPage<OperationLogBean> selectOperationLogPage(Integer current, Integer size) {
IPage<OperationLogBean> page = new Page<>(current, size);
IPage<OperationLogBean> list = operationLogMapper.selectPage(page, null);
return list;
}
@Override
public List<OperationLogBean> selectOperationLog() {
List<OperationLogBean> result = operationLogMapper.selectOperationLog();
return result;
}
@Override
public void insertOperationLog(OperationLogBean operationlogBean) {
operationLogMapper.insertOperationLog(operationlogBean);
}
}

View File

@ -0,0 +1,43 @@
package com.qiwenshare.file.util;
import com.qiwenshare.common.cbb.CollectUtil;
import com.qiwenshare.common.cbb.DateUtil;
import com.qiwenshare.file.domain.OperationLogBean;
import com.qiwenshare.file.domain.UserBean;
import org.apache.shiro.SecurityUtils;
import javax.servlet.http.HttpServletRequest;
public class OperationLogUtil {
/**
* 构造操作日志参数
*
* @param request 请求
* @param isSuccess 操作是否成功成功/失败
* @param source 操作源模块
* @param operation 执行操作
* @param detail 详细信息
* @return 操作日志参数
*/
public static OperationLogBean getOperationLogObj(HttpServletRequest request, UserBean sessionUserBean, String isSuccess, String source, String operation, String detail) {
// UserBean sessionUserBean = (UserBean) SecurityUtils.getSubject().getPrincipal();
//用户需要登录才能进行的操作需要记录操作日志
long userId = 1;
if (sessionUserBean != null) {
userId = sessionUserBean.getUserId();
}
OperationLogBean operationLogBean = new OperationLogBean();
operationLogBean.setUserId(userId);
operationLogBean.setTime(DateUtil.getCurrentTime());
operationLogBean.setTerminal(new CollectUtil().getClientIpAddress(request));
operationLogBean.setSource(source);
operationLogBean.setResult(isSuccess);
operationLogBean.setOperation(operation);
operationLogBean.setDetail(detail);
return operationLogBean;
}
}

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.qiwenshare.file.mapper.OperationLogMapper">
<select id="selectOperationLog" resultType="com.qiwenshare.file.domain.OperationLogBean">
SELECT * FROM operationLog
</select>
<insert id="insertOperationLog" parameterType="com.qiwenshare.file.domain.OperationLogBean" useGeneratedKeys="true"
keyProperty="operationLogId">
INSERT INTO operationLog (operation, userId, terminal, result, detail, source, time, logLevel)
VALUES (#{operation}, #{userId}, #{terminal}, #{result}, #{detail}, #{source}, #{time}, #{logLevel});
</insert>
</mapper>