登录微信公众平台 申请微信公众号https://mp.weixin.qq.com
因为我这里是个人注册的 所以只能测试号 功能较少,但基础功能还是有的
测试公众号
设置->开发者工具->测试号
这个URL要对应你的项目的一个借口 以证明你服 务器真实存在
@ResponseBody
@RequestMapping("/test")
public String test(String signature,String timestamp,String nonce,String echostr){
System.out.println("signature="+signature+"|timestamp"+timestamp+"|nonce"+nonce+"|echostr"+echostr);
return echostr;
}
<!--more-->
获取Access_token
https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140183
微信的所有借口 都需要Access_token作为凭证,所以先获取到Access_token中才可以进行下面的开发
@Autowired
RedisUtil redisUtil;
public String getAccessToken(){
String token=redisUtil.get("wxAccessToKen");
if(StringUtils.isEmpty(token)){
Map<String,String> map=new HashMap<>();
map.put("grant_type","client_credential");
map.put("appid", Constant.APPID);
map.put("secret",Constant.SECRET);
String resule=HttpUtils.sendGet(TOKEN,map);
System.out.println("resule="+resule);
JSONObject jsonObject=JSONObject.parseObject(resule);
String newToken=jsonObject.getString("access_token");
Integer newTime=jsonObject.getInteger("expires_in");
redisUtil.set("wxAccessToKen",newToken,newTime.longValue());
return newToken;
}else{
return token;
}
}
这里我利用了Redis 每次请求获取Access_token接口接口会返回给我们 token和一个时间 这是token有效期,所以我把token存入了Redis时间也就是 有效期,先从Redis中取 取不到再请求接口
自定义菜单创建接口
在做微信授权之前,我们要先给公众号做一个菜单,点击菜单中的按钮跳转页面,页面授权
1、自定义菜单最多包括3个一级菜单,每个一级菜单最多包含5个二级菜单。
2、一级菜单最多4个汉字,二级菜单最多7个汉字,多出来的部分将会以“...”代替。
3、创建自定义菜单后,菜单的刷新策略是,在用户进入公众号会话页或公众号profile页时,如果发现上一次拉取菜单的请求在5分钟以前,就会拉取一下菜单,如果菜单有更新,就会刷新客户端的菜单。测试时可以尝试取消关注公众账号后再次关注,则可以看到创建后的效果。
接口地址 https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN
{
"button": [
{
"name": "用户",
"sub_button": [
{
"type": "view",
"name": "显示用户信息",
"appid": "wx4539efd94f0002d4",
"url": "http://yanhao.s1.natapp.cc/user/userInfo"
},
{
"type": "click",
"name": "弹出用户信息",
"key": "V1001_GOOD"
}
]
}
]
}
为了测试方便,我们使用微信的测试接口
https://mp.weixin.qq.com/debug
查看微信测试号重新关注一下 发现菜单成功修改了 做一个欢迎页userInfo
微信网页授权
如果用户在微信客户端中访问第三方网页,公众号可以通过微信网页授权机制,来获取用户基本信息,进而实现业务逻辑。
关于网页授权的两种scope的区别说明
1、以snsapi_base为scope发起的网页授权,是用来获取进入页面的用户的openid的,并且是静默授权并自动跳转到回调页的。用户感知的就是直接进入了回调页(往往是业务页面)
2、以snsapi_userinfo为scope发起的网页授权,是用来获取用户的基本信息的。但这种授权需要用户手动同意,并且由于用户同意过,所以无须关注,就可在授权后获取该用户的基本信息。
3、用户管理类接口中的“获取用户基本信息接口”,是在用户和公众号产生消息交互或关注后事件推送后,才能根据用户OpenID来获取用户基本信息。这个接口,包括其他微信接口,都是需要该用户(即openid)关注了公众号后,才能调用成功的。
关于网页授权access_token和普通access_token的区别
1、微信网页授权是通过OAuth2.0机制实现的,在用户授权给公众号后,公众号可以获取到一个网页授权特有的接口调用凭证(网页授权access_token),通过网页授权access_token可以进行授权后接口调用,如获取用户基本信息;
2、其他微信接口,需要通过基础支持中的“获取access_token”接口来获取到的普通access_token调用。
user/userInfo 下面我们将访问userInfo的时候需要网页授权 获取OpenId
https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect 若提示“该链接无法访问”,请检查参数是否填写错误,是否拥有scope参数对应的授权作用域权限。
参数 | 是否必须 | 说明 |
---|---|---|
appid | 是 | 公众号的唯一标识 |
redirect_uri | 是 | 授权后重定向的回调链接地址, 请使用 urlEncode 对链接进行处理 |
response_type | 是 | 返回类型,请填写code |
scope | 是 | 应用授权作用域,snsapi_base (不弹出授权页面,直接跳转,只能获取用户openid),snsapi_userinfo (弹出授权页面,可通过openid拿到昵称、性别、所在地。并且, 即使在未关注的情况下,只要用户授权,也能获取其信息 ) |
state | 否 | 重定向后会带上state参数,开发者可以填写a-zA-Z0-9的参数值,最多128字节 |
#wechat_redirect | 是 | 无论直接打开还是做页面302重定向时候,必须带此参数 |
这里是这样的 用微信访问这个连接 将你真正要访问的连接放在redirect_uri中 才能进行第一步获取code
然后拿到code 请求接口 就可以拿到访问这个页面微信的 OpenId
之前我们是将这个连接拼到按钮里,点击按钮的同时授权,但是我觉得那样太乱了所以我今天用自己新方法拦截器
HttpServletRequest request= (HttpServletRequest) servletRequest;
HttpSession session=request.getSession();
String code=request.getParameter("code");
String openid= (String) session.getAttribute("OPENID");
if((code==null||"".equals(code))&&(openid==null||"".equals(openid))){
System.out.println("进入第一步获取Code");
String url = request.getScheme() + "://"
+ request.getServerName()
+ request.getRequestURI()
+ (request.getQueryString() != null ? "?" + request.getQueryString() : "");
System.out.println("请求的URL="+url);
StringBuffer stringBuffer=new StringBuffer("https://open.weixin.qq.com/connect/oauth2/authorize");
stringBuffer.append("?appid="+ Constant.APPID);
stringBuffer.append("&redirect_uri="+ URLEncoder.encode(url));
stringBuffer.append("&response_type=code");
stringBuffer.append("&scope=snsapi_userinfo");
stringBuffer.append("&state=STATE#wechat_redirect");
System.out.println("转发后URL="+stringBuffer);
((HttpServletResponse)servletResponse).sendRedirect(stringBuffer.toString());
}else{
filterChain.doFilter(servletRequest,servletResponse);
}
这是第一个拦截器的代码,拦截菜单URL 拦截URL判断URL中是否有code参数,如果没有 说明第一步还没有执行过,如果没有执行 那么就 将这个连接拼成https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect这个格式,进行授权然后授权完成后会返回到我们写好的重定向连接,这是还会进入这个拦截器 依然判断code 是否有,这次有了进入第二个拦截器
HttpServletRequest request= (HttpServletRequest) servletRequest;
HttpSession session=request.getSession();
String code=request.getParameter("code");
String openid= (String) session.getAttribute("OPENID");
if(openid==null||"".equals(openid)&&code!=null&&!"".equals(code)){
String url = request.getScheme() + "://"
+ request.getServerName()
+ request.getRequestURI()
+ (request.getQueryString() != null ? "?" + request.getQueryString() : "");
System.out.println("请求的URL="+url);
System.out.println("进入第二步获取OPENID");
StringBuffer stringBuffer=new StringBuffer("https://api.weixin.qq.com/sns/oauth2/access_token");
Map<String,String> map=new HashMap<>();
map.put("appid",Constant.APPID);
map.put("secret",Constant.SECRET);
map.put("code",code);
map.put("grant_type","authorization_code");
String result=HttpUtils.sendGet(stringBuffer.toString(),map);
System.out.println(result);
JSONObject jsonObject= (JSONObject) JSONObject.parse(result);
String openId=jsonObject.getString("openid");
System.out.println("OpenId="+openId);
session.setAttribute("OPENID",openId);
System.out.println("获取OPENID完成");
((HttpServletResponse)servletResponse).sendRedirect(url);
}else{
filterChain.doFilter(servletRequest,servletResponse);
}
上面第一步完成后 会进入第二个拦截器 第二个拦截器 拿到code 然后请求接口 拿到URL 存入Session就OK
现在菜单的View事件解决了再来看 Click事件
@ResponseBody
@GetMapping("/test")
public String getTest(String signature,String timestamp,String nonce,String echostr,HttpServletRequest request){
System.out.println("signature="+signature+"|timestamp"+timestamp+"|nonce"+nonce+"|echostr"+echostr);
return echostr;
}
@PostMapping("/test")
public void postTest(HttpServletRequest request,HttpServletResponse response){
ServletInputStream in = null;
int len = request.getContentLength();
byte[] b = new byte[len];
try {
in = request.getInputStream();
in.read(b);
in.close();
} catch (IOException e) {
e.printStackTrace();
}
String xmlReceivedMessage = null;
try {
xmlReceivedMessage = new String(b,"utf-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
System.out.println("微信推送的消息数据为:" + xmlReceivedMessage);
}
刚开始我们设置的接口信息 认证的话会提交到Get
而收信息 收图片 收按钮单击事件 就会进入POST,我这里只是把内容打印了 并未做任何处理
<xml><ToUserName><![CDATA[gh_c3aa36250841]]></ToUserName>
<FromUserName><![CDATA[oUEIRwxo_EOgvgwFYcp076hs0wWk]]></FromUserName>
<CreateTime>1520492080</CreateTime>
<MsgType><![CDATA[event]]></MsgType>
<Event><![CDATA[CLICK]]></Event>
<EventKey><![CDATA[V1001_GOOD]]></EventKey>
</xml>
这是接收按钮事件时接到的信息 你只需要解析他然后判断走你自己的逻辑就OK了
<xml><ToUserName><![CDATA[gh_c3aa36250841]]></ToUserName>
<FromUserName><![CDATA[oUEIRwxo_EOgvgwFYcp076hs0wWk]]></FromUserName>
<CreateTime>1520492387</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[122]]></Content>
<MsgId>6530465076411563234</MsgId>
</xml>
如果别人直接向微信公众号发送信息 你会接到一个这样的结果(我发的是122)
以上就是 微信公众号的基本内容,配置完这些 就可以开发了