概述
基于springboot的微信公众号开发
- 导入依赖
- Controller层
- service层
- ServiceImpl
- 相关工具类
导入依赖
<!-- https://mvnrepository.com/artifact/dom4j/dom4j -->
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.6.1</version>
</dependency>
Controller层
@RestController
public class WeChatController {
@Autowired
private WeChatService weChatService;
@ApiOperation("微信服务器签名验证")
@GetMapping("/wechat")
public String validate(String signature, String timestamp, String nonce, String echostr) {
return weChatService.validate(signature, timestamp, nonce, echostr);
}
@ApiOperation("公众号事件回调")
@PostMapping(value = "/wechat",produces = {"application/xml;charset=utf-8"})
public String processMsg(HttpServletRequest request){
return weChatService.doprocessMsg(request);
}
@ApiOperation("公众号access_token获取")
@GetMapping("/getAccessToken")
public String getAccessToken(){
return weChatService.getAccessToken();
}
@ApiOperation("公众号创建菜单")
@GetMapping("/createMenu")
public boolean createMenu(){
return weChatService.createMenu();
}
}
service层
public interface WeChatService {
//公众号获取access_token
String ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token";
//公众号获取菜单
String MENU_URL = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=";
//公众号获取微信用户
String USER_URL = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=";
/**
* 微信服务器签名验证
* @param signature
* @param timestamp
* @param nonce
* @param echostr
* @return
*/
String validate(String signature, String timestamp, String nonce, String echostr);
/**
* 公众号事件回调
* @param request
* @return
*/
String doprocessMsg(HttpServletRequest request);
/**
* 公众号,获取access_token
* @return
*/
String getAccessToken();
/**
* 创建菜单功能
*/
boolean createMenu();
/**
* 根据用户的openId获取用户信息
* @param openId
* @return
*/
JSONObject getwxUserInfo(String openId);
}
ServiceImpl
import com.alibaba.fastjson.JSONObject;
import com.example.config.TestConfig;
import com.example.config.util.RedisUtil;
import com.example.wechat.service.WeChatService;
import com.example.wechat.util.DequeUtil;
import com.example.wechat.util.MessageUtil;
import com.example.wechat.util.WxValidateUtil;
import com.example.wechat.util.XMLUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
@Service
@Slf4j
public class WeChatServiceImpl implements WeChatService {
@Autowired
private TestConfig config;
@Autowired
private RestTemplate restTemplate;
@Autowired
private WxValidateUtil wxValidateUtil;
@Autowired
private RedisUtil redisUtil;
@Override
public String validate(String signature, String timestamp, String nonce, String echostr) {
log.info("signature:" + signature + ",timestamp:" + timestamp + ",nonce:" + nonce + ",echostr:" + echostr);
// 公众号接入要求若校验成功,则原样返回echostr
return wxValidateUtil.checkSignature(signature, timestamp, nonce) ? echostr : null;
}
@Override
public String doprocessMsg(HttpServletRequest request) {
//解析XML文档,判断消息类型,判断事件类型,实现沟通逻辑
//解析XML文档,转换为Map,可读性更高,获取数据方便
Map<String , String> map = null;
try {
map = XMLUtil.getMap(request.getInputStream());
} catch (IOException e) {
e.printStackTrace();
}
//获取消息类型
String msgType = map.get("MsgType");
//获取消息是谁发的,用户的openid
String fromUser = map.get("FromUserName");
//发送给谁,我们的公众号的账号
String toUser = map.get("ToUserName");
//要回复的内容
String reply = "";
//如果是事件类型的消息
if (msgType.equals("event")) {
//获取事件类型
String event = map.get("Event");
//如果是关注事件
if (event.equals("subscribe")) {
reply = "欢迎您关注微租房平台!";
//在这里实现,获取用户信息,并且信息入库
log.info("openid{}",fromUser);
try {
//放入阻塞队列
DequeUtil.DEQUE.put(fromUser);
} catch (InterruptedException e) {
log.error("阻塞队列插入报错{}",e);
}
//
redisUtil.hset("微信用户",fromUser,getwxUserInfo(fromUser));
}else if (event.equals("CLICK")) {
//如果是点击事件,获取菜单的key值,实现我们自己的业务逻辑
String key = map.get("EventKey");
if (key.equals("get-post")) {
reply = "功能正在建设中,请期待...";
}
}
}else if (msgType.equals("text")) {
//用户发送给我们的消息
String content = map.get("Content");
if (content.equals("1")) {
reply = "请在官网领取优惠券";
}else if (content.equals("2")) {
reply = "在房源详情,可直接联系经纪人";
}else if (content.equals("3")) {
reply = "更多帮助,请联系客服电话:8956-531";
}else {
reply = "请回复您要解决的问题编号:n" +
"1、在哪里可以领取优惠券n" +
"2、怎样联系房源的经纪人n" +
"3、其他帮助";
}
}
int createTime = (int) (new Date().getTime() / 1000);
return MessageUtil.formatMsg(fromUser , toUser , createTime , "text" , reply);
}
@Override
public String getAccessToken() {
HashMap accessToken = restTemplate.getForObject(ACCESS_TOKEN_URL + "?grant_type=client_credential&appid="
+ config.getObs().getAppId() + "&secret=" + config.getObs().getAppsecret(), HashMap.class);
if (!accessToken.containsKey("access_token")){
log.error("公众号配置参数不正确");
return null;
}
return (String) accessToken.get("access_token");
}
@Override
public boolean createMenu() {
String paramStr = "{n" +
"
"button":[n" +
"
{n" +
"
"type":"click",n" +
"
"name":"我的海报",n" +
"
"key":"get-post"n" +
"
},n" +
"
{n" +
"
"name":"智慧服务",n" +
"
"sub_button":[n" +
"
{n" +
"
"type":"view",n" +
"
"name":"平台公告",n" +
"
"url":"https://news.qq.com/"n" +
"
},n" +
"
{n" +
"
"type":"view",n" +
"
"name":"言情小说",n" +
"
"url":"https://news.163.com/"n" +
"
},n" +
"
{n" +
"
"type":"view",n" +
"
"name":"智享搜搜乐",n" +
"
"url":"https://www.baidu.com/index.php?tn=monline_3_dg"n" +
"
}]n" +
"
},n" +
"
{n" +
"
"name":"海量房源",n" +
"
"type":"view",n" +
"
"url":" http://7r2mmb.natappfree.cc//index.html"n" +
"
}]n" +
"}n";
JSONObject jsonObject = JSONObject.parseObject(paramStr);
HashMap menuMap = restTemplate.postForEntity(MENU_URL + getAccessToken(),jsonObject,HashMap.class).getBody();
if ("40018".equals(menuMap.get("errcode").toString())){
log.error("创建菜单失败");
return false;
}
return true;
}
@Override
public JSONObject getwxUserInfo(String openId){
return restTemplate.getForEntity(USER_URL+getAccessToken()+"&openid="+ openId +"&lang=zh_CN",JSONObject.class).getBody();
}
}
相关工具类
XML解析工具类
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class XMLUtil {
/**
*
将XML转换成Map
* @param inputStream 请求体中的输入流
* @return Map
* */
public static Map<String,String> getMap(InputStream inputStream){
//返回的Map
Map<String,String> map = new HashMap<>();
//初始化解析器
SAXReader reader = new SAXReader();
//读取XML文档
Document document = null;
try {
document = reader.read(inputStream);
} catch (DocumentException e) {
e.printStackTrace();
}
//获取XML文档的根节点
Element element = document.getRootElement();
//遍历所有节点,把键和值存入Map
List<Element> elementList = element.elements();
for (Element e : elementList) {
map.put(e.getName(),e.getText());
}
return map;
}
}
MessageUtil 工具类
/**
* 格式化XML消息
*/
public class MessageUtil {
/**
*
格式化消息
* @param toUser 消息接收者
* @param fromUser 消息发送者
* @param createTime 消息创建时间
* @param msgType 消息类型
* @param content 消息内容
* */
public static String formatMsg (String toUser , String fromUser , int createTime , String msgType , String content) {
String str = "<xml>n" +
"
<ToUserName><![CDATA[%s]]></ToUserName>n" +
"
<FromUserName><![CDATA[%s]]></FromUserName>n" +
"
<CreateTime>%d</CreateTime>n" +
"
<MsgType><![CDATA[%s]]></MsgType>n" +
"
<Content><![CDATA[%s]]></Content>n" +
"</xml>n" +
"n";
return String.format(str , toUser , fromUser , createTime , msgType , content);
}
}
WxValidateUtil 工具类
import com.example.config.TestConfig;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
@Slf4j
@Component
public class WxValidateUtil {
@Autowired
TestConfig testConfig;
/**
* 检验signature
*
* @param signature
* @param timestamp
* @param nonce
* @return
*/
public boolean checkSignature(String signature, String timestamp, String nonce) {
// 1)将token、timestamp、nonce三个参数进行字典序排序
String token = testConfig.getMp().getToken();
String[] str = {token, timestamp, nonce};
Arrays.sort(str);
// 2)将三个参数字符串拼接成一个字符串进行sha1加密
StringBuilder sb = new StringBuilder();
for (String s : str) {
sb.append(s);
}
MessageDigest messageDigest = null;
String tmpStr = null;
try {
messageDigest = MessageDigest.getInstance("sha1");
byte[] digest = messageDigest.digest(sb.toString().getBytes());
tmpStr = byteToStr(digest);
} catch (NoSuchAlgorithmException e) {
log.error("异常:", e);
}
// 3)开发者获得加密后的字符串可与signature对比,标识该请求来源于微信
return signature.toUpperCase().equals(tmpStr);
}
/**
* 将字节数组转换为十六进制字符串
*
* @param byteArray
* @return
*/
private static String byteToStr(byte[] byteArray) {
String strDigest = "";
for (int i = 0; i < byteArray.length; i++) {
strDigest += byteToHexStr(byteArray[i]);
}
return strDigest;
}
/**
* 将字节转换为十六进制字符串
*
* @param mByte
* @return
*/
private static String byteToHexStr(byte mByte) {
char[] Digit = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
char[] tempArr = new char[2];
tempArr[0] = Digit[(mByte >>> 4) & 0X0F];
tempArr[1] = Digit[mByte & 0X0F];
return new String(tempArr);
}
}
参考文章
最后
以上就是粗暴冬日为你收集整理的基于springboot的微信公众号开发的全部内容,希望文章能够帮你解决基于springboot的微信公众号开发所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复