Spring Boot如何基于eventType参数将请求内部转发到对应Controller方法
解决方案
以下提供两种可直接落地的实现方式,无需大幅改动现有代码:
方案1:统一入口转发(优先推荐,符合路径变量取eventType的需求)
新增一个调度Controller作为统一入口,解析路径中的eventType参数后做服务器内部转发,完全兼容现有CardController、LaneController的逻辑。
import org.springframework.web.bind.annotation.*; import java.util.HashMap; import java.util.Map; @RestController @RequestMapping("/app") public class EventDispatchController { // eventType action到后端实际路径的映射,若前后端命名一致可省略 private static final Map<String, String> ACTION_MAPPING = new HashMap<>(); static { ACTION_MAPPING.put("addCard", "createCard"); ACTION_MAPPING.put("updateCard", "updateCard"); ACTION_MAPPING.put("addLane", "addLane"); ACTION_MAPPING.put("updateLane", "updateLane"); } @PostMapping("/{roomId}/{eventType}") public String dispatchEvent(@PathVariable Long roomId, @PathVariable String eventType) { // 拆分eventType为模块名和操作名 例:cards.addCard -> ["cards", "addCard"] String[] typeParts = eventType.split("\\."); String module = typeParts[0]; String action = typeParts[1]; // 拼接目标Controller的实际路径 String targetPath = String.format("/%s/%s/%s", module, roomId, ACTION_MAPPING.get(action)); // 服务器内部转发,请求体自动透传,前端无感知,不会产生302跳转 return "forward:" + targetPath; } }
该方案优势:
- 完全兼容现有业务代码,无需修改原有Controller的任何逻辑
- 后续新增事件类型仅需维护
ACTION_MAPPING映射即可,扩展成本极低 - 请求体、请求头参数会自动透传到目标方法,无需额外处理
方案2:自定义请求映射(无转发层,性能更高)
如果事件类型数量较多,不想多一层转发开销,可以自定义Spring的HandlerMapping,在请求路由阶段直接解析eventType匹配到对应Controller方法。
import org.springframework.stereotype.Component; import org.springframework.web.servlet.HandlerExecutionChain; import org.springframework.web.servlet.HandlerMapping; import javax.servlet.http.HttpServletRequest; import java.util.HashMap; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; @Component public class EventTypeHandlerMapping implements HandlerMapping { private static final Pattern EVENT_URI_PATTERN = Pattern.compile("^/app/(\\d+)/([a-z]+\\.[a-zA-Z]+)$"); private static final Map<String, String> ACTION_MAPPING = new HashMap<>(); static { ACTION_MAPPING.put("addCard", "createCard"); ACTION_MAPPING.put("updateCard", "updateCard"); ACTION_MAPPING.put("addLane", "addLane"); ACTION_MAPPING.put("updateLane", "updateLane"); } @Override public HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { String uri = request.getRequestURI(); Matcher matcher = EVENT_URI_PATTERN.matcher(uri); if (matcher.matches()) { String roomId = matcher.group(1); String eventType = matcher.group(2); String[] typeParts = eventType.split("\\."); String targetUri = String.format("/%s/%s/%s", typeParts[0], roomId, ACTION_MAPPING.get(typeParts[1])); // 改写请求URI为实际的Controller路径,走Spring默认的路由匹配逻辑 request.setAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, targetUri); } // 匹配不到返回null,走默认的HandlerMapping处理 return null; } }
若选择eventType放在请求体的实现
只需将方案1中eventType的取值逻辑从路径变量改为从@RequestBody中读取即可,其余转发逻辑完全不变。
内容的提问来源于stack exchange,提问作者Korki Korkig
相关产品推荐
相关产品推荐

