Springcloud学习笔记42(Part02)--HttpUtil工具类(支持application/json,application/x-www-form-urlencoded,MultipartFile格式(请求参数中带文件))
0 Content-type常见类型
Content-type是Http的实体首部字段,在request的请求行(或response的状态码)之后,也是首部的一部分。用于说明请求或返回的消息主体是用何种方式编码,在request header和response header里都存在。
0.1 application/x-www-form-urlencoded
1)浏览器的原生form表单
2) 提交的数据按照 key1=val1&key2=val2 的方式进行编码,key和val都进行了URL转码
POST http://www.example.com HTTP/1.1 Content-Type: application/x-www-form-urlencoded;charset=utf-8 title=test&sub%5B%5D=1&sub%5B%5D=2&sub%5B%5D=3
0.2 .application/json
消息主体是序列化后的 JSON 字符串,这个类型越来越多地被大家所使用
POST http://www.example.com HTTP/1.1 Content-Type: application/json;charset=utf-8 {"title":"test","sub":[1,2,3]}
1.StringEntity 和 UrlEncodedFormEntity 的区别
1.1 StringEntity
HTTPClient进行body传参,要使用StringEntity,而不要使用UrlEncodedFormEntity
后台方法的参数可以直接是一个对象
StringEntity传参:
String param = "{\"a\":\"value1\", \"b\":\"value2\"}"; httpPost.setEntity(new StringEntity(jsonParams, ContentType.create("application/json", "UTF-8"))); //后台方法的参数可以直接是一个对象 @PostMapping(value = "/methodxxx") public Response methodxxx(@RequestBody Paramxxx param){ …… } //paramxxx对象类: class Paramxxx{ private String a; private String b; //getter …… //setter …… }
1.2 UrlEncodedFormEntity
UrlEncodedFormEntity会以字符串键值对形式传给后台,即:{"a":"value1", "b":"value2"},传给java方法,接收到的参数是:a=value1&b=value2,即它不支持json参数传递;
UrlEncodedFormEntity传参:
Map<String,String> paramsMap = new HashMap<>(); paramsMap.put("a","value1"); paramsMap.put("b","value2"); if(null != paramsMap && paramsMap.size() > 0) { List<NameValuePair> nvps = new ArrayList<>(); for (String key : paramsMap.keySet()) { nvps.add(new BasicNameValuePair(key, String.valueOf(paramsMap.get(key)))); } httpPost.setEntity(new UrlEncodedFormEntity(nvps, Const.CHARSET)); } //后台接收的参数 @PostMapping(value = "/methodxxx") public Response methodxxx(String a, String b){ …… }
2.HttpUtil 工具类
该工具类包括发送Http请求的所有基本场景;包括单例模式;get/post请求;
package com.ttbank.flep.util; import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.commons.lang.StringUtils; import org.apache.http.*; import org.apache.http.client.HttpRequestRetryHandler; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpRequestBase; import org.apache.http.client.protocol.HttpClientContext; import org.apache.http.config.Registry; import org.apache.http.config.RegistryBuilder; import org.apache.http.conn.ConnectTimeoutException; import org.apache.http.conn.routing.HttpRoute; import org.apache.http.conn.socket.ConnectionSocketFactory; import org.apache.http.conn.socket.LayeredConnectionSocketFactory; import org.apache.http.conn.socket.PlainConnectionSocketFactory; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.cookie.Cookie; import org.apache.http.entity.ContentType; import org.apache.http.entity.StringEntity; import org.apache.http.entity.mime.HttpMultipartMode; import org.apache.http.entity.mime.MultipartEntityBuilder; import org.apache.http.entity.mime.content.FileBody; import org.apache.http.entity.mime.content.StringBody; import org.apache.http.impl.client.BasicCookieStore; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; import org.apache.http.message.BasicNameValuePair; import org.apache.http.protocol.HttpContext; import org.apache.http.util.CharsetUtils; import org.apache.http.util.EntityUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.net.ssl.SSLException; import javax.net.ssl.SSLHandshakeException; import java.io.File; import java.io.IOException; import java.io.InterruptedIOException; import java.io.UnsupportedEncodingException; import java.net.UnknownHostException; import java.util.*; public class HttpUtil { private static final Logger logger = LoggerFactory.getLogger(HttpUtil.class); static final int timeOut = 25 * 1000; private static BasicCookieStore cookieStore = new BasicCookieStore(); private static CloseableHttpClient httpClient = null; private static ObjectMapper objectMapper = new ObjectMapper(); private final static Object syncLock = new Object(); private static void config(HttpRequestBase httpRequestBase, String headData, String contentType, String charset,String type) throws Exception { // 设置Header等 httpRequestBase .setHeader( "Accept", "text/html,application/json,multipart/form-data,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"); httpRequestBase.setHeader("Accept-Language", "zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3"); httpRequestBase.setHeader("Accept-Charset", "ISO-8859-1,utf-8,gbk,gb2312;q=0.7,*;q=0.7"); //如果是文件传输的场景,则不设置content-type if(!type.equals("multipart")){ httpRequestBase.setHeader("Content-Type", contentType); } httpRequestBase.setHeader("CharacterEncoding", charset); // 处理特殊头信息 if (!StringUtils.isBlank(headData)) { String[] hStrings = headData.split("#"); if (hStrings.length > 0) { for (String hstring : hStrings) { String[] perStrings = hstring.split("@"); if (perStrings.length != 2) { logger.info("HttpUtils-->config-->hstring信息:" + perStrings); } httpRequestBase.setHeader(perStrings[0], perStrings[1]); } } else { logger.info("HttpUtils-->config-->headData信息:" + headData); } } // 请求的超时设置 RequestConfig config = RequestConfig.custom() .setConnectionRequestTimeout(timeOut) .setConnectTimeout(timeOut).setSocketTimeout(timeOut).build(); httpRequestBase.setConfig(config); } /** * 获取CloseableHttpClient对象 * @param url 常规格式是http://127.0.0.1:9002/ * @return */ public static CloseableHttpClient getHttpClient(String url) { String hostname = ""; String[] split = url.split("//"); if (split.length == 1) { hostname = split[0].split("/")[0]; } else { hostname = split[1].split("/")[0]; } int port = 80; if (hostname.contains(":")) { String[] arr = hostname.split(":"); hostname = arr[0]; port = Integer.parseInt(arr[1]); } //双重锁校验,多线程安全,单例模式 if (httpClient == null) { synchronized (syncLock) { if (httpClient == null) { httpClient = createHttpClient(500, 100, 200, hostname, port); } } } return httpClient; } /** * 创建HttpClient对象 * * @Title: createHttpClient * @param maxTotal * @param maxPerRoute * @param maxRoute * @param hostname * @param port * @return */ public static CloseableHttpClient createHttpClient(int maxTotal, int maxPerRoute, int maxRoute, String hostname, int port) { ConnectionSocketFactory plainsf = PlainConnectionSocketFactory .getSocketFactory(); LayeredConnectionSocketFactory sslsf = SSLConnectionSocketFactory .getSocketFactory(); Registry<ConnectionSocketFactory> registry = RegistryBuilder .<ConnectionSocketFactory> create().register("http", plainsf) .register("https", sslsf).build(); PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager( registry); // 将最大连接数增加 cm.setMaxTotal(maxTotal); // 将每个路由基础的连接增加 cm.setDefaultMaxPerRoute(maxPerRoute); HttpHost httpHost = new HttpHost(hostname, port); // 将目标主机的最大连接数增加 cm.setMaxPerRoute(new HttpRoute(httpHost), maxRoute); // 请求重试处理 HttpRequestRetryHandler httpRequestRetryHandler = new HttpRequestRetryHandler() { public boolean retryRequest(IOException exception, int executionCount, HttpContext context) { if (executionCount >= 5) {// 如果已经重试了5次,就放弃 return false; } if (exception instanceof NoHttpResponseException) {// 如果服务器丢掉了连接,那么就重试 return true; } if (exception instanceof SSLHandshakeException) {// 不要重试SSL握手异常 return false; } if (exception instanceof InterruptedIOException) {// 超时 return false; } if (exception instanceof UnknownHostException) {// 目标服务器不可达 return false; } if (exception instanceof ConnectTimeoutException) {// 连接被拒绝 return false; } if (exception instanceof SSLException) {// SSL握手异常 return false; } HttpClientContext clientContext = HttpClientContext .adapt(context); HttpRequest request = clientContext.getRequest(); // 如果请求是幂等的,就再次尝试 if (!(request instanceof HttpEntityEnclosingRequest)) { return true; } return false; }; }; CloseableHttpClient httpClient = HttpClients.custom() .setDefaultCookieStore(cookieStore).setConnectionManager(cm) .setRetryHandler(httpRequestRetryHandler).build(); return httpClient; } /** * POST请求 * * @Title: sendPost * @param url * 请求URL * @param params * 请求数据 * @param contentType * 请求MIME类型 * @param respContentType * 响应MIME类型 * @param type * 请求头信息 * @return * @throws Exception */ public static Object sendPost(String url, Object params, String contentType, String respContentType, String type,String filePath) throws Exception { // if (url.contains("http://192.68.70.150:7004")) { // url = "http://158.58.13.37:8080" + url.substring(25); // } HttpPost httpPost = new HttpPost(url); config(httpPost, "", contentType, "UTF-8",type); CloseableHttpResponse response = null; Object t = null; try { //根据请求场景不同,采用不同的方式 if (type.equals("application/x-www-form-urlencoded")) { // 装填参数 List<NameValuePair> nvps = new ArrayList<NameValuePair>(); if(null!=params){ Set<Map.Entry<String, Object>> entries = ((HashMap<String, Object>) params).entrySet(); for (Map.Entry<String, Object> entry : entries) { Object key = entry.getKey(); Object value = entry.getValue(); nvps.add(new BasicNameValuePair((String) key, (String) value)); } } // 设置参数到请求对象中 httpPost.setEntity(new UrlEncodedFormEntity(nvps, "UTF-8")); logger.info("HttpUtils-->sendPost-->请求服务参数{}", nvps.toString()); } else if(type.equals("multipart")){ //涉及文件传输的场景 MultipartEntityBuilder multipartEntityBuilder=MultipartEntityBuilder.create(); multipartEntityBuilder.setCharset(CharsetUtils.get("UTF-8")); multipartEntityBuilder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE); //解决文件名中文乱码 if(null!=params){ Set<Map.Entry<String, Object>> entries = ((HashMap<String, Object>) params).entrySet(); for (Map.Entry<String, Object> entry : entries) { Object key = entry.getKey(); Object value = entry.getValue(); try { StringBody stringBody=new StringBody((String) value,ContentType.create("text/plain",CharsetUtils.get("UTF-8"))); multipartEntityBuilder.addPart((String) key,stringBody); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } } } File file=new File(filePath); FileBody fileBody=new FileBody(file); multipartEntityBuilder.addPart("file", fileBody); httpPost.setEntity(multipartEntityBuilder.build()); logger.info("111"); } else { //采用json格式传输 String data = objectMapper.writeValueAsString(params); logger.info("HttpUtils-->sendPost-->请求服务参数{}", data); httpPost.setEntity(new StringEntity(data, "UTF-8")); } logger.info("HttpUtils-->sendPost-->请求服务URL:" + url); response = getHttpClient(url).execute(httpPost); int httpStatusCode = response.getStatusLine().getStatusCode(); if (200 == httpStatusCode) { if (url.contains("login")) { List<Cookie> cookies = cookieStore.getCookies(); String cookieData = cookies.get(0).getName() + "=" + cookies.get(0).getValue(); return cookieData; } HttpEntity entity = response.getEntity(); t = convertEntity(entity, respContentType, "UTF-8"); } else { logger.error("请求服务URL[" + url + "]状态错误!错误状态号:[" + response.getStatusLine() + "]"); } } catch (Exception e) { logger.error("{}",e); } finally { try { if (response != null) response.close(); } catch (IOException e) { logger.error("{}",e); } } return t; } /** * 转换请求结果 * * @Title: convertEntity * @param entity * 响应体 * @param contentType * MIME类型 * @param charSet * MIME编码 * @return * @throws Exception */ private static Object convertEntity(HttpEntity entity, String contentType, String charSet) throws Exception { String reValue = ""; String errMsg = ""; try { reValue = (entity == null) ? null : EntityUtils.toString(entity, charSet); EntityUtils.consume(entity); logger.info("HttpUtils-->convertEntity-->服务返回:" + reValue); if (!StringUtils.isBlank(reValue)) { // 处理服务返回数据 // reValue = reValue.replace("\"null\"", // "\"\"").replace(":null", // ":\"\""); Object object = null; // 将json字符串转Map object = objectMapper.readValue(reValue, Map.class); return object; } } catch (ParseException e) { errMsg = e.getMessage(); logger.error("HttpUtils-->convertEntity-->服务返回结果转换异常:" + errMsg); } catch (IOException e) { errMsg = e.getMessage(); logger.error("HttpUtils-->convertEntity-->服务返回IO异常:" + errMsg); }catch (Exception e) { errMsg = e.getMessage(); logger.error("HttpUtils-->convertEntity-->服务返回结果转换异常2:" + errMsg); } return reValue; } /** * 发送GET请求 * * @Title: get * @param url * @return */ public static Object sendGet(String url, String headData,String type) throws Exception { HttpGet httpget = new HttpGet(url); config(httpget, headData, "application/json", "UTF-8",type); CloseableHttpResponse response = null; Object t = null; try { logger.info("HttpUtils-->sendGet-->请求服务URL:{}", url); response = getHttpClient(url).execute(httpget, HttpClientContext.create()); int httpStatusCode = response.getStatusLine().getStatusCode(); if (200 == httpStatusCode) { HttpEntity entity = response.getEntity(); t = convertEntity(entity, "application/json", "UTF-8"); } else { logger.error("请求服务URL[" + url + "]状态错误!错误状态号:[" + response.getStatusLine() + "]"); } } catch (Exception e) { logger.error("{}", e); } finally { try { if (response != null) response.close(); } catch (IOException e) { logger.error("{}", e); } } return t; } }
3.具体使用案例
3.1 利用@RequestBody接收application/json格式
package com.ttbank.flep.controller; import com.ttbank.flep.entity.Param; import com.ttbank.flep.util.HttpUtil; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.discovery.DiscoveryClient; import org.springframework.web.bind.annotation.*; import java.util.HashMap; import java.util.List; import java.util.Map; /** * @Author lucky * @Date 2022/3/9 10:29 */ @Slf4j @RestController @RequestMapping("/cloud/discovery") public class DiscoveryServiceController { @Autowired DiscoveryClient discoveryClient; @PostMapping("/getNacosServiceInfo") public void getNacosServiceInfo(){ List<String> services = discoveryClient.getServices(); services.stream().filter(item -> item.equals("FEIA")).findFirst().map(service -> { List<ServiceInstance> instances = discoveryClient.getInstances(service); return null; }); System.out.println(services); } @PostMapping("/innerFileUpload") public void innerFileUpload(@RequestBody Param param){ log.info("subsysCode:{}",param.getSubsysCode()); } @PostMapping("/getFileInfo") public void getFileInfo(){ String url="http://127.0.0.1:7012/cloud/discovery/innerFileUpload"; Map<String,Object> params=new HashMap<>(); params.put("subsysCode","STPM" ); params.put("contentId","10000001" ); try { Object o = HttpUtil.sendPost(url, params, "application/json", "", ""); } catch (Exception e) { e.printStackTrace(); } } }
postman调用:
debug断点查看:
3.2 利用@RequestParam接收application/x-www-form-urlencoded格式
请求发送方:
package com.ttbank.flep.controller; import com.ttbank.flep.annotation.Handler; import com.ttbank.flep.factory.RequestMsgFactory; import com.ttbank.flep.handler.AkSkHandler; import com.ttbank.flep.handler.RequestHandler; import com.ttbank.flep.handler.TransCodeHandler; import com.ttbank.flep.request.DefaultServerClient; import com.ttbank.flep.pojo.ExecutionContent; import com.ttbank.flep.pojo.RequestMessage; import com.ttbank.flep.request.*; import com.ttbank.flep.util.HttpUtil; import org.springframework.http.HttpMethod; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.stream.Collectors; /** * @Author lucky * @Date 2022/4/21 19:37 */ @RestController @RequestMapping("/httpClient") public class HttpClientController { @PostMapping("/getUserInfo") public void getUserInfo(){ String url="http://127.0.0.1:7012/hello/getCustInfo"; HashMap<String,String> paramMap=new HashMap<>(); paramMap.put("name","lucky" ); paramMap.put("address","tiantai" ); try { HttpUtil.sendPost(url,paramMap ,"application/x-www-form-urlencoded" , "", "Content-Type@application/x-www-form-urlencoded"); } catch (Exception e) { e.printStackTrace(); } } }
请求接收方:
package com.ttbank.flep.controller; import com.ttbank.flep.aspect.MyAnnotation; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.*; /** * @Author lucky * @Date 2022/6/27 9:49 */ @RestController @RequestMapping("/hello") @Api public class HelloController { @PostMapping("/getCustInfo") @ApiOperation(value = "你好") public void getCustInfo(@RequestParam @ApiParam(name="name",value="对话人",required=true) String name, @RequestParam @ApiParam(name="address",value="地址",required=true) String address){ System.out.println("hello!"+name+","+address); } }
debug断点查看:
3.3 利用@RequestPart接收MultipartFile格式(请求参数中带文件)
请求发送方:
@PostMapping("/getUserInfo") public void getUserInfo(){ String url="http://127.0.0.1:7012/hello/getCustFile"; HashMap<String,String> paramMap=new HashMap<>(); paramMap.put("name","lucky" ); paramMap.put("address","tiantai" ); String path="D:\\data\\测试文件.txt"; try { HttpUtil.sendPost(url,paramMap ,null , "", "multipart",path); } catch (Exception e) { e.printStackTrace(); } }
请求接收方:
@PostMapping("/getCustFile") @ApiOperation(value = "你好") public void getCustFile(@RequestParam @ApiParam(name="name",value="对话人",required=true) String name, @RequestParam @ApiParam(name="address",value="地址",required=true) String address, @RequestPart("file") MultipartFile file) throws IOException { System.out.println("hello!"+name+","+address); String filename = file.getOriginalFilename();//得到文件名 System.out.println(filename); OutputStream os=null; InputStream is=null; try { is = file.getInputStream(); os = new FileOutputStream("D:\\data\\3.txt"); //将字节从 InputStream 复制到 OutputStream。实现文件的拷贝 int bytes = IOUtils.copy(is, os); System.out.println("File Written with " + bytes + " bytes"); } catch (Exception e) { e.printStackTrace(); }finally { if(os!=null) os.close(); } }
debug断点查看:
参考文献:https://blog.csdn.net/u014737138/article/details/48313039
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)
2020-05-14 word、ppt、visio、excel的相关操作
2019-05-14 027 Android 可扩展的listview:ExpandableListView的使用案例