RestTemplate較為通用的使用方法
一丶http請求響應
1. http請求主要包括3個部分, 請求行(get,post等請求方法 url地址 http協議版本), 請求頭( key value形式), 請求體(任意文本, 通常與請求頭content-type對應).
2. http響應主要包括3個部分, 響應消息行(協議/版本 響應狀態碼 對響應狀態碼的描述), 響應消息頭(key value形式), 響應消息正文(任意文本, 通常與響應消息頭content-type對應)
更詳細的請看此博文
二丶restTemplate使用簡述
處理http請求, 主要是構造生成http請求報文, 處理轉換http響應報文.
在實際項目中, 主要是使用get, post兩種請求.
1) get請求, 主要是在請求行中的url帶上請求參數, 如http://localhost:8080/server/userId?userId=2 中的userId=2, url路徑中的部分數據也可以作為請求參數, 如http://localhost:8080/server/userId/2中的2, 可以和前一個url等同
restTemplate主要是通過占位符{}來構造url,
#getForObject(url, responseType, uriVariables), #getForEntity(url, responseType, uriVariables) 等方法用於get請求,
其中responseType指定了反序列化響應體后的類型, url, uriVariables 用於構造請求url, getForEntity可以得到響應碼等狀態信息
2) post請求, 主要是在請求體中帶上自定義的數據, 通常為json, 在使用時, 通常需要在請求頭指定請求體的內容類型, json內容類型為 "Content-Type: application/json"
請求頭:對應於org.springframework.http.HttpHeaders
請求體:對應於org.springframework.http.HttpEntity#body屬性
請求頭和請求體 對應於org.springframework.http.HttpEntity
#postForObject(String url, Object request, Class<T> responseType,Object... uriVariables)
#postForEntity(String url, Object request,Class<T> responseType, Object... uriVariables) 等用於Post方法
3) resttemplate較為自由的執行方法
#exchange(String url, HttpMethod method, HttpEntity<?> requestEntity, Class<T> responseType, Map<String, ?> uriVariables)
可以自定義httpmethod, url,請求頭,q請求體,響應類型
4) 簡單總結
使用restTemaplate主要圍繞http報文來使用, 基本熟悉了http報文的結構, 以及resttemaplate的實現思想, 就可以很好的使用resttemplate了
三丶較為通用的使用樣例
@Component @Slf4j public class RestTemplateManager { @Autowired private RestTemplateConfig config; private RestTemplate restTemplate; private String SERVER_PREFIX; @PostConstruct public void init(){ restTemplate=new RestTemplate(); //使用fastjson轉換json restTemplate.getMessageConverters().add(0, new FastJsonHttpMessageConverter()); //打印調試日志 restTemplate.setInterceptors(Arrays.asList(new LoggingRequestInterceptor())); SERVER_PREFIX=config.getUrl(); } /** * get請求 * @param requestDto */ public GetExampleDataDto getExample(GetExampleRequestDto requestDto){ String url=SERVER_PREFIX+"/get-example?userId={userId}&age={age}"; try{ //請求參數 Map vars=(JSONObject)JSON.toJSON(requestDto); ResponseEntity<String> entity=restTemplate.getForEntity(url, String.class, vars); Assert.state(entity.getStatusCode()==HttpStatus.OK, "狀態碼不等於200"); GetExampleDataDto dataDto=getData(entity.getBody(), GetExampleDataDto.class); return dataDto; }catch (Exception e){ String message="請求url: "+url+"出錯"; log.error(message, e); log.error("請求參數: {}", JSON.toJSON(requestDto)); throw new RuntimeException(message, e); } } /** * get請求, 帶上請求頭 * @param requestDto * @param token 登錄token */ public GetExampleDataDto getExampleWithHeader(GetExampleRequestDto requestDto, String token){ String url=SERVER_PREFIX+"/get-example?userId={userId}&age={age}"; try{ //請求參數 Map vars=(JSONObject)JSON.toJSON(requestDto); //一般在請求頭的cookie帶上登錄token HttpCookie tokenCookie=new HttpCookie("token", token); HttpHeaders headers=new HttpHeaders(); headers.add(HttpHeaders.COOKIE, tokenCookie.toString()); HttpEntity requestEntity=new HttpEntity(headers); ResponseEntity<String> entity=restTemplate.exchange(url, HttpMethod.GET, requestEntity, String.class, vars); Assert.state(entity.getStatusCode()==HttpStatus.OK, "狀態碼不等於200"); GetExampleDataDto dataDto=getData(entity.getBody(), GetExampleDataDto.class); return dataDto; }catch (Exception e){ String message="請求url: "+url+"出錯"; log.error(message, e); log.error("請求參數: {}", JSON.toJSON(requestDto)); throw new RuntimeException(message, e); } } /** * post請求 * @param requestDto */ public PostExampleDataDto postExample(PostExampleRequestDto requestDto){ String url=SERVER_PREFIX+"/post-example"; try{ //請求參數 HttpEntity httpEntity=new HttpEntity(requestDto, createJsonHeader()); ResponseEntity<String> entity=restTemplate.postForEntity(url, httpEntity, String.class); Assert.state(entity.getStatusCode()==HttpStatus.OK, "狀態碼不等於200"); PostExampleDataDto dataDto=getData(entity.getBody(), PostExampleDataDto.class); return dataDto; }catch (Exception e){ String message="請求url: "+url+"出錯"; log.error(message, e); log.error("請求參數: {}", JSON.toJSON(requestDto)); throw new RuntimeException(message, e); } } private HttpHeaders createJsonHeader(){ HttpHeaders headers=new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); return headers; } private <T> T getData(String responseString, Class<T> clazz){ StringDataResponseDto responseDto=JSONObject.parseObject(responseString) .toJavaObject(StringDataResponseDto.class); if(responseDto.getCode()!=0){ throw new RuntimeException("code不等於0, 值為["+responseDto.getCode()+"]," + " message=["+responseDto.getMessage()+"]"); } String stringData=responseDto.getData(); return JSONObject.parseObject(stringData).toJavaObject(clazz); } @Data private static class StringDataResponseDto extends ResponseDto<String> { } }
四丶單元測試
主要是使用mockserver來模擬請求服務器 ^_^ 非常好的工具
<dependency> <groupId>org.mock-server</groupId> <artifactId>mockserver-netty</artifactId> <version>5.8.1</version> <scope>test</scope> </dependency>
/** * https://github.com/mock-server/mockserver/tree/master/mockserver-examples * * https://github.com/mock-server/mockserver/blob/master/mockserver-examples/src/main/java/org/mockserver/examples/mockserver/MockServerClientExamples.java * * @author TimFruit * @date 19-12-30 下午7:54 */ @SpringBootTest @RunWith(SpringJUnit4ClassRunner.class) @ActiveProfiles("unittest") public class ResttemplateManagerTests { private int port=8055; @Rule public MockServerRule mockServerRule = new MockServerRule(this, port); private MockServerClient client=new MockServerClient("localhost", port); private String prefixurl="/mockserver"; @Autowired RestTemplateManager templateManager; /* public void createExpectationMockServerClient() { new MockServerClient("localhost", 1080) .when( request() .withMethod("GET") .withPath("/view/cart") .withCookies( cookie("session", "4930456C-C718-476F-971F-CB8E047AB349") ) .withQueryStringParameters( param("cartId", "055CA455-1DF7-45BB-8535-4F83E7266092") ) ) .respond( response() .withBody("some_response_body") ); } */ @Test public void shouldGet() throws IOException { //given String expectedResponseBody=FileUtils.readContent("httpmanager/get-example-response.json"); client.when( request().withMethod("GET").withPath(prefixurl+"/get-example") .withQueryStringParameters( param("userId", "1"), param("age", "1") ) ).respond( response().withContentType(MediaType.APPLICATION_JSON) //mock 結果來驗證 .withBody(expectedResponseBody) ); //when GetExampleRequestDto requestDto=new GetExampleRequestDto(); requestDto.setUserId(1); requestDto.setAge(1); GetExampleDataDto dataDto=templateManager.getExample(requestDto); //then Assert.assertEquals(5, dataDto.getUserId().intValue()); Assert.assertEquals(99, dataDto.getAge().intValue()); } @Test public void shouldGetWithHeader() throws IOException { //given String token="timfruit2019"; String expectedResponseBody=FileUtils.readContent("httpmanager/get-example-response.json"); client.when( request().withMethod("GET").withPath(prefixurl+"/get-example") .withQueryStringParameters( param("userId", "1"), param("age", "1") ) //header-cookie .withCookie("token", token) ).respond( response().withContentType(MediaType.APPLICATION_JSON) //mock 結果來驗證 .withBody(expectedResponseBody) ); //when GetExampleRequestDto requestDto=new GetExampleRequestDto(); requestDto.setUserId(1); requestDto.setAge(1); GetExampleDataDto dataDto=templateManager.getExampleWithHeader(requestDto, token); //then Assert.assertEquals(5, dataDto.getUserId().intValue()); Assert.assertEquals(99, dataDto.getAge().intValue()); } @Test public void shouldPost(){ //given String expectedRequestBody=FileUtils.readContent("httpmanager/post-example-request.json"); String expectedResponseBody=FileUtils.readContent("httpmanager/post-example-response.json"); client.when( request().withMethod("POST").withPath(prefixurl+"/post-example") .withContentType(MediaType.APPLICATION_JSON) .withBody(new JsonBody(expectedRequestBody)) ).respond( response().withContentType(MediaType.APPLICATION_JSON) //mock 結果來驗證 .withBody(expectedResponseBody) ); //when PostExampleRequestDto requestDto=new PostExampleRequestDto(); requestDto.setUserId(5); requestDto.setBookIds(Arrays.asList(1, 2 , 3, 4)); PostExampleDataDto dataDto=templateManager.postExample(requestDto); //then Assert.assertEquals(5, dataDto.getUserId().intValue()); Assert.assertEquals(4, dataDto.getBookIdCount().intValue()); } }
學習資料: