package com.java110.api.aop; import com.alibaba.fastjson.JSONObject; import com.java110.core.context.IPageData; import com.java110.core.context.PageData; import com.java110.core.log.LoggerFactory; import com.java110.utils.constant.CommonConstant; import com.java110.utils.exception.FilterException; import com.java110.utils.util.StringUtil; import com.java110.utils.util.TokenUtil; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; import org.slf4j.Logger; import org.springframework.http.HttpMethod; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Component; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.Enumeration; import java.util.HashMap; import java.util.Map; /** * 数据初始化 * Created by wuxw on 2018/5/2. */ @Aspect @Component public class PageProcessAspect { private static Logger logger = LoggerFactory.getLogger(PageProcessAspect.class); @Pointcut("execution(public * com.java110..*.*Controller.*(..)) ") public void dataProcess() { } /** * 初始化数据 * * @param joinPoint * @throws Throwable */ @Before("dataProcess()") public void deBefore(JoinPoint joinPoint) throws Throwable { // 接收到请求,记录请求内容 ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletRequest request = attributes.getRequest(); IPageData pd = null; String reqData = ""; String userId = ""; String userName = ""; String appId = ""; String sessionId = request.getSession().getId(); appId = request.getHeader("APP_ID"); if (StringUtil.isEmpty(appId)) { appId = request.getHeader("APP-ID"); } logger.debug("请求头信息:" + request.getHeaderNames()); String contentType = request.getContentType(); boolean isMultipart = contentType != null && contentType.startsWith("multipart/form-data"); if ("POST,PUT".contains(request.getMethod()) && !isMultipart) { InputStream in = request.getInputStream(); BufferedReader reader = new BufferedReader(new InputStreamReader(in)); //reader. StringBuffer sb = new StringBuffer(); String str = ""; while ((str = reader.readLine()) != null) { sb.append(str); } reqData = sb.toString(); } //对 get情况下的参数进行封装 else { Map params = request.getParameterMap(); if (params != null && !params.isEmpty()) { JSONObject paramObj = new JSONObject(); for (String key : params.keySet()) { if (params.get(key).length > 0) { String value = ""; for (int paramIndex = 0; paramIndex < params.get(key).length; paramIndex++) { value += (params.get(key)[paramIndex] + ","); } value = value.endsWith(",") ? value.substring(0, value.length() - 1) : value; paramObj.put(key, value); } continue; } reqData = paramObj.toJSONString(); } } // 获取 userId if (request.getAttribute("claims") != null && request.getAttribute("claims") instanceof Map) { Map userInfo = (Map) request.getAttribute("claims"); if (userInfo.containsKey(CommonConstant.LOGIN_USER_ID)) { userId = userInfo.get(CommonConstant.LOGIN_USER_ID); userName = userInfo.get(CommonConstant.LOGIN_USER_NAME); } } // 获取组件名称 和方法名称 String url = request.getRequestURL() != null ? request.getRequestURL().toString() : ""; String componentCode = ""; String componentMethod = ""; if (url.contains("callComponent")) { //组件处理 String[] urls = url.split("/"); if (urls.length == 6) { componentCode = urls[4]; componentMethod = urls[5]; } else { componentCode = "api"; componentMethod = "callApi"; } } else if (url.contains("flow")) { //流程处理 String[] urls = url.split("/"); if (urls.length == 5) { componentCode = urls[4]; } } Map headers = new HashMap<>(); Enumeration reqHeaderEnum = request.getHeaderNames(); while (reqHeaderEnum.hasMoreElements()) { String headerName = (String) reqHeaderEnum.nextElement(); headers.put(headerName.toLowerCase(), request.getHeader(headerName)); } //pd = PageData.newInstance().builder(userId, userName, this.getToken(request), reqData, componentCode, componentMethod, url, sessionId, appId, headers); headers.put(CommonConstant.COOKIE_AUTH_TOKEN, TokenUtil.getToken(request)); pd = PageData.newInstance().builder(userId, userName, "", reqData, componentCode, componentMethod, url, sessionId, appId, headers); pd.setMethod(request.getMethod().equals("GET") ? HttpMethod.GET : HttpMethod.POST); logger.debug("切面 获取到的pd=" + JSONObject.toJSONString(pd)); request.setAttribute(CommonConstant.CONTEXT_PAGE_DATA, pd); // 详细请求入参日志 logger.info("===== 请求开始 ====="); logger.info("请求URL: {} [{}]", url, request.getMethod()); logger.info("请求IP: {}", getIpAddr(request)); logger.info("请求用户: userId={}, userName={}", userId, userName); logger.info("请求参数: {}", reqData); logger.info("请求头: {}", JSONObject.toJSONString(headers)); //调用链 //Java110TraceFactory.createTrace(componentCode + "/" + componentMethod, headers); } @AfterReturning(returning = "ret", pointcut = "dataProcess()") public void doAfterReturning(Object ret) throws Throwable { // 处理完请求,返回内容 } //后置异常通知 @AfterThrowing("dataProcess()") public void throwException(JoinPoint jp) { } //后置最终通知,final增强,不管是抛出异常或者正常退出都会执行 @After("dataProcess()") public void after(JoinPoint jp) throws IOException { // 接收到请求,记录请求内容 ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletRequest request = attributes.getRequest(); //记录调用链 //Java110TraceFactory.putAnnotations(TraceAnnotationsDto.VALUE_CLIENT_RECEIVE); PageData pd = request.getAttribute(CommonConstant.CONTEXT_PAGE_DATA) != null ? (PageData) request.getAttribute(CommonConstant.CONTEXT_PAGE_DATA) : null; //保存日志处理 if (pd == null) { return; } //写cookies信息 writeCookieInfo(pd, attributes); } //环绕通知,环绕增强,相当于MethodInterceptor @Around("dataProcess()") public Object around(ProceedingJoinPoint pjp) { long startTime = System.currentTimeMillis(); Object o = null; Throwable exception = null; try { o = pjp.proceed(); return o; } catch (Throwable e) { exception = e; logger.error("===== 请求异常 ====="); logger.error("异常信息: {}", e.getMessage(), e); return new ResponseEntity(e.getLocalizedMessage(), HttpStatus.BAD_REQUEST); } finally { long elapsedTime = System.currentTimeMillis() - startTime; if (exception != null) { logger.error("请求耗时: {}ms, 返回状态: {}", elapsedTime, HttpStatus.BAD_REQUEST); logger.error("===== 请求结束(异常) ====="); } else { String responseBody = ""; HttpStatus status = HttpStatus.OK; if (o instanceof ResponseEntity) { ResponseEntity responseEntity = (ResponseEntity) o; status = responseEntity.getStatusCode(); if (responseEntity.getBody() != null) { responseBody = responseEntity.getBody().toString(); } } else if (o != null) { responseBody = o.toString(); } logger.info("请求耗时: {}ms, 返回状态: {}", elapsedTime, status); logger.info("返回数据: {}", responseBody); logger.info("===== 请求结束 ====="); } } } /** * 写cookie 信息 * * @param pd 页面封装信息 * @param attributes * @throws IOException */ private void writeCookieInfo(IPageData pd, ServletRequestAttributes attributes) throws IOException { // 这里目前只写到组件级别,如果需要 写成方法级别 && "login".equals(pd.getComponentCode()) //todo 未包含token 不做处理 if (StringUtil.isNullOrNone(pd.getToken())) { return; } HttpServletResponse response = attributes.getResponse(); //讲token写入到cookies 中 Cookie cookie = new Cookie(CommonConstant.COOKIE_AUTH_TOKEN, pd.getToken()); cookie.setHttpOnly(true); cookie.setPath("/"); response.addCookie(cookie); //response.addHeader("Set-Cookie","SameSite=None"); response.flushBuffer(); } private String getIpAddr(HttpServletRequest request) { String ip = request.getHeader("X-Forwarded-For"); if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("Proxy-Client-IP"); } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("WL-Proxy-Client-IP"); } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("HTTP_CLIENT_IP"); } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("HTTP_X_FORWARDED_FOR"); } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getRemoteAddr(); } return ip; } }