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

posted @   雨后观山色  阅读(1344)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享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的使用案例
点击右上角即可分享
微信分享提示