使用CustomRequestMappingHandlerMapping自定义统一处理前后端接口不一致问题

spring mvc或spring boot使用RequestMappingHandlerMapping自定义统一处理前后端接口不一致问题

本文地址:https://www.cnblogs.com/muphy/p/16714292.html

场景

以前老项目漏洞修复升级,前端请求有些带.do后缀,有些没带,后端controller接口也是有些带.do后缀,有些没带,而且他们不是一一对应,不知以前是怎么跑得起来,升级之后就很多接口就404了,还无法全局替换修复,因为业务复杂涉及权限等,短时间无法哈清楚,所以只能考虑兼容方案

方式一

修改后端接口,让所有的都支持两种访问方式:@RequestMapping(value = { "/item/index", "/item/index.do" }),工作量超大

方式二

使用面向切面思想,只需要实现RequestMappingHandlerMapping统一处理,让每个接口方法覆盖两种url方式,适用于 spring mvcspring boot ,代码如下:

package me.muphy;

import org.springframework.stereotype.Component;
import org.springframework.web.servlet.mvc.condition.PatternsRequestCondition;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Locale;
import java.util.Set;

@Component
public class CustomRequestMappingHandlerMapping extends RequestMappingHandlerMapping {

    @Override
    protected boolean isHandler(Class<?> beanType) {
        return super.isHandler(beanType);
    }

    @Override
    protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
        RequestMappingInfo info = super.getMappingForMethod(method, handlerType);
        if (info == null) {
            return info;
        }
        try {
            PatternsRequestCondition patternsCondition = info.getPatternsCondition();
            if (patternsCondition == null) {
                return info;
            }
            Set<String> oldPatterns = patternsCondition.getPatterns();
            //Set<String> patterns = new HashSet<>();
            for (String pattern : oldPatterns) {
                if (pattern.toLowerCase(Locale.ROOT).endsWith(".do")) {
                    String p = pattern.replaceAll("\\.[dD][Oo]$", "");
                    oldPatterns.add(p); // set去重
                } else {
                    if (!pattern.matches(".+\\.\\w+$")) {
                        String p = pattern + ".do";
                        oldPatterns.add(p);
                    }
                }
            }
            for (String pattern : oldPatterns) {
                System.out.println("pattern = " + pattern);
            }
        } catch (Exception e) {
            e.printStackTrace();
            logger.error(e);
        }
        //PatternsRequestCondition patternsRequestCondition = new PatternsRequestCondition(
        //        patterns.toArray( new String[]{} ), null, null, true, true, null );
        //RequestMappingInfo mappingInfo = new RequestMappingInfo(
        //        null, patternsRequestCondition, info.getMethodsCondition(), info.getParamsCondition(), info.getHeadersCondition(), info.getConsumesCondition(),
        //        info.getProducesCondition(), info.getCustomCondition()
        //);
        return info;
    }
}

方式三

上面的方案对处理当前的问题很好,不过如果复杂一点可能会出现地址冲突,使用 @PostConstruct 等实现延时注册避免冲突

package mu.muphy;

import com.alibaba.fastjson.JSON;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.condition.PatternsRequestCondition;
import org.springframework.web.servlet.mvc.condition.RequestMethodsRequestCondition;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import javax.annotation.PostConstruct;
import java.util.*;

@RestController
@RequestMapping("url")
public class UrlHandleController {

    @Autowired
    private RequestMappingHandlerMapping mapping;

    // 同一个对象追加
    @PostConstruct
    public void register() {
        if (mapping == null) {
            return;
        }
        // 获取所有的url
        Set<String> allUrls = new HashSet<>();
        Map<RequestMappingInfo, HandlerMethod> methods = mapping.getHandlerMethods();
        for (Map.Entry<RequestMappingInfo, HandlerMethod> m : methods.entrySet()) {
            RequestMappingInfo info = m.getKey();
            for (String pattern : info.getPatternValues()) {
                allUrls.add(pattern);
            }
        }
        // 注册新的url
        for (Map.Entry<RequestMappingInfo, HandlerMethod> m : methods.entrySet()) {
            RequestMappingInfo info = m.getKey();
            PatternsRequestCondition patternsCondition = info.getPatternsCondition();
            Set<String> patterns = patternsCondition.getPatterns();
            Set<String> ps = new HashSet<>();
            for (String pattern : patterns) {
                if (pattern.toLowerCase(Locale.ROOT).endsWith(".do")) {
                    String p = pattern.replaceAll("\\.[dD][Oo]$", "");
                    if (!allUrls.contains(p)) {
                        ps.add(p); // set去重
                    }
                } else {
                    if (!pattern.matches(".+\\.\\w+$")) {
                        String p = pattern + ".do";
                        if (!allUrls.contains(p)) {
                            ps.add(p); // set去重
                        }
                    }
                }
            }
            patterns.addAll(ps);
        }
    }

