五、微信测试号的申请与连接以获取微信用户信息
在咱们自己的程序里面编写servlet以响应微信号
在接下来的步骤中,我们将在测试号里面设置接口配置信息的URL,一经设置,微信公众号便会发请求到我们设置好的URL去,我们必须编写程序应答才能顺利连通微信公众号,因此咱们需要编写相应的响应程序
需要编写两个类
【SignUtil】

package com.imooc.o2o.util.weixin;import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;/*** 微信请求校验工具类*/
public class SignUtil {// 与接口配置信息中的Token要一致private static String token = "myo2o";/*** 验证签名* * @param signature* @param timestamp* @param nonce* @return*/public static boolean checkSignature(String signature, String timestamp, String nonce) {String[] arr = new String[] { token, timestamp, nonce };// 将token、timestamp、nonce三个参数进行字典序排序Arrays.sort(arr);StringBuilder content = new StringBuilder();for (int i = 0; i < arr.length; i++) {content.append(arr[i]);}MessageDigest md = null;String tmpStr = null;try {md = MessageDigest.getInstance("SHA-1");// 将三个参数字符串拼接成一个字符串进行sha1加密byte[] digest = md.digest(content.toString().getBytes());tmpStr = byteToStr(digest);} catch (NoSuchAlgorithmException e) {e.printStackTrace();}content = null;// 将sha1加密后的字符串可与signature对比,标识该请求来源于微信return tmpStr != null ? tmpStr.equals(signature.toUpperCase()) : false;}/*** 将字节数组转换为十六进制字符串* * @param byteArray* @return*/private static String byteToStr(byte[] byteArray) {String strDigest = "";for (int i = 0; i < byteArray.length; i++) {strDigest += byteToHexStr(byteArray[i]);}return strDigest;}/*** 将字节转换为十六进制字符串* * @param mByte* @return*/private static String byteToHexStr(byte mByte) {char[] Digit = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };char[] tempArr = new char[2];tempArr[0] = Digit[(mByte >>> 4) & 0X0F];tempArr[1] = Digit[mByte & 0X0F];String s = new String(tempArr);return s;}
}

【WechatController】

