zoukankan      html  css  js  c++  java
  • HttpClient多文件上传代码及普通参数中文乱码问题解决

    该随笔记录了在实际项目中使用HttpClient调用外部api,需上传文件和普通参数的代码。

    笔者在使用 HttpClient 调用 http api 接口时,需要服务端上传文件和一些普通参数给 http api,如果使用 Java 自带的 HttpURLConnection 请求的话,发送 multipart/form-data + POST 请求会比较麻烦,需要设置一些边界(将文件与文件、文件与普通参数之间隔开,便于接收者截取,这是 http 协议要求的)。

    因为上传文件和普通参数时,服务端读取报文是根据边界值来截取的,如果使用原生的 HttpURLConnection 则比较麻烦,所以笔者采用 HttpClient 工具,httpclient是apache 软件基金会下的子项目,它很好的封装了Http工具,面向对象的思想省去了很多细节,使程序员关注与业务逻辑处理,不用关注这些通讯细节。

    笔者使用HTTPClient实现文件的上传,使用 MultipartEntityBuilder 构造请求体,实现 multipart/form-data + POST 请求http接口。下面提供了使用时的代码实现,包括服务端和客户端。

    不过,笔者在使用的过程中发现,当传递的普通参数有中文时,对方接到的参数会乱码,因为开始笔者使用的是multipartEntity.addTextBody(key, postParam.get(key));的方式设置普通参数。

    为了解决乱码问题,最后查到了解决办法,记录如下。

    如下代码是可以上传多个文件和普通参数的,使用 multipart/form-data + POST 方式提交,模拟浏览器在页面上 form表单 的提交方式。


    客户端上传文件及普通参数代码:

     1 /**
     2      * httpclient 文件上传
     3      * @param postFiles
     4      * @param postUrl
     5      * @param postParam
     6      * @return
     7      */
     8     public static Map<String, Object> uploadFileByHttpPost(File[] postFiles, String postUrl, Map<String, String> postParam) {
     9         Map<String, Object> resultMap = new HashMap<String, Object>();
    10         CloseableHttpClient httpClient = HttpClients.createDefault();
    11         try {
    12             //把一个普通参数和文件上传给下面这个api接口
    13             HttpPost httpPost = new HttpPost(postUrl);
    14             //设置传输参数,设置编码。设置浏览器兼容模式,解决文件名乱码问题
    15             MultipartEntityBuilder multipartEntity = MultipartEntityBuilder.create().setMode(HttpMultipartMode.RFC6532);
    16             for (int i = 0; i < postFiles.length; i++) {
    17                 File postFile = postFiles[i];
    18                 FileBody fundFileBin = new FileBody(postFile, ContentType.MULTIPART_FORM_DATA);
    19 
    20                 //相当于<input type="file" name="media"/>
    21                 multipartEntity.addPart("upload_file"+i, fundFileBin);
    22             }
    23             //把文件转换成流对象FileBody
    24             Set<String> keySet = postParam.keySet();
    25             for (String key : keySet) {
    26                 //解决中文乱码
    27                 ContentType contentType = ContentType.create("text/plain", Charset.forName("UTF-8"));
    28                 StringBody stringBody = new StringBody(postParam.get(key), contentType);
    29                 multipartEntity.addPart(key, stringBody);
    30                 // multipartEntity.addTextBody(key, postParam.get(key));//这个中文会乱码
    31             }
    32             HttpEntity reqEntity = multipartEntity.build();
    33             httpPost.setEntity(reqEntity);
    34             //发起请求 并返回请求的响应
    35             CloseableHttpResponse response = httpClient.execute(httpPost);
    36             try {
    37                 //打印响应状态
    38                 resultMap.put("statusCode", response.getStatusLine().getStatusCode());
    39                 //获取响应对象
    40                 HttpEntity resEntity = response.getEntity();
    41                 if (resEntity != null) {
    42                     //打印响应内容
    43                     resultMap.put("data", EntityUtils.toString(resEntity, Charset.forName("UTF-8")));
    44                 }
    45                 //销毁
    46                 EntityUtils.consume(resEntity);
    47             } catch (Exception e) {
    48                 e.printStackTrace();
    49             } finally {
    50                 response.close();
    51             }
    52         } catch (ClientProtocolException e1) {
    53             e1.printStackTrace();
    54         } catch (IOException e1) {
    55             e1.printStackTrace();
    56         } finally {
    57             try {
    58                 httpClient.close();
    59             } catch (IOException e) {
    60                 e.printStackTrace();
    61             }
    62         }
    63         return resultMap;
    64     }

     


     服务端处理请求代码

    这是客户端上传的代码,我们看一下怎么接收,使用SpringMVC controller层接收文件和普通参数:

     1 /**
     2      * 上传文件
     3      * @throws IOException
     4      * @throws IllegalStateException
     5      */
     6     @RequestMapping("/postFile")
     7     @ResponseBody
     8     public String postFile(HttpServletRequest request){
     9         Map<String, Object> map = new HashMap<String, Object>();
    10         // 创建一个通用的多部分解析器
    11         CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver(request
    12                 .getSession().getServletContext());
    13         String name = request.getParameter("name");
    14         String age = request.getParameter("age");
    15 
    16         System.out.println(name+","+age);
    17         request.getSession().getServletContext();
    18         // 判断 request 是否有文件上传,即多部分请求
    19         if (multipartResolver.isMultipart(request)) {
    20             // 转换成多部分request
    21             MultipartHttpServletRequest multiRequest = (MultipartHttpServletRequest) request;
    22             // 取得request中的所有文件名
    23             Iterator<String> iter = multiRequest.getFileNames();
    24             while (iter.hasNext()) {//多文件
    25                 // 取得上传文件
    26                 MultipartFile multipartFile = multiRequest.getFile(iter.next());
    27                 if (null != multipartFile) {
    28                     // 取得当前上传文件的文件名称
    29                     String fileName = multipartFile.getOriginalFilename();
    30                     if (fileName.trim() != null && fileName.trim().length() > 0) {
    31                         CommonsMultipartFile cf = (CommonsMultipartFile) multipartFile;
    32                         DiskFileItem fi = (DiskFileItem) cf.getFileItem();
    33                         File tempFile = fi.getStoreLocation();
    34                         // 拿到文件,存储
    35                         try {
    36                             multipartFile.transferTo(new File("F:\static\page\"+multipartFile.getOriginalFilename()));
    37                         } catch (IOException e) {
    38                             e.printStackTrace();
    39                             return "error";
    40                         }
    41                     }
    42                 }
    43             }
    44         }
    45         return "success";
    46     }

     测试代码:

     1 public static void main(String[] args) {
     2         String url = "http://localhost:8080/postFile";
     3         File[] files = new File[2];
     4         files[0] = new File("F:\static\updateFile-demo.docx");
     5         files[1] = new File("F:\static\updateFile-demo02.docx");
     6 
     7         Map<String,String> param = new HashMap<>();
     8         param.put("name","编程大道");
     9         param.put("age","18");
    10 
    11         Map<String, Object> stringObjectMap = HttpClientUtil01.uploadFileByHttpPost(files, url, param);
    12         System.out.println(stringObjectMap);
    13     }

     


    代码验证

    我们上传两个文件和两个普通参数,服务端controller里的处理是,打印这两个普通参数并把两个文件保存到page目录下

     启动服务

     我们先启动服务端,如下图正常启动

     运行测试类,控制台输出如下:

    服务端输出:

    查看是否保存成功

    成功!!


    注意事项:

    但是在成功之前也遇到了问题,如下:

    上传文件:


    传普通参数,注意中文乱码的问题:

  • 相关阅读:
    【Unity游戏开发】Android6.0以上的动态权限申请问题
    【游戏开发】网络编程之浅谈TCP粘包、拆包问题及其解决方案
    【Unity游戏开发】你真的了解UGUI中的IPointerClickHandler吗?
    【Unity游戏开发】记一次解决 LuaFunction has been disposed 的bug的过程
    【年终总结】马三北漂记之8102年总结
    【小白学Lua】之Lua变长参数和unpack函数
    【计算机图形学】计算机图形学中的坐标系统
    【Unity游戏开发】tolua之wrap文件的原理与使用
    【游戏开发】基于VS2017的OpenGL开发环境搭建
    【Unity游戏开发】用C#和Lua实现Unity中的事件分发机制EventDispatcher
  • 原文地址:https://www.cnblogs.com/ibigboy/p/11216786.html
Copyright © 2011-2022 走看看