微信开发_素材管理之下载微信临时素材到本地服务器
一、本节要点
1.获取临时素材接口
请求方式:GET(HTTPS)
请求地址:https://qyapi.weixin.qq.com/cgi-bin/media/get?access_token=ACCESS_TOKEN&media_id=MEDIA_ID
2.获取临时素材接口的返回结果
企业微信官方开发文档中说明的返回结果如下:
若你以为这就是返回结果,然后跟之前一样,先访问接口,从http连接的输入流中的获取回结果的文本内容,你会发现你接收到的结果是一堆乱码。
这是为何?
以图片为例,此处千万要注意,微信返回的结果是一个文件流形式的图片,当我们从http连接的输入流中的获取回结果的文本内容,也就是获取图片的文本内容时,当然就是一堆乱码了。
这就好比你用记事本打开一张图片,然后发现内容是一片乱码。这再正常不过。所以我们接受图片的时候不能只接收文本数据,而是要接收流。
千万得注意:获取临时素材时,微信返回的结果是一个流形式的临时素材。
我们需要做的就是调用接口,获取http连接的输入流中数据,再将输入流中的数据写入到输出流,再通过输出流生成一张图片。这张图片就是微信返回的临时素材了。
3.下载文件时的文件路径
request.getSession().getServletContext().getRealPath("").replaceAll("\\", "/")
将获取路径:%TOMCAT_HOME%/webapp/工程名。若不是这个路径就请参考:Eclipse中的Web项目自动部署到Tomcat
String savePath=request.getSession().getServletContext().getRealPath("").replaceAll("\\", "/")+"/img/";
将获取路径:%TOMCAT_HOME%/webapp/工程名/img/
即从微信服务器下载的图片都保存在这个路径下。
二、代码实现
这里承接上一节。在上一节中我们完成了JSSDK的配置,并且用图片上传接口将图片上传到了微信服务器。这一节我们需要做的就是在图片上传到微信服务器后,根据微信服务器返回的serverId(即mediaId)来调用获取临时素材的接口,进行临时素材的下载,并保存到本地指定的路径下。
2.1 UploadExpenseAccaoutServlet
package com.ray.servlet;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.ray.service.TempMaterialService;
import com.ray.util.WeiXinParamesUtil;
import com.ray.util.WeiXinUtil;
/**
* Servlet implementation class UploadExpenseAccaoutServlet
*/
@WebServlet("/UploadExpenseAccaoutServlet")
public class UploadExpenseAccaoutServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public UploadExpenseAccaoutServlet() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
String mediaId=request.getParameter("serverId");
System.out.println("serverId:"+mediaId);
String accessToken= WeiXinUtil.getAccessToken(WeiXinParamesUtil.corpId, WeiXinParamesUtil.contactsSecret).getToken();
System.out.println("accessToken:"+accessToken);
//String savePath=System.getProperty("user.dir").replaceAll("\\", "/")+"/WebContent/img/"+mediaId+".png";
String savePath=request.getSession().getServletContext().getRealPath("").replaceAll("\\", "/")+"/img/";
System.out.println("savePath:"+savePath);
//2.调用业务类,获取临时素材
TempMaterialService tms=new TempMaterialService();
tms.getTempMaterial(accessToken, mediaId,savePath);
PrintWriter out = response.getWriter();
out.print("HHHHHHHHHH");
out.close();
out = null;
}
}
在此servlet中
(1)接收serverId
(2)调用临时素材业务类的方法TempMaterialService.getTempMaterial(accessToken, mediaId,savePath),获取临时素材。
2.2 临时素材业务类—TempMaterialService
package com.ray.service;
import java.io.File;
import java.io.UnsupportedEncodingException;
import com.ray.util.WeiXinUtil;
import net.sf.json.JSONObject;
/**@desc : 临时素材业务类
*
* @author: shirayner
* @date : 2017-8-18 下午2:07:25
*/
public class TempMaterialService {
//上传临时素材url
public String uploadTempMaterial_url="https://qyapi.weixin.qq.com/cgi-bin/media/upload?access_token=ACCESS_TOKEN&type=TYPE";
//获取临时素材url
public String getTempMaterial_url="https://qyapi.weixin.qq.com/cgi-bin/media/get?access_token=ACCESS_TOKEN&media_id=MEDIA_ID";
/**
* @desc :上传临时素材
*
* @param accessToken 接口访问凭证
* @param type 媒体文件类型,分别有图片(image)、语音(voice)、视频(video),普通文件(file)
* @param fileUrl 本地文件的url。例如 "D/1.img"。
* @return JSONObject 上传成功后,微信服务器返回的参数,有type、media_id 、created_at
*/
public JSONObject uploadTempMaterial(String accessToken,String type,String fileUrl){
//1.创建本地文件
File file=new File(fileUrl);
//2.拼接请求url
uploadTempMaterial_url = uploadTempMaterial_url.replace("ACCESS_TOKEN", accessToken)
.replace("TYPE", type);
//3.调用接口,发送请求,上传文件到微信服务器
String result=WeiXinUtil.httpRequest(uploadTempMaterial_url, file);
//4.json字符串转对象:解析返回值,json反序列化
result = result.replaceAll("[\\]", "");
System.out.println("result:" + result);
JSONObject resultJSON = JSONObject.fromObject(result);
//5.返回参数判断
if (resultJSON != null) {
if (resultJSON.get("media_id") != null) {
System.out.println("上传" + type + "临时素材成功:"+resultJSON.get("media_id"));
return resultJSON;
} else {
System.out.println("上传" + type + "临时素材成功失败");
}
}
return null;
}
/** 2.获取临时素材
*
* @param accessToken
* @param mediaId
* @return
* @throws UnsupportedEncodingException
*/
public void getTempMaterial(String accessToken,String mediaId,String savePath) throws UnsupportedEncodingException{
//String savePath=System.getProperty("user.dir").replaceAll("\\", "/")+"/WebContent/img/"+mediaId+".png";
//System.out.println("service savePath:"+savePath);
//1.拼接请求url
getTempMaterial_url=getTempMaterial_url.replace("ACCESS_TOKEN", accessToken)
.replace("MEDIA_ID", mediaId);
savePath=savePath+mediaId;
//2.调用接口,发送请求,获取临时素材
File file=null;
try {
file = WeiXinUtil.getFile(getTempMaterial_url,savePath);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("file:"+file.getName());
}
}
在此类的获取临时素材方法中:
(1)拼接微信获取临时素材的接口url
(2)调用WeiXinUtil.getFile(getTempMaterial_url,savePath),向微信发起https请求,并将接收到的图片下载到savePath指定的路径下
2.3 微信工具类—WeiXinUtil
package com.ray.util;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.ConnectException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Formatter;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.servlet.http.HttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.ray.pojo.AccessToken;
import net.sf.json.JSONException;
import net.sf.json.JSONObject;
public class WeiXinUtil {
private static Logger log = LoggerFactory.getLogger(WeiXinUtil.class);
//微信的请求url
//获取access_token的接口地址(GET) 限200(次/天)
public final static String access_token_url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid={corpId}&corpsecret={corpsecret}";
//获取jsapi_ticket的接口地址(GET) 限200(次/天)
public final static String jsapi_ticket_url = "https://qyapi.weixin.qq.com/cgi-bin/get_jsapi_ticket?access_token=ACCESSTOKEN";
/**
* 1.发起https请求并获取结果
*
* @param requestUrl 请求地址
* @param requestMethod 请求方式(GET、POST)
* @param outputStr 提交的数据
* @return JSONObject(通过JSONObject.get(key)的方式获取json对象的属性值)
*/
public static JSONObject httpRequest(String requestUrl, String requestMethod, String outputStr) {
JSONObject jsonObject = null;
StringBuffer buffer = new StringBuffer();
try {
// 创建SSLContext对象,并使用我们指定的信任管理器初始化
TrustManager[] tm = { new MyX509TrustManager() };
SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
sslContext.init(null, tm, new java.security.SecureRandom());
// 从上述SSLContext对象中得到SSLSocketFactory对象
SSLSocketFactory ssf = sslContext.getSocketFactory();
URL url = new URL(requestUrl);
HttpsURLConnection httpUrlConn = (HttpsURLConnection) url.openConnection();
httpUrlConn.setSSLSocketFactory(ssf);
httpUrlConn.setDoOutput(true);
httpUrlConn.setDoInput(true);
httpUrlConn.setUseCaches(false);
// 设置请求方式(GET/POST)
httpUrlConn.setRequestMethod(requestMethod);
if ("GET".equalsIgnoreCase(requestMethod))
httpUrlConn.connect();
// 当有数据需要提交时
if (null != outputStr) {
OutputStream outputStream = httpUrlConn.getOutputStream();
// 注意编码格式,防止中文乱码
outputStream.write(outputStr.getBytes("UTF-8"));
outputStream.close();
}
// 将返回的输入流转换成字符串
InputStream inputStream = httpUrlConn.getInputStream();
InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "UTF-8");
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String str = null;
while ((str = bufferedReader.readLine()) != null) {
buffer.append(str);
}
bufferedReader.close();
inputStreamReader.close();
// 释放资源
inputStream.close();
inputStream = null;
httpUrlConn.disconnect();
jsonObject = JSONObject.fromObject(buffer.toString());
} catch (ConnectException ce) {
log.error("Weixin server connection timed out.");
} catch (Exception e) {
log.error("https request error:{}", e);
}
return jsonObject;
}
/**
* 2.发送https请求之获取临时素材
* @param requestUrl
* @param savePath 文件的保存路径,此时还缺一个扩展名
* @return
* @throws Exception
*/
public static File getFile(String requestUrl,String savePath) throws Exception {
//String path=System.getProperty("user.dir")+"/img//1.png";
// 创建SSLContext对象,并使用我们指定的信任管理器初始化
TrustManager[] tm = { new MyX509TrustManager() };
SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
sslContext.init(null, tm, new java.security.SecureRandom());
// 从上述SSLContext对象中得到SSLSocketFactory对象
SSLSocketFactory ssf = sslContext.getSocketFactory();
URL url = new URL(requestUrl);
HttpsURLConnection httpUrlConn = (HttpsURLConnection) url.openConnection();
httpUrlConn.setSSLSocketFactory(ssf);
httpUrlConn.setDoOutput(true);
httpUrlConn.setDoInput(true);
httpUrlConn.setUseCaches(false);
// 设置请求方式(GET/POST)
httpUrlConn.setRequestMethod("GET");
httpUrlConn.connect();
//获取文件扩展名
String ext=getExt(httpUrlConn.getContentType());
savePath=savePath+ext;
System.out.println("savePath"+savePath);
//下载文件到f文件
File file = new File(savePath);
// 获取微信返回的输入流
InputStream in = httpUrlConn.getInputStream();
//输出流,将微信返回的输入流内容写到文件中
FileOutputStream out = new FileOutputStream(file);
int length=100*1024;
byte[] byteBuffer = new byte[length]; //存储文件内容
int byteread =0;
int bytesum=0;
while (( byteread=in.read(byteBuffer)) != -1) {
bytesum += byteread; //字节数 文件大小
out.write(byteBuffer,0,byteread);
}
System.out.println("bytesum: "+bytesum);
in.close();
// 释放资源
out.close();
in = null;
out=null;
httpUrlConn.disconnect();
return file;
}
/**
* @desc :2.微信上传素材的请求方法
*
* @param requestUrl 微信上传临时素材的接口url
* @param file 要上传的文件
* @return String 上传成功后,微信服务器返回的消息
*/
public static String httpRequest(String requestUrl, File file) {
StringBuffer buffer = new StringBuffer();
try{
//1.建立连接
URL url = new URL(requestUrl);
HttpURLConnection httpUrlConn = (HttpURLConnection) url.openConnection(); //打开链接
//1.1输入输出设置
httpUrlConn.setDoInput(true);
httpUrlConn.setDoOutput(true);
httpUrlConn.setUseCaches(false); // post方式不能使用缓存
//1.2设置请求头信息
httpUrlConn.setRequestProperty("Connection", "Keep-Alive");
httpUrlConn.setRequestProperty("Charset", "UTF-8");
//1.3设置边界
String BOUNDARY = "----------" + System.currentTimeMillis();
httpUrlConn.setRequestProperty("Content-Type","multipart/form-data; boundary="+ BOUNDARY);
// 请求正文信息
// 第一部分:
//2.将文件头输出到微信服务器
StringBuilder sb = new StringBuilder();
sb.append("--"); // 必须多两道线
sb.append(BOUNDARY);
sb.append("rn");
sb.append("Content-Disposition: form-data;name="media";filelength="" + file.length()
+ "";filename=""+ file.getName() + ""rn");
sb.append("Content-Type:application/octet-streamrnrn");
byte[] head = sb.toString().getBytes("utf-8");
// 获得输出流
OutputStream outputStream = new DataOutputStream(httpUrlConn.getOutputStream());
// 将表头写入输出流中:输出表头
outputStream.write(head);
//3.将文件正文部分输出到微信服务器
// 把文件以流文件的方式 写入到微信服务器中
DataInputStream in = new DataInputStream(new FileInputStream(file));
int bytes = 0;
byte[] bufferOut = new byte[1024];
while ((bytes = in.read(bufferOut)) != -1) {
outputStream.write(bufferOut, 0, bytes);
}
in.close();
//4.将结尾部分输出到微信服务器
byte[] foot = ("rn--" + BOUNDARY + "--rn").getBytes("utf-8");// 定义最后数据分隔线
outputStream.write(foot);
outputStream.flush();
outputStream.close();
//5.将微信服务器返回的输入流转换成字符串
InputStream inputStream = httpUrlConn.getInputStream();
InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String str = null;
while ((str = bufferedReader.readLine()) != null) {
buffer.append(str);
}
bufferedReader.close();
inputStreamReader.close();
// 释放资源
inputStream.close();
inputStream = null;
httpUrlConn.disconnect();
} catch (IOException e) {
System.out.println("发送POST请求出现异常!" + e);
e.printStackTrace();
}
return buffer.toString();
}
/**
* 2.发起http请求获取返回结果
*
* @param requestUrl 请求地址
* @return
*/
public static String httpRequest(String requestUrl) {
StringBuffer buffer = new StringBuffer();
try {
URL url = new URL(requestUrl);
HttpURLConnection httpUrlConn = (HttpURLConnection) url.openConnection();
httpUrlConn.setDoOutput(false);
httpUrlConn.setDoInput(true);
httpUrlConn.setUseCaches(false);
httpUrlConn.setRequestMethod("GET");
httpUrlConn.connect();
// 将返回的输入流转换成字符串
InputStream inputStream = httpUrlConn.getInputStream();
//InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String str = null;
while ((str = bufferedReader.readLine()) != null) {
buffer.append(str);
}
bufferedReader.close();
inputStreamReader.close();
// 释放资源
inputStream.close();
inputStream = null;
httpUrlConn.disconnect();
} catch (Exception e) {
}
return buffer.toString();
}
/**
* 3.获取access_token
*
* @param appid 凭证
* @param appsecret 密钥
* @return
*/
public static AccessToken getAccessToken(String appid, String appsecret) {
AccessToken accessToken = null;
String requestUrl = access_token_url.replace("{corpId}", appid).replace("{corpsecret}", appsecret);
JSONObject jsonObject = httpRequest(requestUrl, "GET", null);
// 如果请求成功
if (null != jsonObject) {
try {
accessToken = new AccessToken();
accessToken.setToken(jsonObject.getString("access_token"));
accessToken.setExpiresIn(jsonObject.getInt("expires_in"));
} catch (JSONException e) {
accessToken = null;
// 获取token失败
log.error("获取token失败 errcode:{} errmsg:{}", jsonObject.getInt("errcode"), jsonObject.getString("errmsg"));
}
}
return accessToken;
}
/**
* 4. 获取JsapiTicket
* @param accessToken
* @return
*/
public static String getJsapiTicket(String accessToken){
String requestUrl = jsapi_ticket_url.replace("ACCESSTOKEN", accessToken);
JSONObject jsonObject = httpRequest(requestUrl, "GET", null);
String jsapi_ticket="";
// 如果请求成功
if (null != jsonObject) {
try {
jsapi_ticket=jsonObject.getString("ticket");
} catch (JSONException e) {
// 获取token失败
log.error("获取token失败 errcode:{} errmsg:{}", jsonObject.getInt("errcode"), jsonObject.getString(