java实现微信扫一扫详解
一、微信JS-SDK参数配置及查找
JS安全域名配置(查找:微信公众号里-公众号设置-功能设置页)
注:1、安全域名外网必须可以访问的到
2、域名不能有下划线
3、要将(MP_verify_ZTbWVRm4MwKyq8mw.txt)次文件放到项目根目录下,也就是上面的域名+次文件名称外网可以访问的到。
AppID、AppSecret及IP白名单设置。(微信公众号里-开发者中心-基本设置)
注:1、AppSecret获取到一定一定一定要找个地方记下来,不然下一次还要重新获取这样会影响其他已开发项目的使用。
2、IP名单需要配置部署服务器IP。
二、前端代码
首先要引入微信提供的js库
<script src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js"></script>
通过config接口进行权限认证-error接口进行处理失败认证-wx.scanQRCode({})扫一扫接口调用;
注:1、config接口参数,这里是通过ajax方式从后台获取,后面代码会粘出来。
2、debug在调试阶段值设置为true。
<script type="text/javascript"> var timestamp = ""; var nonceStr = ""; var signature = ""; $.ajax({ url:"${pageContext.request.contextPath}/web/wxConfig/getWxConfig", data:{}, type:"POST", dataType:"json", async:false, cache:false, success:function(data){ timestamp = data.wxConfig.timestamp; nonceStr = data.wxConfig.nonceStr; signature = data.wxConfig.signature; } }); wx.config({ debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。 appId: "xxxxxxxxxx", // 必填,公众号的唯一标识 timestamp: timestamp, // 必填,生成签名的时间戳 ${wxConfig.timestamp} nonceStr: nonceStr, // 必填,生成签名的随机串 ${wxConfig.nonceStr} signature: signature,// 必填,签名,见附录1 ${wxConfig.signature} jsApiList: ['scanQRCode'] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2 }); wx.error(function(res) { alert("出错了:" + res.errMsg); }); $("#train_signStatus").click(function() { wx.scanQRCode({ needResult : 1, desc : 'scanQRCode desc', success : function(res) { var url = res.resultStr; var memberId = $.cookie('userId'); var trainingId=url.substr(url.indexOf("trainingId=")+11,32); var type = url.substr(url.indexOf("type=")+5,1); $.ajax({ type: "POST", url: "${pageContext.request.contextPath}/web/webTraining/signInByQRCode", data : { trainingId:trainingId, memberId:memberId, type:type }, dataType : "json", success : function(res) { var status = res.status; if(status=='3'){ alert('已签到'); }else if(status=='5'){ alert('上课签到班主任未开启'); }else if(status=='999'){ alert('签到成功'); } window.location.reload(); } }); } }); }); </script>
三、java后台代码。
下面代码注意事项:
1:url必须和请求jsp的url相同(查看可通过在jsp页面alert输出window.locatiion.href)-----否侧会验证失败
import java.util.Map; import javax.servlet.http.HttpServletRequest; import org.springframework.stereotype.Controller; import org.springframework.ui.ModelMap; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseBody; import com.sms.util.Sign; import com.sms.util.WxUtils; @Controller @RequestMapping("web/wxConfig") public class WebWxConfig { @RequestMapping(value="/getWxConfig",method=RequestMethod.POST) @ResponseBody public ModelMap getWxConfig(HttpServletRequest request,ModelMap map){ //http://localhost/WX/browser/member/membertrain.jsp String url = "http://"+WxUtils.APP_DOMAIN+ request.getContextPath()+"/browser/member/membertrain.jsp"; String ticket = WxUtils.getTicket(); Map<String, String> sign = Sign.sign(ticket, url); for (Map.Entry entry : sign.entrySet()) { System.out.println(entry.getKey() + "," + entry.getValue()); } map.put("wxConfig", sign); return map; } }
下面代码注意事项:
1、AppID和appSecret通过(一)获取
2、getTicket获取票据的方法,票据是微信签名时必须用到的(重点-重点-重点),基本微信所有的接口都是需要票据的。
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.MalformedURLException; import java.net.URL; import java.net.URLConnection; import net.sf.json.JSONObject; public class WxUtils { private static String APP_ID = "XXXXXX"; private static String AppSecret = "XXXXXXXXXXXX"; public static String APP_DOMAIN ="www.oacloudapp.cn"; public static String getTicket(){ String urlToken="https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="+APP_ID+"&secret="+AppSecret+""; String backToken = sendGet(urlToken,"utf-8",60000); System.out.println("token:"+backToken); String accessToken = (String) JSONObject.fromObject(backToken).get("access_token"); String url="https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token="+accessToken+"&type=jsapi"; String backTicket = sendGet(url,"utf-8",60000); System.out.println("Ticket:"+backTicket); String ticket = (String) JSONObject.fromObject(backTicket).get("ticket"); return ticket; } /** * * @title getAccessToken * @Description 获取访问令牌 * @author sss * @Date 2018-5-18上午11:07:18 * @return */ public static String getAccessToken(){ String url="https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="+APP_ID+"&secret="+AppSecret+""; String backData = sendGet(url,"utf-8",10000); String accessToken = (String) JSONObject.fromObject(backData).get("access_token"); return accessToken; } /** * * @title sendGet * @Description * @author sss * @Date 2018-5-18上午11:15:33 * @param url * @param charset * @param timeout * @return */ public static String sendGet(String url, String charset, int timeout) { String result = ""; try { URL u = new URL(url); try { URLConnection conn = u.openConnection(); conn.connect(); conn.setConnectTimeout(timeout); BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream(), charset)); String line=""; while ((line = in.readLine()) != null) { result = result + line; } in.close(); } catch (IOException e) { return result; } } catch (MalformedURLException e) { return result; } return result; } }
以下代码是微信提供的Demo 生成签名时使用。
import java.util.UUID; import java.util.Map; import java.util.HashMap; import java.util.Formatter; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.io.UnsupportedEncodingException; public class Sign { /*public static void main(String[] args) { String ticket = WxUtils.getTicket(); // 注意 URL 一定要动态获取,不能 hardcode String url = "http://"+WxUtils.APP_DOMAIN+"/RAFFLE/gotoLetter"; Map<String, String> ret = sign(ticket, url); for (Map.Entry entry : ret.entrySet()) { System.out.println(entry.getKey() + ", " + entry.getValue()); } };*/ public static Map<String, String> sign(String jsapi_ticket, String url) { Map<String, String> ret = new HashMap<String, String>();
String nonce_str = create_nonce_str();//产生随机串--由程序自己随机产生
String timestamp = create_timestamp();//由程序自己获取当前时间
String string1; String signature = ""; //注意这里参数名必须全部小写,且必须有序 string1 = "jsapi_ticket=" + jsapi_ticket + "&noncestr=" + nonce_str + "×tamp=" + timestamp + "&url=" + url; System.out.println(string1); try { MessageDigest crypt = MessageDigest.getInstance("SHA-1"); crypt.reset(); crypt.update(string1.getBytes("UTF-8")); signature = byteToHex(crypt.digest()); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } ret.put("url", url); ret.put("jsapi_ticket", jsapi_ticket); ret.put("nonceStr", nonce_str); ret.put("timestamp", timestamp); ret.put("signature", signature); return ret; } private static String byteToHex(final byte[] hash) { Formatter formatter = new Formatter(); for (byte b : hash) { formatter.format("%02x", b); } String result = formatter.toString(); formatter.close(); return result; } private static String create_nonce_str() { return UUID.randomUUID().toString().replace("-", ""); } private static String create_timestamp() { return Long.toString(System.currentTimeMillis() / 1000); } }