JAVA 微信公衆號調用攝像頭並上傳圖片至服務器

一、主體思想

1.使用微信JS-SDK工具包。
點擊button,調用拍照接口【chooseImage】和上傳圖片接口【uploadImage】,拿到圖片的服務器端ID,即【mediaId】
2.調用【獲取臨時素材】接口(參數mediaId),拿到返回的流,保存到服務器。

官方文檔:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1455784140&token=&lang=zh_CN

二、實現步驟(爲了整體性,部分複製文檔)

1.綁定域名
先登錄微信公衆平臺進入“公衆號設置”的“功能設置”裏填寫“JS接口安全域名”。
例如:blog.csdn.net

2.在需要調用攝像頭頁面,引入JS文件

<!-- jquery 非必須 -->
<script src="<%=request.getContextPath()%>/staticfile/js/jquery.min.js"></script>
<script src="http://res.wx.qq.com/open/js/jweixin-1.2.0.js"></script>

3.通過config接口注入權限驗證配置

<input type="hidden" id="appId" value="${appId }"/>
<input type="hidden" id="timestamp" value="${timestamp }"/>
<input type="hidden" id="nonceStr" value="${nonceStr }"/>
<input type="hidden" id="signature" value="${signature }"/>
<script>
$(function(){
    wx.config({
        debug: false, // 開啓調試模式,調用的所有api的返回值會在客戶端alert出來,若要查看傳入的參數,可以在pc端打開,參數信息會通過log打出,僅在pc端時纔會打印。
        appId: $('#appId').val(), // 必填,公衆號的唯一標識
        timestamp: $('#timestamp').val(), // 必填,生成簽名的時間戳
        nonceStr: $('#nonceStr').val(), // 必填,生成簽名的隨機串
        signature: $('#signature').val(),// 必填,簽名,見附錄1
        jsApiList: ['chooseImage', 'uploadImage'] // 必填,需要使用的JS接口列表,所有JS接口列表見附錄2
    });
});
</script>

4.JS-SDK使用權限簽名算法,生成第三步中 config接口 所需參數
注意:java代碼使用jfinal3.1框架,使用到的緩存插件、參數獲取等語法不一致,自適應相應修改。

獲取access_token(官方:有效期7200秒,開發者必須在自己的服務全局緩存access_token)、jsapi_ticket、簽名sign

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
public class XXX{
    private static final Logger log = LoggerFactory.getLogger(XXX.class);
    private static final String JSAPI_TICKET_CACHE = "jsapiTicketCache";
    private static final String JSAPI_TICKET_CACHE_KEY = "jsapi_ticket";
    private static final String ACCESS_TOKEN_CACHE = "accessTokenCache";
    private static final String ACCESS_TOKEN_CACHE_KEY = "access_token";

    /**
    * 獲取config接口 所需參數 
    */
    public void index() {
        /**
        * 以下5行代碼,是拼接 訪問該方法的參數列表。
        *
        * 生成簽名sign時,參數url必須是完整的。
        * 例如: http://blog.csdn.net?a=1&b=2
        */
        //request.getParameterMap();
        Map paramMap = getParaMap();
        String paramUrl = "";
        if (!paramMap.isEmpty() && paramMap != null) {
            paramUrl = getParamsStr(paramMap);
        }
        log.info("paramUrl-->{}", paramUrl);

        /**
         * 1、獲取jsapi_ticket
         */
        String jsapi_ticket = CacheKit.get(JSAPI_TICKET_CACHE, JSAPI_TICKET_CACHE_KEY);
        if (StrKit.isBlank(jsapi_ticket)) {
            String access_token = getAccessToken();
            log.info("access_token-->{}", access_token);
            jsapi_ticket = getJsapiTicket(access_token);
            CacheKit.put(JSAPI_TICKET_CACHE, JSAPI_TICKET_CACHE_KEY, jsapi_ticket);
        }
        log.info("jsapi_ticket-->{}", jsapi_ticket);

        /**
         * 2、生成簽名
         */
        SortedMap<Object, Object> params = new TreeMap<Object, Object>();
        String noncestr = WeixinSignUtil.getNonceStr();
        String timestamp = WeixinSignUtil.getTimestamp();
        params.put("noncestr", noncestr);
        params.put("jsapi_ticket", jsapi_ticket);
        params.put("timestamp", timestamp);
        if (StrKit.isBlank(paramUrl)) {
            params.put("url", AppConsts.JSSDKURL);
        } else {
            params.put("url", AppConsts.JSSDKURL + "?" + paramUrl);
        }
        String sign = WeixinSignUtil.createSignBySha1(params);
        log.info("sign-->{}", sign);

        setAttr("appId", AppConsts.APPID);
        setAttr("timestamp", timestamp);
        setAttr("nonceStr", noncestr);
        setAttr("signature", sign);

        render("jsp/index.jsp");
    }

