热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

详解微信开发模式之自定义菜单实现代码

最近有做了关于微信公众号和自己网站用户进行用户关联授权登录的一个功能,主要是用户关注该公众号,点击会员中心,则会弹出需要关联授权的网页授权:OAuth2.0网页授权,然后用户同意获取用户信息,进行用户和网站的关联,然后用户则可以使用微信进行登录。       本次做的是一个在Java的Action层处理各个返回参数获取数据。       一、使用到的工具:           1
最近有做了关于微信公众号和自己网站用户进行用户关联授权登录的一个功能,主要是用户关注该公众号,点击会员中心,则会弹出需要关联授权的网页授权:OAuth2.0网页授权,然后用户同意获取用户信息,进行用户和网站的关联,然后用户则可以使用微信进行登录。

本次做的是一个在Java的http://www.php.cn/java/java-Action.html" target="_blank">Action层处理各个返回参数获取数据。

一、 使用到的工具:

1、ngrok,将你自己的本机映射到公网,这样保证可以随时测试开发;

1、下载ngrok,网址:http://www.tunnel.mobi/

2、将文件放到Tomcat目录下,在cmd中运行ngrok -config ngrok.cfg -subdomain xinzhi 8080

3、ngrok工具为在慕课网@LAOBI 看到的

2、微信公众号测试账号,随时测试,首先保证在测试账号下没有问题后在进行公众号的移植。

二、使用到在Java中发送一个Http请求,然后返回JSON参数,获得JSON参数,然后进行处理。

首先,获取将公众号测试号放到properties文件中,以便我们进行调用或者更换,如:url请用https

Properties代码

AppID = wxf00**c3dd2ebfa0  
AppSecret = 3cb220755f****506dc35391aa5c03ec  
url = https://xinzhi.tunnel.mobi

这里url为我们映射到外网的地址,一会需要用到。然后需要两个工具类,该工具类作用是在Java的Action中发送http请求后获取到去返回值

启用自己有相应的改动,以适应本项目的需求:

WeixinUtil.java 和 MyX509TrustManager.java

Java代码

package com.zhtx.common.util;  
import java.io.BufferedReader;  
import java.io.InputStream;  
import java.io.InputStreamReader;  
import java.io.OutputStream;  
import java.net.ConnectException;  
import java.net.URL;  
import javax.net.ssl.HttpsURLConnection;  
import javax.net.ssl.SSLContext;  
import javax.net.ssl.SSLSocketFactory;  
import javax.net.ssl.TrustManager;  
import org.slf4j.Logger;  
import org.slf4j.LoggerFactory;  
/**
 * 公众平台通用接口工具类
 * 
 * @author xinz
 * @date 2015-10-14
 */
