skyouc
2024-12-21 c635d78b479510ebe2556a420948effcd30a0731
zy-asrs-wms/src/main/java/com/zy/asrs/wms/common/security/CacheFilter.java
@@ -1,202 +1,202 @@
package com.zy.asrs.wms.common.security;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.zy.asrs.framework.common.R;
import com.zy.asrs.wms.common.annotation.CacheData;
import com.zy.asrs.wms.common.constant.Constants;
import com.zy.asrs.wms.common.constant.RedisConstants;
import com.zy.asrs.wms.common.domain.CacheHitDto;
import com.zy.asrs.wms.system.entity.User;
import com.zy.asrs.wms.system.entity.UserLogin;
import com.zy.asrs.wms.system.service.UserService;
import com.zy.asrs.wms.utils.EncryptUtils;
import com.zy.asrs.wms.utils.HttpUtils;
import com.zy.asrs.wms.utils.RedisUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerExecutionChain;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.Map;
import java.util.stream.Collectors;
@Component
public class CacheFilter extends OncePerRequestFilter {
    @Value("${system.enableCache}")
    private Boolean enableCache;
    @Autowired
    private RequestMappingHandlerMapping handlerMapping;
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private UserService userService;
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
        // 获取当前请求的处理器方法
        HandlerExecutionChain handlerChain;
        try {
            handlerChain = handlerMapping.getHandler(request);
            if (handlerChain != null) {
                Object handler = handlerChain.getHandler();
                if (handler instanceof HandlerMethod) {
                    HandlerMethod handlerMethod = (HandlerMethod) handler;
                    Method method = handlerMethod.getMethod();
                    if (method.isAnnotationPresent(CacheData.class)) {
                        CacheData cacheData = method.getAnnotation(CacheData.class);
                        if (enableCache && cacheData.cache()) {
                            // 创建一个包装请求体的 HttpServletRequestWrapper
                            CachedBodyHttpServletRequest cachedBodyHttpServletRequest = new CachedBodyHttpServletRequest(request);
                            // 创建一个包装响应体的 HttpServletResponseWrapper
                            CachedBodyHttpServletResponse cachedBodyHttpServletResponse = new CachedBodyHttpServletResponse(response);
                            String requestParamCode = getRequestParamCode(cachedBodyHttpServletRequest);
                            User user = getUser();
                            ArrayList<Long> roleIds = new ArrayList<>();
                            if (user == null) {
                                roleIds.add(0L);
                            }else {
                                roleIds.addAll(Arrays.asList(user.getUserRoleIds()));
                            }
                            Object object = null;
                            for (Long roleId : roleIds) {
                                Object obj = redisUtil.get(RedisConstants.getCacheKey(RedisConstants.CACHE_DATA, cacheData.tableName(), request.getRequestURI(), requestParamCode, roleId));
                                if(obj != null){
                                    object = obj;
                                    break;
                                }
                            }
                            if (object == null) {
                                chain.doFilter(cachedBodyHttpServletRequest, cachedBodyHttpServletResponse);
                                // 获取响应内容
                                byte[] responseContent = cachedBodyHttpServletResponse.getContent();
                                String responseBody = new String(responseContent);
                                JSONObject result = JSON.parseObject(responseBody);
                                if (Integer.parseInt(result.get("code").toString()) == 200) {
                                    for (Long roleId : roleIds) {
                                        redisUtil.set(RedisConstants.getCacheKey(RedisConstants.CACHE_DATA, cacheData.tableName(), request.getRequestURI(), requestParamCode, roleId), responseBody, 60 * 60 * 24);
                                    }
                                }
                                // 将响应内容写回原始的 HttpServletResponse
                                response.getOutputStream().write(responseContent);
                                response.setContentLength(responseContent.length);
                            }else {
                                // 将响应内容写回原始的 HttpServletResponse
                                byte[] responseContent = object.toString().getBytes();
                                response.setContentType("application/json;charset=UTF-8");
                                response.getOutputStream().write(responseContent);
                                response.setContentLength(responseContent.length);
                            }
                            statisticsCacheHitCount(object, cacheData.tableName(), request.getRequestURI());
                            return;
                        }
                    }
                }
            }
            chain.doFilter(request, response);
        } catch (Exception e) {
            e.printStackTrace();
            HttpUtils.responseError(response, Constants.BAD_CREDENTIALS_CODE, Constants.BAD_CREDENTIALS_MSG,
                    e.toString());
            return;
        }
    }
    private String getRequestParamCode(CachedBodyHttpServletRequest request) throws IOException {
        // 获取请求方法
        String requestMethod = request.getMethod();
        String md5 = "";
        // 检查请求方法并处理
        if ("POST".equalsIgnoreCase(requestMethod)) {
            // 检查是否为 form-data 类型
            String contentType = request.getContentType();
            if (contentType != null && (contentType.startsWith("application/x-www-form-urlencoded") || contentType.startsWith("multipart/form-data"))) {
                // 处理 form-data 参数
                Map<String, String[]> parameterMap = request.getParameterMap();
                String jsonString = JSON.toJSONString(parameterMap);
                md5 = EncryptUtils.md5(jsonString);
            } else {
                // 读取请求体中的 JSON 数据
                String jsonRequestBody = request.getReader().lines().collect(Collectors.joining(System.lineSeparator()));
                md5 = EncryptUtils.md5(jsonRequestBody);
            }
        } else if ("GET".equalsIgnoreCase(requestMethod)) {
            Map<String, String[]> map = request.getParameterMap();
            String jsonString = JSON.toJSONString(map);
            md5 = EncryptUtils.md5(jsonString);
        }
        return md5;
    }
    private User getUser() {
        try {
            Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
            if (authentication != null) {
                Object object = authentication.getPrincipal();
                if (object instanceof User) {
                    return (User) object;
                }
                if(object instanceof UserLogin) {
                    UserLogin userLogin = (UserLogin) object;
                    User user = userService.superGetById(userLogin.getUserId());
                    return user;
                }
            }
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
        return null;
    }
    private void statisticsCacheHitCount(Object object, String[] tableNames, String requestURI) {
        statisticsCacheSaveRedis(object, requestURI);
        for (String tableName : tableNames) {
            statisticsCacheSaveRedis(object, tableName);
        }
    }
    private void statisticsCacheSaveRedis(Object object, String key) {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        String now = format.format(new Date());
        String urlKey = RedisConstants.STATISTICS_CACHE_DATA + ":" + now + ":" + key;
        Object urlCache = redisUtil.get(urlKey);
        CacheHitDto cacheHitDto = new CacheHitDto(0, 0);
        if (urlCache != null) {
            cacheHitDto = JSON.parseObject(urlCache.toString(), CacheHitDto.class);
        }
        if (object == null) {
            cacheHitDto.setMiss(cacheHitDto.getMiss() + 1);
        }else {
            cacheHitDto.setHit(cacheHitDto.getHit() + 1);
        }
        redisUtil.set(urlKey, JSON.toJSONString(cacheHitDto));
    }
}
package com.zy.asrs.wms.common.security;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.zy.asrs.framework.common.R;
import com.zy.asrs.wms.common.annotation.CacheData;
import com.zy.asrs.wms.common.constant.Constants;
import com.zy.asrs.wms.common.constant.RedisConstants;
import com.zy.asrs.wms.common.domain.CacheHitDto;
import com.zy.asrs.wms.system.entity.User;
import com.zy.asrs.wms.system.entity.UserLogin;
import com.zy.asrs.wms.system.service.UserService;
import com.zy.asrs.wms.utils.EncryptUtils;
import com.zy.asrs.wms.utils.HttpUtils;
import com.zy.asrs.wms.utils.RedisUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerExecutionChain;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.Map;
import java.util.stream.Collectors;
@Component
public class CacheFilter extends OncePerRequestFilter {
    @Value("${system.enableCache}")
    private Boolean enableCache;
    @Autowired
    private RequestMappingHandlerMapping handlerMapping;
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private UserService userService;
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
        // 获取当前请求的处理器方法
        HandlerExecutionChain handlerChain;
        try {
            handlerChain = handlerMapping.getHandler(request);
            if (handlerChain != null) {
                Object handler = handlerChain.getHandler();
                if (handler instanceof HandlerMethod) {
                    HandlerMethod handlerMethod = (HandlerMethod) handler;
                    Method method = handlerMethod.getMethod();
                    if (method.isAnnotationPresent(CacheData.class)) {
                        CacheData cacheData = method.getAnnotation(CacheData.class);
                        if (enableCache && cacheData.cache()) {
                            // 创建一个包装请求体的 HttpServletRequestWrapper
                            CachedBodyHttpServletRequest cachedBodyHttpServletRequest = new CachedBodyHttpServletRequest(request);
                            // 创建一个包装响应体的 HttpServletResponseWrapper
                            CachedBodyHttpServletResponse cachedBodyHttpServletResponse = new CachedBodyHttpServletResponse(response);
                            String requestParamCode = getRequestParamCode(cachedBodyHttpServletRequest);
                            User user = getUser();
                            ArrayList<Long> roleIds = new ArrayList<>();
                            if (user == null) {
                                roleIds.add(0L);
                            }else {
                                roleIds.addAll(Arrays.asList(user.getUserRoleIds()));
                            }
                            Object object = null;
                            for (Long roleId : roleIds) {
                                Object obj = redisUtil.get(RedisConstants.getCacheKey(RedisConstants.CACHE_DATA, cacheData.tableName(), request.getRequestURI(), requestParamCode, roleId));
                                if(obj != null){
                                    object = obj;
                                    break;
                                }
                            }
                            if (object == null) {
                                chain.doFilter(cachedBodyHttpServletRequest, cachedBodyHttpServletResponse);
                                // 获取响应内容
                                byte[] responseContent = cachedBodyHttpServletResponse.getContent();
                                String responseBody = new String(responseContent);
                                JSONObject result = JSON.parseObject(responseBody);
                                if (Integer.parseInt(result.get("code").toString()) == 200) {
                                    for (Long roleId : roleIds) {
                                        redisUtil.set(RedisConstants.getCacheKey(RedisConstants.CACHE_DATA, cacheData.tableName(), request.getRequestURI(), requestParamCode, roleId), responseBody, 60 * 60 * 24);
                                    }
                                }
                                // 将响应内容写回原始的 HttpServletResponse
                                response.getOutputStream().write(responseContent);
                                response.setContentLength(responseContent.length);
                            }else {
                                // 将响应内容写回原始的 HttpServletResponse
                                byte[] responseContent = object.toString().getBytes();
                                response.setContentType("application/json;charset=UTF-8");
                                response.getOutputStream().write(responseContent);
                                response.setContentLength(responseContent.length);
                            }
                            statisticsCacheHitCount(object, cacheData.tableName(), request.getRequestURI());
                            return;
                        }
                    }
                }
            }
            chain.doFilter(request, response);
        } catch (Exception e) {
            e.printStackTrace();
            HttpUtils.responseError(response, Constants.BAD_CREDENTIALS_CODE, Constants.BAD_CREDENTIALS_MSG,
                    e.toString());
            return;
        }
    }
    private String getRequestParamCode(CachedBodyHttpServletRequest request) throws IOException {
        // 获取请求方法
        String requestMethod = request.getMethod();
        String md5 = "";
        // 检查请求方法并处理
        if ("POST".equalsIgnoreCase(requestMethod)) {
            // 检查是否为 form-data 类型
            String contentType = request.getContentType();
            if (contentType != null && (contentType.startsWith("application/x-www-form-urlencoded") || contentType.startsWith("multipart/form-data"))) {
                // 处理 form-data 参数
                Map<String, String[]> parameterMap = request.getParameterMap();
                String jsonString = JSON.toJSONString(parameterMap);
                md5 = EncryptUtils.md5(jsonString);
            } else {
                // 读取请求体中的 JSON 数据
                String jsonRequestBody = request.getReader().lines().collect(Collectors.joining(System.lineSeparator()));
                md5 = EncryptUtils.md5(jsonRequestBody);
            }
        } else if ("GET".equalsIgnoreCase(requestMethod)) {
            Map<String, String[]> map = request.getParameterMap();
            String jsonString = JSON.toJSONString(map);
            md5 = EncryptUtils.md5(jsonString);
        }
        return md5;
    }
    private User getUser() {
        try {
            Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
            if (authentication != null) {
                Object object = authentication.getPrincipal();
                if (object instanceof User) {
                    return (User) object;
                }
                if(object instanceof UserLogin) {
                    UserLogin userLogin = (UserLogin) object;
                    User user = userService.superGetById(userLogin.getUserId());
                    return user;
                }
            }
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
        return null;
    }
    private void statisticsCacheHitCount(Object object, String[] tableNames, String requestURI) {
        statisticsCacheSaveRedis(object, requestURI);
        for (String tableName : tableNames) {
            statisticsCacheSaveRedis(object, tableName);
        }
    }
    private void statisticsCacheSaveRedis(Object object, String key) {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        String now = format.format(new Date());
        String urlKey = RedisConstants.STATISTICS_CACHE_DATA + ":" + now + ":" + key;
        Object urlCache = redisUtil.get(urlKey);
        CacheHitDto cacheHitDto = new CacheHitDto(0, 0);
        if (urlCache != null) {
            cacheHitDto = JSON.parseObject(urlCache.toString(), CacheHitDto.class);
        }
        if (object == null) {
            cacheHitDto.setMiss(cacheHitDto.getMiss() + 1);
        }else {
            cacheHitDto.setHit(cacheHitDto.getHit() + 1);
        }
        redisUtil.set(urlKey, JSON.toJSONString(cacheHitDto));
    }
}