微信接口配置失败、接收微信发送的消息
1 微信接口配置失败
因为要注册测试账号,微信需要发送对应请求后,由我们返回特定信息
官网接入文档地址:https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Access_Overview.html
1.1 编写加密类
public class Decript {
public static String SHA1(String decript) {
try {
MessageDigest digest = MessageDigest
.getInstance("SHA-1");
digest.update(decript.getBytes());
byte messageDigest[] = digest.digest();
// Create Hex String
StringBuffer hexString = new StringBuffer();
// 字节数组转换为 十六进制 数
for (int i = 0; i < messageDigest.length; i++) {
String shaHex = Integer.toHexString(messageDigest[i] & 0xFF);
if (shaHex.length() < 2) {
hexString.append(0);
}
hexString.append(shaHex);
}
return hexString.toString();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return "";
}
}
1.2 编写消息处理service
@Service
public class WxSignatureCheckService {
//token,此处token内容与网站上我们填写的token一致
private final String token = "wxtoken";
public String wxSignatureCheck(String signature, String timestamp, String nonce, String echostr) {
ArrayList<String> array = new ArrayList<String>();
array.add(signature);
array.add(timestamp);
array.add(nonce);
//排序
String sortString = sort(token, timestamp, nonce);
//加密
String mytoken = Decript.SHA1(sortString);
//校验签名
if (mytoken != null && mytoken != "" && mytoken.equals(signature)) {
System.out.println("签名校验通过。");
return echostr; //如果检验成功输出echostr,微信服务器接收到此输出,才会确认检验完成。
} else {
System.out.println("签名校验失败。");
return null;
}
}
/**
* 排序方法
* @param token
* @param timestamp
* @param nonce
* @return
*/
public static String sort(String token, String timestamp, String nonce) {
String[] strArray = { token, timestamp, nonce };
Arrays.sort(strArray);
StringBuilder sbuilder = new StringBuilder();
for (String str : strArray) {
sbuilder.append(str);
}
return sbuilder.toString();
}
}
1.3 编写controller类,接收请求
@RestController
public class WxSignatureCheckController {
@Autowired
private WxSignatureCheckService wxSignatureCheckService;
@RequestMapping("/wx")//此处的请求路径与网站上填写的一致
public String wxSignatureCheck(
@RequestParam(value = "signature") String signature,
@RequestParam(value = "timestamp") String timestamp,
@RequestParam(value = "nonce") String nonce,
@RequestParam(value = "echostr") String echostr
){
return wxSignatureCheckService.wxSignatureCheck(signature, timestamp, nonce, echostr);
}
}
注意:此处我使用了内网穿透服务【ngrok】
感兴趣的可以去网上下载然后开启即可,会自动分配给我们一个域名
地址:http://ngrok.cc/login.html
2 接收微信发送的消息
参考官方手册:https://developers.weixin.qq.com/doc/offiaccount/Message_Management/Receiving_standard_messages.html
微信测试账号发送消息是以POST方式发送XML数据
此处以文本信息为例:
<xml>
<ToUserName><![CDATA[toUser]]></ToUserName>
<FromUserName><![CDATA[fromUser]]></FromUserName>
<CreateTime>1348831860</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[this is a test]]></Content>
<MsgId>1234567890123456</MsgId>
<MsgDataId>xxxx</MsgDataId>
<Idx>xxxx</Idx>
</xml>
2.1 扫描自己的测试公众号
地址:https://mp.weixin.qq.com/debug/cgi-bin/sandboxinfo?action=showinfo&t=sandbox/index
2.2 编写请求处理类
因为微信是通过POST请求发送XML数据,所以此处采用dom4j解析XML
①引入dom4j依赖
<!--dom4j-->
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.1</version>
</dependency>
②编写service解析XML
@Service
public class WxService {
/**
* 解析通过dom4j解析XML数据
* @param is
* @return map
*/
public Map<String, String> parseRequest(InputStream is){
Map<String, String> map = new HashMap<>();
SAXReader reader = new SAXReader();
try{
//读取输入流,获取文档对象
Document document = reader.read(is);
//根据文档对象获取根节点
Element root = document.getRootElement();
//获取根节点的所有子节点
List<Element> elements = root.elements();
for(Element e : elements){
map.put(e.getName(), e.getStringValue());
}
return map;
}catch (Exception e){
e.printStackTrace();
}
return null;
}
}
③编写controller接收消息
@RestController
public class WxController {
@Autowired
private WxService wxService;
@PostMapping("/wx")
public void receiveMsg(HttpServletRequest request){
try {
ServletInputStream is = request.getInputStream();
Map<String, String> result = wxService.parseRequest(is);
System.out.println(result);
} catch (IOException e) {
e.printStackTrace();
}
}
}
2.3 发送消息
结果如下:
语音、图片、位置信息等内容,参考官方文档解析即可。
https://developers.weixin.qq.com/doc/offiaccount/Message_Management/Receiving_standard_messages.html
3 接收并恢复消息
3.1 导入依赖构建返回的XML数据
<!--xstream构建返回的XML-->
<dependency>
<groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId>
<version>1.4.14</version>
</dependency>
<!--dom4j解析XML数据-->
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.1</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.24</version>
</dependency>
3.2 构建返回数据
①父类:
@Data
@AllArgsConstructor
@NoArgsConstructor
public class BaseMessage {
@XStreamAlias("ToUserName")
private String toUserName;
@XStreamAlias("FromUserName")
private String fromUserName;
@XStreamAlias("CreateTime")
private String createTime;
@XStreamAlias("MsgType")
private String msgType;
@XStreamAlias("MsgId")
private String msgId;
//初始化默认数据
public BaseMessage(Map<String, String> requestMap){
//开始是请求方,返回数据的时候,就成为了发送方
this.toUserName = requestMap.get("FromUserName");
this.fromUserName = requestMap.get("ToUserName");
//微信中的时间默认是10位数,java的currentTimeMillis是13位,因此要除以1000
this.createTime = System.currentTimeMillis() / 1000 + "";
this.msgId = requestMap.get("MsgId");
}
}
②文本消息
@Data
@AllArgsConstructor
@NoArgsConstructor
@XStreamAlias("xml")
public class TextMessage extends BaseMessage{
//文本内容
@XStreamAlias("Content")
private String content;
public TextMessage(Map<String, String> requestMap, String content){
super(requestMap);
//设置消息类型为文本
super.setMsgType("text");
//设置文本消息
this.content = content;
}
}
③图片消息
@Data
@AllArgsConstructor
@NoArgsConstructor
@XStreamAlias("xml")
public class PicMessage extends BaseMessage{
//图片链接
@XStreamAlias("PicUrl")
private String picUrl;
//图片消息
public PicMessage(Map<String, String> requestMap, String picUrl){
super(requestMap);
this.setMsgType("image");
this.picUrl = picUrl;
}
}
3.3 创建service处理消息
@Service
public class WxService {
/**
* 解析通过dom4j解析XML数据
* @param is
* @return map
*/
public Map<String, String> parseRequest(InputStream is){
Map<String, String> map = new HashMap<>();
SAXReader reader = new SAXReader();
try{
//读取输入流,获取文档对象
Document document = reader.read(is);
//根据文档对象获取根节点
Element root = document.getRootElement();
//获取根节点的所有子节点
List<Element> elements = root.elements();
for(Element e : elements){
map.put(e.getName(), e.getStringValue());
}
return map;
}catch (Exception e){
e.printStackTrace();
}
return null;
}
/**
* 返回的消息
* @param requestMap
* @return
*/
public String getResponse(Map<String, String> requestMap){
String msgType = requestMap.get("MsgType");
//要返回的消息
BaseMessage rtnMsg = null;
switch (msgType){
//根据消息类型,处理不同消息
case "text":
rtnMsg = dealTextMessage(requestMap);
case "image":
//TODO
break;
case "voice":
break;
case "video":
break;
case "shortvideo":
break;
case "location":
break;
case "link":
break;
default:
break;
}
return beanToXML(rtnMsg);
}
/**
* 将消息对象处理为XML数据包
* @param msg
* @return
*/
public String beanToXML(BaseMessage msg){
if(msg == null){
return "";
} //公众号返回信息
XStream stream = new XStream();
//设置需要处理XStreamAlias("xml")注解的类
stream.processAnnotations(TextMessage.class);
stream.processAnnotations(PicMessage.class);
String xml = stream.toXML(msg);
return xml;
}
/**
* 处理文本消息
* @param requestMap
* @return
*/
public BaseMessage dealTextMessage(Map<String, String> requestMap){
String returnMsg = "收到消息!!!";
TextMessage tm = new TextMessage(requestMap, returnMsg);
return tm;
}
}
3.4 构建controller
@PostMapping("/wx")
public void receiveMsg(HttpServletRequest request, HttpServletResponse response){
try {
//设置编码,防止乱码
request.setCharacterEncoding("utf8");
response.setCharacterEncoding("utf8");
//获取请求信息
ServletInputStream is = request.getInputStream();
//处理消息和事件推送
Map<String, String> requestMap = wxService.parseRequest(is);
System.out.println(requestMap);
//准备回复的数据包
String respXML = wxService.getResponse(requestMap);
System.out.println(respXML);
PrintWriter out = response.getWriter();
out.print(respXML);
out.flush();
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
3.5 测试
在测试号上发送消息:
控制台打印消息:
其他消息处理:类似,官方其他消息XML格式
https://developers.weixin.qq.com/doc/offiaccount/Message_Management/Receiving_standard_messages.html