专门做网站的软件是,主题资源网站建设反思,河北省建设工程,广东建设监理协会网站个人账号一、申请微信公众号账号
1、先去微信公众平台 申请一个账号#xff0c;账号类型#xff0c;如果是个人#xff0c;可以选择订阅号#xff0c;如果是企业、单位#xff0c;可以申请服务号#xff08;注意#xff1a;服务号是要收费的#xff09;#xff0c;订阅号不收…一、申请微信公众号账号
1、先去微信公众平台 申请一个账号账号类型如果是个人可以选择订阅号如果是企业、单位可以申请服务号注意服务号是要收费的订阅号不收费但是接口权限较少服务号收费但提供的功能多。 2、根据个人来申请订阅号也可以实现部分有限功能申请完登录进去 找到设置与开发点击基本配置打开如下页面 可以把个人使用的IP白名单填写进去多个IP换行填写。
在服务器配置处注意
服务器URL填写规则域名/个人的微信回调地址我个人的地址是http://hvdkdx.natappfree.cc/weChat/confirmFromWx
令牌Token:随意填写
消息加解密密钥随机生成
举例如下
/*** 文件名: WeChatController* 描述: 微信公众号controller*/
Slf4j
RequestMapping(/weChat)
Controller
public class WeChatController {Autowiredprivate WeChatService weChatService;Autowiredprivate WeChatConfig weChatConfig;/*** 验证消息是否来自微信服务器** param request* param response* return* throws Exception*/RequestMapping(value /confirmFromWx, method {RequestMethod.GET, RequestMethod.POST})public void confirmFromWx(HttpServletRequest request, HttpServletResponse response) throws Exception {log.info(****************来自微信服务器的请求:{}, request.getMethod().toUpperCase());//微信服务器POST请求时,用的是UTF-8编码,在接收时也要用同样的编码,否则中文乱码request.setCharacterEncoding(UTF-8);//响应消息时,也要设置同样的编码response.setCharacterEncoding(UTF-8);//判断请求方式是否是postboolean isPost Objects.equals(POST, request.getMethod().toUpperCase());if (isPost) {log.info(从微信服务器发过来POST请求,准备处理......);//xml转maptry {MapString, String map WeChatUtil.xmlToMap(request);String msgType map.get(MsgType);// 消息类型有eventString xml;//返回的xmlif (MessageType.REQ_MESSAGE_TYPE_EVENT.equals(msgType)) {//事件类型xml weChatService.parseEvent(map);} else {//消息类型xml weChatService.parseMessage(map);}response.setContentType(text/xml);if (StringUtils.isNotBlank(xml)) {response.getWriter().write(xml);} else {response.getWriter().write();}} catch (Exception e) {e.printStackTrace();response.getWriter().write();}log.info(从微信服务器发过来POST请求,处理结束......);} else {log.info(********************验证微信服务器信息开始********************);//微信加密签名signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。String signature request.getParameter(signature);//时间戳String timestamp request.getParameter(timestamp);//随机数String nonce request.getParameter(nonce);//随机字符串String echostr request.getParameter(echostr);if (StringUtils.isEmpty(signature) || StringUtils.isEmpty(timestamp) || StringUtils.isEmpty(nonce) || StringUtils.isEmpty(echostr)) {return;}log.info(weChat: signature is: signature ,timestamp is: timestamp ,nonce is: nonce ,echostr is: echostr);String check weChatService.checkSignature(signature, timestamp, nonce, echostr);if (StringUtils.isNotBlank(check)) {log.info(********************校验成功,确实来自微信服务器,验证结束********************);response.getWriter().write(check);}log.info(********************验证微信服务器信息结束********************);response.getWriter().write();}}
}service实现类Service
Slf4j
public class WeChatServiceImpl implements WeChatService {Autowiredprivate WeChatConfig weChatConfig;Overridepublic String checkSignature(String signature, String timestamp, String nonce, String echostr) {String sign_token weChatConfig.getSign_token();// 1.将token、timestamp、nonce三个参数进行字典序排序log.info(signature:{},sign_token:{},timestamp:{},nonce:{}, signature, sign_token, timestamp, nonce);String sha1 WeChatUtil.getSha1(sign_token, timestamp, nonce);// 2.进行对比log.info(随机字符串echostr:{}, echostr);log.info(sha1算法得到的字符串:{}, sha1);if (sha1.equals(signature.toUpperCase())) {return echostr;}return null;}
}
MessageType类如下
/*** 文件名: MessageType* 描述: 消息类型*/
public class MessageType {/*** 文本消息*/public static final String TEXT_MESSAGE text;/*** 图片消息*/public static final String IMAGE_MESSAGE image;/*** 语音消息*/public static final String VOICE_MESSAGE voice;/*** 视频消息*/public static final String VIDEO_MESSAGE video;/*** 小视频消息*/public static final String SHORTVIDEO_MESSAGE shortvideo;/*** 地理位置消息*/public static final String POSOTION_MESSAGE location;/*** 链接消息*/public static final String LINK_MESSAGE link;/*** 音乐消息*/public static final String MUSIC_MESSAGE music;/*** 图文消息*/public static final String IMAGE_TEXT_MESSAGE news;/*** 请求消息类型事件推送*/public static final String REQ_MESSAGE_TYPE_EVENT event;/*** 事件类型subscribe(订阅)*/public static final String EVENT_TYPE_SUBSCRIBE subscribe;/*** 事件类型unsubscribe(取消订阅)*/public static final String EVENT_TYPE_UNSUBSCRIBE unsubscribe;/*** 事件类型scan(用户已关注时的扫描带参数二维码)*/public static final String EVENT_TYPE_SCAN scan;/*** 事件类型LOCATION(上报地理位置)*/public static final String EVENT_TYPE_LOCATION location;/*** 事件类型CLICK(自定义菜单)*/public static final String EVENT_TYPE_CLICK click;/*** 事件类型: VIEW(点击菜单跳转链接时的事件推送)*/public static final String EVENT_TYPE_VIEW view;/*** 响应消息类型文本*/public static final String RESP_MESSAGE_TYPE_TEXT text;/*** 响应消息类型图片*/public static final String RESP_MESSAGE_TYPE_IMAGE image;/*** 响应消息类型语音*/public static final String RESP_MESSAGE_TYPE_VOICE voice;/*** 响应消息类型视频*/public static final String RESP_MESSAGE_TYPE_VIDEO video;/*** 响应消息类型音乐*/public static final String RESP_MESSAGE_TYPE_MUSIC music;/*** 响应消息类型图文*/public static final String RESP_MESSAGE_TYPE_NEWS news;/*** 公众号回复消息样式* return*/public static String menuText() {StringBuilder sb new StringBuilder();sb.append(感谢关注);sb.append(该公众号已实现以下功能:\n);sb.append(如您在使用该公众号时,有宝贵意见,欢迎反馈!\n\n);sb.append(反馈邮箱:XXXXXX);return sb.toString();}
}
WeChatUtil工具类如下
import cn.hutool.core.date.DateUtil;
import lombok.extern.slf4j.Slf4j;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.InputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;/*** 文件名: WeChatUtil* 描述: 微信工具类*/
Slf4j
public class WeChatUtil {public static void main(String[] args) {long currentSeconds DateUtil.currentSeconds();System.out.println(当前时间戳是currentSeconds);}/*** 用sha-1算法验证token** param sign_token 与公众号中配置的签名token保持一致* param timestamp* param nonce* return*/public static String getSha1(String sign_token, String timestamp, String nonce) {String[] strings new String[]{sign_token, timestamp, nonce};Arrays.sort(strings);StringBuilder stringBuilder new StringBuilder();for (int i 0; i strings.length; i) {stringBuilder.append(strings[i]);}MessageDigest md null;String tmpStr null;try {md MessageDigest.getInstance(SHA-1);//将三个字符串拼到一起,进行sha1加密byte[] digest md.digest(stringBuilder.toString().getBytes());tmpStr byteArrToHexStr(digest);} catch (NoSuchAlgorithmException e) {e.printStackTrace();log.error(错误信息:{}, e.getMessage());}return tmpStr;}/*** 将字节转换成十六进制字符串** param b* return*/private static String byteToHexStr(byte b) {char[] chars {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F};char[] tempChar new char[2];tempChar[0] chars[(b 4) 0X0F];tempChar[1] chars[b 0X0F];return new String(tempChar);}/*** 将字节数组转换成十六进制字符串** param byteArr* return*/private static String byteArrToHexStr(byte[] byteArr) {StringBuilder stringBuilder new StringBuilder();for (int i 0; i byteArr.length; i) {stringBuilder.append(byteToHexStr(byteArr[i]));}return stringBuilder.toString();}/*** xml转map** param request* return* throws IOException* throws DocumentException*/public static MapString, String xmlToMap(HttpServletRequest request) throws IOException, DocumentException {// 将解析结果存储在HashMap中MapString, String map new HashMap();// 从request中取得输入流InputStream inputStream request.getInputStream();// 读取输入流SAXReader reader new SAXReader();Document document reader.read(inputStream);// 得到xml根元素Element element document.getRootElement();// 得到根元素的所有子节点ListElement list element.elements();// 遍历所有子节点for (Element e : list) {map.put(e.getName(), e.getText());}// 释放资源inputStream.close();return map;}
}
WeChatConfig配置类如下
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;/*** 文件名: WeChatConfig* 描述: 微信配置类*/
Component
Data
public class WeChatConfig {private String appId;private String appSecret;private String sign_token;private String server_url;Value(${weChat.appId})public void setAppId(String appId) {this.appId appId;}Value(${weChat.appSecret})public void setAppSecret(String appSecret) {this.appSecret appSecret;}Value(${weChat.sign_token})public void setSign_token(String sign_token) {this.sign_token sign_token;}Value(${weChat.server_url})public void setServer_url(String server_url) {this.server_url server_url;}/*** 1. 获取access_token.*/String ACCESS_TOKEN_URL https://api.weixin.qq.com/cgi-bin/token? grant_typeclient_credentialappidAPPIDsecretAPPSECRET;/*** 2. 获得各种类型的ticket.*/String TICKET_URL https://api.weixin.qq.com/cgi-bin/ticket/getticket?type;/*** 3. 长链接转短链接接口.*/String SHORTURL_API_URL https://api.weixin.qq.com/cgi-bin/shorturl;/*** 4. 语义查询接口.*/String SEMANTIC_SEMPROXY_SEARCH_URL https://api.weixin.qq.com/semantic/semproxy/search;/*** 5. 用code换取oauth2的access token.*/String OAUTH2_ACCESS_TOKEN_URL https://api.weixin.qq.com/sns/oauth2/access_token? appidAPPIDsecretAPPSECRETcodeCODEgrant_typeauthorization_code;/*** 6. 刷新oauth2的access token.*/String OAUTH2_REFRESH_TOKEN_URL https://api.weixin.qq.com/sns/oauth2/refresh_token? appidAPPIDgrant_typerefresh_tokenrefresh_tokenREFRESH_TOKEN;/*** 7. 用oauth2获取用户信息.*/String OAUTH2_USERINFO_URL https://api.weixin.qq.com/sns/userinfo?access_tokenACCESS_TOKENopenidOPENIDlangLANG;/*** 8. 验证oauth2的access token是否有效.*/String OAUTH2_VALIDATE_TOKEN_URL https://api.weixin.qq.com/sns/auth?access_tokenACCESS_TOKENopenidOPENID;/*** 9. 获取微信服务器IP地址.*/String CALLBACK_IP_URL https://api.weixin.qq.com/cgi-bin/getcallbackip;/*** 10. 第三方使用网站应用授权登录的url.*/String QRCONNECT_URL https://open.weixin.qq.com/connect/qrconnect? appidAPPIDredirect_uriREDIRECT_URLresponse_typecodescopeSCOPEstateSTATE#wechat_redirect;/*** 11. oauth2授权的url连接.*/String CONNECT_OAUTH2_AUTHORIZE_URL https://open.weixin.qq.com/connect/oauth2/authorize? appidAPPIDredirect_uriREDIRECT_URLresponse_typecodescopeSCOPE stateSTATE#wechat_redirect;/*** 12. 获取公众号的自动回复规则.*/String CURRENT_AUTOREPLY_INFO_URL https://api.weixin.qq.com/cgi-bin/get_current_autoreply_info;/*** 13.公众号调用或第三方平台帮公众号调用对公众号的所有api调用包括第三方帮其调用次数进行清零.*/String CLEAR_QUOTA_URL https://api.weixin.qq.com/cgi-bin/clear_quota;/*** 14.获取微信公众号用户的基本信息(UnionID机制)*/String USERINFO_URLhttps://api.weixin.qq.com/cgi-bin/user/info?access_tokenACCESS_TOKENopenidOPENIDlangzh_CN;/*** 15.生成带参数的二维码*/String qrCode_URLhttps://api.weixin.qq.com/cgi-bin/qrcode/create?access_tokenTOKEN;/*** 16.显示二维码图片的URL*/String showQrCode_URLhttps://mp.weixin.qq.com/cgi-bin/showqrcode?ticketTICKET;/*** 17.微信公众号长链接转短链接接口,POST请求*/String shortURLhttps://api.weixin.qq.com/cgi-bin/shorturl?access_tokenACCESS_TOKEN;/*** 18.自定义菜单查询接口*/String findMenu_URLhttps://api.weixin.qq.com/cgi-bin/menu/get?access_tokenACCESS_TOKEN;/*** 19.删除自定义菜单接口*/String deleteMenu_URLhttps://api.weixin.qq.com/cgi-bin/menu/delete?access_tokenACCESS_TOKEN;/*** 20.微信 新增临时素材*/String uploadTempMedia_URLhttps://api.weixin.qq.com/cgi-bin/media/upload?access_tokenACCESS_TOKENtypeTYPE;
}application.yml配置微信的如下
weChat:appId: xxxxxxxx #appIdappSecret: xxxxx #appsecretsign_token: xxxx #与公众号中配置的签名sign_token保持一致server_url: xxxxx #服务器域名 3、如果个人不想申请可以申请测试号即可地址是微信公众平台 测试号的接口权限也很多能满足大部分需要。 4、下面是部分接口权限表截图 二、有域名没有域名的处理方法
上面提到测试号填写的URL中包含域名如果个人有域名则直接填上去即可如果没有域名的解决办法可以使用内网穿透来实现我个人使用的 NATAPP来实现的地址是NATAPP-内网穿透 基于ngrok的国内高速内网映射工具 具体可以查看NATAPP文档来获取域名此处不再赘述。如果有不明白的地方可以私我。