管理后台操作日志

后台操作日志

一、自定义注解

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface TitleName {
    String value() default "";

    int order() default 0;

    boolean primaryKey() default false;
}

二、日志解析工具类

public class WebOperatorLogUtil {
    /**
     * 新增模板
     * 样式:
     * XXX
     * [
     * aa:AA,
     * bb:BB,
     * cc:CC
     * ]
     */
    public static final String ADD_OPERATOR_LOG_TEMPLATE = "{}<br/>[<br/>{}<br/>]";

    /**
     * 修改模板
     * 样式:
     * XXX
     * [
     * aa:AA ==> FF,
     * bb:BB ==> GG,
     * cc:CC ==> HH
     * ]
     */
    public static final String UPDATE_OPERATOR_LOG_TEMPLATE = "{}<br/>[<br/>{}<br/>]";

    /**
     * 删除模板
     * 样式:
     * XXX
     * YY
     * [
     * A,
     * B,
     * C
     * ]
     */
    public static final String DELETE_OPERATOR_LOG_TEMPLATE = "{}<br/>{}<br/>[<br/>{}<br/>]";

    /**
     * 默认模板
     * 样式:
     * XXX
     * YY
     * [
     * aa: AA,
     * bb: BB
     * ]
     */
    public static final String DEFAULT_OPERATOR_LOG_TEMPLATE = "{}<br/>[<br/>{}<br/>]";