    private String getParamsStr(Map paramMap) {
        StringBuffer sb = new StringBuffer();
        Set set = paramMap.entrySet();
        Iterator it = set.iterator();
        while (it.hasNext()) {
            Map.Entry entry = (Map.Entry) it.next();
            String k = (String) entry.getKey();
            String[] v = (String[]) entry.getValue();
            for (String s : v) {
                sb.append(k + "=" + s + "&");
            }
        }
        return sb.toString().substring(0, sb.toString().length() - 1);
    }

    private String getAccessToken() {
        String access_token = CacheKit.get(ACCESS_TOKEN_CACHE, ACCESS_TOKEN_CACHE_KEY);
        if (StrKit.isBlank(access_token)) {

            String url = "https://api.weixin.qq.com/cgi-bin/token";
            String params = "grant_type=client_credential&appid=" + AppConsts.APPID + "&secret=" + AppConsts.APPSECRET;
            //http GET方式爬蟲
            String result = HttpURLContent.sendGet(url, params);
            JSONObject jo = JSON.parseObject(result);
            access_token = jo.getString("access_token");

            CacheKit.put(ACCESS_TOKEN_CACHE, ACCESS_TOKEN_CACHE_KEY, access_token);
        }
        return access_token;
    }

    private String getJsapiTicket(String access_token) {
        String url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket";
        String params = "access_token=" + access_token + "&type=jsapi";
        String result = HttpURLContent.sendGet(url, params);
        JSONObject jo = JSON.parseObject(result);
        return jo.getString("ticket");
    }
}

WeixinSignUtil.java

package org.cold.util;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;

/**
 * 微信簽名工具類
 * @author cold
 *
 */
public class WeixinSignUtil {

    @SuppressWarnings("rawtypes")
    public static String createSignBySha1(SortedMap<Object, Object> params) {
        StringBuffer sb = new StringBuffer();
        Set es = params.entrySet();
        Iterator it = es.iterator();
        while (it.hasNext()) {
            Map.Entry entry = (Map.Entry) it.next();
            String k = (String) entry.getKey();
            String v = (String) entry.getValue();
            if (v != null && !v.equals("")) {
                sb.append(k + "=" + v + "&");
            }
        } 
        String result = sb.toString().substring(0, sb.toString().length()-1);
        return Sha1.getSha1(result);
    }

    /**
     * 獲取時間戳(秒)
     */
    public static String getTimestamp() {
        return String.valueOf(System.currentTimeMillis() / 1000);
    }

    /** 
     * 取出一個指定長度大小的隨機正整數. 
     * @param length 
     *            int 設定所取出隨機數的長度。length小於11 
     * @return int 返回生成的隨機數。 
     */  
    public static int buildRandom(int length) {  
        int num = 1;  
        double random = Math.random();  
        if (random < 0.1) {  
            random = random + 0.1;  
        }  
        for (int i = 0; i < length; i++) {  
            num = num * 10;  
        }  
        return (int) ((random * num));  
    }  

