最近搞了下公众号,刚开始遇到了很多问题现在快完事了,总结以下发现挺简单的,小程序、公众号其实都是一个套路,需要什么拿东西去腾讯制定的接口去换就可以了,其实刚开始读文档总是感觉不完整,其实可能是我们位置找错了。下面记录的都是自己的使用经验,纯纯的干货,不喜勿喷 谢谢。
申请公众号啥的就自己解决吧;
------------------------基本配置-------------------------
1.公众还开发信息
开发者ID(AppId):这个是很重要的,建议全部放在后台操作,很多接口都是要验证的。
开发者密码:随机生成的也是十分重要的。
IP白名单:如果在你获取access_token的时候出现
errorCode:40164 原因:ip白名单内没有配置(需要配置公网ip)
2.服务器配置
服务器地址(URL):个人认为这是一个需要注意的地方,官方文档
https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421135319
接入指南
2.1首先服务器必须是80或443端口。
2.2配置的不只是服务器的地址,还有后台需要写验证的代码。
令牌:随意配置,符合要求即可。
密钥:与开发密码区分开就好。
------------------------公众号设置-------------------------
功能设置
网页授权域名:此处需要下载 MP_verify_ifiAlEhS1rcvrNLp.txt 放在域名的根目录,在哪?
tomcat:项目的根目录即可。
springBoot项目:在resources下创建static,放入即可。
另外此处的域名必须是备案的,必须是*域名*
流程:
-----------------------------获取openid流程---------------------------
-- 显示授权
https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect
-- 隐式授权
https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=snsapi_base&state=STATE#wechat_redirect
将APPID换成你的appid,REDIRECT_URI换成你的网页授权域名即可.
注意:域名可以具体到.html or .jsp
成功后会返回你设置的redirect_uri,其中包含了返回的code,code是获取openid(微信的唯一标识)重要凭证,它是有过期时间的同时只能使用一次。
private static String GET_OPENID_URL = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code"; // 获取openId的url
APPID:appid
secret:你的开发密钥
code:刚刚返回的code
-----------------------------获取access_token流程---------------------------
private static String GET_ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=SECRET"; // 获取access_token的url
APPID:appid
secret:你的开发密钥
-----------------------------发送模板消息流程---------------------------
模板消息 --> 添加模板 留存模板id
private static String MSG_MODEL_URL = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=ACCESS_TOKEN"; // 发送模板消息的url
参数一个json
文档中的示例:
被告人:{{msgPerson.DATA}}
案件:{{chargeMsg.DATA}}
出庭时间:{{date.DATA}}
出庭地点:{{address.DATA}}
出庭人员:{{msgPeople.DATA}}
{{remark.DATA}}
那你的json格式就是这样的:
{
touser:"接受微信的openid",
template_id:"你选择模板的id",
url:"当点击该消息时的处理地址",
msgPerson:{value:"",color:""},
chargeMsg:{value:"",color:""},
date:{value:"",color:""},
address:{value:"",color:""},
msgPeople:{value:"",color:""},
remark:{value:"",color:""},
}
每个模板的参数不太一样,但是都是这个结构*.DATA中的 * 指的就是你json里面某一个对象的名字
一些个人感觉比较容易出问题的记录:
1.公众号设置 --> 功能设置 网页授权域名配置
1.1只支持备案的域名。
1.2此处的域名如果不需要授权是否需要配置?
解1.2:想要获取openid就需要设置网页授权域名,因为虽然我们没有使用“显示授权”的方式,但是它的回调url却指向了此处所配置的服务器,所以认命吧。。。。
2.基本配置 --> 服务器配置
2.1如果启用了服务器配置,微信提供的菜单将失去作用。
解2.1:在启用服务器配置的同时开启菜单配置
1)添加功能插件。
2)选择 “自定义菜单”。
3)开通 --> 开启。
2.2服务器配置时需要在后台(服务器)提供相应接口,在后台多ToKen进行校验并返回结果,后台中的Token必须与配置的Token相同。
2.3如果出现URL验证失败等提示可能是因为在后台没有校验ToKen而造成的,域名分别支持80端口和443端口。 (百分之99都是因为后台验证造成的失败)
3.在获取OpenId时,提示域名与后台配置不一致,此处的配置域名指的是 1中的域名 还是 2中所配置的域名?
解:指的是 2 里面的《网页授权域名》配置,因为 在获取openId的时候是需要授权的,不管是隐式、显示获取都需要使用到授权域名。
最后将目前用到的微信公众号的工具类代码贴出来
WxUtil
package com.xxx.xxx.module.wechat.action;
import com.alibaba.fastjson.JSONObject;
import com.xxx.common.util.HttpUtil;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
/**
* @ClassName: WxUtil
* @Description:wx工具类
* @author:
* @date: 2019-04-09 16:52
* @version:1.0
*/
@Controller
@RequestMapping("wxutil")
public class WxUtil {
public static final String TO_KEN = "xxx"; // 微信的token
public static final String APPID = "xxx"; // APPID
public static final String ACC = "xxx"; // 密钥
public static final String MSG_MODEL_ID = "xxx"; // 消息模板id 推送消息时需要使用
private static String GET_ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=SECRET"; // 获取access_token的url
private static String GET_OPENID_URL = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code"; // 获取openId的url
private static String MSG_MODEL_URL = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=ACCESS_TOKEN"; // 模板消息的url
private static String SERVER_URL = "http://xxx.xxx.xxx"; // 服务器的url
// 微信验证URL 基本配置 --> 服务器配置 服务器地址(URL)
@RequestMapping("/token")
public void token(HttpServletRequest request, HttpServletResponse response){
PrintWriter out = null ;
try {
out = response.getWriter();
// 微信加密签名
String signature = request.getParameter("signature");
// 时间戳
String timestamp = request.getParameter("timestamp");
// 随机数
String nonce = request.getParameter("nonce");
// 随机字符串
String echostr = request.getParameter("echostr");
if (checkSignature(signature, timestamp, nonce)) {
try {
out = response.getWriter();
} catch (IOException e) {
e.printStackTrace();
}
out.print(echostr);
out.flush();
out.close();
}
}catch (Exception e){
}finally {
out.close();
}
}
/**
* 校验签名
* @param signature 签名
* @param timestamp 时间戳
* @param nonce 随机数
* @return 布尔值
*/
public static boolean checkSignature(String signature,String timestamp,String nonce){
String checktext = null;
if (null != signature) {
//对ToKen,timestamp,nonce 按字典排序
String[] paramArr = new String[]{TO_KEN,timestamp,nonce};
Arrays.sort(paramArr);
//将排序后的结果拼成一个字符串
String content = paramArr[0].concat(paramArr[1]).concat(paramArr[2]);
try {
MessageDigest md = MessageDigest.getInstance("SHA-1");
//对接后的字符串进行sha1加密
byte[] digest = md.digest(content.toString().getBytes());
checktext = byteToStr(digest);
} catch (NoSuchAlgorithmException e){
e.printStackTrace();
}
}
//将加密后的字符串与signature进行对比
return checktext !=null ? checktext.equals(signature.toUpperCase()) : false;
}
/**
* 将字节数组转化我16进制字符串
* @param byteArrays 字符数组
* @return 字符串
*/
private static String byteToStr(byte[] byteArrays){
String str = "";
for (int i = 0; i < byteArrays.length; i++) {
str += byteToHexStr(byteArrays[i]);
}
return str;
}
/**
* 将字节转化为十六进制字符串
* @param myByte 字节
* @return 字符串
*/
private static String byteToHexStr(byte myByte) {
char[] Digit = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
char[] tampArr = new char[2];
tampArr[0] = Digit[(myByte >>> 4) & 0X0F];
tampArr[1] = Digit[myByte & 0X0F];
String str = new String(tampArr);
return str;
}
/**
* getAccessToken
* @return access_token
*/
public static String getAccessToken(){
HttpUtil http = new HttpUtil();
String url = GET_ACCESS_TOKEN_URL.replace("APPID", APPID).replace("SECRET", ACC);
JSONObject jsonObject = JSONObject.parseObject(http.doGet(url));
return jsonObject.get("access_token").toString();
}
/**
* getOpenId
* @param code
* @return 字符串
*/
public static String getOpenId(String code){
String url = GET_OPENID_URL.replace("APPID",APPID).replace("SECRET",ACC).replace("CODE",code);
String openid = "";
try {
HttpUtil httpUtil = new HttpUtil();
openid = httpUtil.doGet(url);
} catch (Exception e) {
e.printStackTrace();
}
return openid;
}
/**
* URL编码(utf-8)
* @param source
* @return
*/
public static String urlEncodeUTF8(String source) {
String result = source;
try {
result = java.net.URLEncoder.encode(source, "utf-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return result;
}
/**
* 推送模板消息
* @param openId
* @param head 模板消息头信息
* @param
* @param
* @param foot 模板消息尾信息
* @return
*/
public static String sendMsg(String openId,String head,String xxx,String xxx,String foot){
HttpUtil httpUtil = new HttpUtil();
// 获取基础支持的access_token
String accessToken = getAccessToken();
// 发送模板消息
String url = MSG_MODEL_URL.replace("ACCESS_TOKEN", accessToken);
// 封装数据
JSONObject json = new JSONObject(); // 最外层的json
JSONObject dataJson = new JSONObject(); // data:{}
JSONObject firstJson = new JSONObject();
JSONObject key1Json = new JSONObject();
JSONObject key2Json = new JSONObject();
JSONObject remarkJson = new JSONObject();
firstJson.put("value",head);
firstJson.put("color","#173177");
key1Json.put("value",xxx);
key1Json.put("color","#173177");
key2Json.put("value",xxx);
key2Json.put("color","#173177");
remarkJson.put("value",foot);
remarkJson.put("color","#173177");
dataJson.put("first", firstJson);
dataJson.put("keyword1", key1Json);
dataJson.put("keyword2", key2Json);
dataJson.put("remark", remarkJson);
json.put("touser",openId);
json.put("template_id",MSG_MODEL_ID);
json.put("url",SERVER_URL+"/xxx/xxx/xxx.html?paramKey="+paramValue);
json.put("data",dataJson);
String str = httpUtil.doPost(url, json, "utf-8");
JSONObject jsonObject = JSONObject.parseObject(str);
return jsonObject.toString();
}
}
HttpUtil
本来想模拟微信的请求了,但是没成功 如果有成功的可以指点下
package com.xxx.common.util;
import com.alibaba.fastjson.JSONObject;
import java.io.IOException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.entity.StringEntity;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.util.EntityUtils;
/**
* @ClassName: HttpUtil
* @Description:网络请求
* @author:
* @date: 2019-04-04 09:44
* 工具
* @version:1.0
*/
public class HttpUtil {
public String result = "";
/**
* doPost
* @param
* @return 字符串
*/
public String doPost(String url, JSONObject jsonObject, String charset){
HttpClient httpClient = null;
HttpPost httpPost = null;
try{
httpClient = new SSLClient();
httpPost = new HttpPost(url);
//设置参数
System.out.println("jsonObject>>>"+jsonObject);
httpPost.setEntity(new StringEntity(JSONObject.toJSONString(jsonObject),"UTF-8"));
HttpResponse response = httpClient.execute(httpPost);
if(response != null){
HttpEntity resEntity = response.getEntity();
if(resEntity != null){
result = EntityUtils.toString(resEntity,charset);
}else{
result = "{'errcode':'400','errmsg':'请求失败','methodType':'Post'}";
}
}
}catch(Exception ex){
ex.printStackTrace();
}
return result;
}
/**
* doGet
* @param
* @return 字符串
*/
public String doGet(String url) {
try {
HttpClient client = new DefaultHttpClient();
//发送get请求
HttpGet request = new HttpGet(url);
/**在这里我们给请求的头部加上User-Agent来伪装成微信内置浏览器
request.setHeader("User-Agent","Mozilla/5.0 (iPhone; CPU iPhone OS 10_2 like Mac OS X) AppleWebKit/602.3.12 (KHTML, like Gecko) Mobile/14C92 Safari/601.1 wechatdevtools/1.02.1812271 MicroMessenger/6.7.3");
//这个是在网上看到的,要加上这个,避免其他错误
request.setHeader("Referer", "https://www.cardog.top/aileps");*/
HttpResponse response = client.execute(request);
// 请求发送成功,并得到响应
if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
// 读取服务器返回过来的json字符串数据
result = EntityUtils.toString(response.getEntity());
} else{
result ="{'errcode':'400','errmsg':'请求失败','methodType':'Get'}";
}
}
catch (IOException e) {
e.printStackTrace();
}
return result;
}
public class SSLClient extends DefaultHttpClient{
public SSLClient() throws Exception{
super();
SSLContext ctx = SSLContext.getInstance("TLS");
X509TrustManager tm = new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
}
@Override
public void checkServerTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return null;
}
};
ctx.init(null, new TrustManager[]{tm}, null);
SSLSocketFactory ssf = new SSLSocketFactory(ctx,SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
ClientConnectionManager ccm = this.getConnectionManager();
SchemeRegistry sr = ccm.getSchemeRegistry();
sr.register(new Scheme("https", 443, ssf));
}
}
}
还处于学习中,欢迎大家批评指教