public class WeixinUtil {  
    private static Logger log = LoggerFactory.getLogger(WeixinUtil.class);  
    /**
     * 发起https请求并获取结果
     * 
     * @param requestUrl 请求地址
     * @param requestMethod 请求方式(GET、POST)
     * @param outputStr 提交的数据
     * @return JSONObject(通过JSONObject.get(key)的方式获取json对象的属性值)
     */
    public static String httpRequest(String requestUrl, String requestMethod, String outputStr) {  
        StringBuffer buffer = new StringBuffer();  
        try {  
            // 创建SSLContext对象,并使用我们指定的信任管理器初始化
            TrustManager[] tm = { new MyX509TrustManager() };  
            SSLContext sslCOntext= SSLContext.getInstance("SSL", "SunJSSE");  
            sslContext.init(null, tm, new java.security.SecureRandom());  
            // 从上述SSLContext对象中得到SSLSocketFactory对象
            SSLSocketFactory ssf = sslContext.getSocketFactory();  
            URL url = new URL(requestUrl);  
            HttpsURLConnection httpUrlCOnn= (HttpsURLConnection) url.openConnection();  
            httpUrlConn.setSSLSocketFactory(ssf);  
            httpUrlConn.setDoOutput(true);  
            httpUrlConn.setDoInput(true);  
            httpUrlConn.setUseCaches(false);  
            // 设置请求方式(GET/POST)
            httpUrlConn.setRequestMethod(requestMethod);  
            if ("GET".equalsIgnoreCase(requestMethod))  
                httpUrlConn.connect();  
            // 当有数据需要提交时
            if (null != outputStr) {  
                OutputStream outputStream = httpUrlConn.getOutputStream();  
                // 注意编码格式,防止中文乱码
                outputStream.write(outputStr.getBytes("UTF-8"));  
                outputStream.close();  
            }  
            // 将返回的输入流转换成字符串
            InputStream inputStream = httpUrlConn.getInputStream();  
            InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");  
            BufferedReader bufferedReader = new BufferedReader(inputStreamReader);  
            String str = null;  
            while ((str = bufferedReader.readLine()) != null) {  
                buffer.append(str);  
            }  
            bufferedReader.close();  
            inputStreamReader.close();  
            // 释放资源
            inputStream.close();  
            inputStream = null;  
            httpUrlConn.disconnect();  
        } catch (ConnectException ce) {  
            log.error("Weixin server connection timed out.");  
        } catch (Exception e) {  
            log.error("https request error:{}", e);  
        }  
        return buffer.toString();  
    }  
}

对于https请求,我们需要一个证书信任管理器,这个管理器类需要自己定义,但需要实现X509TrustManager接口,代码如下:

Java代码

package com.zhtx.common.util;  
import java.security.cert.CertificateException;  
import java.security.cert.X509Certificate;  
import javax.net.ssl.X509TrustManager;  
/**
 * 证书信任管理器(用于https请求)
 * 
 * @author xinz
 * @date 2015-10-14
 */
public class MyX509TrustManager implements X509TrustManager {  
    public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {  
    }  
    public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {  
    }  
    public X509Certificate[] getAcceptedIssuers() {  
        return null;  
    }  
}

微信返回参数的一个POJO类:

Java代码

private String  openid;  //用户的唯一标识 
private String  nickname;//用户昵称 
private Integer sex;// 用户的性别,值为1时是男性,值为2时是女性,值为0时是未知 
private String  province;//用户个人资料填写的省份 
private String  city;//普通用户个人资料填写的城市 
private String  country;// 国家,如中国为CN 
private String  headimgurl;  // 用户头像,最后一个数值代表正方形头像大小(有0、46、64、96、132数值可选,0代表640*640正方形头像),用户没有头像时该项为空。若用户更换头像,原有头像URL将失效。 
private String  privilege;// 用户特权信息,json 数组,如微信沃卡用户为(chinaunicom) 
private String  unionid;// 只有在用户将公众号绑定到微信开放平台帐号后,才会出现该字段。详见:获取用户个人信息(UnionID机制) 
private String access_token;

授权凭证验证的类:

Java代码

private String errcode;  
private String errmsg;

通过code换取网页授权access_token

Java代码

private String access_token;  
private String expires_in;  
private String refresh_token;  
private String openid;  
private String scope;  
private String unionid;

关于微信头像的,获取的是一个http的url,则需要将图片下载到服务器存储,然后获得相对路径:

Java代码