package com.imooc.o2o.web.wechat;import java.io.IOException;
import java.io.PrintWriter;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;import com.imooc.o2o.util.wechat.SignUtil;@Controller
//一会在设置的URL里面就设置上这个路由
@RequestMapping("wechat")
public class WechatController {private static Logger log = LoggerFactory.getLogger(WechatController.class);@RequestMapping(method = { RequestMethod.GET })public void doGet(HttpServletRequest request, HttpServletResponse response) {log.debug("weixin get...");// 微信加密签名,signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。String signature = request.getParameter("signature");// 时间戳String timestamp = request.getParameter("timestamp");// 随机数String nonce = request.getParameter("nonce");// 随机字符串String echostr = request.getParameter("echostr");// 通过检验signature对请求进行校验,若校验成功则原样返回echostr,表示接入成功,否则接入失败PrintWriter out = null;try {out = response.getWriter();if (SignUtil.checkSignature(signature, timestamp, nonce)) {log.debug("weixin get success....");out.print(echostr);}} catch (IOException e) {e.printStackTrace();} finally {if (out != null)out.close();}}
}

之后重新部署一版最新的程序

访问微信测试号登录页面,通过打开自己手机的微信,扫一扫登录
https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=sandbox/login

进入到测试号页面后,分别看到如下信息
【测试号信息】
appID:开发者ID,是公众号开发识别码,配合开发者密码可以调用微信公众号接口,如获取微信昵称等
appsecret:开发者密码,是检验公众号开发者身份的密码,具有极高的安全性。切记不要把密码交给第三方开发者或者编写到代码里

【接口配置信息】
URL: 是开发者用来接收微信消息和事件的接口URL
Token:由开发者可以任意填写,用作生成签名(该Token会和接口URL中包含的Token进行比对,从而验证安全性)

【JS接口安全域名】
域名:想调用jssdk(如想要通过微信公众号js接口获取地图等工具)必须得填写此域名,在此域名的范围内才能调用jssdk工具,注意这里必须是域名,不是带有http之类的URL,这里直接填写o2o.yitiaojieinfo.com

【测试号二维码】
里面包含了测试号二维码以及已经关注了的用户信息

【体验接口权限表】
这里主要介绍【网页服务】里面的【网页帐号】
网页帐号主要用来设置OAuth2.0里面的网页授权域名,用户在网页授权页同意授权给公众号后,微信会将授权数据传给一个回调页面,回调页面需在此域名下,以确保安全可靠。沙盒号回调地址支持域名和ip,正式公众号回调地址只支持域名。这里直接设置为o2o.yitiaojieinfo.com


有不清楚的地方可以直接参考微信官方文档
https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421135319
接下来需要编写自己的程序以获取关注此公众号的用户信息
需要编写5个类 WechatLoginController.java,UserAccessToken.java,WechatUser.java,WechatUtil.java以及MyX509TrustManager.java
【WechatLoginController】主要用来获取已关注此微信号的用户信息并做相应处理

package com.imooc.o2o.web.wechat;import java.io.IOException;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;import com.imooc.o2o.dto.UserAccessToken;
import com.imooc.o2o.dto.WechatUser;
import com.imooc.o2o.util.wechat.WeiXinUserUtil;@Controller
@RequestMapping("wechatlogin")
/*** 获取关注公众号之后的微信用户信息的接口,如果在微信浏览器里访问* https://open.weixin.qq.com/connect/oauth2/authorize?appid=您的appId&redirect_uri=http://o2o.yitiaojieinfo.com/o2o/wechatlogin/logincheck&role_type=1&response_type=code&scope=snsapi_userinfo&state=1#wechat_redirect* 则这里将会获取到code,之后再可以通过code获取到access_token 进而获取到用户信息* * @author xiangze**/
public class WechatLoginController {private static Logger log = LoggerFactory.getLogger(WechatLoginController.class);@RequestMapping(value = "/logincheck", method = { RequestMethod.GET })public String doGet(HttpServletRequest request, HttpServletResponse response) {log.debug("weixin login get...");// 获取微信公众号传输过来的code,通过code可获取access_token,进而获取用户信息String code = request.getParameter("code");// 这个state可以用来传我们自定义的信息,方便程序调用,这里也可以不用// String roleType = request.getParameter("state");log.debug("weixin login code:" + code);WechatUser user = null;String openId = null;if (null != code) {UserAccessToken token;try {// 通过code获取access_tokentoken = WeiXinUserUtil.getUserAccessToken(code);log.debug("weixin login token:" + token.toString());// 通过token获取accessTokenString accessToken = token.getAccessToken();// 通过token获取openIdopenId = token.getOpenId();// 通过access_token和openId获取用户昵称等信息user = WeiXinUserUtil.getUserInfo(accessToken, openId);log.debug("weixin login user:" + user.toString());request.getSession().setAttribute("openId", openId);} catch (IOException e) {log.error("error in getUserAccessToken or getUserInfo or findByOpenId: " + e.toString());e.printStackTrace();}}// ======todo begin======// 前面咱们获取到openId后,可以通过它去数据库判断该微信帐号是否在我们网站里有对应的帐号了,// 没有的话这里可以自动创建上,直接实现微信与咱们网站的无缝对接。// ======todo end======if (user != null) {// 获取到微信验证的信息后返回到指定的路由(需要自己设定)return "frontend/index";} else {return null;}}
}

【UserAccessToken】用户AccessToken实体类,用来接收accesstoken以及openid等信息

package com.imooc.o2o.dto;import com.fasterxml.jackson.annotation.JsonProperty;/*** 用户授权token* * @author xiangze**/
public class UserAccessToken {// 获取到的凭证@JsonProperty("access_token")private String accessToken;// 凭证有效时间,单位:秒@JsonProperty("expires_in")private String expiresIn;// 表示更新令牌,用来获取下一次的访问令牌,这里没太大用处@JsonProperty("refresh_token")private String refreshToken;// 该用户在此公众号下的身份标识,对于此微信号具有唯一性@JsonProperty("openid")private String openId;// 表示权限范围,这里可省略@JsonProperty("scope")private String scope;public String getAccessToken() {return accessToken;}public void setAccessToken(String accessToken) {this.accessToken = accessToken;}public String getExpiresIn() {return expiresIn;}public void setExpiresIn(String expiresIn) {this.expiresIn = expiresIn;}public String getRefreshToken() {return refreshToken;}public void setRefreshToken(String refreshToken) {this.refreshToken = refreshToken;}public String getOpenId() {return openId;}public void setOpenId(String openId) {this.openId = openId;}public String getScope() {return scope;}public void setScope(String scope) {this.scope = scope;}@Overridepublic String toString() {return "accessToken:" + this.getAccessToken() + ",openId:" + this.getOpenId();}}

【WechatUser】微信用户实体类,用来接收昵称 openid等用户信息

package com.imooc.o2o.dto;import java.io.Serializable;import com.fasterxml.jackson.annotation.JsonProperty;/*** 微信用户实体类* * @author xiangze**/
public class WechatUser implements Serializable {/*** */private static final long serialVersionUID = -4684067645282292327L;// openId,标识该公众号下面的该用户的唯一Id@JsonProperty("openid")private String openId;// 用户昵称@JsonProperty("nickname")private String nickName;// 性别@JsonProperty("sex")private int sex;// 省份@JsonProperty("province")private String province;// 城市@JsonProperty("city")private String city;// 区@JsonProperty("country")private String country;// 头像图片地址@JsonProperty("headimgurl")private String headimgurl;// 语言@JsonProperty("language")private String language;// 用户权限,这里没什么作用@JsonProperty("privilege")private String[] privilege;public String getOpenId() {return openId;}public void setOpenId(String openId) {this.openId = openId;}public String getNickName() {return nickName;}public void setNickName(String nickName) {this.nickName = nickName;}public int getSex() {return sex;}public void setSex(int sex) {this.sex = sex;}public String getProvince() {return province;}public void setProvince(String province) {this.province = province;}public String getCity() {return city;}public void setCity(String city) {this.city = city;}public String getCountry() {return country;}public void setCountry(String country) {this.country = country;}public String getHeadimgurl() {return headimgurl;}public void setHeadimgurl(String headimgurl) {this.headimgurl = headimgurl;}public String getLanguage() {return language;}public void setLanguage(String language) {this.language = language;}public String[] getPrivilege() {return privilege;}public void setPrivilege(String[] privilege) {this.privilege = privilege;}@Overridepublic String toString() {return "openId:" + this.getOpenId() + ",nikename:" + this.getNickName();}
}

【WechatUtil】主要用来提交https请求给微信获取用户信息

package com.imooc.o2o.util.wechat;import java.io.BufferedReader;
import java.io.IOException;
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;import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.imooc.o2o.dto.UserAccessToken;
import com.imooc.o2o.dto.WechatUser;/*** 微信工具类* * @author xiangze**/
public class WechatUtil {private static Logger log = LoggerFactory.getLogger(WechatUtil.class);/*** 获取UserAccessToken实体类* * @param code* @return* @throws IOException*/public static UserAccessToken getUserAccessToken(String code) throws IOException {// 测试号信息里的appIdString appId = "您的appId";log.debug("appId:" + appId);// 测试号信息里的appsecretString appsecret = "您的appsecret";log.debug("secret:" + appsecret);// 根据传入的code,拼接出访问微信定义好的接口的URLString url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=" + appId + "&secret=" + appsecret+ "&code=" + code + "&grant_type=authorization_code";// 向相应URL发送请求获取token json字符串String tokenStr = httpsRequest(url, "GET", null);log.debug("userAccessToken:" + tokenStr);UserAccessToken token = new UserAccessToken();ObjectMapper objectMapper = new ObjectMapper();try {// 将json字符串转换成相应对象token = objectMapper.readValue(tokenStr, UserAccessToken.class);} catch (JsonParseException e) {log.error("获取用户accessToken失败: " + e.getMessage());e.printStackTrace();} catch (JsonMappingException e) {log.error("获取用户accessToken失败: " + e.getMessage());e.printStackTrace();} catch (IOException e) {log.error("获取用户accessToken失败: " + e.getMessage());e.printStackTrace();}if (token == null) {log.error("获取用户accessToken失败。");return null;}return token;}/*** 获取WechatUser实体类* * @param accessToken* @param openId* @return*/public static WechatUser getUserInfo(String accessToken, String openId) {// 根据传入的accessToken以及openId拼接出访问微信定义的端口并获取用户信息的URLString url = "https://api.weixin.qq.com/sns/userinfo?access_token=" + accessToken + "&openid=" + openId+ "&lang=zh_CN";// 访问该URL获取用户信息json 字符串String userStr = httpsRequest(url, "GET", null);log.debug("user info :" + userStr);WechatUser user = new WechatUser();ObjectMapper objectMapper = new ObjectMapper();try {// 将json字符串转换成相应对象user = objectMapper.readValue(userStr, WechatUser.class);} catch (JsonParseException e) {log.error("获取用户信息失败: " + e.getMessage());e.printStackTrace();} catch (JsonMappingException e) {log.error("获取用户信息失败: " + e.getMessage());e.printStackTrace();} catch (IOException e) {log.error("获取用户信息失败: " + e.getMessage());e.printStackTrace();}if (user == null) {log.error("获取用户信息失败。");return null;}return user;}/*** 发起https请求并获取结果* * @param requestUrl*            请求地址* @param requestMethod*            请求方式(GET、POST)* @param outputStr*            提交的数据* @return json字符串*/public static String httpsRequest(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();log.debug("https buffer:" + buffer.toString());} catch (ConnectException ce) {log.error("Weixin server connection timed out.");} catch (Exception e) {log.error("https request error:{}", e);}return buffer.toString();}
}

【MyX509TrustManager】主要继承X509TrustManager做https证书信任管理器

package com.imooc.o2o.util.wechat;import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;import javax.net.ssl.X509TrustManager;/*** 证书信任管理器(用于https请求)* * @author xiangze* */
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;}
}

之后重新打包一个新的war包并发布到服务器tomcat webapps目录下
发布成功后,关注你自己的测试号(即扫描测试号的那个二维码),然后在手机微信里面或者微信开发者工具里访问相应链接:
https://open.weixin.qq.com/connect/oauth2/authorize?appid=您的appid&redirect_uri=http://o2o.yitiaojieinfo.com/o2o/wechatlogin/logincheck&role_type=1&response_type=code&scope=snsapi_userinfo&state=1#wechat_redirect

之后查看日志信息,便能发现确实能够获取到用户的信息了

至此咱们已经从无到有完成了阿里云部署Java网站和微信公众号的开发,文章虽长,但是干货多多,都是傻瓜式的配置,希望大家喜欢。
注意事项:

