使用SpringBoot跨系統調用接口的方案
一、簡介
項目開發中存在系統之間互調問題,又不想用dubbo,這裡提供幾種springboot方案:
1、使用Feign進行消費(推薦)
2、使用原始httpClient請求
3、使用RestTemplate方法
二、方案
方案一:使用Feign進行消費(推薦)
1、在maven中添加依賴
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> <version>2.2.2</version> </dependency>
2、啟動類上加上@EnableFeignClients
@EnableHystrix @EnableDiscoveryClient @EnableFeignClients(basePackages = {"com.aaa.aurora"}) @SpringBootApplication @EnableTransactionManagement @ComponentScan(basePackages = "com.aaa.aurora") @ImportResource(locations= {"classpath:spring.xml","spring-security.xml"}) @MapperScan("com.aaa.aurora.mapper") public class AuroraWebApplication { public static void main(String[] args) { SpringApplication.run(AuroraWebApplication.class, args); } }
3、編寫service接口
@FeignClient(url = "${pangu.url}",name = "panguUrl") public interface PanGuService { @RequestMapping(value = "/pangu/restful/check",method = RequestMethod.POST) JSONObject check(@RequestParam(name="queryEngine") String queryEngine, @RequestParam(name="querySql") String querySql, @RequestParam(name="jobNo") String jobNo); }
其中:pangu.url是配置在application.properties中的ip及端口
pangu.url = 192.168.1.3:8080 /pangu/restful/check是要調的接口名
4、代碼中調用
@Autowired private PanGuService panGuService; JSONObject jsonObject = null; try { jsonObject = panGuService.auroraPriviledge(PRESTO_DRIVER, query.get("sql"), user.getWorkNo()); } catch (Exception e) { throw new Exception("請求系統異常"); } if (PANGU_FAIL.equals(jsonObject.get("code"))) { LOG.info(jsonObject.get("msg").toString()); throw new BusinessException(jsonObject.get("msg").toString()); }
方案二:使用原始httpClient請求
使用HttpClient發送請求、接收響應很簡單,一般需要如下幾步即可。
1. 創建HttpClient對象。
2. 創建請求方法的實例,並指定請求URL。如果需要發送GET請求,創建HttpGet對象;如果需要發送POST請求,創建HttpPost對象。
3. 如果需要發送請求參數,可調用HttpGet、HttpPost共同的setParams(HttpParams params)方法來添加請求參數;對於HttpPost對象而言,也可調用setEntity(HttpEntity entity)方法來設置請求參數。
4. 調用HttpClient對象的execute(HttpUriRequest request)發送請求,該方法返回一個HttpResponse。
5. 調用HttpResponse的getAllHeaders()、getHeaders(String name)等方法可獲取服務器的響應頭;調用HttpResponse的getEntity()方法可獲取HttpEntity對象,該對象包裝瞭服務器的響應內容。程序可通過該對象獲取服務器的響應內容。
6. 釋放連接。無論執行方法是否成功,都必須釋放連接。
public JSONObject doPost(String queryEngine, String querySql, String jobNo) { JSONObject jsonObject = null; //1.創建httpClient對象 CloseableHttpClient client = HttpClients.createDefault(); //2.創建請求方法的實例,並指定請求URL String url = "http://192.168.1.11:8080"; HttpPost post = new HttpPost(url); post.setHeader("Content-Type", "application/json;charset=utf8"); //3.參數 AuroraPriviledge auroraPriviledge = new AuroraPriviledge(); auroraPriviledge.setQueryEngine(queryEngine); auroraPriviledge.setQuerySql(querySql); auroraPriviledge.setJobNo(jobNo); String jsonString = JSON.toJSONString(auroraPriviledge); StringEntity entity = new StringEntity(jsonString, "UTF-8"); post.setEntity(entity); //4.調用execute,返回response CloseableHttpResponse response = null; try { response = client.execute(post); HttpEntity responseEntity = response.getEntity(); } catch (IOException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } finally { try { if (client != null) { client.close(); } if (response != null) { response.close(); } } catch (IOException e) { e.printStackTrace(); } } return jsonObject; }
方案三:使用RestTemplate方法
1.get請求:getForObject(…)和getForEntity(…)兩個方法,區別在於前者直接返回預期的對象,即返回體中的body對象,後者返回的是ResponseEntity封裝類,裡面包含瞭HTTP請求的頭信息。
2.post請求:與get請求類似,隻是多一個request參數,request對象會作為httpEntity進行處理。
package com.yyy.aurora; import org.springframework.http.ResponseEntity; import org.springframework.web.client.RestTemplate; import java.net.URI; import java.util.HashMap; import java.util.Map; /** * Description * * @author Bob * @date 2020/4/15 **/ public class TestRest { public static void main(String[] args) { RestTemplate restTemplate = new RestTemplate(); //get請求 //方法一:getForEntity(String url, Class<T> responseType, Object... uriVariables),沒有參數 String url = "https://restapi.amap.com/v3/ip?key=075b6eddd825148a674dfa8a8558ac62"; ResponseEntity<String> forEntity = restTemplate.getForEntity(url, String.class); System.out.println(forEntity); // <200,{"status":"1","info":"OK","infocode":"10000","province":"上海市","city":"上海市","adcode":"310000","rectangle":"120.8397067,30.77980118;122.1137989,31.66889673"},{Server=[Tengine], Date=[Sat, 18 Apr 2020 02:47:38 GMT], Content-Type=[application/json;charset=UTF-8], Content-Length=[167], Connection=[close], X-Powered-By=[ring/1.0.0], gsid=[011130051098158717805837600019751129378], sc=[0.071], Access-Control-Allow-Origin=[*], Access-Control-Allow-Methods=[*], Access-Control-Allow-Headers=[DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,key,x-biz,x-info,platinfo,encr,enginever,gzipped,poiid]}> String s = restTemplate.getForObject(url, String.class); System.out.println(s); // {"province":"上海市","city":"上海市","adcode":"310000","infocode":"10000","rectangle":"120.8397067,30.77980118;122.1137989,31.66889673","status":"1","info":"OK"} //方法一:getForEntity(String url, Class<T> responseType, Object... uriVariables),url中用占位符,傳入參數 //該方法提供瞭三個參數,其中var1為請求的地址(即url),var2為請求響應body的包裝類型,var3為url中的參數綁定 url = "https://restapi.amap.com/v3/ip?key={?}"; forEntity = restTemplate.getForEntity(url, String.class, "075b6eddd825148a674dfa8a8558ac62"); //方法二:getForEntity(String url, Class<T> responseType, Map<String, ?> uriVariables),map傳參 url = "https://restapi.amap.com/v3/ip?key={key}"; Map<String, Object> map = new HashMap<>(); map.put("key", "075b6eddd825148a674dfa8a8558ac62"); forEntity = restTemplate.getForEntity(url, String.class, map); //方法三:getForEntity(URI url, Class<T> responseType),uri傳參 URI uri = URI.create("https://restapi.amap.com/v3/ip?key=075b6eddd825148a674dfa8a8558ac62"); forEntity = restTemplate.getForEntity(uri, String.class); //post請求,與get請求類型,隻是多一個必填request對象 //postForEntity(String url, @Nullable Object request, Class<T> responseType, Object... uriVariables) forEntity = restTemplate.postForEntity(url, null, String.class, "075b6eddd825148a674dfa8a8558ac62"); s = restTemplate.postForObject(url, null, String.class, "075b6eddd825148a674dfa8a8558ac62"); } }
補充:SpringBoot關於系統之間的遠程互相調用
1、SpringBoot關於系統之間的遠程互相調用
可以采用RestTemplate方式發起Rest Http調用,提供有get、post等方式。
1、1遠程工具類
此處使用Post方式,參考下面封裝的HttpClient類 1.1
/** * Created by @kai on 2018/12/24/024. * Time: 13:54 * Desc: 遠程連接工具類 */ @Service public class HttpClient { /** * 根據遠程地址發起訪問-參數類型為form表單 * @param url 遠程地址 * @param method 遠程方法 * @param params 方法參數 * @return */ public Object client(String url,HttpMethod method,MultiValueMap<String,String> params){ RestTemplate restTemplate = new RestTemplate(); HttpHeaders headers = new HttpHeaders(); headers.add("Content-Type", "application/x-www-form-urlencoded"); HttpEntity<MultiValueMap<String, String>> httpEntity = new HttpEntity<>(params, headers); ResponseEntity<String> responseEntity = restTemplate.postForEntity(url,httpEntity,String.class); String body = responseEntity.getBody(); JSONObject jsonObject = JSONObject.parseObject(body); return jsonObject.get("data"); } /** * 根據遠程地址發起訪問-參數類型為JSON * @param url 遠程地址 * @param method 遠程方法 * @param params 方法參數 * @return */ public Object clientJson(String url,HttpMethod method,Map<String,Object> params){ RestTemplate restTemplate = new RestTemplate(); HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON_UTF8); cn.hutool.json.JSONObject jsonObject = JSONUtil.parseFromMap(params); HttpEntity<cn.hutool.json.JSONObject> httpEntity = new HttpEntity<>(jsonObject, headers); ResponseEntity<String> responseEntity = restTemplate.postForEntity(url,httpEntity,String.class); String body = responseEntity.getBody(); JSONObject jsonObjectResult = JSONObject.parseObject(body); return jsonObjectResult.get("data"); } }
[ 1.1]
1、2遠程參數說明
工具類中提供瞭遠程過程中傳遞參數的兩種格式:
其中 headers.add(“Content-Type”, “application/x-www-form-urlencoded”) 為form表單格式,支持鍵值對數據傳輸;
當參數類型為form表單時,數據需要封裝成MultiValueMap<String,String>格式,前臺使用controller接受時,可以直接使用 MultiValueMap 變量接收,參照代碼如下 1.2
/** * 保存分組策略對象 * @param * @return */ @RequestMapping(value = "/saveDocGroupPolicy",method = RequestMethod.POST) public ApiResult saveGroupPolicy(@RequestParam MultiValueMap<String,String> paramMap,@Valid GroupStrategyIO groupStrategyIO){ Integer userId = ShiroUtil.getExamUserId(); List<String> userList = new ArrayList<>(); userList.add(userId+""); paramMap.put("userId",userList); Object jsonObject = httpClient.client(ExamConfigConstants.url+"/exam/configPolicy/saveDocGroupPolicy", HttpMethod.POST, paramMap); return ApiResult.success(jsonObject); }
[ 1.2] 接受參數為form對象
headers.setContentType(MediaType.APPLICATION_JSON_UTF8)
為json數據格式
當參數為json格式時,遠程服務器接受參數需加上註解@RequestBody,對於復雜參數可以使用對象接受,將對象轉為Map,對數據進行加工,再將map轉化為JSONObject,參照代碼如下:1.3
/** * 保存試卷策略 * @param paperStrategyIO 試卷策略對象 * @return */ @RequestMapping(value = "/savePaperConfig") public ApiResult savePaperConfig(@RequestBody PaperStrategyIO paperStrategyIO){ Map<String, Object> paramMap = BeanUtil.beanToMap(paperStrategyIO); Integer userId = ShiroUtil.getExamUserId(); paramMap.put("userId",userId); Object jsonObject = httpClient.clientJson(ExamConfigConstants.url+"/exam/paper/savePaperConfigWithMap", HttpMethod.POST, paramMap); return ApiResult.success(jsonObject); }
[ 1.3] 接收參數為復雜json串
2、後記
關於RestTemplate還有很多可調用的API,可以查看官方網站瞭解
http://spring.io/blog/2009/03/27/rest-in-spring-3-resttemplate
以上為個人經驗,希望能給大傢一個參考,也希望大傢多多支持WalkonNet。如有錯誤或未考慮完全的地方,望不吝賜教。
推薦閱讀:
- RestTemplate實現發送帶headers的GET請求
- SpringBoot 如何使用RestTemplate來調用接口
- spring boot RestTemplate 發送get請求的踩坑及解決
- java實用型-高並發下RestTemplate的正確使用說明
- 使用spring的restTemplate註意點