参考摘抄:
阿里云部署Java网站和微信开发调试心得技巧(上):https://www.imooc.com/article/20583
阿里云部署Java网站和微信开发调试心得技巧(下):https://www.imooc.com/article/20584
一.运行环境搭建(centos上)
(1) JDK(这里选择的是JDK1.8)
下载地址为:http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html。选择的是jdk-8u144-linux-x64.rpm。
下载完成后执行:rpm -ivh jdk-8u144-linux-x64.rpm
(2) Tomcat 8
下载地址为http://tomcat.apache.org/download-80.cgi#8.0.46选择的是apache-tomcat-8.0.46.tar.gz
解压:tar -zxvf apache-tomcat-8.5.41.tar.gz
启动tomcat:./apache-tomcat-8.5.41/bin/startup.sh
修改Tomcat默认连接端口(8080):apache-tomcat-8.5.41/conf/server.xml
修改完成后重启Tomcat:(注意查看端口是否开启或被占用)
关闭Tomcat服务:./apache-tomcat-8.5.41/bin/shutdown.sh
启动Tomcat服务:./apache-tomcat-8.5.41/bin/startup.sh
查看Tomcat日志是否启动成功
(3) Mysql(我用的是Mariadb)repo源,后通过centos自带的yum安装
下载的地址为https://dev.mysql.com/downloads/repo/yum/。这里选择mysql57-community-release-el7-11.noarch.rpm
(4) Redis(可选,最好预先安装上,这里选择的版本为4.0.2)
下载地址为https://redis.io/download这里选择。redis-4.0.2.tar.gz。
解压:tar xzf redis-5.0.5.tar.gz;
设置redis以支持远程登录:vim redis-5.0.5/redis.conf
还需要给redis.conf添加配置以支持redis作为守护进程一直跑在后台daemonize yes:
注意windows下永久启动redis:
设置服务命令:redis-server --service-install redis.windows-service.conf --loglevel verbose
常用redis服务命令:
卸载服务:redis-server --service-uninstall
开启服务:redis-server --service-start
停止服务:redis-server --service-stop
安装:cd redis-5.0.5
make
启动服务:src/redis-server redis.conf
redis连接测试:
通过redis-cli连接到redis服务器,src/redis-cli,当输入ping 得到pong的回应之后,证明redis配置已经完成
将上面的软件都下载到本地,并上传到服务器(如果您的系统为MAC或LINUX,直接使用SCP命令行上传,具体指令可以查询网上,如果您的系统为WIN,推荐使用filezilla可视化上传工具上传),或者您也可以直接登录服务器,wget+ftp地址直接下载这些软件;同时需要大家注意的是,我们在服务器上部署了数据库之后,需要往数据库里面去补充数据,我们的线上数据访问的是线上的数据库而非本地的数据库。图片包也需要上传到服务器并通过配置server.xml确保能读取到这些图片(前提是docBase配置上的路径已经在服务器上创建)。
注:可以利用xshell工具实现远程连接(rz/sz上传下载文件),xftp等工具实现可视化服务器与本地文件传输。
xshell使用
xftp工具使用
二.在服务器上发布并运行自己的Java web项目
1.将项目打包成War包:
2.打包完成后,将war包上传到服务器上/apache-tomcat-8.5.41/webapps下:
上传成功后,没过几秒tomcat便会在webapps目录下自动从项目war包中解析出项目工程目录来
3.访问目标Ip和端口成功展示:
注:可以通过查看IP加端口查看Tomcat是否启动成功,很本机都是一样的。
4.域名解析:
由于域名比较贵,作为学生党没敢用。以后用的时候简单配置即可。
三.微信开发调试
1.登录微信公众平台提交相关信息
登录微信公总开发平台:https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=sandbox/login
【测试号信息】
appID:开发者ID,是公众号开发识别码,配合开发者密码可以调用微信公众号接口,如获取微信昵称等
appsecret:开发者密码,是检验公众号开发者身份的密码,具有极高的安全性。切记不要把密码交给第三方开发者或者编写到代码里
【接口配置信息】
URL: 是开发者用来接收微信消息和事件的接口URL
Token:由开发者可以任意填写,用作生成签名(该Token会和接口URL中包含的Token进行比对,从而验证安全性)
注:在这里需要验证是否来自微信服务器
微信公众平台开发文档:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421135319
微信请求校验类【SigUtil】:
1 package com.swpu.o2o.util.weixin; 2 3 import java.security.MessageDigest; 4 import java.security.NoSuchAlgorithmException; 5 import java.util.Arrays; 6 7 /** 8 * 微信请求校验工具类 9 */ 10 public class SignUtil { 11 // 与接口配置信息中的Token要一致 12 private static String token = "myo2o"; 13 14 /** 15 * 验证签名 16 * 17 * @param signature 18 * @param timestamp 19 * @param nonce 20 * @return 21 */ 22 public static boolean checkSignature(String signature, String timestamp, String nonce) { 23 String[] arr = new String[] { token, timestamp, nonce }; 24 // 将token、timestamp、nonce三个参数进行字典序排序 25 Arrays.sort(arr); 26 StringBuilder content = new StringBuilder(); 27 for (int i = 0; i < arr.length; i++) { 28 content.append(arr[i]); 29 } 30 MessageDigest md = null; 31 String tmpStr = null; 32 33 try { 34 md = MessageDigest.getInstance("SHA-1"); 35 // 将三个参数字符串拼接成一个字符串进行sha1加密 36 byte[] digest = md.digest(content.toString().getBytes()); 37 tmpStr = byteToStr(digest); 38 } catch (NoSuchAlgorithmException e) { 39 e.printStackTrace(); 40 } 41 42 content = null; 43 // 将sha1加密后的字符串可与signature对比,标识该请求来源于微信 44 return tmpStr != null ? tmpStr.equals(signature.toUpperCase()) : false; 45 } 46 47 /** 48 * 将字节数组转换为十六进制字符串 49 * 50 * @param byteArray 51 * @return 52 */ 53 private static String byteToStr(byte[] byteArray) { 54 String strDigest = ""; 55 for (int i = 0; i < byteArray.length; i++) { 56 strDigest += byteToHexStr(byteArray[i]); 57 } 58 return strDigest; 59 } 60 61 /** 62 * 将字节转换为十六进制字符串 63 * 64 * @param mByte 65 * @return 66 */ 67 private static String byteToHexStr(byte mByte) { 68 char[] Digit = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; 69 char[] tempArr = new char[2]; 70 tempArr[0] = Digit[(mByte >>> 4) & 0X0F]; 71 tempArr[1] = Digit[mByte & 0X0F]; 72 73 String s = new String(tempArr); 74 return s; 75 } 76 }
微信请求Controller【WeChatController】:
1 package com.swpu.o2o.web.wechat; 2 3 import java.io.IOException; 4 import java.io.PrintWriter; 5 6 import javax.servlet.http.HttpServletRequest; 7 import javax.servlet.http.HttpServletResponse; 8 9 import org.slf4j.Logger; 10 import org.slf4j.LoggerFactory; 11 import org.springframework.stereotype.Controller; 12 import org.springframework.web.bind.annotation.RequestMapping; 13 import org.springframework.web.bind.annotation.RequestMethod; 14 15 import com.swpu.o2o.util.weixin.SignUtil; 16 17 @Controller 18 //一会在设置的URL里面就设置上这个路由 19 @RequestMapping("wechat") 20 public class WechatController { 21 22 private static Logger log = LoggerFactory.getLogger(WechatController.class); 23 24 @RequestMapping(method = { RequestMethod.GET }) 25 public void doGet(HttpServletRequest request, HttpServletResponse response) { 26 log.debug("weixin get..."); 27 // 微信加密签名,signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。 28 String signature = request.getParameter("signature"); 29 // 时间戳 30 String timestamp = request.getParameter("timestamp"); 31 // 随机数 32 String nonce = request.getParameter("nonce"); 33 // 随机字符串 34 String echostr = request.getParameter("echostr"); 35 36 // 通过检验signature对请求进行校验,若校验成功则原样返回echostr,表示接入成功,否则接入失败 37 PrintWriter out = null; 38 try { 39 out = response.getWriter(); 40 if (SignUtil.checkSignature(signature, timestamp, nonce)) { 41 log.debug("weixin get success...."); 42 out.print(echostr); 43 } 44 } catch (IOException e) { 45 e.printStackTrace(); 46 } finally { 47 if (out != null) 48 out.close(); 49 } 50 } 51 }
配置成功:
【JS接口安全域名】
域名:想调用jssdk(如想要通过微信公众号js接口获取地图等工具)必须得填写此域名,在此域名的范围内才能调用jssdk工具,注意这里必须是域名(IP),不是带有http之类的URL
【测试号二维码】
里面包含了测试号二维码以及已经关注了的用户信息(微信号扫码)
【体验接口权限表】
有很多权限可以使用如下:
这里主要介绍【网页服务】里面的【网页帐号】
网页帐号主要用来设置OAuth2.0里面的网页授权域名,用户在网页授权页同意授权给公众号后,微信会将授权数据传给一个回调页面,回调页面需在此域名下,以确保安全可靠。沙盒号回调地址支持域名和ip,正式公众号回调地址只支持域名。
2.获取关注此公众号的用户信息(修改后记得重新打包上传到服务器):
2.1【WechatLoginController】主要用来获取已关注此微信号的用户信息并做相应处理
1 package com.swpu.o2o.web.wechat; 2 3 import java.io.IOException; 4 5 import javax.servlet.http.HttpServletRequest; 6 import javax.servlet.http.HttpServletResponse; 7 8 import org.slf4j.Logger; 9 import org.slf4j.LoggerFactory; 10 import org.springframework.stereotype.Controller; 11 import org.springframework.web.bind.annotation.RequestMapping; 12 import org.springframework.web.bind.annotation.RequestMethod; 13 14 import com.swpu.o2o.dto.UserAccessToken; 15 import com.swpu.o2o.dto.WechatUser; 16 import com.swpu.o2o.util.weixin.WechatUtil; 17 18 @Controller 19 @RequestMapping("wechatlogin") 20 /** 21 * 获取关注公众号之后的微信用户信息的接口,如果在微信浏览器里访问 22 * 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 23 * 则这里将会获取到code,之后再可以通过code获取到access_token 进而获取到用户信息 24 * 25 * 26 */ 27 public class WechatLoginController { 28 29 private static Logger log = LoggerFactory.getLogger(WechatLoginController.class); 30 31 @RequestMapping(value = "/logincheck", method = { RequestMethod.GET }) 32 public String doGet(HttpServletRequest request, HttpServletResponse response) { 33 log.debug("weixin login get..."); 34 // 获取微信公众号传输过来的code,通过code可获取access_token,进而获取用户信息 35 String code = request.getParameter("code"); 36 // 这个state可以用来传我们自定义的信息,方便程序调用,这里也可以不用 37 // String roleType = request.getParameter("state"); 38 log.debug("weixin login code:" + code); 39 WechatUser user = null; 40 String openId = null; 41 if (null != code) { 42 UserAccessToken token; 43 try { 44 // 通过code获取access_token 45 token = WechatUtil.getUserAccessToken(code); 46 log.debug("weixin login token:" + token.toString()); 47 // 通过token获取accessToken 48 String accessToken = token.getAccessToken(); 49 // 通过token获取openId 50 openId = token.getOpenId(); 51 // 通过access_token和openId获取用户昵称等信息 52 user = WechatUtil.getUserInfo(accessToken, openId); 53 log.debug("weixin login user:" + user.toString()); 54 request.getSession().setAttribute("openId", openId); 55 } catch (IOException e) { 56 log.error("error in getUserAccessToken or getUserInfo or findByOpenId: " + e.toString()); 57 e.printStackTrace(); 58 } 59 } 60 // ======todo begin====== 61 // 前面咱们获取到openId后,可以通过它去数据库判断该微信帐号是否在我们网站里有对应的帐号了, 62 // 没有的话这里可以自动创建上,直接实现微信与咱们网站的无缝对接。 63 // ======todo end====== 64 if (user != null) { 65 // 获取到微信验证的信息后返回到指定的路由(需要自己设定) 66 return "frontend/index"; 67 } else { 68 return null; 69 } 70 } 71 }
2.1.1用户信息表及Dao层:
1 package com.swpu.o2o.entity; 2 3 import java.util.Date; 4 5 public class PersonInfo { 6 /* 7 * 用户信息表 8 */ 9 private Long userId; 10 private String name; 11 private String profileImg; 12 private String email; 13 private String gender; 14 private Integer enableStatus; 15 // 1.顾客 2.店家 3.超级管理员 16 private Integer userType; 17 public Long getUserId() { 18 return userId; 19 } 20 public void setUserId(Long userId) { 21 this.userId = userId; 22 } 23 public String getName() { 24 return name; 25 } 26 public void setName(String name) { 27 this.name = name; 28 } 29 public String getProfileImg() { 30 return profileImg; 31 } 32 public void setProfileImg(String profileImg) { 33 this.profileImg = profileImg; 34 } 35 public String getEmail() { 36 return email; 37 } 38 public void setEmail(String email) { 39 this.email = email; 40 } 41 public String getGender() { 42 return gender; 43 } 44 public void setGender(String gender) { 45 this.gender = gender; 46 } 47 public Integer getEnableStatus() { 48 return enableStatus; 49 } 50 public void setEnableStatus(Integer enableStatus) { 51 this.enableStatus = enableStatus; 52 } 53 public Integer getUserType() { 54 return userType; 55 } 56 public void setUserType(Integer userType) { 57 this.userType = userType; 58 } 59 public Date getCreateTime() { 60 return createTime; 61 } 62 public void setCreateTime(Date createTime) { 63 this.createTime = createTime; 64 } 65 public Date getLastEditTime() { 66 return lastEditTime; 67 } 68 public void setLastEditTime(Date lastEditTime) { 69 this.lastEditTime = lastEditTime; 70 } 71 private Date createTime; 72 private Date lastEditTime; 73 74 }
1 package com.swpu.o2o.dao; 2 3 import com.swpu.o2o.entity.PersonInfo; 4 5 public interface PersonInfoDao { 6 /** 7 * 通过用户Id查询用户 8 * @param userId 9 * @return 10 */ 11 PersonInfo queryPersonInfoById(long userId); 12 /** 13 * 添加新用户 14 * @param personInfo 15 * @return 16 */ 17 int insertPersonInfo(PersonInfo personInfo); 18 }
2.1.2微信相关信息表Dao层:
1 package com.swpu.o2o.entity; 2 3 import java.util.Date; 4 5 public class WechatAuth { 6 /* 7 * 微信登录表 8 */ 9 private Long wechatAuthId; 10 private String openId; 11 private Date createTime; 12 private PersonInfo personInfo; 13 private Long userId; 14 public Long getWechatAuthId() { 15 return wechatAuthId; 16 } 17 public void setWechatAuthId(Long wechatAuthId) { 18 this.wechatAuthId = wechatAuthId; 19 } 20 public String getOpenId() { 21 return openId; 22 } 23 public void setOpenId(String openId) { 24 this.openId = openId; 25 } 26 public Date getCreateTime() { 27 return createTime; 28 } 29 public void setCreateTime(Date createTime) { 30 this.createTime = createTime; 31 } 32 public PersonInfo getPersonInfo() { 33 return personInfo; 34 } 35 public void setPersonInfo(PersonInfo personInfo) { 36 this.personInfo = personInfo; 37 } 38 public Long getUserId() { 39 return userId; 40 } 41 public void setUserId(Long userId) { 42 this.userId = userId; 43 } 44 }
1 package com.swpu.o2o.dao; 2 3 import com.swpu.o2o.entity.WechatAuth; 4 5 public interface WechatAuthDao { 6 /** 7 * 通过openId查询对应本平台的微信号 8 * @param openId 9 * @return 10 */ 11 WechatAuth queryWechatInfoByOpenId(String openId); 12 /** 13 * 添加对应本平台的微信号 14 * @param wechatAuth 15 * @return 16 */ 17 int insertWechatAuth(WechatAuth wechatAuth); 18 }
2.1.3用户信息接口,微信信息接口对应Mybatis:
用户:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <!DOCTYPE mapper 3 PUBLIC "-//mybatis.org//DTD Config 3.0//EN" 4 "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> 5 <mapper namespace="com.swpu.o2o.dao.PersonInfoDao"> 6 <select id="queryPersonInfoById" resultType="com.swpu.o2o.entity.PersonInfo" 7 parameterType="Long"> 8 SELECT 9 user_id,name,gender,email,profile_img,enable_status,user_type,create_time,last_edit_time 10 FROM tb_person_info where user_id=#{userId} 11 </select> 12 <insert id="insertPersonInfo" parameterType="com.swpu.o2o.entity.PersonInfo" 13 useGeneratedKeys="true" keyProperty="userId" keyColumn="user_id"> 14 INSERT INTO 15 tb_person_info(name,gender,email,profile_img,user_type,create_time,last_edit_time,enable_status) 16 VALUES(#{name},#{gender},#{email},#{profileImg},#{userType},#{createTime},#{lastEditTime},#{enableStatus}) 17 18 </insert> 19 </mapper>
微信信息:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <!DOCTYPE mapper 3 PUBLIC "-//mybatis.org//DTD Config 3.0//EN" 4 "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> 5 <mapper namespace="com.swpu.o2o.dao.WechatAuthDao"> 6 <resultMap id="wechatAuthResultMap" type="com.swpu.o2o.entity.WechatAuth"> 7 <id property="wechatAuthId" column="wechat_auth_id" /> 8 <result property="userId" column="user_id" /> 9 <result property="openId" column="open_id" /> 10 <result property="createTime" column="create_time" /> 11 <association property="personInfo" column="user_id" 12 javaType="com.swpu.o2o.entity.PersonInfo"> 13 <id property="userId" column="user_id" /> 14 <result property="name" column="name" /> 15 <result property="gender" column="gender" /> 16 <result property="phone" column="phone" /> 17 <result property="email" column="email" /> 18 <result property="createTime" column="create_time" /> 19 <result property="lastEditTime" column="last_edit_time" /> 20 <result property="enableStatus" column="enable_status" /> 21 </association> 22 </resultMap> 23 <select id="queryWechatInfoByOpenId" parameterType="String" 24 resultMap="wechatAuthResultMap"> SELECT w.wechat_auth_id, w.user_id, w.open_id, 25 w.create_time, p.user_id, p.name, p.gender, 26 p.email, p.profile_img, p.create_time, p.last_edit_time, p.enable_status FROM 27 tb_wechat_auth w LEFT JOIN tb_person_info p ON w.user_id = p.user_id 28 WHERE w.open_id = #{openId} 29 </select> 30 <insert id="insertWechatAuth" parameterType="com.swpu.o2o.entity.WechatAuth" 31 keyColumn="wechat_auth_id" keyProperty="wechatAuthId" 32 useGeneratedKeys="true"> INSERT INTO 33 tb_wechat_auth(user_id,open_id,create_time) VALUES 34 (#{userId},#{openId},#{createTime}) 35 </insert> 36 <delete id="deleteWechatAuth"> DELETE FROM tb_wechat_auth WHERE wechat_auth_id = 37 #{wechatAuthId} 38 </delete> 39 </mapper>
2.2【UserAccessToken】用户AccessToken实体类,用来接收accesstoken以及openid等信息
1 package com.swpu.o2o.dto; 2 3 import com.fasterxml.jackson.annotation.JsonProperty; 4 5 /** 6 * 用户授权token 7 * 8 * 9 */ 10 public class UserAccessToken { 11 12 // 获取到的凭证 13 @JsonProperty("access_token") 14 private String accessToken; 15 // 凭证有效时间,单位:秒 16 @JsonProperty("expires_in") 17 private String expiresIn; 18 // 表示更新令牌,用来获取下一次的访问令牌,这里没太大用处 19 @JsonProperty("refresh_token") 20 private String refreshToken; 21 // 该用户在此公众号下的身份标识,对于此微信号具有唯一性 22 @JsonProperty("openid") 23 private String openId; 24 // 表示权限范围,这里可省略 25 @JsonProperty("scope") 26 private String scope; 27 28 public String getAccessToken() { 29 return accessToken; 30 } 31 32 public void setAccessToken(String accessToken) { 33 this.accessToken = accessToken; 34 } 35 36 public String getExpiresIn() { 37 return expiresIn; 38 } 39 40 public void setExpiresIn(String expiresIn) { 41 this.expiresIn = expiresIn; 42 } 43 44 public String getRefreshToken() { 45 return refreshToken; 46 } 47 48 public void setRefreshToken(String refreshToken) { 49 this.refreshToken = refreshToken; 50 } 51 52 public String getOpenId() { 53 return openId; 54 } 55 56 public void setOpenId(String openId) { 57 this.openId = openId; 58 } 59 60 public String getScope() { 61 return scope; 62 } 63 64 public void setScope(String scope) { 65 this.scope = scope; 66 } 67 68 @Override 69 public String toString() { 70 return "accessToken:" + this.getAccessToken() + ",openId:" + this.getOpenId(); 71 } 72 73 }
2.3【WechatUser】微信用户实体类,用来接收昵称 openid等用户信息
1 package com.swpu.o2o.dto; 2 import com.fasterxml.jackson.annotation.JsonProperty; 3 import java.io.Serializable; 4 5 /** 6 * 微信用户实体类 7 * 8 * @author xiangze 9 * 10 */ 11 public class WechatUser implements Serializable { 12 13 /** 14 * 15 */ 16 private static final long serialVersionUID = -4684067645282292327L; 17 18 // openId,标识该公众号下面的该用户的唯一Id 19 @JsonProperty("openid") 20 private String openId; 21 // 用户昵称 22 @JsonProperty("nickname") 23 private String nickName; 24 // 性别 25 @JsonProperty("sex") 26 private int sex; 27 // 省份 28 @JsonProperty("province") 29 private String province; 30 // 城市 31 @JsonProperty("city") 32 private String city; 33 // 区 34 @JsonProperty("country") 35 private String country; 36 // 头像图片地址 37 @JsonProperty("headimgurl") 38 private String headimgurl; 39 // 语言 40 @JsonProperty("language") 41 private String language; 42 // 用户权限,这里没什么作用 43 @JsonProperty("privilege") 44 private String[] privilege; 45 46 public String getOpenId() { 47 return openId; 48 } 49 50 public void setOpenId(String openId) { 51 this.openId = openId; 52 } 53 54 public String getNickName() { 55 return nickName; 56 } 57 58 public void setNickName(String nickName) { 59 this.nickName = nickName; 60 } 61 62 public int getSex() { 63 return sex; 64 } 65 66 public void setSex(int sex) { 67 this.sex = sex; 68 } 69 70 public String getProvince() { 71 return province; 72 } 73 74 public void setProvince(String province) { 75 this.province = province; 76 } 77 78 public String getCity() { 79 return city; 80 } 81 82 public void setCity(String city) { 83 this.city = city; 84 } 85 86 public String getCountry() { 87 return country; 88 } 89 90 public void setCountry(String country) { 91 this.country = country; 92 } 93 94 public String getHeadimgurl() { 95 return headimgurl; 96 } 97 98 public void setHeadimgurl(String headimgurl) { 99 this.headimgurl = headimgurl; 100 } 101 102 public String getLanguage() { 103 return language; 104 } 105 106 public void setLanguage(String language) { 107 this.language = language; 108 } 109 110 public String[] getPrivilege() { 111 return privilege; 112 } 113 114 public void setPrivilege(String[] privilege) { 115 this.privilege = privilege; 116 } 117 118 @Override 119 public String toString() { 120 return "openId:" + this.getOpenId() + ",nikename:" + this.getNickName(); 121 } 122 }
2.4【WechatUtil】主要用来提交https请求给微信获取用户信息
1 package com.swpu.o2o.util.weixin; 2 3 import java.io.BufferedReader; 4 import java.io.IOException; 5 import java.io.InputStream; 6 import java.io.InputStreamReader; 7 import java.io.OutputStream; 8 import java.net.ConnectException; 9 import java.net.URL; 10 11 import javax.net.ssl.HttpsURLConnection; 12 import javax.net.ssl.SSLContext; 13 import javax.net.ssl.SSLSocketFactory; 14 import javax.net.ssl.TrustManager; 15 16 import org.slf4j.Logger; 17 import org.slf4j.LoggerFactory; 18 19 import com.fasterxml.jackson.core.JsonParseException; 20 import com.fasterxml.jackson.databind.JsonMappingException; 21 import com.fasterxml.jackson.databind.ObjectMapper; 22 import com.swpu.o2o.dto.UserAccessToken; 23 import com.swpu.o2o.dto.WechatUser; 24 25 /** 26 * 微信工具类 27 * 28 */ 29 public class WechatUtil { 30 31 private static Logger log = LoggerFactory.getLogger(WechatUtil.class); 32 33 /** 34 * 获取UserAccessToken实体类 35 * 36 * @param code 37 * @return 38 * @throws IOException 39 */ 40 public static UserAccessToken getUserAccessToken(String code) throws IOException { 41 // 测试号信息里的appId 42 String appId = "您的appId"; 43 log.debug("appId:" + appId); 44 // 测试号信息里的appsecret 45 String appsecret = "您的appsecret"; 46 log.debug("secret:" + appsecret); 47 // 根据传入的code,拼接出访问微信定义好的接口的URL 48 String url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=" + appId + "&secret=" + appsecret 49 + "&code=" + code + "&grant_type=authorization_code"; 50 // 向相应URL发送请求获取token json字符串 51 String tokenStr = httpsRequest(url, "GET", null); 52 log.debug("userAccessToken:" + tokenStr); 53 UserAccessToken token = new UserAccessToken(); 54 ObjectMapper objectMapper = new ObjectMapper(); 55 try { 56 // 将json字符串转换成相应对象 57 token = objectMapper.readValue(tokenStr, UserAccessToken.class); 58 } catch (JsonParseException e) { 59 log.error("获取用户accessToken失败: " + e.getMessage()); 60 e.printStackTrace(); 61 } catch (JsonMappingException e) { 62 log.error("获取用户accessToken失败: " + e.getMessage()); 63 e.printStackTrace(); 64 } catch (IOException e) { 65 log.error("获取用户accessToken失败: " + e.getMessage()); 66 e.printStackTrace(); 67 } 68 if (token == null) { 69 log.error("获取用户accessToken失败。"); 70 return null; 71 } 72 return token; 73 } 74 75 /** 76 * 获取WechatUser实体类 77 * 78 * @param accessToken 79 * @param openId 80 * @return 81 */ 82 public static WechatUser getUserInfo(String accessToken, String openId) { 83 // 根据传入的accessToken以及openId拼接出访问微信定义的端口并获取用户信息的URL 84 String url = "https://api.weixin.qq.com/sns/userinfo?access_token=" + accessToken + "&openid=" + openId 85 + "&lang=zh_CN"; 86 // 访问该URL获取用户信息json 字符串 87 String userStr = httpsRequest(url, "GET", null); 88 log.debug("user info :" + userStr); 89 WechatUser user = new WechatUser(); 90 ObjectMapper objectMapper = new ObjectMapper(); 91 try { 92 // 将json字符串转换成相应对象 93 user = objectMapper.readValue(userStr, WechatUser.class); 94 } catch (JsonParseException e) { 95 log.error("获取用户信息失败: " + e.getMessage()); 96 e.printStackTrace(); 97 } catch (JsonMappingException e) { 98 log.error("获取用户信息失败: " + e.getMessage()); 99 e.printStackTrace(); 100 } catch (IOException e) { 101 log.error("获取用户信息失败: " + e.getMessage()); 102 e.printStackTrace(); 103 } 104 if (user == null) { 105 log.error("获取用户信息失败。"); 106 return null; 107 } 108 return user; 109 } 110 111 /** 112 * 发起https请求并获取结果 113 * 114 * @param requestUrl 115 * 请求地址 116 * @param requestMethod 117 * 请求方式(GET、POST) 118 * @param outputStr 119 * 提交的数据 120 * @return json字符串 121 */ 122 public static String httpsRequest(String requestUrl, String requestMethod, String outputStr) { 123 StringBuffer buffer = new StringBuffer(); 124 try { 125 // 创建SSLContext对象,并使用我们指定的信任管理器初始化 126 TrustManager[] tm = { new MyX509TrustManager() }; 127 SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE"); 128 sslContext.init(null, tm, new java.security.SecureRandom()); 129 // 从上述SSLContext对象中得到SSLSocketFactory对象 130 SSLSocketFactory ssf = sslContext.getSocketFactory(); 131 132 URL url = new URL(requestUrl); 133 HttpsURLConnection httpUrlConn = (HttpsURLConnection) url.openConnection(); 134 httpUrlConn.setSSLSocketFactory(ssf); 135 136 httpUrlConn.setDoOutput(true); 137 httpUrlConn.setDoInput(true); 138 httpUrlConn.setUseCaches(false); 139 // 设置请求方式(GET/POST) 140 httpUrlConn.setRequestMethod(requestMethod); 141 142 if ("GET".equalsIgnoreCase(requestMethod)) 143 httpUrlConn.connect(); 144 145 // 当有数据需要提交时 146 if (null != outputStr) { 147 OutputStream outputStream = httpUrlConn.getOutputStream(); 148 // 注意编码格式,防止中文乱码 149 outputStream.write(outputStr.getBytes("UTF-8")); 150 outputStream.close(); 151 } 152 153 // 将返回的输入流转换成字符串 154 InputStream inputStream = httpUrlConn.getInputStream(); 155 InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8"); 156 BufferedReader bufferedReader = new BufferedReader(inputStreamReader); 157 158 String str = null; 159 while ((str = bufferedReader.readLine()) != null) { 160 buffer.append(str); 161 } 162 bufferedReader.close(); 163 inputStreamReader.close(); 164 // 释放资源 165 inputStream.close(); 166 inputStream = null; 167 httpUrlConn.disconnect(); 168 log.debug("https buffer:" + buffer.toString()); 169 } catch (ConnectException ce) { 170 log.error("Weixin server connection timed out."); 171 } catch (Exception e) { 172 log.error("https request error:{}", e); 173 } 174 return buffer.toString(); 175 } 176 }
2.5【MyX509TrustManager】主要继承X509TrustManager做https证书信任管理器
1 package com.swpu.o2o.util.weixin; 2 3 import java.security.cert.CertificateException; 4 import java.security.cert.X509Certificate; 5 6 import javax.net.ssl.X509TrustManager; 7 8 /** 9 * 证书信任管理器(用于https请求) 10 * 11 * 12 */ 13 public class MyX509TrustManager implements X509TrustManager { 14 15 public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { 16 } 17 18 public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { 19 } 20 21 public X509Certificate[] getAcceptedIssuers() { 22 return null; 23 } 24 }
3.测试:
3.1到https://developers.weixin.qq.com/miniprogram/dev/devtools/download.html下载对应版本的测试工具:
3.2使用测试工具:
输入网址测试成功:
https://open.weixin.qq.com/connect/oauth2/authorizeappid=你的app_id&redirect_uri=你的网址接口&role_type=1&response_type=code&scope=snsapi_userinfo&state=1#wechat_redirect
查看Tomcat日志获取到相关信息:./apache-tomcat-8.5.41/logs/webapps/debug.log