    /**
     * 返回新增操作日志
     *
     * @param desc
     * @param obj
     * @return
     */
    public static String getAddContent(String desc, Object obj) {
        Map<Integer, String> tempResultMap = new LinkedHashMap<>();
        String eleTemplate = "&nbsp;&nbsp;{}:&nbsp;&nbsp;{}";

        //1.读取注解上的值
        Field[] fields = ReflectUtil.getFields(obj.getClass());
        for (Field field : fields) {
            TitleName titleName = AnnotationUtil.getAnnotation(field, TitleName.class);
            if (titleName == null) {
                continue;
            }

            tempResultMap.put(titleName.order(), field.getName() + StrUtil.COLON + titleName.value());
        }

        //2.排序
        TreeMap<Integer, String> resultMap = CollUtil.sort(tempResultMap, new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o1 - o2;
            }
        });

        //3.拼接数据
        String titleName = "";
        String value = "";
        List<String> result = new ArrayList<>();
        for (Map.Entry<Integer, String> ele : resultMap.entrySet()) {
            String[] dataArray = StrUtil.split(ele.getValue(), StrUtil.COLON);

            titleName = dataArray[1];
            Object fieldValue = ReflectUtil.getFieldValue(obj, dataArray[0]);
            value = fieldValue + "";

            if (fieldValue instanceof Date) {
                value = DateUtil.format(((Date) fieldValue), DatePattern.NORM_DATETIME_PATTERN);
            }

            String eleResult = StrUtil.format(eleTemplate, titleName, value);
            result.add(eleResult);
        }

        return StrUtil.format(ADD_OPERATOR_LOG_TEMPLATE, desc, CollUtil.join(result, "<br/>"));
    }

    /**
     * 返回修改操作日志
     *
     * @param desc
     * @param srcObj
     * @param targetObj
     * @return
     */
    public static String getUpdateContent(String desc, Object srcObj, Object targetObj) {
        Map<Integer, String> tempResultMap = new LinkedHashMap<>();
        String eleTemplate = "&nbsp;&nbsp;{}:&nbsp;&nbsp;{} ==> {}";

        //1.读取注解上的值
        Field[] fields = ReflectUtil.getFields(srcObj.getClass());
        for (Field field : fields) {
            TitleName titleName = AnnotationUtil.getAnnotation(field, TitleName.class);
            if (titleName == null) {
                continue;
            }

            tempResultMap.put(titleName.order(), field.getName() + StrUtil.COLON + titleName.value() + StrUtil.COLON + titleName.primaryKey());
        }

        //2.排序
        TreeMap<Integer, String> resultMap = CollUtil.sort(tempResultMap, new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o1 - o2;
            }
        });

        //3.拼接数据
        String titleName = "";
        String srcValue = "";
        String targetValue = "";
        String primaryKey = "false";

        List<String> result = new ArrayList<>();
        for (Map.Entry<Integer, String> ele : resultMap.entrySet()) {
            String[] dataArray = StrUtil.split(ele.getValue(), StrUtil.COLON);

            titleName = dataArray[1];
            primaryKey = dataArray[2];

            Object srcFieldValue = ReflectUtil.getFieldValue(srcObj, dataArray[0]);
            Object targetFieldValue = ReflectUtil.getFieldValue(targetObj, dataArray[0]);

            srcValue = srcFieldValue + "";
            targetValue = targetFieldValue + "";

            //日期进行格式化显示处理
            if (srcFieldValue instanceof Date) {

                srcValue = DateUtil.format(((Date) srcFieldValue), DatePattern.NORM_DATETIME_PATTERN);
                targetValue = DateUtil.format(((Date) targetFieldValue), DatePattern.NORM_DATETIME_PATTERN);
            }

            //增加主键
            if (StrUtil.equals(primaryKey, "true")) {
                String eleResult = StrUtil.format(eleTemplate, titleName, srcValue, targetValue);
                result.add(eleResult);
            }


            //有更新的数据,突出显示
            if (!StrUtil.equals(srcValue, targetValue)) {
                targetValue = "<font color=\"red\">" + targetValue + "</font>";
                String eleResult = StrUtil.format(eleTemplate, titleName, srcValue, targetValue);
                result.add(eleResult);
            }

        }

        return StrUtil.format(UPDATE_OPERATOR_LOG_TEMPLATE, desc, CollUtil.join(result, "<br/>"));
    }

    /**
     * 返回删除日志
     *
     * @param desc
     * @param clazz
     * @param ids
     * @return
     */
    public static String getDeleteContent(String desc, Class clazz, int[] ids) {
        ArrayList<String> tempResult = new ArrayList<>();
        String eleTemplate = "&nbsp;&nbsp;{}";

        for (int id : ids) {
            tempResult.add(StrUtil.format(eleTemplate, id + ""));
        }

        //1.读取注解上的值
        List<String> primaryKeyTitles = new ArrayList<>();
        Field[] fields = ReflectUtil.getFields(clazz);
        for (Field field : fields) {
            TitleName titleName = AnnotationUtil.getAnnotation(field, TitleName.class);
            if (titleName == null) {
                continue;
            }

            if (titleName.primaryKey() == true) {
                primaryKeyTitles.add(titleName.value());
            }
        }


        return StrUtil.format(DELETE_OPERATOR_LOG_TEMPLATE, desc, CollUtil.join(primaryKeyTitles, StrUtil.COMMA), CollUtil.join(tempResult, "<br/>"));
    }

    /**
     * 返回删除日志
     *
     * @param desc
     * @param clazz
     * @param sids
     * @return
     */
    public static String getDeleteContent(String desc, Class clazz, String[] sids) {
        ArrayList<String> tempResult = new ArrayList<>();
        String eleTemplate = "&nbsp;&nbsp;{}";

        for (String id : sids) {
            tempResult.add(StrUtil.format(eleTemplate, id + ""));
        }

        //1.读取注解上的值
        List<String> primaryKeyTitles = new ArrayList<>();
        Field[] fields = ReflectUtil.getFields(clazz);
        for (Field field : fields) {
            TitleName titleName = AnnotationUtil.getAnnotation(field, TitleName.class);
            if (titleName == null) {
                continue;
            }

            if (titleName.primaryKey() == true) {
                primaryKeyTitles.add(titleName.value());
            }
        }


        return StrUtil.format(DELETE_OPERATOR_LOG_TEMPLATE, desc, CollUtil.join(primaryKeyTitles, StrUtil.COMMA), CollUtil.join(tempResult, "<br/>"));
    }

    /**
     * 联合主键返回删除日志
     * @param desc
     * @param clazz
     * @param sids
     * @param splitBit 分割字符
     * @return
     */
    public static String getDeleteContent2(String desc, Class clazz, String[] sids,String splitBit) {
        ArrayList<String> tempResult = new ArrayList<>();
        String eleTemplate = "&nbsp;&nbsp;{}";


        for (String sid : sids) {
            StringBuilder ids = new StringBuilder();
            String[] arr = sid.split(splitBit);
            for (String value : arr) {
                String s = value + StrUtil.COMMA;
                ids.append(s);
            }
            String scoreResult = ids.substring(0, ids.length() - 1);
            tempResult.add(StrUtil.format(eleTemplate, scoreResult + ""));
        }


        //1.读取注解上的值
        List<String> primaryKeyTitles = new ArrayList<>();
        Field[] fields = ReflectUtil.getFields(clazz);
        for (Field field : fields) {
            TitleName titleName = AnnotationUtil.getAnnotation(field, TitleName.class);
            if (titleName == null) {
                continue;
            }

            if (titleName.primaryKey()) {
                primaryKeyTitles.add(titleName.value());
            }
        }


        return StrUtil.format(DELETE_OPERATOR_LOG_TEMPLATE, desc, CollUtil.join(primaryKeyTitles, StrUtil.COMMA), CollUtil.join(tempResult, "<br/>"));
    }

    /**
     * 返回删除日志
     *
     * @param desc
     * @param clazz
     * @param lids
     * @return
     */
    public static String getDeleteContent(String desc, Class clazz, long[] lids) {
        ArrayList<String> tempResult = new ArrayList<>();
        String eleTemplate = "&nbsp;&nbsp;{}";

        for (long id : lids) {
            tempResult.add(StrUtil.format(eleTemplate, id + ""));
        }

        //1.读取注解上的值
        List<String> primaryKeyTitles = new ArrayList<>();
        Field[] fields = ReflectUtil.getFields(clazz);
        for (Field field : fields) {
            TitleName titleName = AnnotationUtil.getAnnotation(field, TitleName.class);
            if (titleName == null) {
                continue;
            }

            if (titleName.primaryKey()) {
                primaryKeyTitles.add(titleName.value());
            }
        }


        return StrUtil.format(DELETE_OPERATOR_LOG_TEMPLATE, desc, CollUtil.join(primaryKeyTitles, StrUtil.COMMA), CollUtil.join(tempResult, "<br/>"));
    }

    /**
     * 返回默认日志
     *
     * @param desc
     * @return
     */
    public static String getDefaultContent(String desc, Object... params) {
        ArrayList<String> content = new ArrayList<>();
        String eleTemplate = "&nbsp;&nbsp;{}";

        for (Object param : params) {
            content.add(StrUtil.format(eleTemplate, param));
        }

        return StrUtil.format(DEFAULT_OPERATOR_LOG_TEMPLATE, desc, CollUtil.join(content, "<br/>"));
    }
}

