1、微信公众号的申请
具体申请流程此处略过,百度一下有人教你怎样一步一步申请的。
不过,个人账号什么的限制太多,而其他又要求营业执照等,太麻烦,所以如果是小白只是想学一下的话,可以申请一个测试号,具体申请方法见:https://jingyan.baidu.com/article/e2284b2b95f423e2e6118de3.html
2、springBoot多子模块项目的搭建(具体见XXXXX)
该demo后端采用的是springboot,搭建一个这样的项目(具体见springBoot多模块项目的搭建)虽然很简单,但重复的工作没什么意义,所以使用了脚手架(具体见利用velocity模板引擎实现脚手架),一个请求就生成一个springboot多模块项目,如果有需求,还可以直接上传到git。
3、利用业务代码生成器自动生成业务代码(具体见XXXXX)
数据库的crud等基础操作总是那么的让人觉得无奈(毕竟大部分都没什么技术含量),要是用springdata可能还好一点,用mybatis的话,特别是mybatis XML版(非注解版)的话,如果不用生成工具的话,是不是想死。而那个mybatis generator代码生成工具,本人只能说,非常一般般,局限太多了,所以特意推一波业务代码生成器(具体见:springboot多模块项目业务代码生成器),创建好数据库后,执行一个test方法,就可以生成所有的业务代码。
4、基本配置
4.1 基本配置
点击“开发者工具”-〉"开发者文档"-〉"开始开发"-〉"接入指南"-〉""
如下图所示,点击“基本配置”
基本配置的URL包含两个方法:get方法和post方法
get方法,验证消息的确来自微信服务器,点击“提交”按钮时,请求的就是该方法
post方法,现业务逻辑都走该方法,当然前提是上面的“提交”能成功。
4.2 url get方法的开发与验证的实现
4.2.1 get方法开发
get方法的思路:
将填写的token与请求参数signature,timestamp拼接成字符串,然后用sha1加密,如果加密后的值等于nonce,则将请求参数echostr返回。
@RequestMapping(value = {"/connect"},method = RequestMethod.GET)
public String connect(String signature,String timestamp,String nonce,String echostr){
if(WexinSha1.checkSignature(signature, timestamp, nonce)) {
return echostr;
}else{
return null;
}
}
WexinSha1.java
package cn.inovance.wechat.utils.tool;
import java.util.Arrays;
import cn.inovance.wechat.utils.constant.WechatConstant;
import org.apache.commons.codec.digest.DigestUtils;
public class WexinSha1 {
public static boolean checkSignature(String signature,String timestamp,String nonce) {
String[] arr = new String[] {WechatConstant.WECHAT_TOKEN,timestamp,nonce};
Arrays.sort(arr);
StringBuffer content = new StringBuffer();
for(String a:arr) {
content.append(a);
}
String sign = DigestUtils.shaHex(content.toString());
if(sign.equals(signature)) {
return true;
}else {
return false;
}
}
}
4.2.2 公网映射
(土豪能直接进行域名映射的请忽略哈) 那对于普通的开发者,如何进行公网映射呢?
有花生壳,万金维,nat123,dnspod等等,具体用哪个以及具体怎么使用,自己百度哈。
5、具体业务的开发
5.1 url post方法的开发与验证的实现
微信平台和我们自己的平台的主动交互,都是通过该post方法来进行消息的回调的,下面是controller中的post方法。
@RequestMapping(value = {"/connect"},method = RequestMethod.POST)
public String post(HttpServletRequest request){
String result=null;
try {
result= messageService.reponseMessage(request);
} catch (Exception e) {
logger.error("自动回复出错"+e.getMessage());
}
return result;
}
post最终调用了MessageService.java的 reponseMessage(HttpServletRequest request) 方法。该方法主要是被动消息的接收(比如订阅/取消订阅,扫码,用户给公众号发消息等),主动消息的结果回调(比如模板消息,群发消息的回调等),具体大致包括以下内容:
MessageService.java
package cn.inovance.wechat.service.message;
import cn.inovance.wechat.module.message.Message;
import com.github.pagehelper.PageInfo;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Map;
public interface MessageService {
int save(Message message);
int update(Message message);
int delete(String id);
int check(Message message);
Message get(String id);
Message getByKeyWord(String keyWord);
List<Message> getList(Message message);
PageInfo<Map> getListByPage(Map<String, Object> map, int page, int rows);
String reponseMessage(HttpServletRequest request) throws Exception;
}
MessageServiceImpl.java
package cn.inovance.wechat.service.message.impl;
import cn.inovance.wechat.dao.message.MessageMapper;
import cn.inovance.wechat.module.message.EventMessage;
import cn.inovance.wechat.module.message.Message;
import cn.inovance.wechat.module.message.TextMessage;
import cn.inovance.wechat.service.message.MessageService;
import cn.inovance.wechat.utils.constant.WechatConstant;
import cn.inovance.wechat.utils.tool.XmlUtil;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.thoughtworks.xstream.XStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.List;
import java.util.Map;
@Service
public class MessageServiceImpl implements MessageService {
@Autowired
private MessageMapper messageMapper;
protected static final Logger logger= LoggerFactory.getLogger(MessageServiceImpl.class);
@Override
public int save(Message message) {
return messageMapper.save(message);
}
@Override
public int update(Message message) {
return messageMapper.update(message);
}
@Override
public int delete(String id) {
return messageMapper.delete(id);
}
@Override
public int check(Message message) {
Message message1= messageMapper.check(message);
if(message1==null){
return 1;
}else{
return 0;
}
}
@Override
public Message get(String id) {
return messageMapper.get(id);
}
@Override
public Message getByKeyWord(String keyWord) {
return messageMapper.getByKeyWord(keyWord);
}
@Override
public List<Message> getList(Message message) {
return messageMapper.getList(message);
}
@Override
public PageInfo<Map> getListByPage(Map<String, Object> map, int page, int rows) {
PageHelper.startPage(page,rows);
List<Map<String, Object>> collection=messageMapper.getListByPage(map);
return new PageInfo(collection);
}
@Override
public String reponseMessage(HttpServletRequest request) throws Exception {
Map<String,String> map= XmlUtil.xmlToMap(request);
String msgType = map.get("MsgType");
String result=null;
switch (msgType){
case "text":
result=handlerTextMessage(map);
break;
case "event":
result=handlerEventMessage(map);
break;
default:
break;
}
logger.info(result);
return result;
}
public String handlerTextMessage(Map<String,String> map){
Message message=messageMapper.getByKeyWord(map.get("Content"));
TextMessage textMessage=new TextMessage();
textMessage.setToUserName(map.get("FromUserName"));
textMessage.setFromUserName(map.get("ToUserName"));
textMessage.setCreateTime(new Date().getTime());
textMessage.setMsgType(WechatConstant.WECHAT_MESSAGE_TYPE_TEXT);
if(message!=null){
textMessage.setContent(message.getResult());
} else{
textMessage.setContent(WechatConstant.WECHAT_HELPER);
}
return XmlUtil.objToXml(textMessage);
}
public String handlerEventMessage(Map<String,String> map){
String result=null;
String event=map.get("Event");
switch (event){
case "subscribe":
result=handlerSubscribeEventMessage(map);
break;
case "unsubscribe":
result=null;
break;
case "SCAN":
result=handlerScanEventMessage(map);
break;
case "LOCATION":
result=null;
break;
case "CLICK":
result=null;
break;
case "VIEW":
result=null;
break;
case "TEMPLATESENDJOBFINISH":
result=null;
break;
default:
break;
}
return result;
}
public static String handlerSubscribeEventMessage(Map<String,String> map){
TextMessage textMessage=new TextMessage();
textMessage.setToUserName(map.get("FromUserName"));
textMessage.setFromUserName(map.get("ToUserName"));
textMessage.setCreateTime(new Date().getTime());
textMessage.setMsgType(WechatConstant.WECHAT_MESSAGE_TYPE_TEXT);
textMessage.setContent(WechatConstant.WECHAT_SUBSCRIBE);
return XmlUtil.objToXml(textMessage);
}
public static String handlerScanEventMessage(Map<String,String> map){
TextMessage textMessage=new TextMessage();
textMessage.setToUserName(map.get("FromUserName"));
textMessage.setFromUserName(map.get("ToUserName"));
textMessage.setCreateTime(new Date().getTime());
textMessage.setMsgType(WechatConstant.WECHAT_MESSAGE_TYPE_TEXT);
textMessage.setContent(WechatConstant.WECHAT_SCAN);
return XmlUtil.objToXml(textMessage);
}
}
BaseWechatMessage.java
package cn.inovance.wechat.utils.base;
import lombok.Data;
import lombok.ToString;
@Data
@ToString
public class BaseWechatMessage {
// 开发者微信号
private String ToUserName;
// 发送方帐号(一个OpenID)
private String FromUserName;
// 消息创建时间 (整型)
private long CreateTime;
// 消息类型(text/image/location/link)
private String MsgType;
}
TextMessage.java
package cn.inovance.wechat.module.message;
import cn.inovance.wechat.utils.base.BaseWechatMessage;
import lombok.Data;
import lombok.ToString;
@Data
@ToString
public class TextMessage extends BaseWechatMessage{
// 消息id,64位整型
private long MsgId;
// 消息内容
private String Content;
}
BaseModel.java
package cn.inovance.wechat.utils.base;
import lombok.Data;
import lombok.ToString;
import java.io.Serializable;
import java.util.Date;
@Data
@ToString
public class BaseModel implements Serializable {
private static final long serialVersionUID = 1L;
private String id;
private String creator;
private Date createTime;
private String updator;
private String updateTime;
private String description;
}
Message.java
package cn.inovance.wechat.module.message;
import cn.inovance.wechat.utils.base.BaseModel;
import lombok.Data;
import lombok.ToString;
@Data
@ToString
public class Message extends BaseModel{
private String keyWord;
private String result;
}
待会儿继续。。。