一、本節要點
1.官方文檔的media
這個media可以理解為文件,即我們需要以POST方式提交一個文件

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();//2000 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 + "×tamp=" + 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); } }
