(1)GET:通过请求URI得到资源
(2)POST:用于添加新的内容
(3)PUT:用于修改某个内容,若不存在则添加
(4)DELETE:删除某个内容
(5)OPTIONS :询问可以执行哪些方法
(6)HEAD :类似于GET, 但是不返回body信息,用于检查对象是否存在,以及得到对象的元数据
(7)CONNECT :用于代理进行传输,如使用SSL
(8)TRACE:用于远程诊断服务器
RestTemplate是Spring提供的用于访问Rest服务的客户端,RestTemplate提供了多种便捷访问远程Http服务的方法,能够大大提高客户端的编写效率。
(1)restTemplate.getForEntity() 和 restTemplate.getForObject();
restTemplate实现了RestOperations接口的getForObject请求方法如下
T getForObject(URI url, Class responseType) throws RestClientException;
T getForObject(String url, Class responseType, Object... uriVariables) throws RestClientException;
T getForObject(String url, Class responseType, Map uriVariables) throws RestClientException;
使用上面三个接口方法,分别实现发送请求
// 使用方法一,不带参数
String url = "http://114.67.70.75:8090/test/test1?id=00975";
String res = restTemplate.getForObject(url, String.class);
System.out.println(res);
// 使用方法二,传参替换
url = "http://114.67.70.75:8090/test/test1?id={?}";
res = restTemplate.getForObject(url, String.class, "00975");
System.out.println(res);
// 使用方法二,map传参
url = "http://114.67.70.75:8090/test/test1?id={id}&name={name}";
Map params = new HashMap<>();
params.put("id", "00975");
params.put("name","紫光");
res = restTemplate.getForObject(url, String.class, params);
System.out.println(res);
restTemplate.getForEntity()的使用形式与restTemplate.getForObject相同, restTemplate.getForEntity()的响应结果多了
http状态码和responseHeader;
ResponseEntity res2 = restTemplate.getForEntity(url,String.class);
(2) restTemplate.postForObject() 和 restTemplate.postForEntity();
restTemplate实现了RestOperations接口的postForObject请求方法如下
T postForObject(URI url, @Nullable Object request, Class responseType) throws RestClientException;
T postForObject(String url, @Nullable Object request, Class responseType,
Object... uriVariables) throws RestClientException;
T postForObject(String url, @Nullable Object request, Class responseType,
Map uriVariables) throws RestClientException;
使用上面三个接口方法,分别实现发送请求
MultiValueMap request = new LinkedMultiValueMap<>();
request.add("name", name);
request.add("age", age);
Map param = new HashMap();
param.put("name",name);
param.put("age",age);
//使用方法一
String result = restTemplate.postForObject(url, request, String.class);
System.out.println(result);
//使用方法二,表单参数和url相结合
request.clear();
request.add("name", name);
result = restTemplate.postForObject(url + "?age={?}", request, String.class, age);
System.out.println(result);
// 使用方法三,以集合形式传递参数
Map params = new HashMap<>();
params.put("weight", "65kg");
result= restTemplate.postForObject(url + "?weight={weight}", request, String.class, params);
System.out.println(result);
同样postForEntity()方法比postForObject()方法增加了http状态和httpheaders返回
(3) restTemplate.exchange()
ResponseEntity exchange(URI url, HttpMethod method, @Nullable HttpEntity> requestEntity,
Class responseType) throws RestClientException;
ResponseEntity exchange(String url, HttpMethod method, @Nullable HttpEntity> requestEntity,
Class responseType, Object... uriVariables) throws RestClientException;
ResponseEntity exchange(String url, HttpMethod method, @Nullable HttpEntity> requestEntity,
Class responseType, Map uriVariables) throws RestClientException;
exchange 的使用方法和get 、post 的方法基本相同,只不过多了一个HttpMethod参数,来指定需要发送的请求类型
url:表示要调用的服务的地址
method:表示调用请求的方式
httpEntity:表示要传递的参数
responseType:表示返回消息体的数据类型
uriVarables:表示需要格式化到url的参数
注意:HttpEntity用于传递具体的参数值,而uriVariables则用于格式化Http地址。
//第一种,传入MultiValueMap
HttpHeaders headers = new HttpHeaders();
headers.set("Content-Type", "application/x-www-form-urlencoded;charset=utf-8");
MultiValueMap params = new LinkedMultiValueMap();
params.add("id","00975");
params.add("name","tomcat");
HttpEntity httpEntity = new HttpEntity(params, headers);
ans = restTemplate.postForObject(url, httpEntity, String.class);
日志如下:
headers.set("Content-Type", "application/json;charset=utf-8");
Map param = new HashMap();
param.put("id","00975");
param.put("name","tomcat");
httpEntity = new HttpEntity(param, headers);
ans = restTemplate.postForObject(url, httpEntity, String.class);
日志如下:
HttpHeaders设置了Content-Type,httpEntity的传入参数需要与之对应,不然可能会出现错误。
在调用restTemplate的发送方法时,httpEntity也可以传入object, 下面的代码会将其转换为httpEntity对象
public HttpEntityRequestCallback(@Nullable Object requestBody, @Nullable Type responseType) {
super(responseType);
if (requestBody instanceof HttpEntity) {
this.requestEntity = (HttpEntity>) requestBody;
}
else if (requestBody != null) {
this.requestEntity = new HttpEntity<>(requestBody);
}
else {
this.requestEntity = HttpEntity.EMPTY;
}
}
else {
Class> requestBodyClass = requestBody.getClass();
Type requestBodyType = (this.requestEntity instanceof RequestEntity ?
((RequestEntity>)this.requestEntity).getType() : requestBodyClass);
HttpHeaders httpHeaders = httpRequest.getHeaders();
HttpHeaders requestHeaders = this.requestEntity.getHeaders();
MediaType requestContentType = requestHeaders.getContentType();
for (HttpMessageConverter> messageConverter : getMessageConverters()) {
if (messageConverter instanceof GenericHttpMessageConverter) {
GenericHttpMessageConverter
根据传入的requestObject 与restTemplate 能够write的类型匹配,判断messageConverter是否能够处理传入的requestObject,
下面代码是对传入的参数进行转换;
protected void writeInternal(Object object, @Nullable Type type, HttpOutputMessage outputMessage)
throws IOException, HttpMessageNotWritableException {
MediaType contentType = outputMessage.getHeaders().getContentType();
JsonEncoding encoding = getJsonEncoding(contentType);
JsonGenerator generator = this.objectMapper.getFactory().createGenerator(outputMessage.getBody(), encoding);
try {
writePrefix(generator, object);
Object value = object;
Class> serializationView = null;
FilterProvider filters = null;
JavaType javaType = null;
if (object instanceof MappingJacksonValue) {
MappingJacksonValue container = (MappingJacksonValue) object;
value = container.getValue();
serializationView = container.getSerializationView();
filters = container.getFilters();
}
if (type != null && TypeUtils.isAssignable(type, value.getClass())) {
javaType = getJavaType(type, null);
}
ObjectWriter objectWriter = (serializationView != null ?
this.objectMapper.writerWithView(serializationView) : this.objectMapper.writer());
if (filters != null) {
objectWriter = objectWriter.with(filters);
}
if (javaType != null && javaType.isContainerType()) {
objectWriter = objectWriter.forType(javaType);
}
SerializationConfig config = objectWriter.getConfig();
if (contentType != null && contentType.isCompatibleWith(MediaType.TEXT_EVENT_STREAM) &&
config.isEnabled(SerializationFeature.INDENT_OUTPUT)) {
objectWriter = objectWriter.with(this.ssePrettyPrinter);
}
objectWriter.writeValue(generator, value);
writeSuffix(generator, object);
generator.flush();
}
catch (InvalidDefinitionException ex) {
throw new HttpMessageConversionException("Type definition error: " + ex.getType(), ex);
}
catch (JsonProcessingException ex) {
throw new HttpMessageNotWritableException("Could not write JSON: " + ex.getOriginalMessage(), ex);
}
}
最终Map类型会被转换成json串,
1、Content-Type:application/x-www-form-urlencoded;
protected String serializeForm(MultiValueMap formData, Charset charset) {
StringBuilder builder = new StringBuilder();
formData.forEach((name, values) ->
values.forEach(value -> {
try {
if (builder.length() != 0) {
builder.append('&');
}
builder.append(URLEncoder.encode(name, charset.name()));
if (value != null) {
builder.append('=');
builder.append(URLEncoder.encode(String.valueOf(value), charset.name()));
}
}
catch (UnsupportedEncodingException ex) {
throw new IllegalStateException(ex);
}
}));
return builder.toString();
}
这是对MultiValueMap类型的body的创建,可以看出将键值对以“=”链接,将多个键值对使用“&”符链接
httpEntity参数不同,发送内容的形式不同,接收参数的方法也不一样:
根据headers中content-type的设置类型,http能够传输的类型也是很多的,项目中调用API常用的:application/json发送json报文是对象类型的数据,application/x-www-form-urlencoded 数据以前端表单形式提交
同样发送数据时,类型不相同,springboot在接收时的方式也是不相同的,如果使用application/json形式发送数据,springboot在接收数据时,就要以整体的对象形式来接收参数,request.getParameter("key")就不能得到参数了,同样也不能使用注解@RequestParam("key")了,需要以整体的形式来接收,可以使用注解@RequestBody; 同样如果反过来的话,使用application/x-www-form-urlencoded形式发送数据,就需要在parameter中才能得到参数;如下是使用springboot接收两种形式的参数的方法:
@RequestMapping(value="test/acceptParam",method = RequestMethod.POST)
public int acceptParam(@RequestParam("key") String key, HttpServletRequest request) {
System.out.println(request.getParameter("key"));
System.out.println(key);
return 333;
}
@RequestMapping(value="test/acceptJson",method = RequestMethod.POST)
public int acceptJson(@RequestBody String jsonString, HttpServletRequest request) {
request.getParameter("key");
System.out.println(jsonString);
return 333;
}
首先我们来看一下RestTemplaet的构造器
public RestTemplate() {
this.messageConverters.add(new ByteArrayHttpMessageConverter());
this.messageConverters.add(new StringHttpMessageConverter());
this.messageConverters.add(new ResourceHttpMessageConverter(false));
try {
this.messageConverters.add(new SourceHttpMessageConverter<>());
}
catch (Error err) {
// Ignore when no TransformerFactory implementation is available
}
this.messageConverters.add(new AllEncompassingFormHttpMessageConverter());
if (romePresent) {
this.messageConverters.add(new AtomFeedHttpMessageConverter());
this.messageConverters.add(new RssChannelHttpMessageConverter());
}
if (jackson2XmlPresent) {
this.messageConverters.add(new MappingJackson2XmlHttpMessageConverter());
}
else if (jaxb2Present) {
this.messageConverters.add(new Jaxb2RootElementHttpMessageConverter());
}
if (jackson2Present) {
this.messageConverters.add(new MappingJackson2HttpMessageConverter());
}
else if (gsonPresent) {
this.messageConverters.add(new GsonHttpMessageConverter());
}
else if (jsonbPresent) {
this.messageConverters.add(new JsonbHttpMessageConverter());
}
if (jackson2SmilePresent) {
this.messageConverters.add(new MappingJackson2SmileHttpMessageConverter());
}
if (jackson2CborPresent) {
this.messageConverters.add(new MappingJackson2CborHttpMessageConverter());
}
this.uriTemplateHandler = initUriTemplateHandler();
}
这个无参构造器,设置了restTemPlate能够发送的数据类型,这个在3.3中对传入参数进行格式化的时候会用到
public RestTemplate(ClientHttpRequestFactory requestFactory) {
this();
setRequestFactory(requestFactory);
}
这是我们常用的构造器,需要传入ClientHttpRequestFactory,创建restTemplate之前,需要先创建ClientHttpRequestFactory
HttpClient httpClient = HttpClientBuilder.create().setMaxConnTotal(200)//连接池的最大连接数
.setMaxConnPerRoute(20).build();//单个主机最大连接数
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient);
factory.setConnectTimeout(3000);//连接超时时间3秒
factory.setReadTimeout(30000);//读取超时时间30秒
RestTemplate restTemplate = new RestTemplate(factory);
解决中文乱码问题
StringHttpMessageConverter m = new StringHttpMessageConverter(Charset.forName("UTF-8"));
restTemplate.getMessageConverters().set(1,m);
ClientHttpRequestFactory也可以传入SimpleClientHttpRequestFactory:
//HttpComponentsClientHttpRequestFactory
public ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) throws IOException {
HttpClient client = getHttpClient();
HttpUriRequest httpRequest = createHttpUriRequest(httpMethod, uri);
postProcessHttpRequest(httpRequest);
HttpContext context = createHttpContext(httpMethod, uri);
if (context == null) {
context = HttpClientContext.create();
}
//SimpleClientHttpRequestFactory
public ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) throws IOException {
HttpURLConnection connection = openConnection(uri.toURL(), this.proxy);
prepareConnection(connection, httpMethod.name());
if (this.bufferRequestBody) {
return new SimpleBufferingClientHttpRequest(connection, this.outputStreaming);
}
else {
return new SimpleStreamingClientHttpRequest(connection, this.chunkSize, this.outputStreaming);
}
}
ClientHttpRequestFactory 有连接池管理链接,SimpleClientHttpRequestFactory每次调用restTemplate时都要打开一个链接,然后关闭,性能稍差一些。