当前位置: 首页 > news >正文

海淀公安网站备案办理今日头条新闻最全新消息

海淀公安网站备案办理,今日头条新闻最全新消息,免费域名邮箱注册,义乌代加工手工活官网写在最前 如果这个项目让你有所收获,记得 Star 关注哦,这对我是非常不错的鼓励与支持。 源码地址(后端):mingyue: 🎉 基于 Spring Boot、Spring Cloud & Alibaba 的分布式微服务架构基础服务中心 源…

写在最前

如果这个项目让你有所收获,记得 Star 关注哦,这对我是非常不错的鼓励与支持。

源码地址(后端):mingyue: 🎉 基于 Spring Boot、Spring Cloud & Alibaba 的分布式微服务架构基础服务中心

源码地址(前端):mingyue-ui: 🎉 基于 Vue3 + TS + Vite + Element plus 等技术,适配 MingYue 后台微服务

文档地址:Wiki - Gitee.com

为什么要日志插件?

在Java应用程序中记录日志是一种良好的实践,它为开发、运维和支持团队提供了很多好处。以下是一些主要的理由:

  1. 故障排除和调试:

    • 日志是定位和解决问题的重要工具。通过在关键代码路径和操作中插入日志语句,开发人员可以追踪应用程序的执行流程,快速定位潜在的错误和异常。

  2. 性能分析:

    • 记录关键操作的执行时间、资源使用情况等信息,有助于性能分析和优化。通过分析日志,可以确定应用程序的瓶颈并改进性能。

  3. 安全审计:

    • 记录关键的安全事件和用户活动,以便进行审计和检测潜在的安全威胁。登录失败、访问敏感信息等事件的记录对于安全监控至关重要。

  4. 系统状态监控:

    • 通过记录系统状态和关键指标,可以实时监控应用程序的运行状况。这有助于及时发现和解决潜在的问题,以提高系统的稳定性和可用性。

  5. 版本追踪和审计:

    • 在代码中记录版本信息、变更历史和代码提交信息,有助于追踪应用程序的演变过程。审计日志还可以用于追溯特定功能或问题的起源。

  6. 用户行为分析:

    • 对于包含用户交互的应用程序,记录用户活动可以帮助了解他们的使用模式、偏好和行为。这对于改进用户体验和调整产品设计非常有帮助。

  7. 合规性和法规要求:

    • 许多行业和法规要求记录关键事件和操作,以确保企业的合规性。通过日志记录,可以满足这些法规的要求,并提供审计证据。

  8. 持久化数据:

    • 将日志存储在持久化介质中,例如文件或数据库,以便在应用程序重新启动后仍然可以访问日志。这有助于在系统故障或应用程序崩溃时还原状态并进行故障排除。

日志设计

日志类型

系统操作日志和用户登录日志是两种不同类型的日志,它们记录了系统中不同方面的活动

  • 系统操作日志:记录系统的各种操作,包括但不限于增删改查、上传与下载文件等。

  • 用户登录日志:记录用户登录和注销的信息。

记录方式

  • 系统操作日志:采用注解(非侵入)方式记录;

  • 用户登录日志:采用显式(侵入)方式记录;

日志插件

添加 mingyue-common-log 插件

<dependencies><dependency><groupId>com.csp.mingyue</groupId><artifactId>mingyue-common-security</artifactId></dependency>
</dependencies>

Log 注解

