一、本节要点

1.官方文档的media

这个media可以理解为文件,即我们需要以POST方式提交一个文件

Java微信公众平台开发_06_素材管理-LMLPHP

2.媒体文件有效期

媒体文件在微信后台保存时间为3天,即3天后media_id失效。

二、代码实现

1.HTTP请求工具类—HttpHelper.java

package com.ray.weixin.gz.util;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream; import org.apache.http.Consts;
import org.apache.http.Header;
import org.apache.http.HeaderElement;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
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.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.util.EntityUtils; import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject; /**
* HTTP请求封装,建议直接使用sdk的API
*/
public class HttpHelper { /**
* @desc :1.发起GET请求
*
* @param url
* @return JSONObject
* @throws Exception
*/
public static JSONObject doGet(String url) throws Exception { //1.生成一个请求
HttpGet httpGet = new HttpGet(url);
//2.配置请求的属性
RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(5000).setConnectTimeout(5000).build();//
httpGet.setConfig(requestConfig); //3.发起请求,获取响应信息
//3.1 创建httpClient
CloseableHttpClient httpClient = HttpClients.createDefault();
CloseableHttpResponse response = null;
try {
//3.2 发起请求,获取响应信息
response = httpClient.execute(httpGet, new BasicHttpContext()); //如果返回结果的code不等于200,说明出错了
if (response.getStatusLine().getStatusCode() != 200) { System.out.println("request url failed, http code=" + response.getStatusLine().getStatusCode()
+ ", url=" + url);
return null;
}
//4.解析请求结果
HttpEntity entity = response.getEntity(); //reponse返回的数据在entity中
if (entity != null) {
String resultStr = EntityUtils.toString(entity, "utf-8"); //将数据转化为string格式
System.out.println("GET请求结果:"+resultStr);
JSONObject result = JSON.parseObject(resultStr); //将String转换为 JSONObject if(result.getInteger("errcode")==null) {
return result;
}else if (0 == result.getInteger("errcode")) {
return result;
}else {
System.out.println("request url=" + url + ",return value=");
System.out.println(resultStr);
int errCode = result.getInteger("errcode");
String errMsg = result.getString("errmsg");
throw new Exception("error code:"+errCode+", error message:"+errMsg);
}
}
} catch (IOException e) {
System.out.println("request url=" + url + ", exception, msg=" + e.getMessage());
e.printStackTrace();
} finally {
if (response != null) try {
response.close(); //释放资源 } catch (IOException e) {
e.printStackTrace();
}
} return null;
} /** 2.发起POST请求
* @desc :
*
* @param url 请求url
* @param data 请求参数(json)
* @return
* @throws Exception JSONObject
*/
public static JSONObject doPost(String url, Object data) throws Exception {
//1.生成一个请求
HttpPost httpPost = new HttpPost(url); //2.配置请求属性
//2.1 设置请求超时时间
RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(100000).setConnectTimeout(100000).build();
httpPost.setConfig(requestConfig);
//2.2 设置数据传输格式-json
httpPost.addHeader("Content-Type", "application/json");
//2.3 设置请求实体,封装了请求参数
StringEntity requestEntity = new StringEntity(JSON.toJSONString(data), "utf-8");
httpPost.setEntity(requestEntity); //3.发起请求,获取响应信息
//3.1 创建httpClient
CloseableHttpClient httpClient = HttpClients.createDefault();
CloseableHttpResponse response = null; try { //3.3 发起请求,获取响应
response = httpClient.execute(httpPost, new BasicHttpContext()); if (response.getStatusLine().getStatusCode() != 200) { System.out.println("request url failed, http code=" + response.getStatusLine().getStatusCode()
+ ", url=" + url);
return null;
} //获取响应内容
HttpEntity entity = response.getEntity();
if (entity != null) {
String resultStr = EntityUtils.toString(entity, "utf-8");
System.out.println("POST请求结果:"+resultStr); //解析响应内容
JSONObject result = JSON.parseObject(resultStr); if(result.getInteger("errcode")==null) {
return result;
}else if (0 == result.getInteger("errcode")) {
return result;
}else {
System.out.println("request url=" + url + ",return value=");
System.out.println(resultStr);
int errCode = result.getInteger("errcode");
String errMsg = result.getString("errmsg");
throw new Exception("error code:"+errCode+", error message:"+errMsg);
}
}
} catch (IOException e) {
System.out.println("request url=" + url + ", exception, msg=" + e.getMessage());
e.printStackTrace();
} finally {
if (response != null) try {
response.close(); //释放资源 } catch (IOException e) {
e.printStackTrace();
}
} return null;
} /**
* @desc : 3.上传文件
*
* @param url 请求url
* @param file 上传的文件
* @return
* @throws Exception JSONObject
*/
public static JSONObject uploadMedia(String url, File file) throws Exception {
HttpPost httpPost = new HttpPost(url);
CloseableHttpResponse response = null;
CloseableHttpClient httpClient = HttpClients.createDefault();
RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(5000).setConnectTimeout(5000).build();
httpPost.setConfig(requestConfig); //2.3 设置请求实体,封装了请求参数
HttpEntity requestEntity = MultipartEntityBuilder.create().addPart("media",
new FileBody(file, ContentType.create("multipart/form-data", Consts.UTF_8), file.getName())).build(); //FileEntity requestEntity = new FileEntity(file,ContentType.MULTIPART_FORM_DATA); httpPost.setEntity(requestEntity); try {
response = httpClient.execute(httpPost, new BasicHttpContext()); if (response.getStatusLine().getStatusCode() != 200) { System.out.println("request url failed, http code=" + response.getStatusLine().getStatusCode()
+ ", url=" + url);
return null;
}
HttpEntity entity = response.getEntity();
if (entity != null) {
String resultStr = EntityUtils.toString(entity, "utf-8"); JSONObject result = JSON.parseObject(resultStr);
//上传临时素材成功
if (result.getString("errcode")== null) {
// 成功
//result.remove("errcode");
//result.remove("errmsg");
return result;
} else {
System.out.println("request url=" + url + ",return value=");
System.out.println(resultStr);
int errCode = result.getInteger("errcode");
String errMsg = result.getString("errmsg");
throw new Exception("error code:"+errCode+", error message:"+errMsg);
}
}
} catch (IOException e) {
System.out.println("request url=" + url + ", exception, msg=" + e.getMessage());
e.printStackTrace();
} finally {
if (response != null) try {
response.close(); //释放资源 } catch (IOException e) {
e.printStackTrace();
}
} return null;
} /**
* @desc : 上传PDF
* 见微信电子发票章节
* 9. 向用户提供发票或其它消费凭证PDF
*
* @param url
* @param file
* @return
* @throws Exception
* JSONObject
*/
public static JSONObject uploadPDF(String url, File file) throws Exception {
HttpPost httpPost = new HttpPost(url);
CloseableHttpResponse response = null;
CloseableHttpClient httpClient = HttpClients.createDefault();
RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(5000).setConnectTimeout(5000).build();
httpPost.setConfig(requestConfig); //2.3 设置请求实体,封装了请求参数
HttpEntity requestEntity = MultipartEntityBuilder.create().addPart("media",
new FileBody(file, ContentType.create("multipart/form-data", Consts.UTF_8), file.getName())).build(); httpPost.setEntity(requestEntity); try {
response = httpClient.execute(httpPost, new BasicHttpContext()); if (response.getStatusLine().getStatusCode() != 200) { System.out.println("request url failed, http code=" + response.getStatusLine().getStatusCode()
+ ", url=" + url);
return null;
}
HttpEntity entity = response.getEntity();
if (entity != null) {
String resultStr = EntityUtils.toString(entity, "utf-8"); JSONObject result = JSON.parseObject(resultStr);
//上传临时素材成功
if (result.getString("errcode")== null) {
// 成功
//result.remove("errcode");
//result.remove("errmsg");
return result;
} else {
System.out.println("request url=" + url + ",return value=");
System.out.println(resultStr);
int errCode = result.getInteger("errcode");
String errMsg = result.getString("errmsg");
throw new Exception("error code:"+errCode+", error message:"+errMsg);
}
}
} catch (IOException e) {
System.out.println("request url=" + url + ", exception, msg=" + e.getMessage());
e.printStackTrace();
} finally {
if (response != null) try {
response.close(); //释放资源 } catch (IOException e) {
e.printStackTrace();
}
} return null;
}
/**
* @desc : 4.下载文件 -get
*
* @param url 请求url
* @param fileDir 下载路径
* @return
* @throws Exception File
*/
public static File downloadMedia(String url, String fileDir) throws Exception {
//1.生成一个请求
HttpGet httpGet = new HttpGet(url);
//2.配置请求属性
RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(100000).setConnectTimeout(100000).build();
httpGet.setConfig(requestConfig); //3.发起请求,获取响应信息
//3.1 创建httpClient
CloseableHttpClient httpClient = HttpClients.createDefault();
CloseableHttpResponse response = null; //4.设置本地保存的文件
//File file = new File(fileDir);
File file = null;
try {
//5. 发起请求,获取响应信息
response = httpClient.execute(httpGet, new BasicHttpContext());
System.out.println("HttpStatus.SC_OK:"+HttpStatus.SC_OK);
System.out.println("response.getStatusLine().getStatusCode():"+response.getStatusLine().getStatusCode());
System.out.println("http-header:"+JSON.toJSONString( response.getAllHeaders() ));
System.out.println("http-filename:"+getFileName(response) ); //请求成功
if(HttpStatus.SC_OK==response.getStatusLine().getStatusCode()){ //6.取得请求内容
HttpEntity entity = response.getEntity(); if (entity != null) {
//这里可以得到文件的类型 如image/jpg /zip /tiff 等等 但是发现并不是十分有效,有时明明后缀是.rar但是取到的是null,这点特别说明
System.out.println(entity.getContentType());
//可以判断是否是文件数据流
System.out.println(entity.isStreaming()); //6.1 输出流
//6.1.1获取文件名,拼接文件路径
String fileName=getFileName(response);
fileDir=fileDir+fileName;
file = new File(fileDir);
//6.1.2根据文件路径获取输出流
FileOutputStream output = new FileOutputStream(file); //6.2 输入流:从钉钉服务器返回的文件流,得到网络资源并写入文件
InputStream input = entity.getContent(); //6.3 将数据写入文件:将输入流中的数据写入到输出流
byte b[] = new byte[1024];
int j = 0;
while( (j = input.read(b))!=-1){
output.write(b,0,j);
}
output.flush();
output.close();
}
if (entity != null) {
entity.consumeContent();
}
}
} catch (IOException e) {
System.out.println("request url=" + url + ", exception, msg=" + e.getMessage());
e.printStackTrace();
} finally {
if (response != null) try {
response.close(); //释放资源 } catch (IOException e) {
e.printStackTrace();
}
} return file;
} /**
* @desc : 5.下载文件 - post
*
* @param url 请求url
* @param data post请求参数
* @param fileDir 文件下载路径
* @return
* @throws Exception File
*/
public static File downloadMedia(String url, Object data, String fileDir) throws Exception {
//1.生成一个请求
HttpPost httpPost = new HttpPost(url); //2.配置请求属性
//2.1 设置请求超时时间
RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(100000).setConnectTimeout(100000).build();
httpPost.setConfig(requestConfig);
//2.2 设置数据传输格式-json
httpPost.addHeader("Content-Type", "application/json");
//2.3 设置请求参数
StringEntity requestEntity = new StringEntity(JSON.toJSONString(data), "utf-8");
httpPost.setEntity(requestEntity); //3.发起请求,获取响应信息
//3.1 创建httpClient
CloseableHttpClient httpClient = HttpClients.createDefault();
CloseableHttpResponse response = null; //4.设置本地保存的文件
//File file = new File(fileDir);
File file = null;
try {
//5. 发起请求,获取响应信息
response = httpClient.execute(httpPost, new BasicHttpContext());
System.out.println("HttpStatus.SC_OK:"+HttpStatus.SC_OK);
System.out.println("response.getStatusLine().getStatusCode():"+response.getStatusLine().getStatusCode());
System.out.println("http-header:"+JSON.toJSONString( response.getAllHeaders() ));
System.out.println("http-filename:"+getFileName(response) ); //请求成功
if(HttpStatus.SC_OK==response.getStatusLine().getStatusCode()){ //6.取得请求内容
HttpEntity entity = response.getEntity(); if (entity != null) {
//这里可以得到文件的类型 如image/jpg /zip /tiff 等等 但是发现并不是十分有效,有时明明后缀是.rar但是取到的是null,这点特别说明
System.out.println(entity.getContentType());
//可以判断是否是文件数据流
System.out.println(entity.isStreaming()); //6.1 输出流
//6.1.1获取文件名,拼接文件路径
String fileName=getFileName(response);
fileDir=fileDir+fileName;
file = new File(fileDir);
//6.1.2根据文件路径获取输出流
FileOutputStream output = new FileOutputStream(file); //6.2 输入流:从钉钉服务器返回的文件流,得到网络资源并写入文件
InputStream input = entity.getContent(); //6.3 将数据写入文件:将输入流中的数据写入到输出流
byte b[] = new byte[1024];
int j = 0;
while( (j = input.read(b))!=-1){
output.write(b,0,j);
}
output.flush();
output.close();
}
if (entity != null) {
entity.consumeContent();
}
}
} catch (IOException e) {
System.out.println("request url=" + url + ", exception, msg=" + e.getMessage());
e.printStackTrace();
} finally {
if (response != null) try {
response.close(); //释放资源 } catch (IOException e) {
e.printStackTrace();
}
} return file;
} /** 5. 获取response header中Content-Disposition中的filename值
* @desc :
*
* @param response 响应
* @return String
*/
public static String getFileName(HttpResponse response) {
Header contentHeader = response.getFirstHeader("Content-Disposition");
String filename = null;
if (contentHeader != null) {
HeaderElement[] values = contentHeader.getElements();
if (values.length == 1) {
NameValuePair param = values[0].getParameterByName("filename");
if (param != null) {
try {
//filename = new String(param.getValue().toString().getBytes(), "utf-8");
//filename=URLDecoder.decode(param.getValue(),"utf-8");
filename = param.getValue();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
return filename;
} }

2.Token工具类—AuthHelper.java

package com.ray.weixin.gz.util;

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Formatter;
import java.util.UUID; import javax.servlet.http.HttpServletRequest; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import com.alibaba.fastjson.JSONObject;
import com.ray.weixin.gz.config.Env;
import com.ray.weixin.gz.service.invoice.InvoiceService; /**
* 微信公众号 Token、配置工具类
* @desc : AccessToken、Jsticket 、Jsapi
*
* @author: shirayner
* @date : 2017年9月27日 下午5:00:25
*/
public class AuthHelper {
private static final Logger logger = LogManager.getLogger(AuthHelper.class); //1.获取access_token的接口地址,有效期为7200秒
private static final String GET_ACCESSTOKEN_URL="https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";
//2.获取getJsapiTicket的接口地址,有效期为7200秒
private static final String GET_JSAPITICKET_URL="https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi"; //3.通过code换取网页授权access_token
private static final String GET_ACCESSTOKEN_BYCODE_URL="https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code"; /**
* @desc :1.获取access_token
*
* @param appId 第三方用户唯一凭证
* @param appSecret 第三方用户唯一凭证密钥,即appsecret
*
* @return
* access_token 获取到的凭证
* expires_in 凭证有效时间,单位:秒
* @throws Exception String
*/
public static String getAccessToken(String appId,String appSecret) throws Exception {
//1.获取请求url
String url=GET_ACCESSTOKEN_URL.replace("APPID", appId).replace("APPSECRET", appSecret); //2.发起GET请求,获取返回结果
JSONObject jsonObject=HttpHelper.doGet(url);
logger.info("jsonObject:"+jsonObject.toJSONString()); //3.解析结果,获取accessToken
String accessToken="";
if (null != jsonObject) {
//4.错误消息处理
if (jsonObject.getInteger("errcode")!=null && 0 != jsonObject.getInteger("errcode")) {
int errCode = jsonObject.getInteger("errcode");
String errMsg = jsonObject.getString("errmsg");
throw new Exception("error code:"+errCode+", error message:"+errMsg);
//5.成功获取accessToken
}else {
accessToken=jsonObject.getString("access_token");
}
} return accessToken;
} /**
* @desc :2.获取JsapiTicket
*
* @param accessToken 有效凭证
* @return
* @throws Exception String
*/
public static String getJsapiTicket(String accessToken) throws Exception {
//1.获取请求url
String url=GET_JSAPITICKET_URL.replace("ACCESS_TOKEN", accessToken); //2.发起GET请求,获取返回结果
JSONObject jsonObject=HttpHelper.doGet(url);
logger.info("jsonObject:"+jsonObject.toJSONString()); //3.解析结果,获取accessToken
String jsapiTicket="";
if (null != jsonObject) {
//4.错误消息处理
if (jsonObject.getInteger("errcode")!=null && 0 != jsonObject.getInteger("errcode")) {
int errCode = jsonObject.getInteger("errcode");
String errMsg = jsonObject.getString("errmsg");
throw new Exception("error code:"+errCode+", error message:"+errMsg);
//5.成功获取jsapiTicket
}else {
jsapiTicket=jsonObject.getString("ticket");
}
} return jsapiTicket;
} /**
* @desc : 3.通过code换取网页授权access_token
*
* @param appId 第三方用户唯一凭证
* @param appSecret 第三方用户唯一凭证密钥,即appsecret
* @param Code code作为换取access_token的票据,每次用户授权带上的code将不一样,code只能使用一次,5分钟未被使用自动过期。
*
* @return
* access_token 网页授权接口调用凭证,注意:此access_token与基础支持的access_token不同
* expires_in access_token接口调用凭证超时时间,单位(秒)
* refresh_token 用户刷新access_token
* openid 用户唯一标识,请注意,在未关注公众号时,用户访问公众号的网页,也会产生一个用户和公众号唯一的OpenID
* scope 用户授权的作用域,使用逗号(,)分隔
*
* @throws Exception String
*/
public static JSONObject getAccessTokenByCode(String appId,String appSecret,String code) throws Exception {
//1.获取请求url
String url=GET_ACCESSTOKEN_BYCODE_URL.replace("APPID", appId).replace("SECRET", appSecret).replace("CODE", code); //2.发起GET请求,获取返回结果
JSONObject jsonObject=HttpHelper.doGet(url);
logger.info("jsonObject:"+jsonObject.toJSONString()); //3.解析结果,获取accessToken
JSONObject returnJsonObject=null;
if (null != jsonObject) {
//4.错误消息处理
if (jsonObject.getInteger("errcode")!=null && 0 != jsonObject.getInteger("errcode")) {
int errCode = jsonObject.getInteger("errcode");
String errMsg = jsonObject.getString("errmsg");
throw new Exception("error code:"+errCode+", error message:"+errMsg);
//5.成功获取accessToken
}else {
returnJsonObject=jsonObject;
}
} return returnJsonObject;
} /**
* @desc :4.获取前端jsapi需要的配置参数
*
* @param request
* @return String
*/
public static String getJsapiConfig(HttpServletRequest request){ //1.准备好参与签名的字段
//1.1 url
/*
*以http://localhost/test.do?a=b&c=d为例
*request.getRequestURL的结果是http://localhost/test.do
*request.getQueryString的返回值是a=b&c=d
*/
String urlString = request.getRequestURL().toString();
String queryString = request.getQueryString();
String queryStringEncode = null;
String url;
if (queryString != null) {
queryStringEncode = URLDecoder.decode(queryString);
url = urlString + "?" + queryStringEncode;
} else {
url = urlString;
} //1.2 noncestr
String nonceStr=UUID.randomUUID().toString(); //随机数
//1.3 timestamp
long timeStamp = System.currentTimeMillis() / 1000; //时间戳参数 String signedUrl = url; String accessToken = null;
String ticket = null; String signature = null; //签名 try {
//1.4 jsapi_ticket
accessToken=getAccessToken(Env.APP_ID, Env.APP_SECRET);
ticket=getJsapiTicket(accessToken); //2.进行签名,获取signature
signature=getSign(ticket,nonceStr,timeStamp,signedUrl); } catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} logger.info("accessToken:"+accessToken);
logger.info("ticket:"+ticket);
logger.info("nonceStr:"+nonceStr);
logger.info("timeStamp:"+timeStamp);
logger.info("signedUrl:"+signedUrl);
logger.info("signature:"+signature);
logger.info("appId:"+Env.APP_ID); String configValue = "{signature:'" + signature + "',nonceStr:'" + nonceStr + "',timeStamp:'"
+ timeStamp + "',appId:'" + Env.APP_ID + "'}";
logger.info("configValue:"+configValue); return configValue;
} /**
* @desc : 4.1 生成签名的函数
*
* @param ticket jsticket
* @param nonceStr 随机串,自己定义
* @param timeStamp 生成签名用的时间戳
* @param url 需要进行免登鉴权的页面地址,也就是执行dd.config的页面地址
* @return
* @throws Exception String
*/ public static String getSign(String jsTicket, String nonceStr, Long timeStamp, String url) throws Exception {
String plainTex = "jsapi_ticket=" + jsTicket + "&noncestr=" + nonceStr + "&timestamp=" + timeStamp + "&url=" + url;
System.out.println(plainTex);
try {
MessageDigest crypt = MessageDigest.getInstance("SHA-1");
crypt.reset();
crypt.update(plainTex.getBytes("UTF-8"));
return byteToHex(crypt.digest());
} catch (NoSuchAlgorithmException e) {
throw new Exception(e.getMessage());
} catch (UnsupportedEncodingException e) {
throw new Exception(e.getMessage());
}
} /**
* @desc :4.2 将bytes类型的数据转化为16进制类型
*
* @param hash
* @return
* String
*/
private static String byteToHex(byte[] hash) {
Formatter formatter = new Formatter();
for (byte b : hash) {
formatter.format("%02x", new Object[] { Byte.valueOf(b) });
}
String result = formatter.toString();
formatter.close();
return result;
} /** 5.获取前端所需发票签名参数
*
* @desc :
*(1)将 api_ticket、appid、timestamp、nonceStr、cardType的value值进行字符串的字典序排序。
*(2)再将所有参数字符串拼接成一个字符串进行sha1加密,得到cardSign。
*
* @return String
* timestamp :卡券签名时间戳
nonceStr : 卡券签名随机串
signType : 签名方式,默认'SHA1'
cardSign : 卡券签名
*
*/
public static String getInvoiceConfig(){
//1.准备好签名参数
//1.1 api_ticket 授权页ticket
String apiTicket=null;
try {
String accessToken = AuthHelper.getAccessToken(Env.APP_ID, Env.APP_SECRET);
apiTicket=InvoiceService.getAuthPageTicket(accessToken);
} catch (Exception e) {
logger.info("获取授权页ticket失败");
e.printStackTrace();
} //1.2 appid
String appId=Env.APP_ID; //1.3 timestamp 时间戳
String timeStamp = System.currentTimeMillis() / 1000 +""; //1.4 nonceStr 随机数
String nonceStr=UUID.randomUUID().toString(); //1.5 cardType
String cardType="INVOICE"; //2.获取签名
String cardSign=null;
try { cardSign = AuthHelper.getCardSign(apiTicket, appId, timeStamp, nonceStr, cardType); } catch (Exception e) {
logger.info("获取发票签名失败");
e.printStackTrace();
} String signType="SHA1"; logger.info("apiTicket:"+apiTicket);
logger.info("appId:"+appId);
logger.info("timeStamp:"+timeStamp);
logger.info("nonceStr:"+nonceStr);
logger.info("cardType:"+cardType);
logger.info("cardSign:"+cardSign);
logger.info("signType:"+signType); //3.返回前端所需发票签名参数
JSONObject jsonObject=new JSONObject();
jsonObject.put("timestamp", timeStamp);
jsonObject.put("nonceStr",nonceStr );
jsonObject.put("signType",signType );
jsonObject.put("cardSign", cardSign); String configValue = jsonObject.toJSONString();
logger.info("configValue:"+configValue); return configValue;
} /**
* @desc :5.1获取发票签名
*
* @param apiTicket 授权页ticket,见InvoiceService
* @param appId
* @param timeStamp 时间戳
* @param nonceStr 随机串
* @param cardType 填入INVOICE
* @return
* @throws Exception
* String
*/
public static String getCardSign(String apiTicket, String appId, String timeStamp, String nonceStr,String cardType) throws Exception {
//1.将 api_ticket、appid、timestamp、nonceStr、cardType的value值进行字符串的字典序排序。
//注意:是value值值
String[] array = new String[] { apiTicket, appId, timeStamp, nonceStr,cardType};
StringBuffer sb = new StringBuffer();
// 字符串排序
Arrays.sort(array);
for (int i = 0; i < 5; i++) {
sb.append(array[i]);
}
String plainTex = sb.toString(); //String plainTex = apiTicket+appId+cardType+nonceStr+timeStamp; System.out.println("plainTex:"+plainTex);
try {
MessageDigest crypt = MessageDigest.getInstance("SHA-1");
crypt.reset();
crypt.update(plainTex.getBytes("UTF-8"));
return byteToHex(crypt.digest());
} catch (NoSuchAlgorithmException e) {
throw new Exception(e.getMessage());
} catch (UnsupportedEncodingException e) {
throw new Exception(e.getMessage());
}
} public static String getSHA1(String apiTicket, String appId, String timeStamp, String nonceStr,String cardType) throws Exception{
System.out.println("getSHA1-----------");
try {
String[] array = new String[] { apiTicket, appId, timeStamp, nonceStr,cardType};
StringBuffer sb = new StringBuffer();
// 字符串排序
Arrays.sort(array);
for (int i = 0; i < 5; i++) {
sb.append(array[i]);
}
String str = sb.toString();
logger.info("str:"+str);
// SHA1签名生成
MessageDigest md = MessageDigest.getInstance("SHA-1");
md.update(str.getBytes());
byte[] digest = md.digest(); StringBuffer hexstr = new StringBuffer();
String shaHex = "";
for (int i = 0; i < digest.length; i++) {
shaHex = Integer.toHexString(digest[i] & 0xFF);
if (shaHex.length() < 2) {
hexstr.append(0);
}
hexstr.append(shaHex);
}
return hexstr.toString();
} catch (Exception e) {
e.printStackTrace();
throw new Exception("获取发票签名失败");
}
} }

3.素材管理业务类—TempMaterialService.java

package com.ray.weixin.gz.service.tempmaterial;

import java.io.File;
import java.util.HashMap;
import java.util.Map; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.ray.weixin.gz.util.HttpHelper; /**@desc : 素材管理
*
* @author: shirayner
* @date : 2017年11月1日 上午10:16:00
*/
public class TempMaterialService {
private static final Logger logger = LogManager.getLogger(TempMaterialService.class); //1.新增临时素材
private static final String UPLOAD_TEMPMATERIAL_URL="https://api.weixin.qq.com/cgi-bin/media/upload?access_token=ACCESS_TOKEN&type=TYPE";
//2.获取临时素材 ( 即为原“下载多媒体文件”接口 )
private static final String GET_TEMPMATERIAL_URL="https://api.weixin.qq.com/cgi-bin/media/get?access_token=ACCESS_TOKEN&media_id=MEDIA_ID"; //3.新增永久素材(上传)——上传永久图片——上传图文消息内的图片获取URL
private static final String UPLOAD_PERMANENT_IMG_URL="https://api.weixin.qq.com/cgi-bin/media/uploadimg?access_token=ACCESS_TOKEN";
//4.新增永久素材(上传)——新增其他类型永久素材(image、voice、video、thumb)
private static final String UPLOAD_PERMANENT_MATERIAL_URL="https://api.weixin.qq.com/cgi-bin/material/add_material?access_token=ACCESS_TOKEN&type=TYPE";
//5.获取永久素材列表
private static final String LIST_PERMANENT_MATERIAL_URL="https://api.weixin.qq.com/cgi-bin/material/batchget_material?access_token=ACCESS_TOKEN";
//6.获取永久素材(下载)
private static final String GET_PERMANENT_MATERIAL_URL="https://api.weixin.qq.com/cgi-bin/material/get_material?access_token=ACCESS_TOKEN";
//7.删除永久素材
private static final String DELETE_PERMANENT_MATERIAL_URL="https://api.weixin.qq.com/cgi-bin/material/del_material?access_token=ACCESS_TOKEN"; /** 1.新增临时素材
*
* @desc :
* 1、临时素材media_id是可复用的。
* 2、媒体文件在微信后台保存时间为3天,即3天后media_id失效。
* 3、上传临时素材的格式、大小限制与公众平台官网一致。
* 图片(image): 2M,支持PNG\JPEG\JPG\GIF格式
* 语音(voice):2M,播放长度不超过60s,支持AMR\MP3格式
* 视频(video):10MB,支持MP4格式
* 缩略图(thumb):64KB,支持JPG格式
*
* @param accessToken 有效凭证
* @param type 媒体文件类型,分别有图片(image)、语音(voice)、视频(video)和缩略图(thumb)
* @param fileDir 要上传文件所在路径
* @return
* @throws Exception JSONObject
*/
public static JSONObject uploadTempMaterial(String accessToken,String type,String fileDir) throws Exception {
//1.创建本地文件
File file=new File(fileDir); //2.拼接请求url
String url = UPLOAD_TEMPMATERIAL_URL.replace("ACCESS_TOKEN", accessToken).replace("TYPE", type); //3.调用接口,发送请求,上传文件到微信服务器
JSONObject jsonObject=HttpHelper.uploadMedia(url, file);
logger.info("JsonObject:"+jsonObject.toJSONString()); //4.解析结果
if (jsonObject != null) {
if (jsonObject.getString("media_id") != null) {
logger.info("上传" + type + "临时素材成功:"+jsonObject.get("media_id"));
return jsonObject; //5.错误消息处理
} else {
logger.error("上传" + type + "临时素材成功失败");
}
}
return null; } /**
* @desc :2.获取临时素材
*
* @param accessToken 调用接口凭证
* @param mediaId 媒体文件ID
* @param fileDir 文件下载路径(文件所在文件夹路径),如 D:/img/download/,会与文件名拼接成文件下载路径
* @return
* @throws Exception File
*/
public static File getTempMaterial(String accessToken,String mediaId,String fileDir) throws Exception {
//1.拼接请求url
String url = GET_TEMPMATERIAL_URL.replace("ACCESS_TOKEN", accessToken).replace("MEDIA_ID", mediaId); //2.调用接口,发送请求,下载文件到本地
File file=HttpHelper.downloadMedia(url, fileDir);
logger.info("fileName:"+file.getName()); return file; } /** 3.新增永久素材——上传永久图片——上传图文消息内的图片获取URL
* @desc :
*
* @param accessToken
* @param fileDir
* @return
* @throws Exception String
*/
public static String uploadPermanentImg(String accessToken,String fileDir) throws Exception {
//1.创建本地文件
File file=new File(fileDir); //2.拼接请求url
String url = UPLOAD_PERMANENT_IMG_URL.replace("ACCESS_TOKEN", accessToken); //3.调用接口,发送请求,上传文件到微信服务器
JSONObject jsonObject=HttpHelper.uploadMedia(url, file);
logger.info("JsonObject:"+jsonObject.toJSONString()); String ImgUrl=null;
//4.解析结果
if (jsonObject != null) {
if (jsonObject.getString("url") != null) { ImgUrl=jsonObject.getString("url"); logger.info("新增永久素材成功:"+ImgUrl); //5.错误消息处理
} else {
logger.info("新增永久素材失败");
}
}
return ImgUrl;
} /**
* @desc : 4.新增永久素材——新增其他类型永久素材(image、voice、thumb)
*
* @param accessToken 调用接口凭证
* @param type 媒体文件类型,分别有图片(image)、语音(voice)、视频(video)和缩略图(thumb)
* @param fileDir 本地图片路径
*
* @return
* media_id 新增的永久素材的media_id
* url 新增的图片素材的图片URL(仅新增图片素材时会返回该字段)
*
* @throws Exception String
*/
public static JSONObject uploadPermanentMaterial(String accessToken,String type,String fileDir) throws Exception {
//1.创建本地文件
File file=new File(fileDir); //2.拼接请求url
String url = UPLOAD_PERMANENT_MATERIAL_URL.replace("ACCESS_TOKEN", accessToken).replace("TYPE", type); //3.调用接口,发送请求,上传文件到微信服务器
JSONObject jsonObject=HttpHelper.uploadMedia(url, file);
logger.info("JsonObject:"+jsonObject.toJSONString()); //4.解析结果
JSONObject returnJsonObject=null;
if (jsonObject != null) {
if (jsonObject.getString("media_id") != null) { logger.info("新增永久素材成功:"+jsonObject.getString("media_id"));
returnJsonObject= jsonObject;
//5.错误消息处理
} else {
int errCode = jsonObject.getInteger("errcode");
String errMsg = jsonObject.getString("errmsg");
logger.error("新增永久素材失败"+" errcode:"+errCode+", errmsg:"+errMsg);
}
}
return returnJsonObject;
} /**
* @desc :5.获取永久素材列表
*
* @param accessToken 调用接口凭证
* @param type 素材的类型,图片(image)、视频(video)、语音 (voice)、图文(news)
* @param offset 从全部素材的该偏移位置开始返回,0表示从第一个素材 返回
* @param count 返回素材的数量,取值在1到20之间
* @return
* @throws Exception JSONObject
*/
public static JSONObject listPermanentMaterial(String accessToken, String type, String offset,String count) throws Exception {
//1.准备好json请求参数
Map<String,String> paramMap=new HashMap<String,String>();
paramMap.put("type", type);
paramMap.put("offset", offset);
paramMap.put("count", count); Object data=JSON.toJSON(paramMap); //2.准备好请求url
String url=LIST_PERMANENT_MATERIAL_URL.replace("ACCESS_TOKEN", accessToken); //3.发起HTTP请求,获取返回结果
JSONObject jsonObject=HttpHelper.doPost(url, data);
logger.info("jsonObject:"+jsonObject.toJSONString()); //4.解析结果
JSONObject returnJsonObject=null;
if (jsonObject != null) { //4.1 错误消息处理
if (jsonObject.getInteger("errcode") != null) {
int errCode = jsonObject.getInteger("errcode");
String errMsg = jsonObject.getString("errmsg");
logger.error("获取永久素材列表失败 "+"errcode:"+errCode+", errmsg:"+errMsg); //4.2 新增成功
} else {
logger.info("获取永久素材列表成功 ");
returnJsonObject= jsonObject;
}
}
return returnJsonObject;
} /**
* @desc :6.获取永久素材
*
* @param accessToken 调用接口凭证
* @param mediaId 媒体文件ID
* @param fileDir 文件下载路径(文件所在文件夹路径),如 D:/img/download/,会与文件名拼接成文件下载路径
* @return
* @throws Exception File
*/
public static File getPermanentMaterial(String accessToken, String mediaId,String fileDir) throws Exception {
//1.准备好json请求参数
Map<String,String> paramMap=new HashMap<String,String>();
paramMap.put("media_id", mediaId); Object data=JSON.toJSON(paramMap); //2.准备好请求url
String url=GET_PERMANENT_MATERIAL_URL.replace("ACCESS_TOKEN", accessToken); //3.调用接口,发送HTTP请求,下载文件到本地
File file=HttpHelper.downloadMedia(url, data,fileDir);
logger.info("fileName:"+file.getName()); return file;
} /**
* @desc :7.删除永久素材
*
* @param accessToken 调用接口凭证
* @param mediaId 媒体文件ID
* @return
*
* @throws Exception JSONObject
*/
public static JSONObject deletePermanentMaterial(String accessToken, String mediaId) throws Exception {
//1.准备好json请求参数
Map<String,String> paramMap=new HashMap<String,String>();
paramMap.put("media_id", mediaId); Object data=JSON.toJSON(paramMap); //2.准备好请求url
String url=DELETE_PERMANENT_MATERIAL_URL.replace("ACCESS_TOKEN", accessToken); //3.发起HTTP请求,获取返回结果
JSONObject jsonObject=HttpHelper.doPost(url, data);
logger.info("jsonObject:"+jsonObject.toJSONString()); //4.解析结果
JSONObject returnJsonObject=null;
if (jsonObject != null) { //4.1 错误消息处理
if (jsonObject.getInteger("errcode") != 0) {
int errCode = jsonObject.getInteger("errcode");
String errMsg = jsonObject.getString("errmsg");
logger.error("删除永久素材失败 "+"errcode:"+errCode+", errmsg:"+errMsg); //4.2 新增成功
} else {
logger.info("删除永久素材成功 ");
returnJsonObject= jsonObject;
}
}
return returnJsonObject;
} }

4.素材管理测试类—TempMaterialServiceTest.java

package com.ray.weixin.gz.service.tempmaterial;

import org.junit.Test;

import com.ray.weixin.gz.config.Env;
import com.ray.weixin.gz.service.tempmaterial.TempMaterialService;
import com.ray.weixin.gz.util.AuthHelper; /**@desc : 素材管理
*
* @author: shirayner
* @date : 2017年11月1日 上午10:30:13
*/
public class TempMaterialServiceTest { /**
* @desc : 1.新增临时素材
*
* @throws Exception void
*/
@Test
public void testUploadTempMaterial() throws Exception {
String accessToken=AuthHelper.getAccessToken(Env.APP_ID, Env.APP_SECRET);
String type="image";
//String fileDir="D:/img/1.jpg"; //5BXY7DI-uz3N-m8HuZP3Lqzy-WrtegzUKW04OcLNlUjMBcyEyCdgorBsotQqpH0r String fileDir="D:/img/2.png"; //bdARqt5NClDYbP_og5NwBRwO4sCIIwF1ZeVQQKTvB1bkn2rL9Yq52Y6S656lTxf1 TempMaterialService.uploadTempMaterial(accessToken, type, fileDir); } /**
* @desc : 2.获取临时素材
*
* @throws Exception void
*/
@Test
public void testGetTempMaterial() throws Exception {
String accessToken=AuthHelper.getAccessToken(Env.APP_ID, Env.APP_SECRET);
// String mediaId="5BXY7DI-uz3N-m8HuZP3Lqzy-WrtegzUKW04OcLNlUjMBcyEyCdgorBsotQqpH0r"; // D:/img/1.jpg
String mediaId="4nPOsc2NL2e5MfRB3ePannbbuRrz0ZKi3udO4sP-6Nf7-SFJXM6D4sOyf1d_Khic"; // D:/img/2.png
String fileDir="D:/img/download/"; TempMaterialService.getTempMaterial(accessToken, mediaId, fileDir); } /**
* @desc : 3.新增永久素材——上传永久图片——上传图文消息内的图片获取URL
*
* @throws Exception void
*/
@Test
public void testUploadPermanentImg() throws Exception {
String accessToken=AuthHelper.getAccessToken(Env.APP_ID, Env.APP_SECRET); //String fileDir="D:/img/1.jpg";
String fileDir="D:/img/2.png"; TempMaterialService.uploadPermanentImg(accessToken, fileDir); } /**
* @desc : 4.新增永久素材——新增其他类型永久素材(image、voice、thumb)
*
* @throws Exception void
*/
@Test
public void testUploadPermanentMaterial() throws Exception {
String accessToken=AuthHelper.getAccessToken(Env.APP_ID, Env.APP_SECRET);
String type="image";
//String fileDir="D:/img/1.jpg";
String fileDir="D:/img/2.png"; TempMaterialService.uploadPermanentMaterial(accessToken, type, fileDir); } /**
* @desc : 5.获取永久素材列表
*
* @throws Exception void
*/
@Test
public void testListPermanentMaterial() throws Exception {
String accessToken=AuthHelper.getAccessToken(Env.APP_ID, Env.APP_SECRET);
String type="image";
String offset="0";
String count="2"; TempMaterialService.listPermanentMaterial(accessToken, type, offset, count); } /**
* @desc :6.获取永久素材
*
* @throws Exception void
*/
@Test
public void testGetPermanentMaterial() throws Exception {
String accessToken=AuthHelper.getAccessToken(Env.APP_ID, Env.APP_SECRET);
String mediaId="NFREZRuTaNgMSgnxT5agYkff8xLCKRjZPMXhS-lT6aE";
String fileDir="D:/img/download/"; TempMaterialService.getPermanentMaterial(accessToken, mediaId, fileDir); } /**
* @desc :7.删除永久素材
*
* @throws Exception void
*/
@Test
public void testDeletePermanentMaterial() throws Exception {
String accessToken=AuthHelper.getAccessToken(Env.APP_ID, Env.APP_SECRET);
String mediaId="NFREZRuTaNgMSgnxT5agYkff8xLCKRjZPMXhS-lT6aE"; TempMaterialService.deletePermanentMaterial(accessToken, mediaId); } }
05-06 15:41