  1. 由于tomcat咱们没有调优,启动较慢,建议每次重启等待几分钟再去访问,否则会假死,需要kill掉再重启
  2. 经过认证的微信服务号跟测试号其实是一样的,大家可以按照上述去配置

作者: xiangzepro 
链接:http://www.imooc.com/article/20584
来源:慕课网
本文原创发布于慕课网 ,转载请注明出处,谢谢合作!

阿里云部署Java网站和微信开发调试心得技巧(下)相关推荐

  1. 阿里云部署Java网站和微信开发调试心得技巧(上)

    本篇手记旨在帮助大家从0开始: 申请阿里云服务器 搭建出程序的执行环境 在服务器上发布并运行自己的web project 域名解析 微信测试号的申请与连接以获取微信用户信息 全篇文章主要以如何去完成目 ...

  2. 阿里云部署Java开发环境

    阿里云部署Java网站和微信开发调试心得技巧(上) 本文主要是记录在阿里云服务器从零开始搭建Java执行环境并且部署web project的过程,方面以后查阅. 一.申请阿里云服务器 购买阿里云服务器 ...

  3. 阿里云部署java web

    转载请注明出处http://blog.csdn.net/evankaka 摘要:本文主要讲了如何在阿里云上安装JDK.Tomcat以及其配置过程.最后以一个实例来演示在阿里云上部署Java web项目 ...

