JAVA微信公众号网页开发 —— 用户授权获取openid和用户微信信息
官方文档:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140842
HttpClientUtil.java
package com.test; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.net.MalformedURLException; import java.net.URI; import java.net.URL; import java.net.URLConnection; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; import org.apache.commons.lang.StringUtils; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.StatusLine; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.HttpClient; import org.apache.http.client.HttpResponseException; import org.apache.http.client.ResponseHandler; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.impl.client.HttpClients; import org.apache.http.util.EntityUtils; public class HttpClientUtil { private static class SingletonHolder{ private final static HttpClientUtil INSTANCE=new HttpClientUtil(); } private HttpClientUtil(){} public static HttpClientUtil getInstance(){ return SingletonHolder.INSTANCE; } public String get(String url){ CharsetHandler handler = new CharsetHandler("UTF-8"); CloseableHttpClient client = null; try { HttpGet httpget = new HttpGet(new URI(url)); HttpClientBuilder httpClientBuilder = HttpClientBuilder.create(); client= httpClientBuilder.build(); client = (CloseableHttpClient) wrapClient(client); return client.execute(httpget, handler); } catch (Exception e) { //e.printStackTrace(); return ""; }finally { try { if(client!=null){ client.close(); } } catch (IOException e) { e.printStackTrace(); } } } public static String post(String url, String params,String contentType) { //创建HttpClientBuilder HttpClientBuilder httpClientBuilder = HttpClientBuilder.create(); //HttpClient CloseableHttpClient client = httpClientBuilder.build(); client = (CloseableHttpClient) wrapClient(client); HttpPost post = new HttpPost(url); CloseableHttpResponse res = null; try { StringEntity s = new StringEntity(params,"UTF-8"); if(StringUtils.isBlank(contentType)){ s.setContentType("application/json"); } s.setContentType(contentType); s.setContentEncoding("utf-8"); post.setEntity(s); res = client.execute(post); HttpEntity entity = res.getEntity(); return EntityUtils.toString(entity, "utf-8"); } catch (Exception e) { e.printStackTrace(); } finally { try { res.close(); client.close(); } catch (IOException e) { e.printStackTrace(); } } return ""; } public static String post(String urlStr,String xmlInfo) { String line1 = ""; try { URL url = new URL(urlStr); URLConnection con = url.openConnection(); con.setDoOutput(true); //con.setRequestProperty("Pragma:", "no-cache"); con.setRequestProperty("Cache-Control", "no-cache"); con.setRequestProperty("Content-Type", "text/xml"); OutputStreamWriter out = new OutputStreamWriter(con .getOutputStream()); out.write(new String(xmlInfo.getBytes("utf-8"))); out.flush(); out.close(); BufferedReader br = new BufferedReader(new InputStreamReader(con .getInputStream())); String line = ""; for (line = br.readLine(); line != null; line = br.readLine()) { line1+=line; } return new String(line1.getBytes(),"utf-8"); } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return null; } private class CharsetHandler implements ResponseHandler<String> { private String charset; public CharsetHandler(String charset) { this.charset = charset; } public String handleResponse(HttpResponse response) throws ClientProtocolException, IOException { StatusLine statusLine = response.getStatusLine(); if (statusLine.getStatusCode() >= 300) { throw new HttpResponseException(statusLine.getStatusCode(), statusLine.getReasonPhrase()); } HttpEntity entity = response.getEntity(); if (entity != null) { if (!StringUtils.isBlank(charset)) { return EntityUtils.toString(entity, charset); } else { return EntityUtils.toString(entity); } } else { return null; } } } private static HttpClient wrapClient(HttpClient base) { try { SSLContext ctx = SSLContext.getInstance("TLSv1"); X509TrustManager tm = new X509TrustManager() { public void checkClientTrusted(X509Certificate[] xcs, String string) throws CertificateException { } public void checkServerTrusted(X509Certificate[] xcs, String string) throws CertificateException { } public X509Certificate[] getAcceptedIssuers() { return null; } }; ctx.init(null, new TrustManager[] { tm }, null); SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(ctx, new String[] { "TLSv1" }, null, SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER); CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build(); return httpclient; } catch (Exception ex) { return null; } } }
(注:获取到的code只能使用一次,每次请求都要重新获取一次code,因此以下方法,如果用户重新刷新了页面,就会报错,建议把使用过的code放在缓存中,每次请求接口前判断code是否已经使用,如果使用了就重新获取code去请求接口)
MessageAct.java 控制器类
import com.redis.RedisService; import org.apache.commons.lang.StringUtils; import org.json.JSONException; import org.json.JSONObject; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.ModelMap; import org.springframework.web.bind.annotation.RequestMapping; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; import java.net.URLEncoder; @Controller public class MessageAct { private String appid="公众号的APP_ID"; private String secret="公众号的APP_SECRET"; /** * redis注入,这里可以根据自己的来 */ @Autowired private RedisService redisService; /** * 微信登录 * * @param code * @param redirectUrl 返回用户的登录地址 * @param request * @param response * @param model * @return * @throws IOException */ @RequestMapping(value = "/weixinLogin") public String weixinLogin(String code, String redirectUrl, HttpServletRequest request, HttpServletResponse response, ModelMap model) throws IOException { String redirect_uri = "redirectUrl是授权登录后要进行跳转的链接"; //-----在这里判断code是否已经存在于缓存中,如果存在,说明code已经使用过,需要重新获取code------ Object o = redisService.get(code); if (StringUtils.isNotBlank(code) && o!=null) { //用过了 code = ""; } //获取code if (StringUtils.isBlank(code)) { try { PrintWriter out = response.getWriter(); out.println("<script>window.location.href='" + getCodeUrl(redirect_uri) + "'</script>"); out.flush(); out.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } return null; } String[] s = getOpenId(code); String openId = s[0]; String accessToken = s[1]; //获取用户信息 String[] userInfo = getUserInfo(openId, accessToken); System.out.println("手机登录openId=================================>" + openId); //查询用户是否存在,openId 作为查询条件 User user = userMng.findById(openId); if (user != null) { //用户已经存在 } else { //用户不存在,进行注册操作 } return "redirect:" + redirectUrl; } /** * 获取用户授权 得到openId,accessToken * * @param code * @return */ public String[] getOpenId(String code) { String tokenUrl = "https://api.weixin.qq.com/sns/oauth2/access_token?grant_type=authorization_code"; tokenUrl = tokenUrl + "&appid=" + appid + "&secret=" + secret + "&code=" + code; JSONObject json = null; try { json = new JSONObject(HttpClientUtil.getInstance().get(tokenUrl)); //------------在这里把使用过的code存入到缓存中,我这里使用的是redis-------- redisService.set(code,""); } catch (JSONException e2) { e2.printStackTrace(); } String openId = ""; String accessToken = ""; String[] s = new String[2]; if (json != null) { try { openId = json.getString("openid"); accessToken = json.getString("access_token"); s[0] = openId; s[1] = accessToken; } catch (JSONException e) { String errcode = null; try { errcode = json.getString("errcode"); System.out.println("errcode================>手机登录 获取用户授权失败" + errcode); } catch (JSONException e1) { e1.printStackTrace(); } } } return s; } /** * 获取用户信息 拉取用户信息(需scope为 snsapi_userinfo) * 只有在用户将公众号绑定到微信开放平台帐号后,可以获取unionid * * @param * @param * @return */ public String[] getUserInfo(String openid, String accessToken) { String userInfoUrl = "https://api.weixin.qq.com/sns/userinfo?lang=zh_CN"; userInfoUrl = userInfoUrl + "&access_token=" + accessToken + "&openid=" + openid; JSONObject json = null; try { json = new JSONObject(HttpClientUtil.getInstance().get(userInfoUrl)); } catch (JSONException e2) { e2.printStackTrace(); } String nickname = ""; //用户昵称 String sex = ""; //用户的性别 String province = ""; //用户个人资料填写的省份 String city = ""; //普通用户个人资料填写的城市 String country = ""; //国家,如中国为CN String headimgurl = ""; //用户头像, String unionid = ""; // String[] s = new String[6]; if (json != null) { try { nickname = json.getString("nickname"); sex = json.getString("sex"); province = json.getString("province"); city = json.getString("city"); country = json.getString("country"); headimgurl = json.getString("headimgurl"); s[0] = nickname; s[1] = sex; s[2] = province; s[3] = city; s[4] = country; s[5] = headimgurl; } catch (JSONException e) { String errcode = null; try { errcode = json.getString("errcode"); System.out.println("errcode================>获取用户信息失败" + errcode); } catch (JSONException e1) { e1.printStackTrace(); } } } return s; } /** * 获取code请求地址 * * @param redirect_uri 回调地址 这个回调地址需要在微信公众号后台也进行配置 不然会显示"redirect_uri域名还是与后台配置不一致" * @param * @return */ public String getCodeUrl(String redirect_uri) { redirect_uri= URLEncoder.encode(redirect_uri); //使用 urlEncode 对链接进行处理 String codeUrl = "https://open.weixin.qq.com/connect/oauth2/authorize"; codeUrl = codeUrl + "?appid=" + appid + "&redirect_uri=" + redirect_uri + "&response_type=code&scope=snsapi_userinfo&state=jetcms#wechat_redirect"; return codeUrl; } }
-----------------------有任何问题可以在评论区评论,也可以私信我,我看到的话会进行回复,欢迎大家指教------------------------
(蓝奏云官网有些地址失效了,需要把请求地址lanzous改成lanzoux才可以)