@RestController @RequestMapping("/proxy") public class ProxyController { @Autowired private RestTemplate restTemplate; // 堆代码 duidaima.com @GetMapping("/data") public String forwardRequest() { String targetUrl = "http://example.com/api/data"; // 发送GET请求并返回字符串响应 String response = restTemplate.getForObject(targetUrl, String.class); return response; } }使用 WebClient
@RestController @RequestMapping("/proxy") public class ProxyController { private final WebClient webClient; public ProxyController() { this.webClient = WebClient.builder().baseUrl("http://example.com/api").build(); } @GetMapping("/data") public Mono<String> forwardRequest() { return webClient.get() .uri("/data") .accept(MediaType.APPLICATION_JSON) .retrieve() .bodyToMono(String.class); } }当需要处理大量的接口转发时,使用上述方法可能会导致代码冗余,并且每增加一个新的接口转发逻辑都需要修改现有代码。这不仅增加了代码的复杂度,也降低了代码的可维护性和扩展性。
<?xml version="1.0" encoding="UTF-8" ?> <controllers> <controller name="queryUser" desc="此处的beanName为注册进入Spring容器的名称,需保证唯一性"> <input desc="请求方服务能力开放平台配置"> <requesthead url="/queryUser" method="POST" token="" contenttype="" ></requesthead> <parameters desc="请求参数配置"> <parameter name="operator" desc="参数1描述">1</parameter> </parameters> </input> <auth desc="向第三方平台发起认证请求配置,若非必须发送发送认证请求,此处可不配置"> <requesthead url="http://localhost:8081/test/auth" method="POST" token="" contenttype="application/json" ></requesthead> <parameters desc="请求参数配置"> <parameter name="username" desc="认证请求参数配置-用户名">yian</parameter> <parameter name="password" desc="认证请求参数配置-密码">123456</parameter> </parameters> <responses desc="认证返回结果封装"> <parameter name="token" desc="认证token解析参数名"></parameter> </responses> </auth> <output desc="按运营商统计近24小时内认证成功总数相关配置"> <requesthead url="http://localhost:8081/test/authResult" method="GET" token="abcd" contenttype="" ></requesthead> <parameters desc="按运营商统计近24小时内认证成功总数请求参数配置"> <parameter name="operator" desc="请求参数配置">1</parameter> </parameters> <responses desc="最终返回结果封装" removeAttr="port"> <parameter name="code" desc="响应结果码"></parameter> <parameter name="msg" desc="响应结果描述"></parameter> <parameter name="data" desc="响应结果"></parameter> </responses> </output> </controller> </controllers>对于XML转POJO对象,可以借助其注解实现,伪代码:
@Data @NoArgsConstructor @AllArgsConstructor @XmlRootElement(name = "controllers") @XmlAccessorType(XmlAccessType.FIELD) public class ControllerBeanList { @XmlElement(name = "controller") private List<ControllerBean> controllerBeanList; } @Data @NoArgsConstructor @AllArgsConstructor @XmlRootElement(name = "controller") @XmlAccessorType(XmlAccessType.FIELD) public class ControllerBean { @XmlAttribute(name = "name") private String name; @XmlElement(name = "input") private InputBean inputBean; @XmlElement(name = "auth") private AuthBean authBean; @XmlElement(name = "output") private OutputBean outputBean; }将XML转为指定的POJO对象
/** * 将XML转为指定的POJO对象 * * @param clazz 需要转换的类 * @param xmlStr xml数据 * @return */ public static Object xmlStrToObject(Class<?> clazz, String xmlStr) throws Exception { Object xmlObject = null; Reader reader = null; //利用JAXBContext将类转为一个实例 JAXBContext context = JAXBContext.newInstance(clazz); //XMl 转为对象的接口 Unmarshaller unmarshaller = context.createUnmarshaller(); reader = new StringReader(xmlStr); xmlObject = unmarshaller.unmarshal(reader); if (reader != null) { reader.close(); } return xmlObject; }配置动态生成RouterFunction
private RouterFunction builderRouterFunction(ControllerBean controllerBean){ String reqUrl = controllerBean.getInputBean().getRequestHeadBean().getUrl(); String reqMethod = controllerBean.getInputBean().getRequestHeadBean().getMethod(); //构建RequestPredicate RequestPredicate requestPredicate=null; switch (reqMethod){ case METHOD_GET: requestPredicate = RequestPredicates.GET(reqUrl).and(RequestPredicates.accept(MediaType.ALL)); break; case METHOD_POST: requestPredicate = RequestPredicates.POST(reqUrl).and(RequestPredicates.accept(MediaType.ALL)); break; case METHOD_PUT: requestPredicate = RequestPredicates.PUT(reqUrl).and(RequestPredicates.accept(MediaType.ALL)); break; case METHOD_DELETE: requestPredicate = RequestPredicates.DELETE(reqUrl).and(RequestPredicates.accept(MediaType.ALL)); break; default: requestPredicate = RequestPredicates.GET(reqUrl).and(RequestPredicates.accept(MediaType.ALL)); } //封装处理Handler HandlerFunction<ServerResponse> handlerFunction = new HandlerFunction<ServerResponse>() { @Override public ServerResponse handle(ServerRequest request) throws Exception { //TODO 验证请求头 //TODO 验证接口权限 //TODO 构建第三方Auth请求 //TODO 正式发送转发请求 String outMethod = controllerBean.getOutputBean().getRequestHeadBean().getMethod(); switch (outMethod){ case METHOD_POST: outResponseStr = HttpRequest.post(outPutUrl).header(outTokenKey,tokenValue).body(JSONObject.toJSONString(outBody)).execute().body(); break; case METHOD_PUT: outResponseStr = HttpRequest.put(outPutUrl).header(outTokenKey,tokenValue).body(JSONObject.toJSONString(outBody)).execute().body(); break; case METHOD_DELETE: outResponseStr = HttpRequest.delete(outPutUrl).header(outTokenKey,tokenValue).body(JSONObject.toJSONString(outBody)).execute().body(); break; default: outResponseStr = HttpRequest.get(outPutUrl).header(outTokenKey,tokenValue).form(BeanUtil.beanToMap(outBody)).execute().body(); } //将转发请求的结果进行封装 return ServerResponse.ok().contentType(MediaType.APPLICATION_JSON).body(result.toJSONString()); } }; return RouterFunctions.route(requestPredicate,handlerFunction); }注册进入Spring容器中
/** * 动态注册Web/WebFlux * @param beanName * @param routerFunction */ private void reginstControllerBean(String beanName,RouterFunction routerFunction){ //动态生成Web/WebFlux对象,并注入Spring容器 //将applicationContext转换为ConfigurableApplicationContext ConfigurableApplicationContext configurableApplicationContext = (ConfigurableApplicationContext) applicationContext; //获取BeanFactory DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) configurableApplicationContext.getAutowireCapableBeanFactory(); //动态生成Controller+注册bean defaultListableBeanFactory.registerSingleton(beanName,routerFunction); }到这里已基本完成,当需要新增或修改路由规则时,只需要更改配置文件即可。
启动验证