|
@@ -1,308 +0,0 @@
|
|
|
-package com.fdkankan.gateway.filter;
|
|
|
-
|
|
|
-import cn.dev33.satoken.stp.StpUtil;
|
|
|
-import cn.hutool.core.net.URLDecoder;
|
|
|
-import cn.hutool.core.util.StrUtil;
|
|
|
-import com.alibaba.fastjson.JSON;
|
|
|
-import com.alibaba.fastjson.JSONObject;
|
|
|
-import com.fdkankan.gateway.log.OperLog;
|
|
|
-import com.fdkankan.gateway.response.ResultData;
|
|
|
-import com.fdkankan.gateway.util.CacheUtil;
|
|
|
-import com.fdkankan.gateway.util.WebUtil;
|
|
|
-import com.fdkankan.redis.util.RedisUtil;
|
|
|
-import lombok.extern.slf4j.Slf4j;
|
|
|
-import org.reactivestreams.Publisher;
|
|
|
-import org.springframework.beans.factory.annotation.Autowired;
|
|
|
-import org.springframework.cloud.gateway.filter.GatewayFilterChain;
|
|
|
-import org.springframework.cloud.gateway.filter.factory.rewrite.CachedBodyOutputMessage;
|
|
|
-import org.springframework.cloud.gateway.route.Route;
|
|
|
-import org.springframework.cloud.gateway.support.BodyInserterContext;
|
|
|
-import org.springframework.cloud.gateway.support.ServerWebExchangeUtils;
|
|
|
-import org.springframework.core.io.buffer.DataBuffer;
|
|
|
-import org.springframework.core.io.buffer.DataBufferFactory;
|
|
|
-import org.springframework.core.io.buffer.DataBufferUtils;
|
|
|
-import org.springframework.core.io.buffer.DefaultDataBufferFactory;
|
|
|
-import org.springframework.http.HttpHeaders;
|
|
|
-import org.springframework.http.HttpStatus;
|
|
|
-import org.springframework.http.MediaType;
|
|
|
-import org.springframework.http.codec.HttpMessageReader;
|
|
|
-import org.springframework.http.server.reactive.ServerHttpRequest;
|
|
|
-import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
|
|
|
-import org.springframework.http.server.reactive.ServerHttpResponse;
|
|
|
-import org.springframework.http.server.reactive.ServerHttpResponseDecorator;
|
|
|
-import org.springframework.stereotype.Component;
|
|
|
-import org.springframework.util.MultiValueMap;
|
|
|
-import org.springframework.util.StringUtils;
|
|
|
-import org.springframework.web.reactive.function.BodyInserter;
|
|
|
-import org.springframework.web.reactive.function.BodyInserters;
|
|
|
-import org.springframework.web.reactive.function.server.HandlerStrategies;
|
|
|
-import org.springframework.web.reactive.function.server.ServerRequest;
|
|
|
-import org.springframework.web.server.ServerWebExchange;
|
|
|
-import reactor.core.publisher.Flux;
|
|
|
-import reactor.core.publisher.Mono;
|
|
|
-
|
|
|
-import java.nio.charset.StandardCharsets;
|
|
|
-import java.util.*;
|
|
|
-
|
|
|
-@Component
|
|
|
-@Slf4j
|
|
|
-public class CommonLogService {
|
|
|
-
|
|
|
- private final List<HttpMessageReader<?>> messageReaders = HandlerStrategies.withDefaults().messageReaders();
|
|
|
-
|
|
|
- @Autowired
|
|
|
- RedisUtil redisUtil;
|
|
|
-
|
|
|
- public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
|
|
|
-
|
|
|
- ServerHttpRequest request = exchange.getRequest();
|
|
|
- // 请求路径
|
|
|
- String uri = request.getPath().pathWithinApplication().value();
|
|
|
- String requestPath;
|
|
|
-
|
|
|
- Long userId = null;
|
|
|
- String userName = null;
|
|
|
- String nickName = null;
|
|
|
- if(uri.equals("/service/auth/manage/login")){
|
|
|
- requestPath = "登录";
|
|
|
- }else {
|
|
|
- requestPath = getRequestPath(uri);
|
|
|
- userId =Long.valueOf( StpUtil.getExtra("userId").toString());
|
|
|
- userName = StpUtil.getExtra("userName").toString();
|
|
|
- nickName = StpUtil.getExtra("nickName").toString();
|
|
|
- }
|
|
|
- String operationType;
|
|
|
- if(uri.contains("manage")){
|
|
|
- operationType = "manage";
|
|
|
- }else {
|
|
|
- operationType ="other";
|
|
|
- }
|
|
|
- String ipAddress = WebUtil.getIpAddress(request);
|
|
|
- String browser = WebUtil.getBrowser(request);
|
|
|
-
|
|
|
- OperLog operLog = new OperLog();
|
|
|
- operLog.setMethod(request.getMethodValue());
|
|
|
- operLog.setUri(uri);
|
|
|
- operLog.setCreateTime(new Date());
|
|
|
- operLog.setIp(ipAddress);
|
|
|
- operLog.setBrowser(browser);
|
|
|
- operLog.setRequestPath(requestPath);
|
|
|
- operLog.setOperationType(operationType);
|
|
|
-
|
|
|
- operLog.setUserId(userId);
|
|
|
- operLog.setUserName(userName);
|
|
|
- operLog.setNickName(nickName);
|
|
|
-
|
|
|
-
|
|
|
- MediaType mediaType = request.getHeaders().getContentType();
|
|
|
-
|
|
|
- if(MediaType.APPLICATION_FORM_URLENCODED.isCompatibleWith(mediaType)
|
|
|
- || MediaType.APPLICATION_JSON.isCompatibleWith(mediaType)){
|
|
|
- return writeBodyLog(exchange, chain, operLog);
|
|
|
- }else{
|
|
|
- return writeBasicLog(exchange, chain, operLog);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- private String getRequestPath(String uri) {
|
|
|
- JSONObject jsonObject = CacheUtil.manageMenuUrl.get(uri);
|
|
|
-
|
|
|
- if(StringUtils.isEmpty(jsonObject)){
|
|
|
- return null;
|
|
|
- }
|
|
|
- List<String> list = new ArrayList<>();
|
|
|
- getMenuName(list,jsonObject.getString("id"));
|
|
|
- Collections.reverse(list);
|
|
|
- StringBuilder requestPath = new StringBuilder();
|
|
|
- for (String path : list) {
|
|
|
- requestPath.append("[").append(path).append("]").append("->");
|
|
|
- }
|
|
|
- int i = requestPath.lastIndexOf("->");
|
|
|
- if(i < 0){
|
|
|
- return requestPath.toString();
|
|
|
- }
|
|
|
- return requestPath.substring(0,i);
|
|
|
- }
|
|
|
-
|
|
|
- private int getMenuName( List<String> list,String menuId){
|
|
|
- JSONObject jsonObject = CacheUtil.manageMenuId.get(menuId);
|
|
|
- if(StringUtils.isEmpty(jsonObject)){
|
|
|
- return -1;
|
|
|
- }
|
|
|
- list.add( jsonObject.getString("name"));
|
|
|
- String parentId = jsonObject.getString("parentId");
|
|
|
- if(!StringUtils.isEmpty(parentId)){
|
|
|
- return getMenuName(list,parentId);
|
|
|
- }
|
|
|
- return 1;
|
|
|
- }
|
|
|
-
|
|
|
- private Mono<Void> writeBasicLog(ServerWebExchange exchange, GatewayFilterChain chain, OperLog operLog) {
|
|
|
- StringBuilder builder = new StringBuilder();
|
|
|
- MultiValueMap<String, String> queryParams = exchange.getRequest().getQueryParams();
|
|
|
- for (Map.Entry<String, List<String>> entry : queryParams.entrySet()) {
|
|
|
- builder.append(entry.getKey()).append("=").append(StrUtil.join(",", entry.getValue()));
|
|
|
- }
|
|
|
- operLog.setParams(builder.toString());
|
|
|
-
|
|
|
- //获取响应体
|
|
|
- ServerHttpResponseDecorator decoratedResponse = recordResponseLog(exchange, operLog);
|
|
|
-
|
|
|
- return chain.filter(exchange.mutate().response(decoratedResponse).build())
|
|
|
- .then(Mono.fromRunnable(() -> {
|
|
|
- // 打印日志
|
|
|
- writeAccessLog(operLog);
|
|
|
- }));
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- /**
|
|
|
- * 参考: org.springframework.cloud.gateway.filter.factory.rewrite.ModifyRequestBodyGatewayFilterFactory
|
|
|
- * @param exchange
|
|
|
- * @param chain
|
|
|
- * @param operLog
|
|
|
- * @return
|
|
|
- */
|
|
|
- @SuppressWarnings("unchecked")
|
|
|
- private Mono writeBodyLog(ServerWebExchange exchange, GatewayFilterChain chain, OperLog operLog) {
|
|
|
- ServerRequest serverRequest = ServerRequest.create(exchange,messageReaders);
|
|
|
-
|
|
|
- Mono<String> modifiedBody = serverRequest.bodyToMono(String.class)
|
|
|
- .flatMap(body ->{
|
|
|
- operLog.setParams(URLDecoder.decode(body, StandardCharsets.UTF_8));
|
|
|
- return Mono.just(body);
|
|
|
- });
|
|
|
-
|
|
|
- // 通过 BodyInserter 插入 body(支持修改body), 避免 request body 只能获取一次
|
|
|
- BodyInserter bodyInserter = BodyInserters.fromPublisher(modifiedBody, String.class);
|
|
|
- HttpHeaders headers = new HttpHeaders();
|
|
|
- headers.putAll(exchange.getRequest().getHeaders());
|
|
|
- // the new content type will be computed by bodyInserter
|
|
|
- // and then set in the request decorator
|
|
|
- headers.remove(HttpHeaders.CONTENT_LENGTH);
|
|
|
-
|
|
|
- CachedBodyOutputMessage outputMessage = new CachedBodyOutputMessage(exchange, headers);
|
|
|
-
|
|
|
- return bodyInserter.insert(outputMessage,new BodyInserterContext())
|
|
|
- .then(Mono.defer(() -> {
|
|
|
-
|
|
|
- // 重新封装请求
|
|
|
- ServerHttpRequest decoratedRequest = requestDecorate(exchange, headers, outputMessage);
|
|
|
-
|
|
|
- // 记录响应日志
|
|
|
- ServerHttpResponseDecorator decoratedResponse = recordResponseLog(exchange, operLog);
|
|
|
-
|
|
|
- // 记录普通的
|
|
|
- return chain.filter(exchange.mutate().request(decoratedRequest).response(decoratedResponse).build())
|
|
|
- .then(Mono.fromRunnable(() -> {
|
|
|
- // 打印日志
|
|
|
- writeAccessLog(operLog);
|
|
|
- }));
|
|
|
- }));
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 打印日志
|
|
|
- * @param operLog 网关日志
|
|
|
- */
|
|
|
- private void writeAccessLog(OperLog operLog) {
|
|
|
- log.info(JSON.toJSONString(operLog));
|
|
|
- //日志写入mongodb
|
|
|
-// mongoTemplate.insert(operLog, "OperLog");
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- private Route getGatewayRoute(ServerWebExchange exchange) {
|
|
|
- return exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR);
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- /**
|
|
|
- * 请求装饰器,重新计算 headers
|
|
|
- * @param exchange
|
|
|
- * @param headers
|
|
|
- * @param outputMessage
|
|
|
- * @return
|
|
|
- */
|
|
|
- private ServerHttpRequestDecorator requestDecorate(ServerWebExchange exchange, HttpHeaders headers,
|
|
|
- CachedBodyOutputMessage outputMessage) {
|
|
|
- return new ServerHttpRequestDecorator(exchange.getRequest()) {
|
|
|
- @Override
|
|
|
- public HttpHeaders getHeaders() {
|
|
|
- long contentLength = headers.getContentLength();
|
|
|
- HttpHeaders httpHeaders = new HttpHeaders();
|
|
|
- httpHeaders.putAll(super.getHeaders());
|
|
|
- if (contentLength > 0) {
|
|
|
- httpHeaders.setContentLength(contentLength);
|
|
|
- } else {
|
|
|
- httpHeaders.set(HttpHeaders.TRANSFER_ENCODING, "chunked");
|
|
|
- }
|
|
|
- return httpHeaders;
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public Flux<DataBuffer> getBody() {
|
|
|
- return outputMessage.getBody();
|
|
|
- }
|
|
|
- };
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- /**
|
|
|
- * 记录响应日志
|
|
|
- * 通过 DataBufferFactory 解决响应体分段传输问题。
|
|
|
- */
|
|
|
- private ServerHttpResponseDecorator recordResponseLog(ServerWebExchange exchange, OperLog operLog) {
|
|
|
- ServerHttpResponse response = exchange.getResponse();
|
|
|
- DataBufferFactory bufferFactory = response.bufferFactory();
|
|
|
-
|
|
|
- return new ServerHttpResponseDecorator(response) {
|
|
|
-
|
|
|
- @Override
|
|
|
- public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
|
|
|
- if (body instanceof Flux) {
|
|
|
- // 获取响应类型,如果是 json 就打印
|
|
|
- String originalResponseContentType = exchange.getAttribute(ServerWebExchangeUtils.ORIGINAL_RESPONSE_CONTENT_TYPE_ATTR);
|
|
|
-
|
|
|
- if (this.getStatusCode().equals(HttpStatus.OK)
|
|
|
- && StrUtil.isNotBlank(originalResponseContentType)
|
|
|
-// && originalResponseContentType.contains("application/json")
|
|
|
- ) {
|
|
|
-
|
|
|
- Flux<? extends DataBuffer> fluxBody = Flux.from(body);
|
|
|
- return super.writeWith(fluxBody.buffer().map(dataBuffers -> {
|
|
|
-
|
|
|
- // 合并多个流集合,解决返回体分段传输
|
|
|
- DataBufferFactory dataBufferFactory = new DefaultDataBufferFactory();
|
|
|
- DataBuffer join = dataBufferFactory.join(dataBuffers);
|
|
|
- byte[] content = new byte[join.readableByteCount()];
|
|
|
- join.read(content);
|
|
|
-
|
|
|
- // 释放掉内存
|
|
|
- DataBufferUtils.release(join);
|
|
|
- String responseResult = new String(content, StandardCharsets.UTF_8);
|
|
|
-
|
|
|
- ResultData resultData = JSON.parseObject(responseResult, ResultData.class);
|
|
|
- if(resultData.getCode() == 0){
|
|
|
- operLog.setResult("操作成功");
|
|
|
- if(operLog.getUserId() == null){
|
|
|
- JSONObject jsonObject = (JSONObject) resultData.getData();
|
|
|
- operLog.setUserId( Long.valueOf(jsonObject.getString("id")));
|
|
|
- operLog.setUserName(jsonObject.getString("userName"));
|
|
|
- operLog.setNickName(jsonObject.getString("nickName"));
|
|
|
- }
|
|
|
- }else {
|
|
|
- operLog.setResult("操作失败");
|
|
|
- }
|
|
|
-
|
|
|
- return bufferFactory.wrap(content);
|
|
|
- }));
|
|
|
- }
|
|
|
- }
|
|
|
- // if body is not a flux. never got there.
|
|
|
- return super.writeWith(body);
|
|
|
- }
|
|
|
- };
|
|
|
- }
|
|
|
-}
|