这允许处理多值参数

发布时间:2025-06-24 20:09:52  作者:北方职教升学中心  阅读量:754


* @param jsonResult 方法返回的对象,用于日志记录,此参数可能为null。

  • 审计与合规:记录关键操作,满足法律法规和行业标准的要求,防止恶意操作和数据泄露。总结

  • 在这里插入图片描述

    前言

    在企业应用开发中,操作日志记录是确保系统安全性、通过记录用户的操作行为,不仅可以帮助开发者快速定位问题,还能满足审计和合规需求。 * * @param joinPoint 切点对象,用于获取方法名和参数信息。 * @param excludeParamNames 需要排除的参数名数组,这些参数不会被转换为字符串。它不仅能够记录用户的操作行为,还能帮助开发和运维人员快速定位和解决问题,提升系统的稳定性和安全性。 */privatestaticMap<String,String[]>getParameterMap(){// 从Spring的RequestContextHolder中获取当前请求的属性RequestAttributesrequestAttributes =RequestContextHolder.getRequestAttributes();// 将RequestAttributes强制转换为ServletRequestAttributes,以便访问HTTP请求特定的属性ServletRequestAttributesservletRequestAttributes =(ServletRequestAttributes)requestAttributes;// 从ServletRequestAttributes中获取当前HTTP请求对象HttpServletRequestrequest =(HttpServletRequest)servletRequestAttributes.getRequest();// 获取请求的所有参数Map<String,String[]>parameterMap =request.getParameterMap();returnparameterMap;}/** * 忽略敏感属性 * * @param excludeParamNames 需要排除的参数名数组 * @return {@link PropertyPreFilters.MySimplePropertyPreFilter} */publicPropertyPreFilters.MySimplePropertyPreFilterexcludePropertyPreFilter(String[]excludeParamNames){returnnewPropertyPreFilters().addFilter().addExcludes(ArrayUtils.addAll(EXCLUDE_PROPERTIES,excludeParamNames));}/** * 将对象数组转换为字符串,排除指定的参数名(敏感参数)。方法信息、在文章的开始,我们探讨了在SpringBoot应用程序中实现日志操作日志记录的重要性,随后采用基于AOP+注解的解决方案,以将日志数据存储到数据库中。 * @param operLog 操作日志对象,用于设置请求参数信息。 * @param jsonResult 方法的返回结果,用于判断是否需要记录响应数据。sysOperLog.setErrorMsg(e.getMessage());}// 获取ip地址StringipAddress =IpUtil.getIpAddress(request);// 设置ip地址sysOperLog.setOperIp(ipAddress);// 设置请求地址sysOperLog.setOperUrl(request.getRequestURI());// 获取当前登录的用户信息。

    一、准备工作

    3.1 创建操作日志记录表

    CREATETABLE`sys_oper_log` (`id` bigint(20)NOTNULLAUTO_INCREMENTCOMMENT'日志主键',`title` varchar(50)DEFAULT'' COMMENT'模块标题',`business_type` varchar(20)DEFAULT'0'COMMENT'业务类型(0其它 1新增 2修改 3删除)',`method` varchar(100)DEFAULT'' COMMENT'方法名称',`request_method` varchar(10)DEFAULT'' COMMENT'请求方式',`oper_name` varchar(50)DEFAULT'' COMMENT'操作人员',`oper_url` varchar(255)DEFAULT'' COMMENT'请求URL',`oper_ip` varchar(128)DEFAULT'' COMMENT'主机地址',`oper_param` varchar(2000)DEFAULT'' COMMENT'请求参数',`json_result` varchar(2000)DEFAULT'' COMMENT'返回参数',`status` int(1)DEFAULT'0'COMMENT'操作状态(1正常 0异常)',`error_msg` varchar(2000)DEFAULT'' COMMENT'错误消息',`oper_time` datetime DEFAULTNULLCOMMENT'操作时间',`execute_time` bigint(20)NOTNULLDEFAULT'0'COMMENT'执行时长(毫秒)',PRIMARYKEY(`id`))ENGINE=InnoDBAUTO_INCREMENT=64DEFAULTCHARSET=utf8 COMMENT='操作日志记录';

    3.2 创建系统日志实体类

    /** * 操作日志记录 * * @date 2024/07/14 */@Data@Schema(description ="操作日志记录")@TableName(value ="sys_oper_log")publicclassSysOperLogimplementsSerializable{@TableField(exist =false)privatestaticfinallongserialVersionUID =1L;@TableId(type =IdType.AUTO)@Schema(description ="日志主键")privateLongid;@Schema(description ="模块标题")privateStringtitle;@Schema(description ="业务类型(0其它 1新增 2修改 3删除)")privateStringbusinessType;@Schema(description ="方法名称")privateStringmethod;@Schema(description ="请求方式")privateStringrequestMethod;@Schema(description ="操作类别(0其它 1后台用户 2手机端用户)")privateStringoperatorType;@Schema(description ="操作人员")privateStringoperName;@Schema(description ="请求URL")privateStringoperUrl;@Schema(description ="主机地址")privateStringoperIp;@Schema(description ="请求参数")privateStringoperParam;@Schema(description ="返回参数")privateStringjsonResult;@Schema(description ="操作状态(1正常 0异常)")privateIntegerstatus;@Schema(description ="错误消息")privateStringerrorMsg;@Schema(description ="操作时间")privateDateoperTime;@Schema(description ="执行时长")privatelongexecuteTime;}

    四、// 设置操作人员sysOperLog.setOperName(username);// 获取并设置请求方法,例如GET、 * @param e 异常对象,如果方法执行过程中抛出异常。sysOperLog.setRequestMethod(request.getMethod());// 获取目标对象的类名。StringclassName =joinPoint.getTarget().getClass().getName();// 获取方法名StringmethodName =joinPoint.getSignature().getName();// 设置方法名称sysOperLog.setMethod(className +"."+methodName +"()");// 获取注解中对方法的描述信息getControllerMethodDescription(joinPoint,controllerLog,jsonResult,sysOperLog);// 计算执行时长(毫秒)longexecuteTime =System.currentTimeMillis()-TIME_THREADLOCAL.get();sysOperLog.setExecuteTime(executeTime);// 设置操作时间。sysOperLog.setOperTime(newDate());// 保存操作日志sysOperLogService.save(sysOperLog);}catch(Exceptionex){// 记录处理日志过程中发生的异常。
    @AfterReturning(pointcut ="@annotation(controllerLog)",returning ="jsonResult")publicvoiddoAfterReturning(JoinPointjoinPoint,LogcontrollerLog,ObjectjsonResult){handleLog(joinPoint,controllerLog,null,jsonResult);}
    • 异常返回:如果目标方法执行过程中抛出异常,切面会执行doAfterThrowing方法。简介
      • 1.1 操作日志在企业应用中的重要性
      • 1.2 使用AOP和注解实现操作日志记录的好处
    • 二、 */@SuppressWarnings("rawtypes")publicbooleanisFilterObject(finalObjecto){// 获取对象的类类型Class<?>clazz =o.getClass();// 检查对象是否为数组类型if(clazz.isArray()){// 如果数组的组件类型可以被MultipartFile类转换,则返回truereturnclazz.getComponentType().isAssignableFrom(MultipartFile.class);}elseif(Collection.class.isAssignableFrom(clazz)){// 如果对象是集合类型,将其转换为Collection接口实例Collectioncollection =(Collection)o;// 遍历集合中的每个元素,如果任意元素是MultipartFile实例,则返回truefor(Objectvalue :collection){returnvalue instanceofMultipartFile;}}elseif(Map.class.isAssignableFrom(clazz)){// 如果对象是Map类型,将其转换为Map接口实例Mapmap =(Map)o;// 遍历Map中的每个条目,如果任意条目的值是MultipartFile实例,则返回truefor(Objectvalue :map.entrySet()){Map.Entryentry =(Map.Entry)value;returnentry.getValue()instanceofMultipartFile;}}// 如果对象不是数组、HttpServletResponse或BindingResult实例returno instanceofMultipartFile||o instanceofHttpServletRequest||o instanceofHttpServletResponse||o instanceofBindingResult;}}

      执行流程分析:

      1. 请求到达:当一个请求到达目标方法时,切面会首先执行boBefore方法,记录方法的开始时间。 * * @param joinPoint 切点 * @param controllerLog 一个注解对象,表示目标方法上标注的注解。

    二、代码实现及测试验证等步骤。简介

    1.1 操作日志在企业应用中的重要性

    操作日志在企业应用中扮演着至关重要的角色。Useruser =UserHolder.getUser();// 获取用户名Stringusername =UserHolder.getUser().getUserName();// 设置操作者名称。 * @param excludeParamNames 需要排除的参数名数组,这些参数不会被记录在日志中。sysOperLog.setStatus(BusinessStatus.SUCCESS.ordinal());// 如果方法执行过程中抛出异常,则将操作状态设置为异常。RequestAttributesrequestAttributes =RequestContextHolder.getRequestAttributes();// 如果请求属性为空,则直接返回,不处理日志。本文旨在探讨如何在SpringBoot应用程序中通过AOP(面向切面编程)和自定义注解实现操作日志记录,并将日志存储到数据库中。 * * @param joinPoint 切点,用于获取方法参数。RequestAttributesattributes =RequestContextHolder.getRequestAttributes();ServletRequestAttributeshttp =(ServletRequestAttributes)attributes;// 再次获取HttpServletRequest对象。

  • 统一管理与维护:集中管理日志记录逻辑,方便后续的功能扩展和维护。
  • 1.2 使用AOP和注解实现操作日志记录的好处

    在SpringBoot项目中,通过AOP(面向切面编程)和自定义注解来实现操作日志记录具有诸多好处:

    • 分离关注点:将日志记录逻辑从业务代码中分离出来,保持代码的清洁和可维护性。

    • 4.6 操作日志注解使用

      /**     * 获取用户信息     *     * @param id 用户id     * @return {@link Result}<{@link UserInfo}>     */@Log(title ="获取用户信息",businessType =BusinessType.OTHER)@Operation(description ="获取用户信息")@GetMapping("/{id}")publicResult<UserInfo>getUser(@PathVariableLongid){returnResult.success(userInfoService.getById(id));}/**     * 插入用户信息     *     * @param userInfo 用户信息     * @return {@link Result}<{@link String}>     */@Log(title ="插入用户信息",businessType =BusinessType.INSERT)@Operation(description ="插入用户信息")@PostMappingpublicResult<String>insertUser(@RequestBodyUserInfouserInfo){booleansaved =userInfoService.save(userInfo);if(!saved){returnResult.error("插入失败");}returnResult.success();}/**     * 更新用户信息     *     * @param userInfo 用户信息     * @return {@link Result}<{@link String}>     */@Log(title ="更新用户信息",businessType =BusinessType.UPDATE)@Operation(description ="更新用户信息")@PutMappingpublicResult<String>updateUser(@RequestBodyUserInfouserInfo){booleanupdated =userInfoService.updateById(userInfo);if(!updated){returnResult.error("更新失败");}returnResult.success();}/**     * 删除用户信息     * @param id i用户id     * @return {@link Result}<{@link String}>     */@Log(title ="删除用户信息",businessType =BusinessType.DELETE)@Operation(description ="删除用户信息")@DeleteMapping("/{id}")publicResult<String>deleteUser(@PathVariableLongid){booleandeleted =userInfoService.removeById(id);if(!deleted){returnResult.error("删除失败");}returnResult.success();}

      五、
    • 灵活性与可配置性:通过注解配置不同的日志记录需求,灵活应对各种场景。这里用于判断方法是否应该被此切面处理。
    • 故障排查:发生问题时,通过日志快速找到问题的根源,缩短问题排查时间。 * * @param joinPoint 切点,用于获取目标方法的信息。
    • 减少重复代码:避免在每个业务方法中手动添加日志记录代码,提升开发效率。 */privatevoidgetControllerMethodDescription(JoinPointjoinPoint,LogcontrollerLog,ObjectjsonResult,SysOperLogsysOperLog){//设置操作模块sysOperLog.setTitle(controllerLog.title());//设置业务类型sysOperLog.setBusinessType(controllerLog.businessType().name());// 判断是否需要保存请求数据,如果需要,则调用setRequestValue方法进行处理if(controllerLog.isSaveRequestData()){//调用设置请求数据的方法setRequestValue(joinPoint,sysOperLog,controllerLog.excludeParamNames());}// 判断是否需要保存响应数据且返回结果不为空,如果满足条件,则将返回结果转为JSON字符串并保存到操作日志中if(controllerLog.isSaveResponseData()&&!StringUtils.isEmpty(jsonResult)){//设置响应数据sysOperLog.setJsonResult(JSON.toJSONString(jsonResult));}}/** * 设置操作日志的请求参数信息。可追溯性以及调试分析的重要手段之一。


      附录:

      若依仓库地址

      在这里插入图片描述