一定说明,这种方法我还没有测试,如果有疑问欢迎在评论区域讨论.
....................
...................
谢谢.
微信官方提供的生成二维码接口得到的是当前公众号的二维码。
1、临时二维码,是有过期时间的,最长可以设置为在二维码生成后的30天(即2592000秒)后过期,但能够生成较多数量,主要用于帐号绑定等不要求二维码永久保存的业务场景
2、永久二维码,是无过期时间的,但数量较少(目前为最多10万个),主要用于适用于帐号绑定、用户来源统计等场景
参考文档详见https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1443433542&token=&lang=zh_CN
获取带参数的二维码的过程包括两步,首先创建二维码ticket,然后凭借ticket到指定URL换取二维码,但是得到ticket之前首先获取到access_token。
1.创建access_token的bean
可以不写,因为我是每小时定时获取一次token存储到数据库或者直接存到application
- public class AccessToken {
- // 获取到的凭证
- private String token;
- // 凭证有效时间,单位:秒
- private int expiresIn;
- public String getToken() {
- return token;
- }
- public void setToken(String token) {
- this.token = token;
- }
- public int getExpiresIn() {
- return expiresIn;
- }
- public void setExpiresIn(int expiresIn) {
- this.expiresIn = expiresIn;
- }
- }
2.创建获取accessToken的方法
调用接口时,请登录“微信公众平台-开发-基本配置”提前将服务器IP地址添加到IP白名单中,否则将无法调用成功
- /**
- * 获取access_token
- * @param appid 凭证
- * @param appsecret 密钥
- * @return
- */
- public static String getAccessToken(String appid, String appsecret) {
- String result = HttpRequestUtil.getAccessToken(appid,appsecret);
- JSONObject jsonObject = JSONObject.fromObject(result);
- if (null != jsonObject) {
- try {
- result = jsonObject.getString("access_token");
- } catch (JSONException e) {
- logger.info("获取token失败 errcode:"+jsonObject.getInt("errcode") +",errmsg:"+ jsonObject.getString("errmsg"));
- }
- }
- return result;
- }
3.获取二维码的Ticket
- // 临时二维码
- private final static String QR_SCENE = "QR_SCENE";
- // 永久二维码
- private final static String QR_LIMIT_SCENE = "QR_LIMIT_SCENE";
- // 永久二维码(字符串)
- private final static String QR_LIMIT_STR_SCENE = "QR_LIMIT_STR_SCENE";
- // 创建二维码
- private String create_ticket_path = "https://api.weixin.qq.com/cgi-bin/qrcode/create";
- // 通过ticket换取二维码
- private String showqrcode_path = "https://mp.weixin.qq.com/cgi-bin/showqrcode";
- /**
- * 创建临时带参数二维码
- * @param accessToken
- * @expireSeconds 该二维码有效时间,以秒为单位。 最大不超过2592000(即30天),此字段如果不填,则默认有效期为30秒。
- * @param sceneId 场景Id
- * @return
- */
- public String createTempTicket(String accessToken, String expireSeconds, int sceneId) {
- WeiXinQRCode wxQRCode = null;
- TreeMap<String,String> params = new TreeMap<String,String>();
- params.put("access_token", accessToken);
- Map<String,Integer> intMap = new HashMap<String,Integer>();
- intMap.put("scene_id",sceneId);
- Map<String,Map<String,Integer>> mapMap = new HashMap<String,Map<String,Integer>>();
- mapMap.put("scene", intMap);
- //
- Map<String,Object> paramsMap = new HashMap<String,Object>();
- paramsMap.put("expire_seconds", expireSeconds);
- paramsMap.put("action_name", QR_SCENE);
- paramsMap.put("action_info", mapMap);
- String data = new Gson().toJson(paramsMap);
- data = HttpRequestUtil.HttpsDefaultExecute(HttpRequestUtil.POST_METHOD,create_ticket_path,params,data);
- try {
- wxQRCode = new Gson().fromJson(data, WeiXinQRCode.class);
- } catch (JsonSyntaxException e) {
- wxQRCode = null;
- e.printStackTrace();
- }
- return wxQRCode==null?null:wxQRCode.getTicket();
- }
- /**
- * 创建永久二维码(数字)
- * @param accessToken
- * @param sceneId 场景Id
- * @return
- */
- public String createForeverTicket(String accessToken, int sceneId) {
- TreeMap<String,String> params = new TreeMap<String,String>();
- params.put("access_token", accessToken);
- //output data
- Map<String,Integer> intMap = new HashMap<String,Integer>();
- intMap.put("scene_id",sceneId);
- Map<String,Map<String,Integer>> mapMap = new HashMap<String,Map<String,Integer>>();
- mapMap.put("scene", intMap);
- //
- Map<String,Object> paramsMap = new HashMap<String,Object>();
- paramsMap.put("action_name", QR_LIMIT_SCENE);
- paramsMap.put("action_info", mapMap);
- String data = new Gson().toJson(paramsMap);
- data = HttpRequestUtil.HttpsDefaultExecute(HttpRequestUtil.POST_METHOD,create_ticket_path,params,data);
- WeiXinQRCode wxQRCode = null;
- try {
- wxQRCode = new Gson().fromJson(data, WeiXinQRCode.class);
- } catch (JsonSyntaxException e) {
- wxQRCode = null;
- e.printStackTrace();
- }
- return wxQRCode==null?null:wxQRCode.getTicket();
- }
- /**
- * 创建永久二维码(字符串)
- *
- * @param accessToken
- * @param sceneStr 场景str
- * @return
- */
- public String createForeverStrTicket(String accessToken, String sceneStr){
- TreeMap<String,String> params = new TreeMap<String,String>();
- params.put("access_token", accessToken);
- //output data
- Map<String,String> intMap = new HashMap<String,String>();
- intMap.put("scene_str",sceneStr);
- Map<String,Map<String,String>> mapMap = new HashMap<String,Map<String,String>>();
- mapMap.put("scene", intMap);
- Map<String,Object> paramsMap = new HashMap<String,Object>();
- paramsMap.put("action_name", QR_LIMIT_STR_SCENE);
- paramsMap.put("action_info", mapMap);
- String data = new Gson().toJson(paramsMap);
- data = HttpRequestUtil.HttpsDefaultExecute(HttpRequestUtil.POST_METHOD,create_ticket_path,params,data);
- WeiXinQRCode wxQRCode = null;
- try {
- wxQRCode = new Gson().fromJson(data, WeiXinQRCode.class);
- } catch (JsonSyntaxException e) {
- wxQRCode = null;
- }
- return wxQRCode==null?null:wxQRCode.getTicket();
- }
强烈建议用测试号生成永久的
4.通过ticket凭证直接获取二维码
- /**
- * 获取二维码ticket后,通过ticket换取二维码图片展示
- * @param ticket
- * @return
- */
- public String showQrcode(String ticket){
- Map<String,String> params = new TreeMap<String,String>();
- params.put("ticket", HttpRequestUtil.urlEncode(ticket, HttpRequestUtil.DEFAULT_CHARSET));
- try {
- showqrcode_path = HttpRequestUtil.setParmas(params,showqrcode_path,"");
- } catch (Exception e) {
- e.printStackTrace();
- }
- return showqrcode_path;
- }
- /**
- * 获取二维码ticket后,通过ticket换取二维码图片
- * @param ticket
- * @param savePath 保存的路径,例如 F:\\test\test.jpg
- * @return Result.success = true 表示下载图片下载成功
- */
- public WeiXinResult showQrcode(String ticket,String savePath) throws Exception{
- TreeMap<String,String> params = new TreeMap<String,String>();
- params.put("ticket", HttpRequestUtil.urlEncode(ticket, HttpRequestUtil.DEFAULT_CHARSET));
- WeiXinResult result = HttpRequestUtil.downMeaterMetod(params,HttpRequestUtil.GET_METHOD,showqrcode_path,savePath);
- return result;
- }
5.用户扫描带参数的二维码的处理
如果没有关注的话,用户可以关注公众号,并且会这个场景值就是所谓的参数推送给开发者,参数是EventKey,直接用request获取即可,注意qrscene_的之后才是二维码的参数值
如果已经关注,微信会直接把场景值的扫描事件直接推送给开发者
6.参考类
WeiXinResult.Java
- /**
- * 返回的结果对象
- * @author fjing
- *
- */
- public class WeiXinResult {
- public static final int NEWSMSG = 1; //图文消息
- private boolean isSuccess;
- private Object obj;
- private int type;
- private String msg;
- public String getMsg() {
- return msg;
- }
- public void setMsg(String msg) {
- this.msg = msg;
- }
- public int getType() {
- return type;
- }
- public void setType(int type) {
- this.type = type;
- }
- public boolean isSuccess() {
- return isSuccess;
- }
- public void setSuccess(boolean isSuccess) {
- this.isSuccess = isSuccess;
- }
- public Object getObj() {
- return obj;
- }
- public void setObj(Object obj) {
- this.obj = obj;
- }
- }
HttpRequestUtil.java
- import java.io.File;
- import java.io.FileNotFoundException;
- import java.io.FileOutputStream;
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.OutputStream;
- import java.io.UnsupportedEncodingException;
- import java.net.HttpURLConnection;
- import java.net.MalformedURLException;
- import java.net.URL;
- import java.net.URLEncoder;
- import java.util.Map;
- import java.util.Map.Entry;
- import java.util.Set;
- import java.util.TreeMap;
- import javax.net.ssl.HostnameVerifier;
- import javax.net.ssl.HttpsURLConnection;
- import javax.net.ssl.KeyManager;
- import javax.net.ssl.SSLContext;
- import javax.net.ssl.SSLSession;
- import javax.net.ssl.TrustManager;
- import com.dingshu.model.result.WeiXinResult;
- public class HttpRequestUtil {
- //private static Logger logger = Logger.getLogger(HttpRequestUtil.class);
- public static final String GET_METHOD = "GET";
- public static final String POST_METHOD = "POST";
- public static final String DEFAULT_CHARSET = "utf-8";
- private static int DEFAULT_CONNTIME = 5000;
- private static int DEFAULT_READTIME = 5000;
- // 获取access_token的路径
- private static String token_path = "https://api.weixin.qq.com/cgi-bin/token";
- /**
- * http请求
- *
- * @param method
- * 请求方法GET/POST
- * @param path
- * 请求路径
- * @param timeout
- * 连接超时时间 默认为5000
- * @param readTimeout
- * 读取超时时间 默认为5000
- * @param data 数据
- * @return
- */
- public static String defaultConnection(String method, String path, int timeout, int readTimeout, String data)
- throws Exception {
- String result = "";
- URL url = new URL(path);
- if (url != null) {
- HttpURLConnection conn = getConnection(method, url);
- conn.setConnectTimeout(timeout == 0 ? DEFAULT_CONNTIME : timeout);
- conn.setReadTimeout(readTimeout == 0 ? DEFAULT_READTIME : readTimeout);
- if (data != null && !"".equals(data)) {
- OutputStream output = conn.getOutputStream();
- output.write(data.getBytes(DEFAULT_CHARSET));
- output.flush();
- output.close();
- }
- if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {
- InputStream input = conn.getInputStream();
- result = inputToStr(input);
- input.close();
- conn.disconnect();
- }
- }
- return result;
- }
- /**
- * 根据url的协议选择对应的请求方式 例如 http://www.baidu.com 则使用http请求,https://www.baidu.com
- * 则使用https请求
- *
- * @param method
- * 请求的方法
- * @return
- * @throws IOException
- */
- private static HttpURLConnection getConnection(String method, URL url) throws IOException {
- HttpURLConnection conn = null;
- if ("https".equals(url.getProtocol())) {
- SSLContext context = null;
- try {
- context = SSLContext.getInstance("SSL", "SunJSSE");
- context.init(new KeyManager[0], new TrustManager[] { new MyX509TrustManager() },
- new java.security.SecureRandom());
- } catch (Exception e) {
- throw new IOException(e);
- }
- HttpsURLConnection connHttps = (HttpsURLConnection) url.openConnection();
- connHttps.setSSLSocketFactory(context.getSocketFactory());
- connHttps.setHostnameVerifier(new HostnameVerifier() {
- @Override
- public boolean verify(String arg0, SSLSession arg1) {
- return true;
- }
- });
- conn = connHttps;
- } else {
- conn = (HttpURLConnection) url.openConnection();
- }
- conn.setRequestMethod(method);
- conn.setUseCaches(false);
- conn.setDoInput(true);
- conn.setDoOutput(true);
- return conn;
- }
- /**
- * 将输入流转换为字符串
- *
- * @param input
- * 输入流
- * @return 转换后的字符串
- */
- public static String inputToStr(InputStream input) {
- String result = "";
- if (input != null) {
- byte[] array = new byte[1024];
- StringBuffer buffer = new StringBuffer();
- try {
- for (int index; (index = (input.read(array))) > -1;) {
- buffer.append(new String(array, 0, index, DEFAULT_CHARSET));
- }
- result = buffer.toString();
- } catch (IOException e) {
- e.printStackTrace();
- result = "";
- }
- }
- return result;
- }
- /**
- * 设置参数
- *
- * @param map
- * 参数map
- * @param path
- * 需要赋值的path
- * @param charset
- * 编码格式 默认编码为utf-8(取消默认)
- * @return 已经赋值好的url 只需要访问即可
- */
- public static String setParmas(Map<String, String> map, String path, String charset) throws Exception {
- String result = "";
- boolean hasParams = false;
- if (path != null && !"".equals(path)) {
- if (map != null && map.size() > 0) {
- StringBuilder builder = new StringBuilder();
- Set<Entry<String, String>> params = map.entrySet();
- for (Entry<String, String> entry : params) {
- String key = entry.getKey().trim();
- String value = entry.getValue().trim();
- if (hasParams) {
- builder.append("&");
- } else {
- hasParams = true;
- }
- if(charset != null && !"".equals(charset)){
- //builder.append(key).append("=").append(URLDecoder.(value, charset));
- builder.append(key).append("=").append(urlEncode(value, charset));
- }else{
- builder.append(key).append("=").append(value);
- }
- }
- result = builder.toString();
- }
- }
- return doUrlPath(path, result).toString();
- }
- /**
- * 设置连接参数
- *
- * @param path
- * 路径
- * @return
- */
- private static URL doUrlPath(String path, String query) throws Exception {
- URL url = new URL(path);
- if (org.apache.commons.lang.StringUtils.isEmpty(path)) {
- return url;
- }
- if (org.apache.commons.lang.StringUtils.isEmpty(url.getQuery())) {
- if (path.endsWith("?")) {
- path += query;
- } else {
- path = path + "?" + query;
- }
- } else {
- if (path.endsWith("&")) {
- path += query;
- } else {
- path = path + "&" + query;
- }
- }
- return new URL(path);
- }
- /**
- * 默认的http请求执行方法,返回
- *
- * @param method
- * 请求的方法 POST/GET
- * @param path
- * 请求path 路径
- * @param map
- * 请求参数集合
- * @param data
- * 输入的数据 允许为空
- * @return
- */
- public static String HttpDefaultExecute(String method, String path, Map<String, String> map, String data) {
- String result = "";
- try {
- String url = setParmas((TreeMap<String, String>) map, path, "");
- result = defaultConnection(method, url, DEFAULT_CONNTIME, DEFAULT_READTIME, data);
- } catch (Exception e) {
- e.printStackTrace();
- }
- return result;
- }
- /**
- * 默认的https执行方法,返回
- *
- * @param method
- * 请求的方法 POST/GET
- * @param path
- * 请求path 路径
- * @param map
- * 请求参数集合
- * @param data
- * 输入的数据 允许为空
- * @return
- */
- public static String HttpsDefaultExecute(String method, String path, Map<String, String> map, String data) {
- String result = "";
- try {
- String url = setParmas((TreeMap<String, String>) map, path, "");
- result = defaultConnection(method, url, DEFAULT_CONNTIME, DEFAULT_READTIME, data);
- } catch (Exception e) {
- e.printStackTrace();
- }
- return result;
- }
- /**
- * 获取授权token
- *
- * @param key 应用key
- * @param secret 应用密匙
- * @return json格式的字符串
- */
- public static String getAccessToken(String key, String secret) {
- TreeMap<String, String> map = new TreeMap<String, String>();
- map.put("grant_type", "client_credential");
- map.put("appid", key);
- map.put("secret", secret);
- String result = HttpDefaultExecute(GET_METHOD, token_path, map, "");
- return result;
- }
- /**
- * 默认的下载素材方法
- *
- * @param method http方法 POST/GET
- * @param apiPath api路径
- * @param savePath 素材需要保存的路径
- * @return 是否下载成功 Reuslt.success==true 表示下载成功
- */
- public static WeiXinResult downMeaterMetod(TreeMap<String, String> params, String method, String apiPath, String savePath) {
- WeiXinResult result = new WeiXinResult();
- try {
- apiPath = setParmas(params, apiPath, "");
- URL url = new URL(apiPath);
- HttpURLConnection conn = getConnection(method, url);
- if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {
- String contentType = conn.getContentType();
- result = ContentType(contentType, conn, savePath);
- } else {
- result.setObj(conn.getResponseCode() + " " + conn.getResponseMessage());
- }
- } catch (MalformedURLException e) {
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- } catch (Exception e) {
- e.printStackTrace();
- }
- return result;
- }
- /**
- * 根据返回的头信息返回具体信息
- *
- * @param contentType
- * ContentType请求头信息
- * @return Result.type==1 表示文本消息,
- */
- private static WeiXinResult ContentType(String contentType, HttpURLConnection conn, String savePath) {
- WeiXinResult result = new WeiXinResult();
- try {
- if (conn != null) {
- InputStream input = conn.getInputStream();
- if (contentType.equals("image/gif")) { // gif图片
- result = InputStreamToMedia(input, savePath, "gif");
- } else if (contentType.equals("image/jpeg")) { // jpg图片
- result = InputStreamToMedia(input, savePath, "jpg");
- } else if (contentType.equals("image/jpg")) { // jpg图片
- result = InputStreamToMedia(input, savePath, "jpg");
- } else if (contentType.equals("image/png")) { // png图片
- result = InputStreamToMedia(input, savePath, "png");
- } else if (contentType.equals("image/bmp")) { // bmp图片
- result = InputStreamToMedia(input, savePath, "bmp");
- } else if (contentType.equals("audio/x-wav")) { // wav语音
- result = InputStreamToMedia(input, savePath, "wav");
- } else if (contentType.equals("audio/x-ms-wma")) { // wma语言
- result = InputStreamToMedia(input, savePath, "wma");
- } else if (contentType.equals("audio/mpeg")) { // mp3语言
- result = InputStreamToMedia(input, savePath, "mp3");
- } else if (contentType.equals("text/plain")) { // 文本信息
- String str = inputToStr(input);
- result.setObj(str);
- } else if (contentType.equals("application/json")) { // 返回json格式的数据
- String str = inputToStr(input);
- result.setObj(str);
- } else { // 此处有问题
- String str = inputToStr(input);
- result.setObj(str);
- }
- } else {
- result.setObj("conn is null!");
- }
- } catch (Exception ex) {
- ex.printStackTrace();
- }
- return result;
- }
- /**
- * 将字符流转换为图片文件
- *
- * @param input 字符流
- * @param savePath 图片需要保存的路径
- * @param 类型 jpg/png等
- * @return
- */
- private static WeiXinResult InputStreamToMedia(InputStream input, String savePath, String type) {
- WeiXinResult result = new WeiXinResult();
- try {
- File file = null;
- file = new File(savePath);
- String paramPath = file.getParent(); // 路径
- String fileName = file.getName(); //
- String newName = fileName.substring(0, fileName.lastIndexOf(".")) + "." + type;// 根据实际返回的文件类型后缀
- savePath = paramPath + "\\" + newName;
- if (!file.exists()) {
- File dirFile = new File(paramPath);
- dirFile.mkdirs();
- }
- file = new File(savePath);
- FileOutputStream output = new FileOutputStream(file);
- int len = 0;
- byte[] array = new byte[1024];
- while ((len = input.read(array)) != -1) {
- output.write(array, 0, len);
- }
- output.flush();
- output.close();
- result.setSuccess(true);
- result.setObj("save success!");
- } catch (FileNotFoundException e) {
- e.printStackTrace();
- result.setSuccess(false);
- result.setObj(e.getMessage());
- } catch (IOException e) {
- e.printStackTrace();
- result.setSuccess(false);
- result.setObj(e.getMessage());
- }
- return result;
- }
- public static String urlEncode(String source, String encode) {
- String result = source;
- try {
- result = URLEncoder.encode(source, encode);
- } catch (UnsupportedEncodingException e) {
- e.printStackTrace();
- }
- return result;
- }
- }
- /**
- * 信任管理器
- * @author fjing
- *
- */
- public class MyX509TrustManager implements X509TrustManager {
- @Override
- public void checkClientTrusted(X509Certificate[] arg0, String arg1)
- throws CertificateException {
- }
- @Override
- public void checkServerTrusted(X509Certificate[] arg0, String arg1)
- throws CertificateException {
- }
- @Override
- public X509Certificate[] getAcceptedIssuers() {
- return null;
- }
- }