需求:通过
RestTemplate
从接口获取数据,然后写入数据库同时保存该数据副本到服务器
由于之前并没有怎么使用过 RestTemplate请求数据,只是用过 Feign 去跨服务调用。。看来我太菜了哈哈。
实现
我发现设置请求body的时候有许多重复的代码,于是我就用 builder模式 改造了下
登录获取token
//登录获取token
//--loginKey转成Base64的格式
String dataStr = RestConstant.BIG_SCREEN_TOKEN + DateUtils.dateToStamp();
String loginKey = Base64Utils.encodeToString(dataStr.getBytes());
//--body
MultiValueMap<String, String> requestTokenBody = new RequestBody.RequestBodyBuilder()
.setGrantType("xxx")
.setAuthType("xxx")
.setLoginKey(loginKey)
.build().getRequestBody();
HttpEntity requestEntity = new HttpEntity(requestTokenBody,null);
//--获取 accessToken
ResponseEntity<String> responseEntity = restTemplate.postForEntity("http://"+url + "/login/bigScreen", requestEntity, String.class);
builder 模式
public class RequestBody {
private MultiValueMap<String, String> requestBody;
public MultiValueMap<String, String> getRequestBody() {
return requestBody;
}
public RequestBody(RequestBodyBuilder builder) {
this.requestBody = builder.requestBody;
}
public static class RequestBodyBuilder{
private String grantType;
private String authType;
private MultiValueMap<String, String> requestBody;
public RequestBodyBuilder() {
this.requestBody = new LinkedMultiValueMap<>();
}
public RequestBodyBuilder setGrantType(String grantType) {
this.requestBody.add("xxx",grantType);
return this;
}
public RequestBodyBuilder setAuthType(String authType) {
this.requestBody.add("xxx",authType);
return this;
}
public RequestBody build(){
return new RequestBody(this);
}
}
}
GET 请求
在RestTemplate中,发送一个GET请求,我们可以通过如下两种方式:
第一种:getForEntity
getForEntity方法的返回值是一个ResponseEntity,ResponseEntity是Spring对HTTP请求响应的封装,包括了几个重要的元素,如响应码、contentType、contentLength、响应消息体等。比如下面一个例子:
ResponseEntity<String> responseEntity = restTemplate.getForEntity("http://HELLO-SERVICE/hello", String.class);
- 第一个参数为要调用的服务的地址,这里我调用了服务提供者提供的/hello接口,注意这里是通过服务名调用而不是服务地址,如果写成服务地址就没法实现客户端负载均衡了。
- 第二个参数String.class表示希望返回的body类型是String
有时候我在调用服务提供者提供的接口时,可能需要传递参数,有两种不同的方式,如下:
ResponseEntity<String> responseEntity = restTemplate.getForEntity("http://HELLO-SERVICE/sayhello?name={1}", String.class, "张三");
//
ResponseEntity<String> responseEntity = restTemplate.getForEntity("http://HELLO-SERVICE/sayhello?name={name}", String.class, map);
- 可以用一个数字做占位符,最后是一个可变长度的参数,来一一替换前面的占位符
- 也可以前面使用name={name}这种形式,最后一个参数是一个map,map的key即为前边占位符的名字,map的value为参数值
第二种:getForObject
getForObject函数实际上是对getForEntity函数的进一步封装,如果你只关注返回的消息体的内容,对其他信息都不关注,此时可以使用getForObject,举一个简单的例子,如下:
@RequestMapping("/book2")
public Book book2() {
Book book = restTemplate.getForObject("http://HELLO-SERVICE/getbook1", Book.class);
return book;
}
POST请求
在 RestTemplate 中,POST 请求可以通过如下三个方法发起:
第一种:postForEntity
@RequestMapping("/book3")
public Book book3() {
Book book = new Book();
book.setName("红楼梦");
ResponseEntity<Book> responseEntity = restTemplate.postForEntity("http://HELLO-SERVICE/getbook2", book, Book.class);
return responseEntity.getBody();
}
- 第一个参数表示要调用服务的地址
- 第二个参数表示上传的参数
- 第三个参数表示返回的消息体的数据类型
我这里创建了一个Book对象,这个Book对象只有name属性有值,将之传递到服务提供者那里去,服务提供者代码如下:
@RequestMapping(value = "/getbook2", method = RequestMethod.POST)
public Book book2(@RequestBody Book book) {
System.out.println(book.getName());
book.setPrice(33);
book.setAuthor("曹雪芹");
book.setPublisher("人民文学出版社");
return book;
}
第二种:postForObject
如果你只关注,返回的消息体,可以直接使用postForObject。用法和getForObject一致。
第三种:postForLocation
postForLocation也是提交新资源,提交成功之后,返回新资源的URI,postForLocation的参数和前面两种的参数基本一致,只不过该方法的返回值为Uri,这个只需要服务提供者返回一个Uri即可,该Uri表示新资源的位置。
PUT 请求
在RestTemplate中,PUT请求可以通过put方法调用,put方法的参数和前面介绍的postForEntity方法的参数基本一致,只是put方法没有返回值而已。举一个简单的例子,如下:
@RequestMapping("/put")
public void put() {
Book book = new Book();
book.setName("红楼梦");
restTemplate.put("http://HELLO-SERVICE/getbook3/{1}", book, 99);
}
book对象是我要提交的参数,最后的99用来替换前面的占位符{1}
DELETE请求
delete请求我们可以通过delete方法调用来实现,如下例子:
@RequestMapping("/delete")
public void delete() {
restTemplate.delete("http://HELLO-SERVICE/getbook4/{1}", 100);
}
底层原理
todo:未完待续…