栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

springboot集成系统操作日志超详细

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

springboot集成系统操作日志超详细

我使用的是springboot框架,写系统日志之前需要先引入pom依赖:

		
            org.springframework.boot
            spring-boot-starter-aop
        

 

1.日志表 (我使用的时postgre,其他数据库需要修改脚本)

-- public.sys_log definition

-- Drop table

-- DROP TABLE sys_log;

CREATE TABLE sys_log (
	id varchar(38) NOT NULL,
	username varchar(30) NOT NULL,
	"method" varchar(255) NULL, -- 方法名
	params varchar(1000) NULL, -- 参数
	ip varchar(20) NULL,
	create_date timestamp(0) NULL,
	"type" varchar(20) NULL, -- 类型 : 查询、新增等等
	model varchar(50) NULL, -- 模块
	"result" varchar(50) NULL, -- 操作结果
	description varchar(255) NULL,
	url varchar(400) NULL, -- 请求url
	ConSTRAINT log_pk PRIMARY KEY (id)
);

-- Column comments

COMMENT ON COLUMN public.sys_log."method" IS '方法名';
COMMENT ON COLUMN public.sys_log.params IS '参数';
COMMENT ON COLUMN public.sys_log."type" IS '类型 : 查询、新增等等';
COMMENT ON COLUMN public.sys_log.model IS '模块';
COMMENT ON COLUMN public.sys_log."result" IS '操作结果';
COMMENT ON COLUMN public.sys_log.url IS '请求url';

2. 日志实体


import java.util.Date;

import javax.persistence.*;

import lombok.Data;

@Data
@Table(name = "sys_log")
public class SysLog {
    
    @Id
    private String id;

    @Column(name = "username")
    private String username; //用户名

    @Column(name = "method")
    private String method; //方法名

    @Column(name = "params")
    private String params; //参数

    @Column(name = "ip")
    private String ip; //ip地址
    
    @Column(name = "url")
    private String url; //请求url
    
    @Column(name = "type")
    private String type; //操作类型 :新增、删除等等
    
    @Column(name = "model")
    private String model; //模块

    @Column(name = "create_date")
    private Date createDate; //操作时间
    
    @Column(name = "result")
    private String result; //操作结果
    
    @Column(name = "description")
    private String description;//描述
    
}

3. dao (继承了tk.mapper中的Mymapper,所以没有写插入日志方法),因没有业务相关代码,所以没有写service以及的impl

import org.springframework.stereotype.Repository;

import com.album.manager.pojo.SysLog;

import tk.mapper.MyMapper;

@Repository
public interface LogMapper extends MyMapper{
}

4. 自定义注解类(用于拦截操作方法并插入日志)

import java.lang.annotation.documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;


@Target(ElementType.METHOD)//注解放置的目标位置即方法级别
@Retention(RetentionPolicy.RUNTIME)//注解在哪个阶段执行
@documented
public @interface SysLogAnnotation {
    String operModul() default ""; // 操作模块

    String operType() default "";  // 操作类型

    String operDesc() default "";  // 操作说明
}

5. AOP拦截插入日志类:

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
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.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;

import com.album.manager.common.utils.IPUtils;
import com.album.manager.common.utils.SysLogAnnotation;
import com.album.manager.dao.LogMapper;
import com.album.manager.pojo.SysLog;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

import cn.hutool.core.lang.id.NanoId;
import lombok.extern.slf4j.Slf4j;

import javax.servlet.http.HttpServletRequest;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;


