SSM框架接入微信公共号
准备微信服务器项目、数据库
百度云:https://pan.baidu.com/s/1qGkvaYntr2ODlEy2h03k9Q记得配置文件修改正确
把内网映射到外网:在映射软件里cmd进入输入下面第一句命令
ngrok -config=ngrok.cfg -subdomain yygwxtest 80
yygwxtest -->你自己想要的子网域名
80-->监听的80端口
记住导入项目后配置的tomcat端口要一致
显示以下,使用http开头的网址,它被映射到外网上
正式号接入认证
告知微信服务器我的公众号使用那个服务器的相关配置
主要有两大步骤:
1: 先进入公共测试平台认证
url是映射的外网地址,token随便写,但要与基本配置一样
IndexContrller的后台打印显示,代码在下面
2:认证完才能基本信息配置(点击修改配置)
点击提交会传入几个参数到controller接收:并启用
timestamp 时间戳
nonce 随机数
echostr 随机字符串
signature 微信加密签名
3:验证服务器地址的有效性
验证代码实现
@Controller
@RequestMapping("/index")
public class IndexController {
/**
* 处理微信认证,get提交
* 微信公众号的接入验证
*/
@RequestMapping(method = RequestMethod.GET)
public void signature(HttpServletRequest request, HttpServletResponse response) throws Exception {
System.out.println("index......");
String token = "weixin";
String timestamp = request.getParameter("timestamp");//时间戳
String nonce = request.getParameter("nonce");//随机数
String echostr = request.getParameter("echostr");//随机字符串
String signature = request.getParameter("signature");//微信加密签名
System.out.println(timestamp);
System.out.println(nonce);
System.out.println(echostr);
System.out.println(signature);
// response.getWriter().print(echostr);//不能直接输出,虽然可以成功提交,但是不能保证请求来自微信
// 1)将token、timestamp、nonce三个参数进行字典序排序
String[] arr={token,timestamp,nonce};
Arrays.sort(arr);
System.out.println(arr);
// 2)将三个参数字符串拼接成一个字符串进行sha1加密
StringBuffer sb=new StringBuffer();
for (String str : arr) {
sb.append(str);
}
String shaStr = SecurityUtil.sha1(sb.toString());
// 3)开发者获得加密后的字符串可与signature对比,标识该请求来源于微信
if(signature.equals(shaStr)){
System.out.println("验证正常。。。。。");
//来自于微信:
response.getWriter().println(echostr);
}else{
throw new RuntimeException("非法的请求,不受理。。。。。");
}
}
}
sha1加密工具
public class SecurityUtil {
public static String sha1(String str) {
try {
StringBuilder sb = new StringBuilder();
MessageDigest digest = MessageDigest.getInstance("sha1");
// 放入加密字符串
digest.update(str.getBytes());
//进行加密
byte[] digestMsg = digest.digest();
// byte转换16进制
for (byte b : digestMsg) {
sb.append(String.format("%02x", b));
}
return sb.toString();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return str;
}
}
可以参考接入指南,开发者工具->开发者文档->开始开发->接入指南
微信公众号交互响应
需要导入Jar包:xmlpull-1.1.3.1.jar ;kxml2-2.3.0.jar
请求解析器工具
package cn.itsource.weixin.utils;
import java.io.Reader;
import java.io.StringReader;
import java.util.Map;
import java.util.Set;
import org.apache.commons.collections.map.HashedMap;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;
/**
* 解析xml,使用xmlpullparser
* @param reader io流
* @return
* @throws Exception
*/
public class XmlParserUtils {
public static Map<String, String> parserXml(Reader reader){
//创建map容器存储解析的数据
Map<String, String> map=new HashedMap();
try {
//得到一个xml解析器
XmlPullParser pullParser = XmlPullParserFactory.newInstance().newPullParser();
//设置解析的输入流
pullParser.setInput(reader);
/*int START_DOCUMENT = 0; 文档开始
int END_DOCUMENT = 1; 文档结束
int START_TAG = 2; 标签开始
int END_TAG = 3; 标签结束*/
//获取当前的事件类型
int eventType = pullParser.getEventType();
//判断如果不是文档结束的事件类型就一直解析
while(eventType!=XmlPullParser.END_DOCUMENT){
//获取当前标签名称
String tagName = pullParser.getName();
//当标签是开始xml直接跳过,并且是开始事件类型
if(!"xml".equals(tagName)&&eventType==XmlPullParser.START_TAG){
//获取当前的值
String text = pullParser.nextText();
map.put(tagName, text);
}
//把下一个节点的状态值赋给eventype
eventType= pullParser.next();
}
} catch (Exception e) {
e.printStackTrace();
}
return map;
}
//测试
public static void main(String[] args) {
String xmlData = "<xml><ToUserName><![CDATA[gh_55e547acb71e]]></ToUserName>"
+ "<FromUserName><![CDATA[o9cEf0iZn8aKK4-MKWmqO2fs36xE]]></FromUserName>"
+ "<CreateTime>1505114547</CreateTime>" + "<MsgType><![CDATA[text]]></MsgType>"
+ "<Content><![CDATA[水电费三分]]></Content>" + "
<MsgId>6464417756529124601</MsgId>" + "</xml>";
Map<String, String> map = parserXml(new StringReader(xmlData));
Set<String> keySet = map.keySet();
for (String key : keySet) {
System.out.println(key+":"+map.get(key));
}
}
}
查看文档 点击 开发者工具->开发者文档->消息管理->被动返回消息格式
请求响应两种方式
拼接字符串
@RequestMapping(method = RequestMethod.POST)
public void index(HttpServletRequest request, HttpServletResponse response) throws Exception {
// 获取请求的字节流
ServletInputStream inputStream = request.getInputStream();
//转换为字符流
InputStreamReader inputStreamReader = new InputStreamReader(inputStream,"utf-8");
//得到缓冲流
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
Map<String, String> map = XmlParserUtils.parserXml(bufferedReader);
String content = null;
// 一行一行读取
while ((content = bufferedReader.readLine()) != null) {
System.out.println(content);
}
//拼接xml字符串响应请求
response.getWriter().println(createXml(map));
}
private String createXml(Map<String, String> map) {
StringBuffer sBuffer=new StringBuffer();
sBuffer.append("<xml>");
sBuffer.append("<ToUserName>"+map.get("FromUserName")+"</ToUserName>");//回馈给谁
sBuffer.append("<FromUserName>"+map.get("ToUserName")+"</FromUserName>");//从哪里请求来
sBuffer.append("<CreateTime>"+map.get("CreateTime")+"</CreateTime>");//请求时间
sBuffer.append("<MsgType>"+map.get("MsgType")+"</MsgType>");//回馈消息类型
if(map.get("MsgType").equals("text")){//回复文本类型
sBuffer.append("<Content>"+map.get("Content")+"</Content>");
}else if(map.get("MsgType").equals("Image")){//回复图片类型
sBuffer.append("<Image><MediaId><![CDATA["+map.get("MediaId")+"]]></MediaId></Image>");
}else if(map.get("MsgType").equals("voice")){//回复录音类型
sBuffer.append("<Voice><MediaId><![CDATA["+map.get("MediaId")+"]]></MediaId></Voice>");
}else if(map.get("MsgType").equals("video")){//回复视频类型 有点小问题
sBuffer.append("<Video><MediaId><![CDATA["+map.get("MediaId")+"]]></MediaId>"
+ "<Title><![CDATA["+map.get("Title")+"]]></Title>"
+ "<Description><![CDATA["+map.get("description")+"]]></Description>"
+ "</Video>");
}
sBuffer.append("</xml>");
return sBuffer.toString();//返回出去
}
Jsp模板返回视图
// 接收请求处理业务 响应回去
@RequestMapping(method = RequestMethod.POST)
public ModelAndView modelAndView(HttpServletRequest request, HttpServletResponse response) throws Exception {
//设置编码问题
response.setContentType("text/html; charset=UTF-8");
//获取字节流
ServletInputStream inputStream = request.getInputStream();
//转换字符流
InputStreamReader inputStreamReader = new InputStreamReader(inputStream,"utf-8");
//缓冲流
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
//调用请求内容解析器工具类解析封装map
Map<String, String> map=XmlParserUtils.parserXml(bufferedReader);
//用于关注向用户提示(手机微信扫自己微信二维码时自动提示)
String type = map.get("MsgType");
String eve = map.get("Event");
//判断是否属于关注事件
if("event".equals(type)&&"subscribe".equals(eve)){
map.put("Content", "欢迎关注久城公共号,有你更美好");
map.put("MsgType", "text");
}
ModelAndView mv = new ModelAndView();//创建
mv.addObject("map", map); //weixin.jsp可以从map取出
mv.setViewName("weixin");//xml有视图解析器 会拼接访问地址到WEB-INF/views/weixin.jsp
return mv;
}
<%@ page contentType="text/xml; charset=UTF-8" pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<xml>
<%把返回的xml写到jsp里,响应类型、内容从map取出%>
<ToUserName><![CDATA[${map['FromUserName']}]]></ToUserName>
<FromUserName><![CDATA[${map['ToUserName']}]]></FromUserName>
<CreateTime><![CDATA[${map['CreateTime']}]]></CreateTime>
<MsgType><![CDATA[${map['MsgType']}]]></MsgType>
<%判断响应给用户信息类型%>
<c:choose>
<c:when test="${map['MsgType']=='image'}">
<Image>
<MediaId><![CDATA[${map['MediaId']}]]></MediaId>
</Image>
</c:when>
<c:when test="${map['MsgType']=='voice'}">
<Voice>
<MediaId><![CDATA[${map['MediaId']}]]></MediaId>
</Voice>
</c:when>
<c:when test="${map['MsgType']=='video'}">
<Video>
<MediaId><![CDATA[${map['MediaId']}]]></MediaId>
<Title><![CDATA[${map['Title']}]]></Title>
<Description><![CDATA[${map['Description']}]]></Description>
</Video>
</c:when>
<c:otherwise>
<Content><![CDATA[${map['Content']}]]></Content>
</c:otherwise>
</c:choose>
</xml>