@Target({ ElementType.PARAMETER, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Log {
​/*** 模块*/String module() default "";
​/*** 功能*/BusinessType businessType() default BusinessType.OTHER;
​/*** 操作人类别*/OperatorUserType operatorUserType() default OperatorUserType.MANAGE;
​/*** 是否保存请求的参数*/boolean isSaveRequestData() default true;
​/*** 是否保存响应的参数*/boolean isSaveResponseData() default true;
​/*** 排除指定的请求参数*/String[] excludeParamNames() default {};
​
}

Log 切面

操作日志记录核心类

@Slf4j
@Aspect
@RequiredArgsConstructor
@AutoConfiguration
public class LogAspect {
​private final ServiceInstance serviceInstance;
​/*** 排除敏感属性字段*/public static final String[] EXCLUDE_PROPERTIES = { "password", "oldPassword", "newPassword", "confirmPassword" };
​/*** 处理完请求后执行* @param joinPoint 切点*/@AfterReturning(pointcut = "@annotation(controllerLog)", returning = "jsonResult")public void doAfterReturning(JoinPoint joinPoint, Log controllerLog, Object jsonResult) {handleLog(joinPoint, controllerLog, null, jsonResult);}
​/*** 拦截异常操作* @param joinPoint 切点* @param e 异常*/@AfterThrowing(value = "@annotation(controllerLog)", throwing = "e")public void doAfterThrowing(JoinPoint joinPoint, Log controllerLog, Exception e) {handleLog(joinPoint, controllerLog, e, null);}
​protected void handleLog(final JoinPoint joinPoint, Log controllerLog, final Exception e, Object jsonResult) {// 日志记录开始时间Long startTime = System.currentTimeMillis();
​// ========数据库日志========OperateLogEvent operateLog = new OperateLogEvent();
​try {// 请求信息String ip = ServletUtils.getClientIP();operateLog.setReqIp(ip);operateLog.setServiceId(serviceInstance.getServiceId());operateLog.setReqAddress(AddressUtils.getRealAddressByIP(ip));operateLog.setReqUrl(StrUtil.sub(Objects.requireNonNull(ServletUtils.getRequest()).getRequestURI(), 0, 255));
​operateLog.setStatus(BusinessStatus.SUCCESS.ordinal());
​// 用户信息LoginUser loginUser = LoginHelper.getLoginUser();operateLog.setUserId(loginUser.getUserId());operateLog.setUserName(loginUser.getUsername());
​if (e != null) {operateLog.setStatus(BusinessStatus.FAIL.ordinal());operateLog.setException(StrUtil.sub(e.getMessage(), 0, 2000));}
​// 设置方法名称String className = joinPoint.getTarget().getClass().getName();String methodName = joinPoint.getSignature().getName();operateLog.setMethod(className + "." + methodName + "()");
​// 设置User-AgentoperateLog.setUserAgent(ServletUtils.getRequest().getHeader(HttpHeaders.USER_AGENT));// 设置请求方式operateLog.setReqMethod(ServletUtils.getRequest().getMethod());// 处理设置注解上的参数getControllerMethodDescription(joinPoint, controllerLog, operateLog, jsonResult);}catch (Exception exp) {// 记录本地异常日志log.error("异常信息:{}", exp.getMessage());}finally {Long endTime = System.currentTimeMillis();operateLog.setDuration(endTime - startTime);// 发布事件保存数据库SpringUtils.context().publishEvent(operateLog);}}
​/*** 获取注解中对方法的描述信息 用于Controller层注解* @param log 日志* @param operateLog 操作日志*/public void getControllerMethodDescription(JoinPoint joinPoint, Log log, OperateLogEvent operateLog,Object jsonResult) throws Exception {// 设置标题operateLog.setModule(log.module());// 设置 action 动作operateLog.setBusinessType(log.businessType().ordinal());// 设置操作人类别operateLog.setUserType(log.operatorUserType().ordinal());// 是否需要保存 request,参数和值if (log.isSaveRequestData()) {// 获取参数的信息,传入到数据库中。setRequestValue(joinPoint, operateLog, log.excludeParamNames());}// 是否需要保存 response,参数和值if (log.isSaveResponseData() && ObjectUtil.isNotNull(jsonResult)) {R resp = JSONUtil.toBean(JSONUtil.toJsonStr(jsonResult), R.class);operateLog.setRespMsg(resp.getMsg());operateLog.setRespCode(resp.getCode());operateLog.setRespResult(StrUtil.sub(JSONUtil.toJsonStr(jsonResult), 0, 2000));}}
​/*** 获取请求的参数,放到log中* @param operLog 操作日志* @throws Exception 异常*/private void setRequestValue(JoinPoint joinPoint, OperateLogEvent operLog, String[] excludeParamNames)throws Exception {Map<String, String> paramsMap = ServletUtils.getParamMap(ServletUtils.getRequest());String requestMethod = operLog.getReqMethod();if (MapUtil.isEmpty(paramsMap) && HttpMethod.PUT.name().equals(requestMethod)|| HttpMethod.POST.name().equals(requestMethod)) {String params = argsArrayToString(joinPoint.getArgs(), excludeParamNames);operLog.setReqParams(StrUtil.sub(params, 0, 2000));}else {MapUtil.removeAny(paramsMap, EXCLUDE_PROPERTIES);MapUtil.removeAny(paramsMap, excludeParamNames);operLog.setReqParams(StrUtil.sub(JSONUtil.toJsonStr(paramsMap), 0, 2000));}}
​/*** 参数拼装*/private String argsArrayToString(Object[] paramsArray, String[] excludeParamNames) {StringJoiner params = new StringJoiner(" ");if (ArrayUtil.isEmpty(paramsArray)) {return params.toString();}for (Object o : paramsArray) {if (ObjectUtil.isNotNull(o) && !isFilterObject(o)) {String str = JSONUtil.toJsonStr(o);Dict dict = JsonUtils.parseMap(str);if (MapUtil.isNotEmpty(dict)) {MapUtil.removeAny(dict, EXCLUDE_PROPERTIES);MapUtil.removeAny(dict, excludeParamNames);str = JSONUtil.toJsonStr(dict);}params.add(str);}}return params.toString();}
​/*** 判断是否需要过滤的对象。* @param o 对象信息。* @return 如果是需要过滤的对象,则返回true;否则返回false。*/@SuppressWarnings("rawtypes")public boolean isFilterObject(final Object o) {Class<?> clazz = o.getClass();if (clazz.isArray()) {return clazz.getComponentType().isAssignableFrom(MultipartFile.class);}else if (Collection.class.isAssignableFrom(clazz)) {Collection collection = (Collection) o;for (Object value : collection) {return value instanceof MultipartFile;}}else if (Map.class.isAssignableFrom(clazz)) {Map map = (Map) o;for (Object value : map.values()) {return value instanceof MultipartFile;}}return o instanceof MultipartFile || o instanceof HttpServletRequest || o instanceof HttpServletResponse|| o instanceof BindingResult;}
​
}

异步调用日志服务

@Slf4j
@Component
@RequiredArgsConstructor
public class LogEventListener {
​private final RemoteLogService remoteLogService;
​/*** 保存系统日志记录*/@Async@EventListenerpublic void saveLog(OperateLogEvent operateLog) {log.info("保存系统日志记录落库「{}」", JSONUtil.toJsonStr(operateLog));remoteLogService.saveSysOperateLog(BeanUtil.copyProperties(operateLog, SysOperateLog.class));}
​
}

自动注入日志类

org.springframework.boot.autoconfigure.AutoConfiguration.imports

com.csp.mingyue.common.log.event.LogEventListener
com.csp.mingyue.common.log.aspect.LogAspect

系统操作日志表设计

DROP TABLE IF EXISTS sys_operate_log;
CREATE TABLE sys_operate_log (operate_log_id    BIGINT(20)         NOT NULL                 COMMENT '操作日志ID',module            VARCHAR(50)        DEFAULT ''               COMMENT '模块',business_type     INT(2)             DEFAULT 0                COMMENT '业务类型(0其它 1新增 2修改 3删除)',method            VARCHAR(100)       DEFAULT ''               COMMENT '方法名称',service_id        VARCHAR(32)        DEFAULT NULL             COMMENT '服务ID',user_id           BIGINT(20)         NOT NULL                 COMMENT '用户ID',user_name         VARCHAR(50)        NOT NULL                 COMMENT '用户账号',user_type         TINYINT(1)         DEFAULT 0                COMMENT '用户类型(0其它 1系统用户)',user_agent        VARCHAR(1000)      DEFAULT NULL             COMMENT '用户代理',req_ip            VARCHAR(128)       DEFAULT ''               COMMENT '请求IP',req_address       VARCHAR(255)       DEFAULT ''               COMMENT '请求地点',req_url           VARCHAR(255)       DEFAULT ''               COMMENT '请求URL',req_method        VARCHAR(20)        DEFAULT NULL             COMMENT '请求方式',req_params        TEXT               DEFAULT NULL             COMMENT '请求参数',duration          BIGINT             NOT NULL                 COMMENT '执行时长,单位(ms)',resp_code         INT                DEFAULT NULL             COMMENT '结果码',resp_msg          VARCHAR(512)       NULL DEFAULT ''          COMMENT '结果提示',resp_result       VARCHAR(2000)      DEFAULT ''               COMMENT '返回参数',status            CHAR(1)            DEFAULT 0                COMMENT '操作状态(0正常 1异常)',exception         TEXT               DEFAULT NULL             COMMENT '异常信息',operate_time      DATETIME           NOT NULL                 COMMENT '操作时间',is_deleted        CHAR(1)            DEFAULT '0'              COMMENT '删除标志(0正常,1删除)',create_by         VARCHAR(64)        DEFAULT ''               COMMENT '创建者',create_time       DATETIME           DEFAULT NULL             COMMENT '创建时间',update_by         VARCHAR(64)        DEFAULT ''               COMMENT '更新者',update_time       DATETIME           DEFAULT NULL             COMMENT '更新时间',PRIMARY KEY (operate_log_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin ROW_FORMAT=DYNAMIC COMMENT='系统操作日志';

测试日志注解

使用注解

@Log(module = "用户管理", businessType = BusinessType.DELETE)

@DeleteMapping("{userId}")
@Log(module = "用户管理", businessType = BusinessType.DELETE)
@Operation(summary = "删除用户", parameters = { @Parameter(name = "userId", description = "用户ID", required = true) })
public R<Boolean> delUser(@PathVariable Long userId) {return R.ok(sysUserService.delUser(userId));
}

调用接口

调用完成后查看数据库是否存在该操作记录即可

curl -X 'DELETE'   'http://192.168.63.114:7100/system/sysUser/111111111'   -H 'accept: */*'   -H 'Authorization: UWapduuggQcNSqg1oQZ17ZyfPHDxxt8Q'
http://www.hkea.cn/news/407964/

相关文章:

  • 个人如何免费建网站seo在线优化工具 si
  • 双线主机可以做彩票网站吗网络推广合作协议
  • 做外贸的b2b网站域名批量查询系统
  • 建设网站需要哪些职位网站建设策划书
  • 苏州网站建设哪里好网站点击排名优化
  • 网站建设收费标准策划百度推广关键词越多越好吗
  • 网站怎么做更新吗如何建立网页
  • 国外建设工程招聘信息网站tool站长工具
  • 专业做相册书的网站电商网站建设制作
  • 银川网站开发公司电话东莞网
  • 环境保护局网站管理制度建设百度指数的主要功能有
  • 安装wordpress提示500错误关键词优化的策略有哪些
  • 企业网站建设公司排名深圳高端seo公司助力企业
  • 做网站套餐网站seo
  • 网站上的代码网页怎么做的下载百度软件
  • 网站功能模块建设搜狗推广
  • 网站做推广有用吗网站页面设计
  • 做简报的网站广州搜发网络科技有限公司
  • 南乐县住房和城乡建设局网站制作网站的步骤是什么
  • 金华做网站最专业的公司搜易网提供的技术服务
  • wordpress适合门户网站吗怎么营销自己的产品
  • 常用的网站类型有哪些seo优化专员编辑
  • 网站专题框架怎么做海阳seo排名
  • 手机网站代码下载黄页网站推广服务
  • 做网站前端多少钱在线bt种子
  • wordpress+模版+推荐专业网站seo推广
  • 浦项建设公司员工网站2023免费推广入口
  • 如何查询某个网站的设计公司最新推广注册app拿佣金
  • 八宝山做网站公司打广告
  • wordpress vip查看插件南宁seo费用服务