    /** 
     * 獲取當前時間 yyyyMMddHHmmss 
     */  
    public static String getCurrTime() {  
        Date now = new Date();  
        SimpleDateFormat outFormat = new SimpleDateFormat("yyyyMMddHHmmss");  
        String s = outFormat.format(now);  
        return s;  
    }  

    /**
     * 生成隨機字符串
     */ 
    public static String getNonceStr() {
        String currTime = getCurrTime();  
        String strTime = currTime.substring(8, currTime.length());  
        String strRandom = buildRandom(4) + "";  
        return strTime + strRandom;
    }
}

5.調用攝像頭,獲取 mediaId

<button onclick="takePicture()">拍照</button>
<script>
function takePicture(){
    wx.chooseImage({
        count: 1, // 默認9
        sizeType: ['original', 'compressed'], // 可以指定是原圖還是壓縮圖,默認二者都有
        sourceType: ['album', 'camera'], // 可以指定來源是相冊還是相機,默認二者都有
        success: function (res) {
            var localIds = res.localIds; // 返回選定照片的本地ID列表,localId可以作爲img標籤的src屬性顯示圖片

            wx.uploadImage({
                localId: localIds.toString(), // 需要上傳的圖片的本地ID,由chooseImage接口獲得
                isShowProgressTips: 1, // 默認爲1,顯示進度提示
                success: function (res) {
                    var mediaId = res.serverId; // 返回圖片的服務器端ID,即mediaId
                    //將獲取到的 mediaId 傳入後臺 方法savePicture
                    $.post("<%=request.getContextPath()%>/savePicture",{mediaId:mediaId},function(res){
                        if(res.t == 'success'){

                        }else{
                            alert(res.msg)
                        }
                    })
                },
                fail: function (res) {
                    alertModal('上傳圖片失敗,請重試')
                }
            }); 
        }
    });
}
</script>

6.後臺接受參數mediaId,保存圖片至服務器

public void savePicture() {
        // request.getParameter("mediaId")
        String mediaId = getPara("mediaId", "");
        //保存圖片 路徑  PathKit.getWebRootPath() + "/vehicleupload/" + filename;
        String filename = saveImageToDisk(mediaId);


        setAttr("t", "success");
        renderJson();
}

/**
 * 獲取臨時素材
 */
private InputStream getMedia(String mediaId) {
    String url = "https://api.weixin.qq.com/cgi-bin/media/get";
    String access_token = getAccessToken();
    String params = "access_token=" + access_token + "&media_id=" + mediaId;
       InputStream is = null;
       try {
        String urlNameString = url + "?" + params;
           URL urlGet = new URL(urlNameString);
           HttpURLConnection http = (HttpURLConnection) urlGet.openConnection();
           http.setRequestMethod("GET"); // 必須是get方式請求
           http.setRequestProperty("Content-Type","application/x-www-form-urlencoded");
           http.setDoOutput(true);
           http.setDoInput(true);
           http.connect();
           // 獲取文件轉化爲byte流
           is = http.getInputStream();
       } catch (Exception e) {
           e.printStackTrace();
       }
    return is;
}

/**
 * 保存圖片至服務器 
 * @param mediaId
 * @return 文件名
 */
public String saveImageToDisk(String mediaId){
    String filename = "";
    InputStream inputStream = getMedia(mediaId);
    byte[] data = new byte[1024];
    int len = 0;
    FileOutputStream fileOutputStream = null;
    try {
        //服務器存圖路徑
        String path = PathKit.getWebRootPath() + "/vehicleupload/";
        filename = System.currentTimeMillis() + WeixinSignUtil.getNonceStr() + ".jpg";
        fileOutputStream = new FileOutputStream(path + filename);
        while ((len = inputStream.read(data)) != -1) {
            fileOutputStream.write(data, 0, len);
        }
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        if (inputStream != null) {
            try {
                inputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if (fileOutputStream != null) {
            try {
                fileOutputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    return filename;
}
發佈了44 篇原創文章 · 獲贊 66 · 訪問量 21萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章