/**
     * 使用url或者http存入文件
     * @Title: fileUpload
     * @param @param fileUrl  文件url,可以是http
     * @param @param path     文件存储路径
     * @return void
     * @throws xinz
     */
    public static void fileUpload (String fileUrl,String path){  
         //读取文件
          String s1 = fileUrl;     
          java.io.InputStream is = null; //定义一个输入流。
          BufferedInputStream bis = null;//定义一个带缓冲的输入流 。 
        //写到本地 
          BufferedOutputStream bos = null; //定义一个带缓冲的输出流。
          try{   
            java.net.URL url = new java.net.URL(s1);//创建一个URL对象。
            is = url.openStream();//打开到此 URL 的连接并返回一个用于从该连接读入的 InputStream。
            bis = new java.io.BufferedInputStream(is);       
            File file = new File(path);     
            if(!file.exists()){ //测试此抽象路径名表示的文件或目录是否存在。  
                file.createNewFile();   //创建此抽象路径名表示的文件或目录。
            }     
          bos = new BufferedOutputStream(new FileOutputStream(file));;       
          byte[] b = new byte[1024]; //创建字节数组。
          while(bis.read(b)!=-1){//输入流中的数据如果还有下一行(!=-1)将继续循环
              bos.write(b);//将字节数组写入输出流。    
          }   
          }catch(Exception   e){       
              System.out.println(e.toString());         
          }finally{       
              try{       
                  bos.flush();//刷新此缓冲的输出流。 
                  bis.close(); //关闭此输入流 。 
              }catch(Exception   e){       
                  System.out.println(e.toString());         
              }       
          }    
    }

现在是基础工作都做完了,现在开发代码的开发,然后我们按照这个步骤开发:

第一步:用户同意授权,获取code

这里的url就是前面所准备在properties中的url了。

Java代码

/**
     * 微信用户授权
     * @Title: wechatOauth
     * @param @param request
     * @param @param response
     * @param @param model
     * @param @return
     * @return String
     * @throws xinz
     */
    @RequestMapping("wechatOauth")  
    public String wechatOauth(HttpServletRequest request,HttpServletResponse response,Model model)  {  
        /**
         *  1 第一步:用户同意授权,获取code
         */
        //首先拿到微信公众号的AppID、AppSecret等参数
        String AppID = ZhtxHelper.getApplicationResourcesProp("sendSms","AppID");  
        String urlOpen = ZhtxHelper.getApplicationResourcesProp("sendSms","url");  
        //如果用户授权成功则跳转到此url
        String loginUrl = ""+urlOpen+"/zhtx-wap/weixin/getAccessToken";  
        //用户授权,获取code
        String url = "https://open.weixin.qq.com/connect/oauth2/authorize?"
                    + "appid="+AppID+""
                    + "&redirect_uri="+loginUrl+""
                    + "&response_type=code"
                    + "&scope=snsapi_userinfo"
                    + "&state=123#wechat_redirect";  
        //forward redirect
        return "redirect:"+url+"";   
    }

第二步:通过code换取网页授权access_token

Java代码