  4. 如何在阿里云部署个人网站

    文章目录 部署mysql 部署tomcat 安装jdk 安装tomcat 部署nginx 安装nginx 配置nginx 启动nginx 配置域名 可能出现的其他问题 云服务器常见问题 Unable ...

  5. arm搭建云手机教程_教你从0开始部署阿里云服务器,阿里云服务器搭建网站教程...

    教你从0开始部署阿里云服务器,阿里云服务器部署网站的办法,阿里云搭建项目的办法,阿里云服务器搭建网站教程 1.购买 登录官网点击下面链接: 企业上云甄选​partner.aliyun.com 查看云服 ...

  6. 【阿里云部署网站——零基础七步上云】

    本文将阿里云部署网站流程分为起步七步(古有曹植七步作诗,今有白马七步部署阿里云),新手上路,老司机让路.话不多说,直接上图. 一.注册登录   浏览器输入https://www.aliyun.com/ ...

  7. Win10环境下基于Hexo的静态博客环境搭建,及其阿里云部署

    引言 1.为什么要搭建自己的个人博客 工作和学习过程中,我们经常遇到一些这样或那样的问题,此时我们可能会在网上找到相应的解决方法.但是过了一段时间之后,当我们再次碰到类似的问题时,早已忘记以前是怎么解 ...

