编程常用代码大全南山网站建设公司乐云seo

张小明 2026/3/13 5:51:49
编程常用代码大全,南山网站建设公司乐云seo,在线看seo网站,常州网站建设工作室注意#xff1a; 不要把日志逻辑写在 AuthAspect 里#xff0c;那是做权限的。我们新建一个 LogAspect 专门处理日志。 异步入库#xff1a;写日志是“辅助业务”#xff0c;绝不能因为数据库插入慢而阻塞主业务接口的响应速度。 实体类 (SysOperationLog) 对应你的数据库表…注意不要把日志逻辑写在 AuthAspect 里那是做权限的。我们新建一个 LogAspect 专门处理日志。异步入库写日志是“辅助业务”绝不能因为数据库插入慢而阻塞主业务接口的响应速度。实体类 (SysOperationLog)对应你的数据库表结构。packagecom.yige.entity;importlombok.Data;importjava.util.Date;DatapublicclassSysOperationLog{privateLongid;privateDateoperateTime;// 操作时间privateStringoperateUser;// 操作用户privateStringoperateType;// 操作类型 (查询/新增/导出...)privateStringmodule;// 模块 (法规库/聊天助手...)privateStringipAddress;// IP地址privateStringstatus;// 状态 (成功/失败)}异步日志服务 (LogService)我们需要一个 Service 来专门负责插入数据库。关键点是加上 Async 注解。packagecom.yige.service;importcom.yige.entity.SysOperationLog;importorg.springframework.scheduling.annotation.Async;importorg.springframework.stereotype.Service;// 假设你使用 MyBatis 或 MyBatis-Plus// import com.yige.mapper.SysOperationLogMapper;ServicepublicclassLogService{// Autowired// private SysOperationLogMapper logMapper;/** * 异步保存日志不阻塞主线程 */Async(taskExecutor)// 需要配置线程池如果没有配默认也可以publicvoidsaveLog(SysOperationLoglog){try{System.out.println(【异步日志入库】正在保存日志: log);// logMapper.insert(log);// 模拟入库耗时Thread.sleep(50);}catch(Exceptione){System.err.println(日志入库失败: e.getMessage());}}}注意要在启动类 Application.java 上加 EnableAsync 开启异步支持。日志切面 (LogAspect) —— 核心逻辑这是最关键的部分。它会拦截请求分析 URL提取用户信息并判断成功还是失败。package com.yige.aspect;importcom.yige.entity.SysOperationLog;importcom.yige.security.SessionManager;importcom.yige.service.LogService;importorg.aspectj.lang.ProceedingJoinPoint;importorg.aspectj.lang.annotation.Around;importorg.aspectj.lang.annotation.Aspect;importorg.aspectj.lang.annotation.Pointcut;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.stereotype.Component;importorg.springframework.web.context.request.RequestContextHolder;importorg.springframework.web.context.request.ServletRequestAttributes;importjavax.servlet.http.HttpServletRequest;importjava.util.Date;AspectComponentpublicclassLogAspect{Autowiredprivate LogService logService;Autowiredprivate SessionManager sessionManager;// 用来获取当前用户// 拦截所有 controller排除登录接口(如果登录不记日志)和 WebSocket// 这里的规则和 AuthAspect 类似但通常登录接口也需要记录日志看你需求Pointcut(execution(public * com.yige.controller..*.*(..)) !within(javax.websocket.server.ServerEndpoint))publicvoidlogPointCut(){}Around(logPointCut())public ObjectrecordLog(ProceedingJoinPoint point)throws Throwable{long beginTimeSystem.currentTimeMillis();// 1. 获取 Request 信息ServletRequestAttributes attributes(ServletRequestAttributes)RequestContextHolder.getRequestAttributes();HttpServletRequest requestattributes!null?attributes.getRequest():null;Object resultnull;String status成功;String errorMsgnull;try{// 2. 执行目标方法resultpoint.proceed();}catch(Exception e){status失败;errorMsge.getMessage();throwe;// 异常必须抛出去不然前端收不到报错}finally{// 3. 无论成功失败都在 finally 里组装日志if(request!null){saveSysLog(request,status);}}returnresult;}privatevoidsaveSysLog(HttpServletRequest request,String status){SysOperationLog lognewSysOperationLog();log.setOperateTime(newDate());log.setStatus(status);log.setIpAddress(getIpAddress(request));// --- A. 解析用户 (从 Token 获取) ---String tokenrequest.getHeader(Authorization);String userId访客/未知;if(token!null){// 这里需要在 SessionManager 加一个 public String getUserId(String token) 方法// 或者直接访问 sessionManager 里的 map (如果改为 public)String foundUsersessionManager.getUserIdByToken(token);if(foundUser!null){userIdfoundUser;}}log.setOperateUser(userId);// --- B. 解析模块和操作类型 (核心逻辑) ---String urirequest.getRequestURI();// 例如: /api/repo/saveString methodrequest.getMethod();// GET, POSTanalyzeModuleAndType(uri,method,log);// --- C. 异步调用 Service 入库 ---logService.saveLog(log);}/** * 根据 URL 前缀判断 模块 和 操作类型 */privatevoidanalyzeModuleAndType(String uri,String method,SysOperationLog log){// 默认值String module其他模块;String type未知操作;// 1. 判断模块 (根据一级路径)if(uri.contains(/api/repo)){module法规知识库;}elseif(uri.contains(/api/chat)){moduleAI知识助手;}elseif(uri.contains(/api/device)){module设备监测;}elseif(uri.contains(/api/user)){module系统管理;}// 2. 判断操作类型 (根据二级路径 或 请求方法)// 优先根据 URL 关键词判断if(uri.endsWith(/save)||uri.endsWith(/add)||uri.endsWith(/create)){type新增;}elseif(uri.endsWith(/update)||uri.endsWith(/edit)){type修改;}elseif(uri.endsWith(/delete)||uri.endsWith(/remove)){type删除;}elseif(uri.endsWith(/export)||uri.endsWith(/download)){type导出/下载;}elseif(uri.endsWith(/upload)||uri.endsWith(/import)){type导入/上传;}elseif(uri.endsWith(/ask)||uri.endsWith(/chat)){typeAI问答;}else{// 如果 URL 看不出就根据 HTTP 方法兜底if(GET.equals(method))type查询;elseif(POST.equals(method))type提交;elseif(DELETE.equals(method))type删除;elseif(PUT.equals(method))type更新;}log.setModule(module);log.setOperateType(type);}// 获取真实IP的工具方法private StringgetIpAddress(HttpServletRequest request){String iprequest.getHeader(x-forwarded-for);if(ipnull||ip.length()0||unknown.equalsIgnoreCase(ip)){iprequest.getHeader(Proxy-Client-IP);}if(ipnull||ip.length()0||unknown.equalsIgnoreCase(ip)){iprequest.getHeader(WL-Proxy-Client-IP);}if(ipnull||ip.length()0||unknown.equalsIgnoreCase(ip)){iprequest.getRemoteAddr();}returnip!nullip.contains(,)?ip.split(,)[0]:ip;}}补充 SessionManager 的支持因为 LogAspect 需要知道是谁在操作而 SessionManager 之前是把 Map 设为 private 的。你需要在这个类里加一个查询方法在 SessionManager.java 中添加/** * 根据 Token 获取用户 ID (用于日志记录等) * 不抛异常找不到就返回 null */publicStringgetUserIdByToken(Stringtoken){if(tokennull)returnnull;returntokenToUserMap.get(token);}不用在每个 Controller 方法里写日志代码加个注解或者什么都不用做AOP 全局拦截。日志入库是异步的不影响用户体验。线程池配置package com.yige.config;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importorg.springframework.scheduling.annotation.EnableAsync;importorg.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;importjava.util.concurrent.Executor;importjava.util.concurrent.ThreadPoolExecutor;ConfigurationEnableAsync// 开启异步注解支持publicclassThreadPoolConfig{/** * 定义名为 taskExecutor 的线程池 * 专门用于处理 Async(taskExecutor) 的任务 */Bean(taskExecutor)public ExecutortaskExecutor(){ThreadPoolTaskExecutor executornewThreadPoolTaskExecutor();// 1. 核心线程数平时干活的线程// 对于 IO 密集型任务如写日志/读库建议设置为 CPU核数 * 2// 假设服务器是 4核这里设为 8 或 10 都可以executor.setCorePoolSize(10);// 2. 最大线程数忙不过来时临时雇佣的线程// 当队列满了之后会创建新线程直到达到这个值executor.setMaxPoolSize(20);// 3. 队列容量缓冲池// 重要日志任务因为不涉及返回结果可以允许排队。// 设置大一点比如 500-1000防止瞬时流量高峰导致丢日志executor.setQueueCapacity(1000);// 4. 线程名称前缀方便排查日志报错时能看到是 log-thread-xxexecutor.setThreadNamePrefix(async-log-);// 5. 拒绝策略当队列满了且线程达到最大值新任务怎么办// CALLER_RUNS_POLICY (推荐)由调用者所在的线程主线程来执行。// 好处虽然会稍微拖慢一点主接口的响应速度但保证了**日志绝对不会丢失**。// 坏处高并发下可能会阻塞主线程。// 如果你觉得日志丢几条无所谓想保主业务可以用 DiscardPolicy (直接丢弃)。executor.setRejectedExecutionHandler(newThreadPoolExecutor.CallerRunsPolicy());// 6. 优雅关闭应用关闭时是否等待任务执行完executor.setWaitForTasksToCompleteOnShutdown(true);// 等待时间秒超过这个时间强制销毁executor.setAwaitTerminationSeconds(60);executor.initialize();returnexecutor;}}
版权声明:本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