    // 才分成两个对象
    //@PostConstruct
    public void register2() {
        if (mapping == null) {
            return;
        }
        // 获取所有的url
        Set<String> allUrls = new HashSet<>();
        Map<RequestMappingInfo, HandlerMethod> methods = mapping.getHandlerMethods();
        for (Map.Entry<RequestMappingInfo, HandlerMethod> m : methods.entrySet()) {
            RequestMappingInfo info = m.getKey();
            for (String pattern : info.getPatternValues()) {
                allUrls.add(pattern);
            }
        }
        // 注册新的url
        for (Map.Entry<RequestMappingInfo, HandlerMethod> m : methods.entrySet()) {
            RequestMappingInfo info = m.getKey();
            HandlerMethod handlerMethod = m.getValue();
            Set<String> patterns = new HashSet<>();
            for (String pattern : info.getPatternValues()) {
                if (pattern.toLowerCase(Locale.ROOT).endsWith(".do")) {
                    String p = pattern.replaceAll("\\.[dD][Oo]$", "");
                    if (!allUrls.contains(p)) {
                        patterns.add(p); // set去重
                    }
                } else {
                    if (!pattern.matches(".+\\.\\w+$")) {
                        String p = pattern + ".do";
                        if (!allUrls.contains(p)) {
                            patterns.add(p); // set去重
                        }
                    }
                }
            }
            if (!patterns.isEmpty()) {
                try {
                    PatternsRequestCondition patternsRequestCondition = new PatternsRequestCondition(
                        patterns.toArray(new String[]{}), null, null, true, true, null);
                    RequestMappingInfo mappingInfo = new RequestMappingInfo(
                        null, patternsRequestCondition, info.getMethodsCondition(), info.getParamsCondition(), info.getHeadersCondition(), info.getConsumesCondition(),
                        info.getProducesCondition(), info.getCustomCondition()
                    );
                    mapping.registerMapping(mappingInfo, handlerMethod.getBean(), handlerMethod.getMethod());
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    @GetMapping("/list")
    public List<Map<String, String>> getAllUrl(String parentUrl) {
        if (mapping == null) {
            return new ArrayList<>();
        }
        Map<RequestMappingInfo, HandlerMethod> methods = mapping.getHandlerMethods();
        List<Map<String, String>> list = new ArrayList<>();
        for (Map.Entry<RequestMappingInfo, HandlerMethod> m : methods.entrySet()) {
            Map<String, String> map = new HashMap<>();
            RequestMappingInfo info = m.getKey();
            HandlerMethod method = m.getValue();
            PatternsRequestCondition p = info.getPatternsCondition();
            map.put("className", method.getMethod().getDeclaringClass().getName()); // 类名
            map.put("method", method.getMethod().getName()); // 方法名
            map.put("url", Arrays.toString(p.getPatterns().toArray()));
            map.put("parameterTypes", JSON.toJSONString(method.getMethod().getParameterTypes()));
            RequestMethodsRequestCondition methodsCondition = info.getMethodsCondition();
            for (RequestMethod requestMethod : methodsCondition.getMethods()) {
                map.put("type", requestMethod.toString());
            }
            if (!StringUtils.isEmpty(map.get("url")) && (StringUtils.isEmpty(parentUrl) || map.get("url").contains(parentUrl))) {
                list.add(map);
            }
        }
        return list;
    }

}

测试

var myHeaders = new Headers();
myHeaders.append("Authorization", "Bearer 6d611410-60ee-45e6-b64d-85b500a7eb50");

var requestOptions = {
  method: 'GET',
  headers: myHeaders,
  redirect: 'follow'
};

fetch("http://localhost:8881/url/list.do", requestOptions)
  .then(response => response.text())
  .then(result => console.log(result))
  .catch(error => console.log('error', error));

posted @ 2022-09-21 06:08  明月心~  阅读(650)  评论(0编辑  收藏  举报