/**
     * 通过code换取网页授权access_token
     * @Title: getAccessToken
     * @param @param request
     * @param @param response
     * @param @param model
     * @param @return
     * @return String
     * @throws xinz
     */
    @RequestMapping("getAccessToken")  
    public String getAccessToken(HttpServletRequest request,HttpServletResponse response,Model model) {  
        //获取到返回的参数
        try {  
            //首先拿到微信公众号的AppID、AppSecret等参数
            String AppID = ZhtxHelper.getApplicationResourcesProp("sendSms","AppID");  
            String AppSecret = ZhtxHelper.getApplicationResourcesProp("sendSms","AppSecret");  
            String code = request.getParameter("code");  
            String url = null;  
            if(code!=null){  
                /**
                 *  2 第二步:通过code换取网页授权access_token
                 */
                //用户授权,获取code
                url = "https://api.weixin.qq.com/sns/oauth2/access_token?"
                        + "appid="+AppID+""
                        + "&secret="+AppSecret+""
                        + "&code="+code+""
                        + "&grant_type=authorization_code";  
                String requestMethod = "GET";  
                String outputStr = "";  
                String httpRequest = WeixinUtil.httpRequest(url, requestMethod, outputStr);  
                System.out.println("通过code换取网页授权access_token="+httpRequest);  
                AccessTokenModel accTok = JSON.parseObject(httpRequest, AccessTokenModel.class);  
                /**
                 *  4 第四步:拉取用户信息(需scope为 snsapi_userinfo)
                 */
                //用户授权,获取code
                String urlUser = "https://api.weixin.qq.com/sns/userinfo?"
                        + "access_token="+accTok.getAccess_token()+""
                        + "&openid="+accTok.getOpenid()+""
                        + "&lang=zh_CN";  
                String httpUser = WeixinUtil.httpRequest(urlUser, requestMethod, outputStr);  
                System.out.println("拉取用户信息=="+httpUser);  
                WechatUser wechatUser = JSON.parseObject(httpUser, WechatUser.class);  
                wechatUser.setAccess_token(accTok.getAccess_token());  
                /**
                 *  5 附:检验授权凭证(access_token)是否有效
                 */
                WechatMsg checkAccessToken = checkAccessToken(wechatUser.getAccess_token(), wechatUser.getOpenid());  
                if(checkAccessToken.getErrcode().equals("0")){  
                    CurrentSession.setAttribute("wechatUser", wechatUser);  
                    WechatUser wechatU = new WechatUser();  
                    wechatU.setOpenid(wechatUser.getOpenid());  
                    List findWechatUser = wechatUserService.findWechatUser(wechatU);  
                    if(findWechatUser.size()>0){  
                        UserRegister userRegister = userService.findUserByOpenid(wechatUser.getOpenid());  
                        CurrentSession.setAttribute("user", userRegister);  
                        return "redirect:/user/userCenter";  
                    }else{  
                        return "/jsp/wechat/wechatregister";   
                    }  
                }else{  
                    //如果access_token失效,则再次进行调用,并存储access_token值,access_token有效期为2个小时
                    this.wechatOauth(request, response, model);   
                }  
            }  
        } catch (Exception e) {  
            System.out.println("===拉取用户出错===");  
            e.printStackTrace();  
        }  
        //forward redirect
        return "/jsp/wechat/wechatregister";   
    }

第四步:拉取用户,和自己网站用户绑定

Java代码

/**
     * 微信关联用户
     * @Title: saveWechatUser
     * @param @param mobilePhone
     * @param @param password
     * @param @param validataCode
     * @param @return
     * @return String
     * @throws xinz
     */
    @RequestMapping("saveWechatUser")  
    public String saveWechatUser(HttpServletResponse response,String mobilePhone,String password,String validataCode){  
        //使用手机号来判断该手机是否在注册
        UserRegister userRegister = userService.findUserByPhone(mobilePhone);  
        WechatUser wechatUser = (WechatUser)CurrentSession.getAttribute("wechatUser");  
        WechatUser wechatU = new WechatUser();  
        wechatU.setOpenid(wechatUser.getOpenid());  
        List findWechatUser = wechatUserService.findWechatUser(wechatU);  
        if(findWechatUser.size()>0 && userRegister.getOpenid()!=null){  
            CurrentSession.setAttribute("user", userRegister);  
            return "redirect:/user/userCenter";  
        }else{  
            //如果没有注册,开始注册
            if(userRegister==null){  
                Result saveUserInfoApp = userRegisterService.saveUserInfoApp(mobilePhone, password, validataCode,wechatUser);  
                if(saveUserInfoApp.getState()==1){  
                    //进行微信和用户的关联
                    wechatUserService.saveWechatUser(wechatUser);  
                    CurrentSession.setAttribute("user", userRegister);  
                    return "redirect:/user/userCenter";  
                }  
            }else if(userRegister.getOpenid()==null || userRegister.getOpenid().equals("")){  
            //否则,查询出用户信息,放入session中,关联微信,跳转到用户中心    
                UserRegister userReg = new UserRegister();  
                userReg.setId(userRegister.getId());  
                //存入微信openid
                userReg.setOpenid(wechatUser.getOpenid());  
                userService.upUser(userReg);  
                UserInfo user = new UserInfo();  
                //存入微信头像
                //图片类型
                String dateStr =DateUtil.format(DateUtil.getCurrentDate(), "yyyyMMdd")  + "/";  
                //图片类型
                String imgType = "JPG";  
                //微信头像名称
                String app2DBarNameAndType = UuidUtil.getUUID()+"."+imgType;  
                //微信头像路径
                String path =   ZhtxHelper.getApplicationResourcesProp("application","app.img.projectpath")+ SysConstant.GOODS2DBARPATH + dateStr;  
                File file1 = new File(path);  
                file1.mkdirs();  
                //图片全路径
                String imgUrl = SysConstant.GOODS2DBARPATH + dateStr+app2DBarNameAndType;  
                FileUtil.fileUpload(wechatUser.getHeadimgurl(), path);  
                user.setRegisterId(userRegister.getId());  
                user.setImageUrl(imgUrl);  
                userInfoService.updateUserInfo(user);  
                //存入微信用户
                wechatUserService.saveWechatUser(wechatUser);  
                UserRegister userW = userService.findUserByPhone(mobilePhone);  
                CurrentSession.setAttribute("user", userW);  
                return "redirect:/user/userCenter";  
            }else{  
                CurrentSession.setAttribute("user", userRegister);  
                return "redirect:/user/userCenter";  
            }  
        }  
        return "redirect:/user/userCenter";  
    }

