微信公众号开发--第二章 获取用户信息

前言:本文主要内容是微信后端逻辑。

前言:本项目前端用vue,微信后端用ssm,后台用ssm。后端主要处理与微信的交互,转发入参给后台,接收后台给的出参,转发出参给前端。后台是真正涉及业务的。

前言:本文依据的项目,前端后端在本地启动,后台部署在linux服务器上。后端通过拼接接口路径访问后台。部署配置,详情见第一章。

微信公众号开发–第二章 获取用户信息

一、页面操作

1、本地启动前后端后,在微信开发者工具上,输入超链接local.test.com:8989。

2、页面自动进入授权页面
在这里插入图片描述

​ 若没有跳到授权链接,报redirect_uri参数错误,返回码是10003,应该是回调地址写错了,参考第一章的配置的授权回调页面域名。

​ 微信授权机制,详情请参考官方文档https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html

3、点击同意,获取code,进入公众号首页
在这里插入图片描述
​ 前端请求头Request Headers会封装进后端入参HttpServletRequest request。客户端浏览器发出的请求被封装成为一个HttpServletRequest对象。对象包含了客户端请求信息包括请求的地址,请求的参数,提交的数据,上传的文件客户端的ip甚至客户端操作系统都包含在其内。

​ 前端请求参数body,对应后端入参UserBean bean,由@RequestBody自动装配。

二、微信后端逻辑

​ 1、获取前端传来的code。请求https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code获取access_token和openid。

​ 2、根据access_token和openid,请求https://api.weixin.qq.com/sns/userinfo?access_token=TOKEN&openid=OPENID&lang=zh_CN拉取用户信息。

​ 3、根据用户信息,判断用户是否关注了公众号。没有关注,则返回error并提示用户关注。若关注了进行第4步。

​ 4、从后台拿到tokenid,tokenid其实就是后台redis的key。

​ 5、根据tokenid,在后端生成redis的key和value,使后端的value和tokenid相同。这样后端就能方便地调用后台接口。

三、微信后端代码

接口定义
/**
 * 通过code获取用户信息
 * @param request
 * @return 返回用户信息
 * @throws Exception
 */
@RequestMapping(value = "/getUserInfo", method = RequestMethod.POST)
@ResponseBody
public Result getUserInfo(@RequestBody UserBean bean, HttpServletRequest request)
      throws Exception {}
接口入参
public class UserBean {
   private String tokenid;// 权限验证码,对应后台redis的key
   private String channelcode;// 渠道
   private String accountName;// 用户名
   private String accountPwd;// 密码
   private String openid;// 微信openid
   private String code;// 微信网页授权中获取的code
}

javax.servlet.http.HttpServletRequest
方法:根据code,获取access_token和openid
//网页授权授权地址
private final String oauthApiURL = "https://api.weixin.qq.com/sns";

/**
* 方法:根据code,获取access_token和openid
* @param code
* @return result
* result包括access_token、expires_in、efresh_token、openid和scope
* appid、appSecret 是测试号信息,详见第一章
*/
public JSONObject getUserInfoAuth(String code) {
	String apiUrl = oauthApiURL+ "/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code";
	apiUrl = apiUrl.replace("APPID", appid).replace("SECRET", appSecret).replace("CODE", code);
	JSONObject result = httpRequest(apiUrl);
	if (!result.isNullObject() && result.containsKey("openid")) {
		this.access_token = result.getString("access_token");
		return result;
	} else {
		log.info("获取openid失败:code{}/errmsg:{}");
		return null;
	}
}

//方法:httpRequest()。发起https请求并获取结果。太长了,文章末尾贴出来。
方法:根据access_token和openid,拉取用户信息
/*
* 方法:根据access_token和openid,拉取用户信息
*/
public JSONObject getUserInfoByOpenid(String accessToken, String openid) {
   String apiUrl = oauthApiURL + "/userinfo?access_token=TOKEN&openid=OPENID&lang=zh_CN";
   apiUrl = apiUrl.replace("TOKEN", accessToken).replace("OPENID", openid);
   JSONObject res = httpRequest(apiUrl);
   if (!res.isNullObject() && res.containsKey("openid")) {
      return res;
   } else {
      return null;
   }
}
方法:设置redis

