6.9.3 上传多媒体文件方法封装

通过上面的分析,笔者将上传多媒体文件的操作封装成uploadMedia()方法,该方法的实现如下:

  1. 1  **
  2. 2  * 上传媒体文件
  3. 3  *
  4. 4  * @param accessToken 接口访问凭证
  5. 5  * @param type 媒体文件类型(imagevoicevideothumb
  6. 6  * @param mediaFileUrl 媒体文件的url
  7. 7  */
  8. 8 public static WeixinMedia uploadMedia(String accessToken, String type, String
  9.    mediaFileUrl)
  10. 9 {
  11. 10  WeixinMedia weixinMedia = null;
  12. 11  // 拼装请求地址
  13. 12  String uploadMediaUrl =
  14.    "http://file.api.weixin.qq.com/cgi-bin/media/upload?access_token=ACCESS_
  15.    TOKEN&type=TYPE";
  16. 13  uploadMediaUrl = uploadMediaUrl.replace("ACCESS_TOKEN", accessToken).
  17.    replace("TYPE", type);
  18. 14
  19. 15  // 定义数据分隔符
  20. 16  String boundary = "------------7da2e536604c8";
  21. 17  try {
  22. 18  URL uploadUrl = new URL(uploadMediaUrl);
  23. 19  HttpURLConnection uploadConn = (HttpURLConnection) uploadUrl.
  24.    openConnection();
  25. 20  uploadConn.setDoOutput(true);
  26. 21  uploadConn.setDoInput(true);
  27. 22  uploadConn.setRequestMethod("POST");
  28. 23  // 设置请求头Content-Type
  29. 24  uploadConn.setRequestProperty("Content-Type", "multipart/form-data;
  30.    boundary=" + boundary);
  31. 25  // 获取媒体文件上传的输出流(往微信服务器写数据)
  32. 26  OutputStream outputStream = uploadConn.getOutputStream();
  33. 27
  34. 28  URL mediaUrl = new URL(mediaFileUrl);
  35. 29  HttpURLConnection meidaConn = (HttpURLConnection) mediaUrl.openConnection();
  36. 30  meidaConn.setDoOutput(true);
  37. 31  meidaConn.setRequestMethod("GET");
  38. 32
  39. 33  // 从请求头中获取内容类型
  40. 34  String contentType = meidaConn.getHeaderField("Content-Type");
  41. 35  // 根据内容类型判断文件扩展名
  42. 36  String fileExt = CommonUtil.getFileExt(contentType);
  43. 37  // 请求体开始
  44. 38  outputStream.write(("--" + boundary + "\r\n").getBytes());
  45. 39  outputStream.write(String.format("Content-Disposition: form-data;
  46.    name=\"media\";filename=\"file1%s\"\r\n", fileExt).getBytes());
  47. 40  outputStream.write(String.format("Content-Type: %s\r\n\r\n",
  48.    contentType).getBytes());
  49. 41
  50. 42  // 获取媒体文件的输入流(读取文件)
  51. 43  BufferedInputStream bis = new BufferedInputStream(meidaConn.getInputStream());
  52. 44  byte[] buf = new byte[8096];
  53. 45  int size = 0;
  54. 46  while ((size = bis.read(buf)) != -1) {
  55. 47  // 将媒体文件写到输出流(往微信服务器写数据)
  56. 48  outputStream.write(buf, 0, size);
  57. 49  }
  58. 50  // 请求体结束
  59. 51  outputStream.write(("\r\n--" + boundary + "--\r\n").getBytes());
  60. 52  outputStream.close();
  61. 53  bis.close();
  62. 54  meidaConn.disconnect();
  63. 55
  64. 56  // 获取媒体文件上传的输入流(从微信服务器读数据)
  65. 57  InputStream inputStream = uploadConn.getInputStream();
  66. 58  InputStreamReader inputStreamReader = new InputStreamReader(inputStream,
  67.    "utf-8");
  68. 59  BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
  69. 60  StringBuffer buffer = new StringBuffer();
  70. 61  String str = null;
  71. 62  while ((str = bufferedReader.readLine()) != null) {
  72. 63  buffer.append(str);
  73. 64  }
  74. 65  bufferedReader.close();
  75. 66  inputStreamReader.close();
  76. 67  // 释放资源
  77. 68  inputStream.close();
  78. 69  inputStream = null;
  79. 70  uploadConn.disconnect();
  80. 71
  81. 72  // 使用JSON-lib解析返回结果
  82. 73  JSONObject jsonObject = JSONObject.fromObject(buffer.toString());
  83. 74  System.out.println(jsonObject);
  84. 75  weixinMedia = new WeixinMedia();
  85. 76  weixinMedia.setType(jsonObject.getString("type"));
  86. 77  // type等于thumb时的返回结果和其他类型不一样
  87. 78  if ("thumb".equals(type))
  88. 79  weixinMedia.setMediaId(jsonObject.getString("thumb_media_id"));
  89. 80  else
  90. 81  weixinMedia.setMediaId(jsonObject.getString("media_id"));
  91. 82  weixinMedia.setCreatedAt(jsonObject.getInt("created_at"));
  92. 83  } catch (Exception e) {
  93. 84  weixinMedia = null;
  94. 85  log.error("上传媒体文件失败:{}", e);
  95. 86  }
  96. 87  return weixinMedia;
  97. 88  }

第16行代码定义了一个数据分隔符boundary,虽然它的长度没有限制,但也要确保它不会与请求头或请求体中的其他内容重复,最好是随机生成十几位以上的字符串。

第18~24行的作用是与微信服务器建立连接,并设置请求头Content-Type。

第26行的作用是获取媒体文件上传的输出流,准备往微信服务器写数据(请求体)。

第28~31行的作用是与准备上传的媒体文件建立连接,为读取媒体文件做准备。

第34~40行开始构造请求体,并根据媒体文件类型设置请求体中的Content-Disposition和Content-Type,这里调用了CommonUtil类的getFileExt()方法,该方法的定义如下:

  1. /**
  2. * 根据内容类型判断文件扩展名
  3. *
  4. * @param contentType 内容类型
  5. * @return
  6. */
  7. public static String getFileExt(String contentType) {
  8. String fileExt = "";
  9. if ("image/jpeg".equals(contentType))
  10. fileExt = ".jpg";
  11. else if ("audio/mpeg".equals(contentType))
  12. fileExt = ".mp3";
  13. else if ("audio/amr".equals(contentType))
  14. fileExt = ".amr";
  15. else if ("video/mp4".equals(contentType))
  16. fileExt = ".mp4";
  17. else if ("video/mpeg4".equals(contentType))
  18. fileExt = ".mp4";
  19. return fileExt;
  20. }

uploadMedia()方法的第43~49行是往请求体中追加媒体文件的内容。

第51行是往请求体中追加结束符。

第57~70行的作用是读取上传文件后微信服务器返回的内容。

第73~82行使用JSON-lib解析返回的JSON数据,需要注意的是,如果上传的媒体文件类型为thumb,上传成功后返回的结果与其他3种类型(图片、语音和视频)的不一样,前者返回的媒体文件标识是thumb_media_id,后者返回的文件标识是media_id。最后,将所有返回参数封装在WeixinMedia中,该类的代码如下:

  1. package org.liufeng.course.pojo;
  2.  
  3. /**
  4. * 媒体文件信息
  5. *
  6. * @author liufeng
  7. * @date 2013-11-09
  8. */
  9. public class WeixinMedia {
  10. // 媒体文件类型
  11. private String type;
  12. // 媒体文件标识或缩略图的媒体文件标识
  13. private String mediaId;
  14. // 媒体文件上传的时间
  15. private int createdAt;
  16.  
  17. public String getType() {
  18. return type;
  19. }
  20.  
  21. public void setType(String type) {
  22. this.type = type;
  23. }
  24.  
  25. public String getMediaId() {
  26. return mediaId;
  27. }
  28.  
  29. public void setMediaId(String mediaId) {
  30. this.mediaId = mediaId;
  31. }
  32.  
  33. public int getCreatedAt() {
  34. return createdAt;
  35. }
  36.  
  37. public void setCreatedAt(int createdAt) {
  38. this.createdAt = createdAt;
  39. }
  40. }