package jnpf; import cn.hutool.http.useragent.UserAgent; import cn.hutool.http.useragent.UserAgentUtil; import jnpf.annotation.HandleLog; import jnpf.base.LogSortEnum; import jnpf.base.UserInfo; import jnpf.base.entity.LogEntity; import jnpf.config.ConfigValueUtil; import jnpf.provider.system.LogProvider; import jnpf.util.*; import lombok.extern.slf4j.Slf4j; import org.apache.dubbo.config.annotation.DubboReference; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.Signature; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.aspectj.lang.reflect.MethodSignature; import jakarta.servlet.ServletRequest; import jakarta.servlet.ServletResponse; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; import org.springframework.validation.BindingResult; import org.springframework.web.multipart.MultipartFile; import java.io.InputStream; import java.io.OutputStream; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Date; import java.util.List; /** * 日志记录 * * @author JNPF开发平台组 * @version V3.1.0 * @copyright 引迈信息技术有限公司 * @date 2021年3月13日 上午9:18 */ @Slf4j @Aspect @Component @Order(2) public class RequestLogAspect { @Autowired private ConfigValueUtil configValueUtil; @DubboReference(injvm = false, async = true, url = "${jnpf.log-provider.url:dubbo://cx-system:20880}") private LogProvider logProvider; @Pointcut("within(jnpf.*.controller..*) || within(jnpf.controller..*) " + "|| within(jnpf.tmsController..*) || within(jnpf.limsController..*) " + "|| within(jnpf.dmsController..*) || within(jnpf.elnController..*)") public void requestLog() { } @Around("requestLog()") public Object doAroundService(ProceedingJoinPoint pjp) throws Throwable { long startTime = System.currentTimeMillis(); Object obj = pjp.proceed(); if(ServletUtil.getRequest() == null){ return obj; } long costTime = System.currentTimeMillis() - startTime; UserInfo userInfo = UserProvider.getUser(); if(userInfo.getUserId() != null && (!configValueUtil.isMultiTenancy() || TenantHolder.getLocalTenantCache() != null)) { // 得到请求参数 Object[] args = pjp.getArgs(); Signature signature = pjp.getSignature(); try { printLog(userInfo, costTime, obj, args, signature); } catch (Exception e) { log.error("记录请求日志发生错误:" + e.getMessage()); } try { // 判断是否需要操作日志 MethodSignature methodSignature = (MethodSignature) pjp.getSignature(); // 得到请求方法 Method method = methodSignature.getMethod(); HandleLog methodAnnotation = method.getAnnotation(HandleLog.class); if (methodAnnotation != null) { String moduleName = methodAnnotation.moduleName(); String requestMethod = methodAnnotation.requestMethod(); handleLog(userInfo, costTime, obj, moduleName, requestMethod, args, signature); } } catch (Exception e) { log.error("记录操作日志发生错误:" + e.getMessage()); } } return obj; } /** * 请求日志 * * @param userInfo * @param costTime */ private void printLog(UserInfo userInfo, long costTime, Object obj, Object[] args, Signature signature) { LogEntity entity = new LogEntity(); entity.setId(RandomUtil.uuId()); entity.setType(LogSortEnum.REQUEST.getCode()); entity.setUserId(userInfo.getUserId()); entity.setUserName(userInfo.getUserName() + "/" + userInfo.getUserAccount()); //请求耗时 entity.setRequestDuration((int) costTime); entity.setRequestUrl(ServletUtil.getRequest().getServletPath()); entity.setRequestMethod(ServletUtil.getRequest().getMethod()); String ipAddr = IpUtil.getIpAddr(); entity.setIpAddress(ipAddr); entity.setIpAddressName(IpUtil.getIpCity(ipAddr)); entity.setCreatorTime(new Date()); UserAgent userAgent = UserAgentUtil.parse(ServletUtil.getUserAgent()); if (userAgent != null) { entity.setPlatForm(userAgent.getPlatform().getName() + " " + userAgent.getOsVersion()); entity.setBrowser(userAgent.getBrowser().getName() + " " + userAgent.getVersion()); } String declaringTypeName = signature.getDeclaringTypeName(); String name = signature.getName(); entity.setRequestTarget(declaringTypeName + "." + name); entity.setJsons(safeResultText(obj)); entity.setRequestParam(buildRequestParam(args)); logProvider.writeLogRequest(entity); } /** * 添加操作日志 * * @param userInfo 用户信息 * @param costTime 操作耗时 * @param obj 请求结果 * @param moduleName 模块名称 * @param requestMethod 请求方法 * @param arg 请求参数 */ private void handleLog(UserInfo userInfo, long costTime, Object obj, String moduleName, String requestMethod, Object[] args, Signature signature) { LogEntity entity = new LogEntity(); entity.setId(RandomUtil.uuId()); entity.setType(LogSortEnum.OPERATE.getCode()); entity.setUserId(userInfo.getUserId()); entity.setUserName(userInfo.getUserName() + "/" + userInfo.getUserAccount()); //请求耗时 entity.setRequestDuration((int) costTime); entity.setRequestMethod(ServletUtil.getRequest().getMethod()); entity.setRequestUrl(ServletUtil.getRequest().getServletPath()); String ipAddr = IpUtil.getIpAddr(); entity.setIpAddress(ipAddr); entity.setIpAddressName(IpUtil.getIpCity(ipAddr)); entity.setCreatorTime(new Date()); // 请求设备 UserAgent userAgent = UserAgentUtil.parse(ServletUtil.getUserAgent()); if (userAgent != null) { entity.setPlatForm(userAgent.getPlatform().getName() + " " + userAgent.getOsVersion()); entity.setBrowser(userAgent.getBrowser().getName() + " " + userAgent.getVersion()); } // 操作模块 entity.setModuleName(moduleName); String declaringTypeName = signature.getDeclaringTypeName(); String name = signature.getName(); entity.setRequestTarget(declaringTypeName + "." + name); entity.setRequestParam(buildRequestParam(args)); entity.setJsons(safeResultText(obj)); logProvider.writeLogRequest(entity); } /** * 导出等接口已占用 response 输出流,不可再对 Request/Response 做 FastJSON 序列化。 */ private static String buildRequestParam(Object[] args) { if (args == null || args.length == 0) { return ""; } StringBuilder multipart = new StringBuilder(); List serializable = new ArrayList<>(args.length); for (Object o : args) { if (o == null) { continue; } if (o instanceof MultipartFile) { MultipartFile file = (MultipartFile) o; multipart.append("{\"originalFilename\":\"").append(file.getOriginalFilename()).append("\","); multipart.append("\"contentType\":\"").append(file.getContentType()).append("\","); multipart.append("\"name\":\"").append(file.getName()).append("\","); multipart.append("\"resource\":\"").append(file.getResource()).append("\","); multipart.append("\"size\":\"").append(file.getSize()).append("\"}"); continue; } if (skipLogArg(o)) { continue; } serializable.add(o); } if (multipart.length() > 0) { return multipart.toString(); } if (serializable.isEmpty()) { return ""; } return JsonUtil.getObjectToString(serializable.toArray()); } private static boolean skipLogArg(Object o) { return o instanceof ServletRequest || o instanceof ServletResponse || o instanceof BindingResult || o instanceof InputStream || o instanceof OutputStream; } /** void 导出等无返回体时避免把 response 之类写进日志 */ private static String safeResultText(Object obj) { if (obj == null) { return ""; } if (skipLogArg(obj)) { return ""; } return String.valueOf(obj); } }