说明
步骤后台代码
maven消息接收接口类帮助类实体类 结尾
说明本文主要是对接公众号的基础能接口
消息自动回复
用户信息事件
模板消息推送
…
1.申请公众号
2.进入公众号后台 获取 appid 和 secret
3.设置微信公众号后台接口地址,与关注用户的互动都会发到这个地址
消息接收org.springframework.boot spring-boot-starter-web cn.hutool hutool-all 5.4.1 org.springframework.boot spring-boot-starter-test test org.projectlombok lombok org.springframework.boot spring-boot-devtools true true commons-io commons-io 2.3 com.alibaba fastjson 1.2.59 dom4j dom4j 1.6.1
将服务器地址设置为http:xxx/mainCall
将自己ip设为在白名单里面
将token 设置 与CheckUtil 一致
废话少说 上代码
//接收微信消息接口
@RestController
public class WxCallBackApi {
@Autowired
WxSubscription wxSubscription;
@RequestMapping("/mainCall")
public void mainCall(HttpServletRequest request, HttpServletResponse response){
try {
Signature sg = new Signature(
request.getParameter("signature"),
request.getParameter("timestamp"),
request.getParameter("nonce"),
request.getParameter("echostr"));
String method = request.getMethod();
// 配置服务器域名 回调地址时 会发送一条验证消息 是GET请求
if ("GET".equals(method)) {
if (sg != null && CheckUtil.checkSignature(sg)) {
wxSubscription.reply(response,sg.getEchostr());
}
}
// 后续如果公众号收到用户消息 各种事件 是POST请求
if ("POST".equals(method)) {
if (CheckUtil.checkSignature(sg)) {
wxSubscription.callWeChatMessage(request,response);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
接口类
@Slf4j
@EnableScheduling
@Component
public class WxSubscription {
private final String base_URL = "https://api.weixin.qq.com";
private final String URL_TOKEN = base_URL+"/cgi-bin/token";
private final String URL_MENU_CREATE = base_URL+"/cgi-bin/menu/create";
private final String URL_GET_CURRENT_SELFMENU_INFO = base_URL+"/cgi-bin/get_current_selfmenu_info";
private final String URL_MEDIA_UPLOAD = base_URL+"/cgi-bin/media/upload";
private final String URL_MEDIA_GET = base_URL+"/cgi-bin/media/get";
private final String URL_USER_GET = base_URL+"/cgi-bin/user/get";
private final String URL_USER_INFO = base_URL+"/cgi-bin/user/info";
private final String URL_TEMPLATE_GET_ALL_PRIVATE_TEMPLATE = base_URL+"/cgi-bin/template/get_all_private_template";
private final String URL_MESSAGE_TEMPLATE_SEND= base_URL+"/cgi-bin/message/template/send";
//获取AccessToken
public String getAccessToken(){
HashMap param = new HashMap();
param.put("grant_type","client_credential");
param.put("appid",CheckUtil.appid);
param.put("secret",CheckUtil.secret);
String jsonstr = HttpUtil.get(URL_TOKEN,param);
JSONObject result = JSONObject.parseObject(jsonstr);
if(StrUtil.isBlank(result.getString("errcode"))){
return result.getString("access_token");
}
return "";
}
//每小时刷新access_token
@Scheduled(cron = "0 0 1 * * ?")
@PostConstruct//启动时执行一次
public void flushAccessToken(){
CheckUtil.access_token = getAccessToken();
log.info("========定期刷新token========{}",CheckUtil.access_token);
}
//创建公众号菜单
//需开启后台配置地址
//参数参考文档 https://developers.weixin.qq.com/doc/offiaccount/Custom_Menus/Creating_Custom-Defined_Menu.html
public boolean createMenu(JSONObject param){
String validUrl = URL_MENU_CREATE +"?access_token="+CheckUtil.access_token;
String jsonstr = HttpUtil.post(validUrl,param.toJSONString());
JSONObject result = JSONObject.parseObject(jsonstr);
return returnBoolean(result);
}
//获取当前菜单信息
//参数参考文档 https://developers.weixin.qq.com/doc/offiaccount/Custom_Menus/Querying_Custom_Menus.html
public JSONObject getMenuInfo(){
String validUrl = URL_GET_CURRENT_SELFMENU_INFO +"?access_token="+CheckUtil.access_token;
String jsonstr = HttpUtil.get(validUrl);
JSONObject result = JSONObject.parseObject(jsonstr);
if(StrUtil.isBlank(result.getString("errcode"))){
return result;
}
return null;
}
//删除菜单(不常用 懒得写)
//参数参考文档 https://developers.weixin.qq.com/doc/offiaccount/Custom_Menus/Deleting_Custom-Defined_Menu.html
//创建个性化菜单(不常用 懒得写)
//参数参考文档 https://developers.weixin.qq.com/doc/offiaccount/Custom_Menus/Personalized_menu_interface.html
//接收公众用户消息、事件
public void callWeChatMessage(HttpServletRequest request, HttpServletResponse response) throws IOException {
try {
//把微信返回的xml信息转成map
Map map = XmlUtil.xmlToMap(request);
//发送方用用户帐号(OpenID)
String fromUserName = map.get("FromUserName");
//开发者(公众号)
String toUserName = map.get("ToUserName");
//消息类型
String msgType = map.get("MsgType");
//消息内容
String content = map.get("Content");
String eventType = map.get("Event");
if(CheckUtil.MSGTYPE_EVENT.equalsIgnoreCase(msgType)){
//如果为事件类型
if(CheckUtil.MESSAGE_SUBSCIBE.equalsIgnoreCase(eventType)){
//处理关注事件
if(StringUtils.isNotEmpty(fromUserName)){
//用户信息入库 ybc
}
}else if(CheckUtil.MESSAGE_UNSUBSCIBE.equalsIgnoreCase(eventType)){
//处理取消关注事件
}else if(CheckUtil.MESSAGE_CLICK.equalsIgnoreCase(eventType)){
//处理菜单点击事件
String EventKey = map.get("EventKey");
}
}else if(CheckUtil.MESSAGE_TEXT.equalsIgnoreCase(msgType)){
//用户发送文字
//返回文字消息
//测试
HashMap param = new HashMap();
param.put("ToUserName",fromUserName);
param.put("FromUserName",toUserName);
param.put("CreateTime","12345678");
param.put("MsgType",CheckUtil.MESSAGE_TEXT);
param.put("Content","你好");
//返回图片消息
// HashMap param = new HashMap();
// param.put("ToUserName",fromUserName);
// param.put("FromUserName",toUserName);
// param.put("CreateTime","12345678");
// param.put("MsgType",CheckUtil.MESSAGE_IMAGE);
// HashMap Image = new HashMap();
// Image.put("MediaId","2qvNch5UW27Q-6IdwchvMj7XEOihDGo2Myb1o3F1xrELcHEQE90Zjjv9zDQLSmob");//通过上传素材接口返回的id 或直接在微信公众号后台上传
// param.put("Image",Image);
//其他类型参考 https://developers.weixin.qq.com/doc/offiaccount/Message_Management/Passive_user_reply_message.html
reply(response,param);
return;
}
//...其他类型自己加
} catch (Exception e) {
e.printStackTrace();
}
reply(response,"success");
}
//无回复类型
public void reply(HttpServletResponse response,String str) {
try {
response.setCharacterEncoding("UTF-8");
PrintWriter writer = response.getWriter();
writer.write(str);
writer.close();
}catch (Exception e){
e.printStackTrace();
}
}
//被动回复用户消息
//参数参考 https://developers.weixin.qq.com/doc/offiaccount/Message_Management/Passive_user_reply_message.html#%E5%9B%9E%E5%A4%8D%E6%96%87%E6%9C%AC%E6%B6%88%E6%81%AF
public void reply(HttpServletResponse response,Map map)throws Exception{
XmlUtil.mapToXmlResponse(response,map);
}
//新增临时素材
//参考 https://developers.weixin.qq.com/doc/offiaccount/Asset_Management/New_temporary_materials.html
public boolean materialAddNews(String filepath){
HashMap param = new HashMap();
param.put("access_token",CheckUtil.access_token);
param.put("type",CheckUtil.MESSAGE_IMAGE);
param.put("media", FileUtil.file(filepath));
String jsonstr = HttpUtil.post(URL_MEDIA_UPLOAD,param);
JSONObject result = JSONObject.parseObject(jsonstr);
log.info("请求地址{},返回值{}",URL_MEDIA_UPLOAD,jsonstr);
return returnBoolean(result);
}
//获取临时素材
//参考 https://developers.weixin.qq.com/doc/offiaccount/Asset_Management/Get_temporary_materials.html
public void mediaDownload(String media_id,String filepath){
String validUrl = URL_MEDIA_GET+"?access_token="+CheckUtil.access_token+"&media_id="+media_id;
HttpUtil.downloadFile(validUrl,filepath);
log.info("请求地址{}",validUrl);
}
/
public static Map xmlToMap(HttpServletRequest request) throws IOException, documentException {
HashMap map = new HashMap();
SAXReader reader = new SAXReader();
InputStream ins = request.getInputStream();
document doc = reader.read(ins);
Element root = doc.getRootElement();
@SuppressWarnings("unchecked")
List list = (List)root.elements();
for(Element e:list){
map.put(e.getName(), e.getText());
}
ins.close();
return map;
}
public static void mapToXmlResponse(HttpServletResponse response, Map map) throws Exception {
response.setContentType("text/xml");
response.setCharacterEncoding("UTF-8");
PrintWriter writer = response.getWriter();
writer.write(mapToXml(map));
writer.close();
}
public static String mapToXml(Map map) throws Exception{
if (null == map) return null;
// System.out.println("转换前的Map对象数据:" + map.toString());
StringBuffer sb = new StringBuffer();
// sb.append("");
sb.append("");
mapToXmlHelp(map, sb);
sb.append(" ");
// System.out.println("将map转成xml后的数据:" + sb.toString());
return sb.toString();
}
private static void mapToXmlHelp(Map map, StringBuffer str) throws Exception{
Set set = map.keySet();
for (Iterator it = set.iterator(); it.hasNext();) {
String key = (String) it.next();
Object value = map.get(key);
if (null == value)
value = "";
if (value.getClass().getName().equals("java.util.ArrayList")) {
ArrayList list = (ArrayList) map.get(key);
str.append("<" + key + ">");
for (int i = 0; i < list.size(); i++) {
HashMap hm = (HashMap) list.get(i);
mapToXmlHelp(hm, str);
}
str.append("" + key + ">");
if (null !=list && !list.isEmpty() && list.size() <= 1) {
str.append("<" + key + ">");
for (int i = 0; i < list.size(); i++) {
HashMap hm = (HashMap) list.get(i);
mapToXmlHelp(hm, str);
}
str.append("" + key + ">");
}
} else {
if (value instanceof HashMap) {
str.append("<" + key + ">");
mapToXmlHelp((HashMap) value, str);
str.append("" + key + ">");
} else {
str.append("<" + key + ">" + value + "" + key + ">");
}
}
}
}
}
实体类
Signature
@Data
@NoArgsConstructor //无参构造
@AllArgsConstructor
public class Signature {
private String signature;
private String timestamp;
private String nonce;
private String echostr;
}
结尾
实际上公众号不需要配置后台地址也可以用,如果想与自建系统互动,则可参照上述代码。
写了一下常用接口,代码有点乱,为了方便很多都没分开,如果能给到大佬们一点点帮助,请给我一点点动力,让我相信光
后续将完成更多接口,顺便将返回值JsonObject 用实体类代替哦,代码没什么技术含量,只想用劳动造福社会
gitee地址:https://gitee.com/yangbaocai/wxInterface



