主要原理:
1.从微信公众号发来的get请求为验证服务器安全性的
2.从微信公众号发来的post请求为接受和回复用户信息的
3.先根据是否有code来进行判断,如果有code的话,根据code换取openid,如果没有code的话,发送请求到微信授权页,微信授权页会带着code转发到当前的页面,然后根据code换取openid
package cn.jbolt.wx;
import java.io.InputStream;
import .URLEncoder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import mons.lang3.StringUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import com.jfinal.core.Controller;
import com.jfinal.plugin.redis.Redis;
import cn.jbolt.utils.HttpClientUtils;
import cn.jbolt.wx.model.WxReurnMap;
import net.sf.json.JSONObject;
public class wxController extends Controller {
public static String TOKEN = ""; // 这里填写自己的 token
public static String APPID = ""; // 这里填写自己的 token APPID
public static final String APPSECRET = "";
public void bind() throws Exception {
String result="";
if( getRequest().getMethod().equals("GET")) {
result= singGet();
}
if( getRequest().getMethod().equals("POST")) {
result= singPost();
}
renderJson(result);
}
public String singGet() {
String sign=getPara("signature");
String timestamp=getPara("timestamp");
String nonce=getPara("nonce");
String echostr=getPara("echostr");
List<String> list = new ArrayList<String>();
list.add(nonce);
list.add(TOKEN);
list.add(timestamp);
Collections.sort(list);
String hash = getHash(list.get(0)+list.get(1)+list.get(2), "SHA-1");
if(sign.equals(hash)){ // 验证下签名是否正确
return echostr;
}else{
return "";
}
}
public String singPost() {
HttpServletRequest request=getRequest();
try {
String url="https://open./connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect ";
String redirectUrl="/jeeplus_union/WxUnion/index.html";
url=url.replace("APPID",APPID).replace("REDIRECT_URI", redirectUrl);
String resAHref="<a href='"+url+"'>登录</a>";
System.out.println(resAHref);
Map<String,String> requestMap=parseRequest(request.getInputStream());
String responseXml="<xml><ToUserName><![CDATA["+requestMap.get("FromUserName")+"]]></ToUserName><FromUserName><![CDATA["+requestMap.get("ToUserName")+"]]></FromUserName><CreateTime>"+System.currentTimeMillis()/1000+"</CreateTime><MsgType><![CDATA[text]]></MsgType><Content><![CDATA["+resAHref+"]]></Content></xml>";
return responseXml;
}catch (Exception e) {
e.printStackTrace();
}
return "";
}
public String getHash(String source, String hashType) {
StringBuilder sb = new StringBuilder();
MessageDigest md5;
try {
md5 = MessageDigest.getInstance(hashType);
md5.update(source.getBytes());
for (byte b : md5.digest()) {
sb.append(String.format("%02x", b));
}
return sb.toString();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return null;
}
public static Map<String, String> parseRequest(InputStream in) throws DocumentException {
Map<String,String> map=new HashMap<String, String>();
SAXReader reader = new SAXReader();
Document document = reader.read(in);
Element root = document.getRootElement();
Iterator it = root.elementIterator();
while (it.hasNext()) {
Element element = (Element) it.next();
map.put(element.getName(), element.getStringValue());
}
return map;
}
//获取用户的openid
public void openid() throws Exception {
Map<String ,Object> resultMap = new HashMap<String ,Object>();
String code=getPara("code");
String reUrl=getPara("reUrl");
String openid="";
if(StringUtils.isNotEmpty(code)){
String wxUrl="https://api./sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code";
wxUrl=wxUrl.replace("APPID",APPID).replace("SECRET", APPSECRET).replace("CODE", code);
HttpClientUtils httpUtils = new HttpClientUtils();
//解析成Json格式
JSONObject jsonObject=JSONObject.fromObject(httpUtils.doGet(wxUrl));
openid = jsonObject.getString("openid");
resultMap.put("openid", openid);
Redis.use("gc_wx").setex(openid+"_access_token", 7200,jsonObject.getString("access_token"));
Redis.use("gc_wx").setex(openid+"_refresh_token", 108000,jsonObject.getString("refresh_token"));
renderJson( new WxReurnMap(1,resultMap)); //操作码2001为跳转reUrl
}else if(StringUtils.isNotEmpty(reUrl)){
resultMap.put("reUrl", "https://open./connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=snsapi_base&state=STATE#wechat_redirect".replace("APPID",APPID).replace("REDIRECT_URI",URLEncoder.encode(reUrl,"utf8")));
renderJson( new WxReurnMap(1,resultMap,2001)); //操作码2001为跳转reUrl
}
}
//获取access_token的方法
public String getAccessToken(String openid) throws Exception {
String openid_access_token= Redis.use("gc_wx").get(openid+"_access_token");
if(StringUtils.isNotEmpty(openid_access_token)) {
return openid_access_token;
}else {
String flushAccessTokenUrl="https://api./sns/oauth2/refresh_token?appid=APPID&grant_type=refresh_token&refresh_token=REFRESH_TOKEN";
String code=getPara("code");
Map<String ,Object> resultMap = new HashMap<String ,Object>();
String refresh_token= Redis.use("gc_wx").get(openid+"_refresh_token");
flushAccessTokenUrl=flushAccessTokenUrl.replace("APPID",APPID).replace("REFRESH_TOKEN", refresh_token);
HttpClientUtils httpUtils = new HttpClientUtils();
//解析成Json格式
JSONObject jsonObject=JSONObject.fromObject(httpUtils.doGet(flushAccessTokenUrl));
openid_access_token=jsonObject.getString("access_token");
Redis.use("gc_wx").setex(openid+"_access_token", 7200,openid_access_token);
}
return openid_access_token;
}
//根据openid获取头像
public void getUserInfo() throws Exception {
Map<String ,Object> resultMap = new HashMap<String ,Object>();
String openid=getPara("openid");
String access_token=getAccessToken(openid);
String wxUrl=" https://api./sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN".replace("ACCESS_TOKEN",access_token).replace("OPENID",openid);
HttpClientUtils httpUtils = new HttpClientUtils();
//解析成Json格式
JSONObject jsonObject=JSONObject.fromObject(httpUtils.doGet(wxUrl));
resultMap.put("nickname", jsonObject.getString("nickname"));
resultMap.put("language", jsonObject.getString("language"));
resultMap.put("headimgurl", jsonObject.getString("headimgurl"));
resultMap.put("province", jsonObject.getString("province"));
resultMap.put("country", jsonObject.getString("country"));
resultMap.put("headimgurl", jsonObject.getString("headimgurl"));
renderJson( new WxReurnMap(1,resultMap));
}
}
================================================================================================前端请求代码:
var wxdata = {
redirect_uri: window.location.href,
openid:"",
openid_url :function(){
return "/kejin/wxController/openid";
},
// 获取openid
get_openid : function(){
//若openid未过期,返回缓存的openid
if(localStorage.getItem("openid")!=""){
return localStorage.getItem("openid");
}
var code = $.getUrlParam('code');
$.ajax({
type : "GET",
url : wxdata.openid_url(),
data:{code:code,reUrl:wxdata.redirect_uri},
async : false,
success : function(rtnData) {
//放到缓存
console.log(rtnData);
if(rtnData.optionCode==2001){
//跳转页面
window.location.href=rtnData.data.reUrl;
}else{
var opid=rtnData.data.openid;
localStorage.setItem("openid",opid);
}
},
error : function(msg){
alert("get openid error!!! ");
}
});
}
//其他
}
================================================================================================
get-url.js:
/*获取到Url里面的参数*/
(function($) {
//只能是英文
$.getUrlParam = function(key) {
var reg = new RegExp("(^|&)" + key + "=([^&]*)(&|$)");
var r = window.location.search.substr(1).match(reg);
if(r != null) return unescape(r[2]);
return null;
}
//可以是中文,可以是英文
$.getCNUrlParam = function(key) {
// 获取参数
var url = window.location.search;
// 正则筛选地址栏
var reg = new RegExp("(^|&)" + key + "=([^&]*)(&|$)");
// 匹配目标参数
var result = url.substr(1).match(reg);
//返回参数值
return result ? decodeURIComponent(result[2]) : null;
}
})(jQuery);
================================================================================================HttpClientUtils:
package cn.jbolt.utils;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import .URL;
import .URLConnection;
public class HttpClientUtils {
public String doPost(String url, String param) {
PrintWriter out = null;
BufferedReader in = null;
String result = "";
try {
URL realUrl = new URL(url);
// 打开和URL之间的连接
URLConnection conn = realUrl.openConnection();
// 设置通用的请求属性
conn.setRequestProperty("accept", "*/*");
conn.setRequestProperty("connection", "Keep-Alive");
conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
// 发送POST请求必须设置如下两行
conn.setDoOutput(true);
conn.setDoInput(true);
// 获取URLConnection对象对应的输出流
out = new PrintWriter(conn.getOutputStream());
// 发送请求参数
out.print(param);
// flush输出流的缓冲
out.flush();
// 定义BufferedReader输入流来读取URL的响应
in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String line;
while ((line = in.readLine()) != null) {
result += line;
}
} catch (Exception e) {
System.out.println("[POST请求]向地址:" + url + " 发送数据:" + param + " 发生错误!");
} finally {// 使用finally块来关闭输出流、输入流
try {
if (out != null) {
out.close();
}
if (in != null) {
in.close();
}
} catch (IOException ex) {
System.out.println("关闭流异常");
}
}
return result;
}
public String doGet(String url) {
String result = "";
BufferedReader in = null;
try {
String urlName = url;
URL realUrl = new URL(urlName);
URLConnection conn = realUrl.openConnection();// 打开和URL之间的连接
conn.setRequestProperty("accept", "*/*");// 设置通用的请求属性
conn.setRequestProperty("connection", "Keep-Alive");
conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)");
conn.setConnectTimeout(4000);
conn.connect();// 建立实际的连接
in = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"));// 定义BufferedReader输入流来读取URL的响应
String line;
while ((line = in.readLine()) != null) {
result += line;
}
} catch (Exception e) {
System.out.println("发送GET请求出现异常!" + e);
} finally {// 使用finally块来关闭输入流
try {
if (in != null) {
in.close();
}
} catch (IOException ex) {
System.out.println("关闭流异常");
}
}
return result;
}
}