附:检验授权凭证(access_token)是否有效

Java代码

/**
     * 检验授权凭证(access_token)是否有效
     * @Title: checkAccessToken
     * @param @param access_token 网页授权接口调用凭证,注意:此access_token与基础支持的access_token不同 
     * @param @param openid 用户的唯一标识 
     * @return WechatMsg   返回消息实体
     * @throws xinz
     */
    public static WechatMsg checkAccessToken(String access_token,String openid){  
         String requestMethod = "GET";  
         String outputStr = "";   
         String url = "https://api.weixin.qq.com/sns/auth?"
                + "access_token="+access_token+""
                + "&openid="+openid+"";  
         String httpmsg = WeixinUtil.httpRequest(url, requestMethod, outputStr);  
         System.out.println("拉取用户信息返回消息=="+httpmsg);  
         WechatMsg msg = JSON.parseObject(httpmsg, WechatMsg.class);  
         return msg;  
    }

然后在网页端,则是需要编写H5页面,进行自己网站和微信用户的关联,我这里是使用手机号,用户输入手机号,进行判断,如果注册过就直接关联,如果用户没有注册则进行注册后关联,完成后跳转到会员中心。


以上就是详解微信开发模式之自定义菜单实现代码的详细内容,更多请关注其它相关文章!


推荐阅读
  • 本文介绍了在开发Android新闻App时,搭建本地服务器的步骤。通过使用XAMPP软件,可以一键式搭建起开发环境,包括Apache、MySQL、PHP、PERL。在本地服务器上新建数据库和表,并设置相应的属性。最后,给出了创建new表的SQL语句。这个教程适合初学者参考。 ... [详细]
  • 如何实现织梦DedeCms全站伪静态
    本文介绍了如何通过修改织梦DedeCms源代码来实现全站伪静态,以提高管理和SEO效果。全站伪静态可以避免重复URL的问题,同时通过使用mod_rewrite伪静态模块和.htaccess正则表达式,可以更好地适应搜索引擎的需求。文章还提到了一些相关的技术和工具,如Ubuntu、qt编程、tomcat端口、爬虫、php request根目录等。 ... [详细]
  • 这是原文链接:sendingformdata许多情况下,我们使用表单发送数据到服务器。服务器处理数据并返回响应给用户。这看起来很简单,但是 ... [详细]
  • 分享css中提升优先级属性!important的用法总结
    web前端|css教程css!importantweb前端-css教程本文分享css中提升优先级属性!important的用法总结微信门店展示源码,vscode如何管理站点,ubu ... [详细]
  • 本文介绍了如何使用jQuery和AJAX来实现动态更新两个div的方法。通过调用PHP文件并返回JSON字符串,可以将不同的文本分别插入到两个div中,从而实现页面的动态更新。 ... [详细]
  • Servlet多用户登录时HttpSession会话信息覆盖问题的解决方案
    本文讨论了在Servlet多用户登录时可能出现的HttpSession会话信息覆盖问题,并提供了解决方案。通过分析JSESSIONID的作用机制和编码方式,我们可以得出每个HttpSession对象都是通过客户端发送的唯一JSESSIONID来识别的,因此无需担心会话信息被覆盖的问题。需要注意的是,本文讨论的是多个客户端级别上的多用户登录,而非同一个浏览器级别上的多用户登录。 ... [详细]
  • 微软头条实习生分享深度学习自学指南
    本文介绍了一位微软头条实习生自学深度学习的经验分享,包括学习资源推荐、重要基础知识的学习要点等。作者强调了学好Python和数学基础的重要性,并提供了一些建议。 ... [详细]
  • 在Docker中,将主机目录挂载到容器中作为volume使用时,常常会遇到文件权限问题。这是因为容器内外的UID不同所导致的。本文介绍了解决这个问题的方法,包括使用gosu和suexec工具以及在Dockerfile中配置volume的权限。通过这些方法,可以避免在使用Docker时出现无写权限的情况。 ... [详细]
  • 本文介绍了数据库的存储结构及其重要性,强调了关系数据库范例中将逻辑存储与物理存储分开的必要性。通过逻辑结构和物理结构的分离,可以实现对物理存储的重新组织和数据库的迁移,而应用程序不会察觉到任何更改。文章还展示了Oracle数据库的逻辑结构和物理结构,并介绍了表空间的概念和作用。 ... [详细]
  • 使用在线工具jsonschema2pojo根据json生成java对象
    本文介绍了使用在线工具jsonschema2pojo根据json生成java对象的方法。通过该工具,用户只需将json字符串复制到输入框中,即可自动将其转换成java对象。该工具还能解析列表式的json数据,并将嵌套在内层的对象也解析出来。本文以请求github的api为例,展示了使用该工具的步骤和效果。 ... [详细]
  • 本文介绍了高校天文共享平台的开发过程中的思考和规划。该平台旨在为高校学生提供天象预报、科普知识、观测活动、图片分享等功能。文章分析了项目的技术栈选择、网站前端布局、业务流程、数据库结构等方面,并总结了项目存在的问题,如前后端未分离、代码混乱等。作者表示希望通过记录和规划,能够理清思路,进一步完善该平台。 ... [详细]
  • 使用正则表达式爬取36Kr网站首页新闻的操作步骤和代码示例
    本文介绍了使用正则表达式来爬取36Kr网站首页所有新闻的操作步骤和代码示例。通过访问网站、查找关键词、编写代码等步骤,可以获取到网站首页的新闻数据。代码示例使用Python编写,并使用正则表达式来提取所需的数据。详细的操作步骤和代码示例可以参考本文内容。 ... [详细]
  • 如何实现JDK版本的切换功能,解决开发环境冲突问题
    本文介绍了在开发过程中遇到JDK版本冲突的情况,以及如何通过修改环境变量实现JDK版本的切换功能,解决开发环境冲突的问题。通过合理的切换环境,可以更好地进行项目开发。同时,提醒读者注意不仅限于1.7和1.8版本的转换,还要适应不同项目和个人开发习惯的需求。 ... [详细]
  • express工程中的json调用方法
    本文介绍了在express工程中如何调用json数据,包括建立app.js文件、创建数据接口以及获取全部数据和typeid为1的数据的方法。 ... [详细]
  • 本文介绍了Java后台Jsonp处理方法及其应用场景。首先解释了Jsonp是一个非官方的协议,它允许在服务器端通过Script tags返回至客户端,并通过javascript callback的形式实现跨域访问。然后介绍了JSON系统开发方法,它是一种面向数据结构的分析和设计方法,以活动为中心,将一连串的活动顺序组合成一个完整的工作进程。接着给出了一个客户端示例代码,使用了jQuery的ajax方法请求一个Jsonp数据。 ... [详细]
author-avatar
df0134330
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有