从后台拿到tokenid,tokenid其实就是后台redis的key。

然后,根据tokenid,在后端生成redis的key和value

/**
 * 方法:从后台拿到tokenid,tokenid其实就是后台redis的key。然后,根据tokenid,在后端生成redis的key	和value。
 * 备注:入参sessionId,设为key的前缀
 */
public Result login(UserBean bean, String sessionId) {
   String url = "http://balabala/bala/bala/bala/checkLogin";//后台登录接口路径
    
   JSONObject jsonData = new JSONObject();
   jsonData.put("channelcode", bean.getChannelcode());
   jsonData.put("username", bean.getAccountName());
   jsonData.put("password", bean.getAccountPwd());
    
   String result = (String) getWebClient(url, jsonData, String.class);//调后台接口
    
   JSONObject jsonResult = Common.strToJSONObject(result);
   if (null == jsonResult) {
      return error("接口请求错误");
   }
   String statusCode = jsonResult.getString("statusCode");
   if (statusCode.equals("200")) {
      try {
          //在后端生成redis的key和value。value设成跟tokenid一样
         JedisUtil.setValue(sessionId + "_tokenid", jsonResult.getString("data"));
      } catch (Exception e) {
         e.printStackTrace();
      }
   }
   return result(statusCode, jsonResult.getString("message"), jsonResult.get("data"));
}


/*
* 方法:调后台接口
* 备注:ClientConfig、Client、WebResource、ClientResponse,都是包com.sun.jersey.api.client里的
*/
public static Object getWebClient(String url, JSONObject json, Class<?> resultClass) {
    ClientConfig cc = new DefaultClientConfig();
	Client client = Client.create(cc);
	WebResource webResource = client.resource(url);
    //javax.ws.rs.core.MediaType
	ClientResponse response = webResource.accept(MediaType.APPLICATION_JSON_TYPE)
.type(MediaType.APPLICATION_JSON_TYPE).post(ClientResponse.class, json.toString());
	client.destroy();
	return response.getEntity(resultClass);
}

/**
* 方法:redis,设置key和value
* 备注:JedisPool、Jedis都是包redis.clients.jedis里的
*/
public static void setValue(String key, String value, Integer outTime)
			throws Exception {
	JedisPool publicJedisPool = null;
	Jedis publicJedis = null;
	try {
		publicJedisPool = DataBase.getJedisPublicPool();
		publicJedis = publicJedisPool.getResource();
		publicJedis.setex(key, 60 * outTime, value);
	} catch (Exception e) {
		if (publicJedisPool != null) {
		publicJedisPool.returnBrokenResource(publicJedis);
	}
	throw new Exception("设置redis失败: key:" + key + ",value:" + value, e);
	} finally {
		if (publicJedis != null) {
		publicJedisPool.returnResource(publicJedis);
		}
	}
}

//方法:根据code,获取access_token和openid。里用的。

/*
* 用到javax.net.ssl.HttpsURLConnection、 javax.net.ssl.SSLSocketFactory、*java.io.OutputStream、java.io.InputStream
*/

/**
 * 发起https请求并获取结果
 * 
 * @param requestUrl
 *            请求地址
 * @param requestMethod
 *            请求方式(GET、POST)
 * @param outputStr
 *            提交的数据
 * @return JSONObject(通过JSONObject.get(key)的方式获取json对象的属性值)
 */
public static JSONObject httpRequest(String requestUrl, String requestMethod, String outputStr) {
   JSONObject jsonObject = new JSONObject();
   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();
      jsonObject = JSONObject.fromObject(buffer.toString());
   } catch (ConnectException ce) {
      System.out.println("微信服务连接超时");
   } catch (Exception e) {
      System.out.println("https请求错误:" + e);
   }
   return jsonObject;
}
发布了13 篇原创文章 · 获赞 12 · 访问量 2615

猜你喜欢

转载自blog.csdn.net/Sharylala/article/details/105495723
今日推荐