@Aspect
@Component
@Slf4j
public class SysLogAspect {
    @Autowired
    LogMapper logDao;

    
    @Pointcut("@annotation(com.album.manager.common.utils.SysLogAnnotation)") 
    public void operLogPoinCut() {
    }

    
    @AfterReturning(returning = "result", value = "operLogPoinCut()")
    public void saveOperLog(JoinPoint joinPoint, Object result) throws Throwable {
        // 获取RequestAttributes
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        // 从获取RequestAttributes中获取HttpServletRequest的信息
        HttpServletRequest request = (HttpServletRequest) requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST);
        try {
            SysLog sysLog = new SysLog();
            // 从切面织入点处通过反射机制获取织入点处的方法
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            //获取切入点所在的方法
            Method method = signature.getMethod();
            //获取操作
            SysLogAnnotation annotation = method.getAnnotation(SysLogAnnotation.class);
            if (annotation != null) {
                sysLog.setModel(annotation.operModul());
                sysLog.setType(annotation.operType());
                sysLog.setDescription(annotation.operDesc());
            }
            
            // 获取请求的类名
            String className = joinPoint.getTarget().getClass().getName();
            // 获取请求的方法名
            String methodName = method.getName();
            methodName = className + "." + methodName;
            sysLog.setMethod(methodName); // 类名.请求方法
            
            sysLog.setCreateDate(new Date()); //操作时间
            //操作用户 --登录时有把用户的信息保存在session中,可以直接取出
            String user = (String)request.getSession().getAttribute("user");
            sysLog.setUsername(user);
            
            sysLog.setIp(IPUtils.getIpAddr(request)); //操作IP IPUtils工具类网上大把的,比如工具类集锦的hutool.jar
            sysLog.setUrl(request.getRequestURI()); // 请求URI
            
            // 方法请求的参数
            Map rtnMap = converMap(request.getParameterMap());
            // 将参数所在的数组转换成json
            String params = JSON.toJSonString(rtnMap);
            //获取json的请求参数
            if (rtnMap == null || rtnMap.size() == 0) {
                params = getJsonStrByRequest(request);
            }
            sysLog.setParams(params); // 请求参数
            Map  dataResult = (Map )result;  //返回值信息
            //需要先判断返回值是不是Map ,如果不是會拋異常,需要控制层的接口返回数据格式统一
            //如果嫌返回格式统一太麻烦建议日志保存时去掉操作结果
        	sysLog.setResult(dataResult.get("msg").toString()); //獲取方法返回值中的msg,如果上面的類型錯誤就拿不到msg就會拋異常
          
            //保存日志
            sysLog.setId(NanoId.randomNanoId());
            logDao.insert(sysLog);

        } catch (Exception e) {
            e.printStackTrace();
            log.error("日誌記錄異常,請檢查返回值是否是Map 類型");
        }
    }
    
    
    public Map converMap(Map paramMap) {
        Map rtnMap = new HashMap();
        for (String key : paramMap.keySet()) {
            rtnMap.put(key, paramMap.get(key)[0]);
        }
        return rtnMap;
    }
    
    
    public String getJsonStrByRequest(HttpServletRequest request) {
        String param = null;
        try {
            BufferedReader streamReader = new BufferedReader(new InputStreamReader(request.getInputStream(), "UTF-8"));
            StringBuilder responseStrBuilder = new StringBuilder();
            String inputStr;
            while ((inputStr = streamReader.readLine()) != null) {
                responseStrBuilder.append(inputStr);
            }

            JSonObject jsonObject = JSONObject.parseObject(responseStrBuilder.toString());
            param = jsonObject.toJSonString();
            System.out.println(param);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return param;
    }
    

    
    public String stackTraceToString(String exceptionName, String exceptionMessage, StackTraceElement[] elements) {
        StringBuffer strbuff = new StringBuffer();
        for (StackTraceElement stet : elements) {
            strbuff.append(stet + "n");
        }
        String message = exceptionName + ":" + exceptionMessage + "nt" + strbuff.toString();
        return message;
    }

}

6. Controller层接口(也是操作被拦截的地方):

 @RequestMapping(value = "/setUser", method = RequestMethod.POST)
 @ResponseBody
 @SysLogAnnotation(operModul = "系统管理>>用户管理", operType = "新增", operDesc = "新增用户")
    public Map setUser(baseAdminUser user) {
        Map data = new HashMap();
        if(user.getId().isBlank()){
            data = adminUserService.addUser(user);
        }
        return data;
    }
7. 特别特别特别需要注意,如果系统日志中需要插入操作结果,那么就一定需要统一返回格式,比如上面代码中返回结果 Map data = new HashMap(),service代码:
@Transactional(rollbackFor = Exception.class)
    public Map addUser(baseAdminUser user) {
        Map data = new HashMap();
        try {
            baseAdminUser old = baseAdminUserMapper.getUserByUserName(user.getSysUserName(),null);
            if(old != null){
                data.put("code",0);
                data.put("msg","用户名已存在!");
                log.error("用户[新增],结果=用户名已存在!");
                return data;
            }
            String phone = user.getUserPhone();
            if(phone.length() != 11){
                data.put("code",0);
                data.put("msg","手机号位数不对!");
                log.error("设置用户[新增或更新],结果=手机号位数不对!");
                return data;
            }
            String username = user.getSysUserName();
            if(user.getSysUserPwd() == null){
                String password = DigestUtils.Md5(username,"123456");
                user.setSysUserPwd(password);
            }else{
                String password = DigestUtils.Md5(username,user.getSysUserPwd());
                user.setSysUserPwd(password);
            }
            user.setRegTime(DateUtils.getCurrentDate());
            user.setUserStatus(1);
            user.setId(UUID.randomUUID().toString());
            int result = baseAdminUserMapper.insert(user);
            if(result == 0){
                data.put("code",0);
                data.put("msg","新增失败!");
                log.error("用户[新增],结果=新增失败!");
                return data;
            }
        	data.put("code",1);
        	data.put("msg","新增成功!");
        	log.info("用户[新增],结果=新增成功!");
        } catch (Exception e) {
            e.printStackTrace();
            data.put("code",0);
            data.put("msg","新增异常失败!");
            log.error("用户[新增]异常!", e);
            TransactionAspectSupport.currentTransactionStatus().setRollbackonly();//捕捉的异常需要手动回滚
        }
        return data;
    }

上面service代码中返回的map格式定义有没有code都可以,视页面处理而定,如果系统操作日志需要保存结果,那么这个msg就必须要有,步骤5中的 AOP拦截插入日志类中获取操作结果时获取的就是map中的msg

分享个工具类jar 的依赖(官网:Hutool参考文档 , API文档:hutool-码云(gitee.com)):


    cn.hutool
    hutool-all
    5.7.19

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/704949.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号