  8. React+SSM+阿里云部署(JDK, MySQL8, Tomcat)

    前言 最近学了React和SSM,恰好工作室有个餐馆的外卖项目,于是尝试使用React+SSM的方式做了一个. 因为是初次接触这种整合以及服务器部署,翻了不少文档与博客.记录下来详细过程,以供参考. ...

  9. 服务器部署java网站,服务器部署java网站

    服务器部署java网站 内容精选 换一换 通常情况下,需要结合客户的实际业务环境和具体需求进行业务改造评估,建议您进行服务咨询.这里仅描述一些通用的策略供您参考,主要分如下几方面进行考虑:业务迁移不管 ...

  10. Linux虚拟机或阿里云部署本地Javaweb项目

    Linux系统部署本地项目 服务器 Linux 阿里云.华为云.腾讯云 安装虚拟机,虚拟机就是在你的电脑中安装一台虚拟的计算机,内存.CPU.硬盘,Linux 安装到虚拟机中. CentOS7,企业级 ...

最新文章

  1. 应用服务攻击工具clusterd
  2. strftime和strptime使用
  3. 如何理解subplot绘制不规则子图的参数设置
  4. 数据可视化 信息可视化_可视化哲学的黎明
  5. c语言sort函数_C语言的那些经典程序 第八期
  6. java quartz job_用 Quartz 进行作业调度
  7. Python读写CSV格式文件
  8. mysql semi sync_MySQL Semisync
  9. SQL Server高级查询之常见数据库对象(触发器)第五章节
  10. 群集之 COROSYNC OPENAIS +PACEMAKER +REBD+WEB
  11. php_redis配置安装php_redis-5.1.1-7.4-nts-vc15-x64.zip
  12. Java项目:药品管理系统(java+SSM+html+jQuery+Tomcat+mysql)
  13. 2023年安徽大学科学技术哲学考研上岸前辈备考经验指导
  14. Hi3519AV100开发记录
  15. PHP裂变红包源码,php版本微信裂变红包api详解
  16. 洛谷P5545 炸弹攻击2
  17. 数字字符串转为数字 C语言实现
  18. 移动网络能“接管”生活?2014十大猜想
  19. 2022电大国家开放大学网上形考任务-客户关系管理非免费(非答案)
  20. (字符串处理)A-B

热门文章

  1. 五.爬虫--京东登录破解(一)
  2. 用Markdown来创建待办事项
  3. 《计算机网络》笔记摘抄汇总
  4. 校园网使用家用无线路由器
  5. 20165232 结对编程第二周总结
  6. 基于java springboot android 安卓记账本源码(毕设)
  7. linux 加速度传感器数据获取,Android传感器SensorEventListener之加速度传感器
  8. 要了命了,我亲自包了20000个红包送你
  9. 三维GIS与游戏引擎的跨界融合,打造数字化孪生的平行世界
  10. 天使轮和种子轮投资降温!2019风投趋势如何走?