杭州有没有专业做网站的公司东莞网站推广裙

2025企业AI网关终极指南:3大架构策略实现多模型统一治理 【免费下载链接】APIPark 🦄云原生、超高性能 AI&API网关,LLM API 管理、分发系统、开放平台,支持所有AI API,不限于OpenAI、Azure、Anthropic Claude、Goo…

张小明 2026/3/5 2:35:06 网站建设

建筑起名字最大气合肥seo建站

第一章:Open-AutoGLM 跨应用数据安全机制概述Open-AutoGLM 作为一款面向多应用环境的自动化语言模型集成框架,其核心设计目标之一是确保跨应用间的数据流转安全。该机制通过统一的身份认证、细粒度权限控制与端到端加密策略,构建了多层次的安…

张小明 2026/3/5 2:35:09 网站建设

外贸网站谷歌seo怎样换wordpress域名

🍊作者:计算机毕设匠心工作室 🍊简介:毕业后就一直专业从事计算机软件程序开发,至今也有8年工作经验。擅长Java、Python、微信小程序、安卓、大数据、PHP、.NET|C#、Golang等。 擅长:按照需求定制化开发项目…

张小明 2026/3/5 2:35:19 网站建设

影响网站打开速度怎样清理网站后门

Spring Boot 整合 Kafka 进行日志处理是一个常见的任务,可以帮助你更好地管理和分析应用程序的日志。以下是一个基本的步骤指南,帮助你完成这个整合。 本文介绍了如何在SpringBoot应用中整合Kafka,利用Logback收集日志并发送到Kafka。详细步…

张小明 2026/3/5 2:35:10 网站建设

2014年沈阳建设银行网站国内精品网站建设

本教程中,我们将学习使用ODBC APIs的细节.因为我们的程序并不与ODBC驱动程序直接通信,而是通过ODBC管理器来定义一系列APIs供你的程序调用以完成工作,所以我们需要包含odbc32.inc和odbc32.lib文件,当然还有windows.inc。连接数据源…

张小明 2026/3/5 2:35:11 网站建设