三、定义切面

/**
 * 系统日志切面
 */
@Aspect
@Component
public class OperatorLogAspect {

    @Resource
    private WebOperatorLogsMapper webOperatorLogsMapper;

    @Autowired
    private HttpServletRequest request;

    @Pointcut("@annotation(higgs.ball.manage.annotation.WebOperationTag)")
    public void logPointCut() {
    }

    /**
     * 环绕通知 @Around
     */
    @Around("logPointCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        Object result = point.proceed();
        try {
            insertLog(point);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 保存日志
     */
    private void insertLog(ProceedingJoinPoint point) throws UnsupportedEncodingException {
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();
        BaseController target = (BaseController) point.getTarget();
        WebOperationTag annotation = method.getAnnotation(WebOperationTag.class);
        String operationType = annotation.value().getName();
        // 操作信息
        String operationLog = Arrays.toString(target.getOperationLogArgs());
        String content = operationLog.substring(1, operationLog.length() - 1);
        // 操作内容为空,不记日志
        if (StringUtils.isBlank(content)) {
            return;
        }
        // 操作记录太长截取
        if (content.getBytes("GBK").length > 800) {
            content = this.subStringByByte(content, 800);
        }
        String module = method.getDeclaringClass().getName();
        module = module.substring(module.lastIndexOf(".") + 1, module.lastIndexOf("Controller"));
        // 构造
        WebOperatorLogs log = new WebOperatorLogs();
        log.setLogTime(new Date());
        log.setOperatorType(operationType);
        log.setOperatorModule(module);
        // 身份
        Identity identity = CookieUtil.getIdentityInfo(request);
        log.setOperatorName(identity.getTrueName());
        log.setOperatorId(identity.getUserId());
        log.setContent(content);
        log.setUserName(identity.getUserName());
        webOperatorLogsMapper.add(log);

    }

    /**
     * 按字节截取字符串
     *
     * @param str
     * @param splitByteNum
     * @return
     * @throws UnsupportedEncodingException
     */
    private String subStringByByte(String str, int splitByteNum) throws UnsupportedEncodingException {
        //输入无效判断
        if (StringUtils.isEmpty(str) || splitByteNum <= 0) {
            return "";
        }
        String subStr = str.substring(0, splitByteNum > str.length() ? str.length() : splitByteNum);
        int subStrByteNum = subStr.getBytes("GBK").length;
        int len = splitByteNum;
        while (subStrByteNum > len) {
            int subStrLength = --splitByteNum;
            subStr = str.substring(0, subStrLength > str.length() ? str.length() : subStrLength);
            subStrByteNum = subStr.getBytes("GBK").length;
        }
        return subStr;
    }
}

四、实体类添加注解

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Dict extends ToStringBase {
    private static final long serialVersionUID = -72567329833900420L;

    @TitleName(value = "主键ID",primaryKey = true)
    private long id;

    @TitleName(value = "字典KEY",order = 1)
    private String paramName;

    @TitleName(value = "注释",order = 2)
    private String remark;

    @TitleName(value = "字典值",order = 3)
    private String paramVal;
}

五、示例

I、新增

在这里插入图片描述

II、修改

在这里插入图片描述

III、删除

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
一、简介 通过这个课程带大家从零开发一款功能全面的后台管理系统,包括项目搭建、功能实现到最后的Linux系统部署全过程。本课程使用SpringMVC + Spring + Mybatis作为主体框架,使用AdminLTE作为前端框架,使用主流关系型数据库Mysql作为存储数据库,使用非关系型数据库Redis作为缓存数据库,并集成SpringSecuriy安全框架做权限的动态管理,集成Swagger2自动生成接口文档,集成Druid连接池进行SQL性能监控,集成ActiveMQ消息中间件进行异步解耦,提高性能。最后使用linux系统进行服务部署,并搭建nginx反向代理服务器提高网站性能。 二、学习目标 通过本课程的学习带大家掌握SSM框架的开发流程,并熟练使用SpringSecurity做为安全框架进行权限管理,整合相关优秀的开源框架进行功能开发。还在项目中带大家学习前端相关的Jquery、Bootstrap等知识。课程结束之后希望大家能做到独立进行开发项目的目的,增强解决问题的能力,具备功能落地实现的能力。 三、课程涉及知识点 SpringMVC源码分析Mybatis源码分析通用MapperMysql数据库Redis缓存实现ActiveMQ消息中间件SpringSecurity鉴权Swagger2接口文档生成自定义注解AOP切面编程自定义过滤器Logback日志整合Druid性能监控Linux系统Nginx反向代理Ajax异步请求技术Jquery基本使用AdminLTE前端框架Chart图表-线状图和饼状图百度地图定位城市BootStrap前端框架BootStrap-Table插件BootStrap-Treeview插件Markdown编辑器403、404、500错误页面配置数据库事务消息提示插件toastr.js图片上传插件bootstrap fileinput数字滚动效果pv/uv流量统计...四、课程部分内容截图如下 1、首页 2、菜单管理 3、图床管理 4、图标管理 5、留言反馈管理 6、druid监控 7、登录日志
后台管理系统页面操作日志的设计与代码实现可以参考以下步骤: 1. 设计数据库表结构 可以创建一个名为“sys_log”的表来保存操作日志。表中可以包含以下字段:日志ID、操作人员、操作时间、操作模块、操作类型、操作对象、操作结果等。 2. 编写AOP切面 使用AOP技术,在系统中切入日志记录代码。在AOP切面中,可以通过注解或者切入点来确定需要记录日志的方法,并在方法执行前后记录相关操作日志信息。 3. 编写日志记录代码 在AOP切面中编写日志记录代码,将日志信息保存到数据库中。可以使用Spring JDBC或MyBatis等数据库操作框架来进行数据持久化操作。 4. 集成日志管理模块 可以在系统中集成日志管理模块,将保存的日志信息展示给管理员。管理员可以根据需求查询、导出、删除等日志操作。 以下是一个简单的AOP切面示例,用于记录操作日志: ```java @Component @Aspect public class LogAspect { @Autowired private LogService logService; @Pointcut("execution(* com.example.controller.*.*(..))") public void logPointcut() {} @AfterReturning(pointcut = "logPointcut()") public void doAfterReturning(JoinPoint joinPoint) { HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); User user = (User) request.getSession().getAttribute("user"); if (user != null) { String username = user.getUsername(); String ip = request.getRemoteAddr(); String method = joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName(); String params = Arrays.toString(joinPoint.getArgs()); String operation = "操作描述"; String result = "操作结果"; Log log = new Log(username, ip, method, params, operation, result); logService.saveLog(log); } } } ``` 在上述代码中,@Pointcut注解用于定义切入点,@AfterReturning注解用于定义在方法执行后记录日志操作。在记录日志时,可以获取当前用户、请求IP、请求方法、请求参数等信息,并将这些信息保存到数据库中。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

刘星星star

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值