RestTemplate通过泛型实现POST、PUT、DELETE、GET、集合请求以及文件上传(可批量文件、可带参数)的统一封装(可打印日志)
目录
- 1、RestTemplate配置
- 2、请求体封装
- 3、GET请求
- 4、POST请求
- 5、PUT请求
- 6、DELETE请求
- 7、List集合响应请求
- 8、文件传递请求(可批量文件、可带参数)
1、RestTemplate配置
引入POM:
<dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.13</version></dependency>
RestTemplateLog(请求日志打印) :
import lombok.extern.slf4j.Slf4j;import org.springframework.http.HttpRequest;import org.springframework.http.client.ClientHttpRequestExecution;import org.springframework.http.client.ClientHttpRequestInterceptor;import org.springframework.http.client.ClientHttpResponse;import org.springframework.stereotype.Component;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.nio.charset.StandardCharsets;@Slf4j@Componentpublic class RestTemplateLog implements ClientHttpRequestInterceptor { @Override public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException { traceRequest(request, body); ClientHttpResponse response = execution.execute(request, body); traceResponse(response); return response; } private void traceRequest(HttpRequest request, byte[] body) { String path = request.getURI().getPath(); String header = String.valueOf(request.getHeaders()); String param = new String(body, StandardCharsets.UTF_8); log.info("RestTemplate请求信息:【请求URL:{},请求头:{},请求参数:{}】", path, header, param); } private void traceResponse(ClientHttpResponse response) throws IOException { StringBuilder inputStringBuilder = new StringBuilder(); try (BufferedReader bufferedReader =new BufferedReader(new InputStreamReader(response.getBody(), StandardCharsets.UTF_8))) { String line = bufferedReader.readLine(); while (line != null) { inputStringBuilder.append(line); inputStringBuilder.append('\n'); line = bufferedReader.readLine(); } } int status = response.getStatusCode().value(); String body = String.valueOf(inputStringBuilder).trim(); log.info("RestTemplate响应信息:【状态码:{},响应参数:{}】", status, body); }}
RestTemplateConfig(请求配置):
import org.apache.http.conn.HttpClientConnectionManager;import org.apache.http.impl.client.HttpClientBuilder;import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;import org.springframework.boot.web.client.RestTemplateBuilder;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.http.client.ClientHttpRequestFactory;import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;import org.springframework.http.converter.HttpMessageConverter;import org.springframework.http.converter.StringHttpMessageConverter;import org.springframework.web.client.RestTemplate;import java.nio.charset.StandardCharsets;import java.util.Iterator;import java.util.List;@Configurationpublic class RestTemplateConfig { @Resource private RestTemplateLog restTemplateLog; @Bean public RestTemplate restTemplate(RestTemplateBuilder builder) { RestTemplate restTemplate = builder.build(); // 添加拦截器 List<ClientHttpRequestInterceptor> interceptors = new ArrayList<>(); interceptors.add(restTemplateLog); restTemplate.setInterceptors(interceptors); restTemplate.setRequestFactory(clientHttpRequestFactory()); // 使用 utf-8 编码集的 conver 替换默认的 conver(默认的 string conver 的编码集为"ISO-8859-1") List<HttpMessageConverter<?>> messageConverters = restTemplate.getMessageConverters(); Iterator<HttpMessageConverter<?>> iterator = messageConverters.iterator(); while (iterator.hasNext()) { HttpMessageConverter<?> converter = iterator.next(); if (converter instanceof StringHttpMessageConverter) { iterator.remove(); } } messageConverters.add(new StringHttpMessageConverter(StandardCharsets.UTF_8)); return restTemplate; } @Bean public HttpClientConnectionManager poolingConnectionManager() { PoolingHttpClientConnectionManager poolingConnectionManager = new PoolingHttpClientConnectionManager(); // 连接池最大连接数 poolingConnectionManager.setMaxTotal(10000); // 每个主机的并发 poolingConnectionManager.setDefaultMaxPerRoute(10000); return poolingConnectionManager; } @Bean public HttpClientBuilder httpClientBuilder() { HttpClientBuilder httpClientBuilder = HttpClientBuilder.create(); //设置HTTP连接管理器 httpClientBuilder.setConnectionManager(poolingConnectionManager()); return httpClientBuilder; } @Bean public ClientHttpRequestFactory clientHttpRequestFactory() { HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory(); clientHttpRequestFactory.setHttpClient(httpClientBuilder().build()); // 连接超时,毫秒 clientHttpRequestFactory.setConnectTimeout(6000); // 读写超时,毫秒 clientHttpRequestFactory.setReadTimeout(6000); return clientHttpRequestFactory; }}
2、请求体封装
通过RestTemplate
封装统一的POST、PUT、DELETE、GET,适合返回任意类型的对象,分别为doHttp
与doHttpList
两个方法,一个方法接收单个对象类型,一个方法接收集合对象;
FileRequestServer:
import org.springframework.core.ParameterizedTypeReference;import org.springframework.http.*;import org.springframework.stereotype.Component;import org.springframework.web.client.RestTemplate;import javax.annotation.Resource;import java.lang.reflect.Field;import java.util.ArrayList;import java.util.List;import java.util.Map;@Componentpublic class FileRequestServer { @Resource private RestTemplate restTemplate; / * 默认不带头,并且请求类型为json * * @param url * @param method * @param obj * @param tClass 为需要返回的实体类型 * @return */ public <T> T doHttp(String url, HttpMethod method, Object obj, Class<T> tClass) { return doHttp(url, MediaType.APPLICATION_JSON, null, method, obj, tClass); } / * 默认不带头 * * @param url * @param contentType * @param method * @param obj * @param tClass 为需要返回的实体类型 * @return */ public <T> T doHttp(String url, MediaType contentType, HttpMethod method, Object obj, Class<T> tClass) { return doHttp(url, contentType, null, method, obj, tClass); } / * 默认带头,并且请求类型为json * * @param url * @param headerMap * @param method * @param obj * @param tClass 为需要返回的实体类型 * @return */ public <T> T doHttp(String url, Map<String, String> headerMap, HttpMethod method, Object obj, Class<T> tClass) { return doHttp(url, null, headerMap, method, obj, tClass); } / * @param url * @param contentType * @param headerMap * @param method * @param obj * @param tClass 为需要返回的实体类型 * @return */ public <T> T doHttp(String url, MediaType contentType, Map<String, String> headerMap, HttpMethod method, Object obj, Class<T> tClass) { HttpHeaders headers = new HttpHeaders(); contentType = contentType == null ? MediaType.APPLICATION_JSON : contentType; headers.setContentType(contentType); if (headerMap != null && headerMap.size() > 0) { for (Map.Entry<String, String> entry : headerMap.entrySet()) { headers.add(entry.getKey(), entry.getValue()); } } HttpEntity entity = new HttpEntity(obj, headers); ResponseEntity<T> exchange = restTemplate.exchange(url, method, entity, tClass); return exchange.getBody(); } / * 默认不带头,并且请求类型为json,返回List集合对象 * * @param url * @param method * @param obj * @param tClass * @return */ public <T> List<T> doHttpList(String url, HttpMethod method, Object obj, Class<T> tClass) { return doHttpList(url, MediaType.APPLICATION_JSON, null, method, obj, tClass); } / * 默认不带头,返回List集合对象 * * @param url * @param contentType * @param method * @param obj * @param tClass 为需要返回的实体类型 * @return */ public < T> List<T> doHttpList(String url, MediaType contentType, HttpMethod method, Object obj, Class<T> tClass) { return doHttpList(url, contentType, null, method, obj, tClass); } / * 默认带头,并且请求类型为json,返回List集合对象 * * @param url * @param headerMap * @param method * @param obj * @param tClass * @return */ public < T> List<T> doHttpList(String url, Map<String, String> headerMap, HttpMethod method, Object obj, Class<T> tClass) { return doHttpList(url, null, headerMap, method, obj, tClass); } / * 返回List集合对象 * * @param url * @param contentType * @param headerMap * @param method * @param obj * @param tClass 为需要返回的实体类型 * @param * @return */ public < T> List<T> doHttpList(String url, MediaType contentType, Map<String, String> headerMap, HttpMethod method, Object obj, Class<T> tClass) { HttpHeaders headers = new HttpHeaders(); contentType = contentType == null ? MediaType.APPLICATION_JSON : contentType; headers.setContentType(contentType); if (headerMap != null && headerMap.size() > 0) { for (Map.Entry<String, String> entry : headerMap.entrySet()) { headers.add(entry.getKey(), entry.getValue()); } } HttpEntity entity = new HttpEntity(obj, headers); ParameterizedTypeReference<List<T>> responseType = new ParameterizedTypeReference<List<T>>() { }; ResponseEntity<List<T>> exchange = restTemplate.exchange(url, method, entity, responseType); // RestTemplate 会将List转为List List<T> list = exchange.getBody(); return mapToEntity(list, tClass); } public static <T> List<T> mapToEntity(List<T> body, Class<T> clazz) { List<T> list = new ArrayList<>(); if (body.size() <= 0) { return list; } List<Map<String, Object>> mapList = new ArrayList<>(); for (T t : body) { Map<String, Object> map = (Map<String, Object>) t; mapList.add(map); } try { Field[] declaredFields = clazz.getDeclaredFields(); for (Map<String, Object> map : mapList) { T t = clazz.newInstance(); for (Field declaredField : declaredFields) { declaredField.setAccessible(true); String name = declaredField.getName(); if (null != map.get(name)) { declaredField.set(t, map.get(name)); } } list.add(t); } } catch (Exception e) { throw new RuntimeException("属性设置失败!"); } return list; }}
3、GET请求
@RestControllerpublic class Controller {@RequestMapping("/test")public String sendThymeleaf() {// 请求URL(有参数就封装)String url = "http://127.0.0.1:9898/other/test2?name=测试&age=123"; // 封装头 Map<String, String> headerMap = new HashMap<>(); headerMap.put("token", "123456"); // 设置响应实体,比如为User,那么传入User.class即可 User user = fileRequestServer.doHttp(url, MediaType.APPLICATION_JSON, headerMap, HttpMethod.GET, null, User.class); System.out.println(user.toString()); }}
4、POST请求
@RestControllerpublic class Controller {@RequestMapping("/test")public String sendThymeleaf() {String url = "http://127.0.0.1:9898/other/test2"; // POST请求时,参数可以为Map对象也可以为具体的实体对象,二选一 Map<String, Object> paramMap = new HashMap<>(); paramMap.put("name", "测试名称"); paramMap.put("gender", "男"); paramMap.put("age", 10);// POST请求时,参数可以为Map对象也可以为具体的实体对象,二选一 // UserParam param= new UserParam (); // param.setName("测试名称"); // param.setgender("男"); // param.setAge(10); // 封装头 Map<String, String> headerMap = new HashMap<>(); headerMap.put("token", "123456"); // 设置响应实体,比如为User,那么传入User.class即可 User user = fileRequestServer.doHttp(url, MediaType.APPLICATION_JSON, headerMap, HttpMethod.POST, paramMap, User.class); System.out.println(user.toString()); }}
5、PUT请求
@RestControllerpublic class Controller {@RequestMapping("/test")public String sendThymeleaf() {String url = "http://127.0.0.1:9898/other/test2"; // PUT请求时,参数可以为Map对象也可以为具体的实体对象,二选一 // Map paramMap = new HashMap(); // paramMap.put("name", "测试名称"); // paramMap.put("gender", "男"); // paramMap.put("age", 10);// PUT请求时,参数可以为Map对象也可以为具体的实体对象,二选一 UserParam param= new UserParam (); param.setName("测试名称"); param.setgender("男"); param.setAge(10); // 封装头 Map<String, String> headerMap = new HashMap<>(); headerMap.put("token", "123456"); // 设置响应实体,比如为User,那么传入User.class即可 User user = fileRequestServer.doHttp(url, MediaType.APPLICATION_JSON, headerMap, HttpMethod.PUT, param, User.class); System.out.println(user.toString()); }}
6、DELETE请求
@RestControllerpublic class Controller {@RequestMapping("/test")public String sendThymeleaf() {// 123456为DELETE请求时的参数,比如:test2/{id}String url = "http://127.0.0.1:9898/other/test2/123456"; // DELETE请求时,如果需要body参数,那么可以为Map对象也可以为具体的实体对象,二选一 // Map paramMap = new HashMap(); // paramMap.put("name", "测试名称"); // paramMap.put("gender", "男"); // paramMap.put("age", 10); // DELETE请求时,如果需要body参数,那么可以为Map对象也可以为具体的实体对象,二选一 // UserParam param= new UserParam (); // param.setName("测试名称"); // param.setgender("男"); // param.setAge(10); // 封装头 Map<String, String> headerMap = new HashMap<>(); headerMap.put("token", "123456"); // 设置响应实体,比如为User,那么传入User.class即可 // DELETE 如果不需要参数,那么obj传入null即可,如果需要body参数就传递响应参数 User user = fileRequestServer.doHttp(url, MediaType.APPLICATION_JSON, headerMap, HttpMethod.PUT, null, User.class); System.out.println(user.toString()); }}
7、List集合响应请求
当返回对象是一个List时,则使用doHttpList()
方法;
@RestControllerpublic class Controller {@RequestMapping("/test")public String sendThymeleaf() {// 请求URL(有参数就封装)String url = "http://127.0.0.1:9898/other/test2?name=测试&age=123"; // 封装头 Map<String, String> headerMap = new HashMap<>(); headerMap.put("token", "123456"); // 设置响应实体,比如为User,那么传入User.class即可 List<User> user = fileRequestServer.doHttpList(url, MediaType.APPLICATION_JSON, headerMap, HttpMethod.GET, null, User.class); System.out.println(user.toString()); }}
8、文件传递请求(可批量文件、可带参数)
@RestControllerpublic class Controller {@PostMapping("/test") public void test(@RequestParam("files") MultipartFile[] file) throws IOException { String url = "http://127.0.0.1:9898/other/test"; // 上传文件 String originalFilename = file.getOriginalFilename(); System.out.println("文件名称:" + originalFilename);MultiValueMap<String, Object> paramMap = new LinkedMultiValueMap<>(); // 遍历多个MultipartFile对象; for (MultipartFile file : files) { ByteArrayResource resource = new ByteArrayResource(file.getBytes()) { @Override public String getFilename() { return file.getOriginalFilename(); } }; // 写入文件流:每遍历一次,就add一次 paramMap.add("files", resource); } // 其他参数 paramMap.add("name", "测试名称"); paramMap.add("age", 10); // 封装头 Map<String, String> headerMap = new HashMap<>(); headerMap.put("token", "12333"); String s = fileRequestServer.doHttp(url, MediaType.MULTIPART_FORM_DATA, headerMap, HttpMethod.POST, paramMap, String.class); System.out.println(s); }}
被调用方Controller层定义:
如果在传入文件流的同时,还存在参数的话,那么参与需要使用@RequestParam
进行定义;
public String test(@RequestParam("files") MultipartFile[] file, @RequestParam String name, @RequestParam Integer age){............}