1.需求:微信服务号模板消息推送
2.流程:
1. 设计模板样式
2. 获得微信的全局调用凭证+接口
3. 设计库
4. 获得关注服务号的用户
5. 填充内容
6. 推送模板
7. 推送成功/失败返回结果
设计模板
登录公司或个人的微信公众平台-功能模板消息-模板库,这里有微信自己的设计好的模板库的样式,也可以自己设计,
本人用的是微信模板库的模板
获得微信的接口调用凭证+接口
在微信服务号的开发者工具-开发者文档里有一则模板消息接口的文档,里面介绍了推送模板消息的用到的接口信息。
1. 获取接口调用凭证access_token
access_token是公众号的全局唯一接口调用凭据,公众号调用各接口时都需使用 access_token。开发者需要进行妥善保存。access_token的存储至少要保留512个字符空间。access_token的有效期目前为2个小时,需定时刷新,重复获取将导致上次获取的access_token失效。
接口调用请求说明:
https请求方式: GET
https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET
参数说明:
返回说明
2. 发送模板消息接口
接口调用请求说明
http请求方式: POST
https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=ACCESS_TOKEN
3. 获得关注用户id
公众号可通过本接口来获取帐号的关注者列表,关注者列表由一串OpenID(加密后的微信号,每个用户对每个公众号的OpenID是唯一的)组成。一次拉取调用最多拉取10000个关注者的OpenID,可以通过多次拉取的方式来满足需求。
接口调用请求说明
http请求方式: GET(请使用https协议)
https://api.weixin.qq.com/cgi-bin/user/get?access_token=ACCESS_TOKEN&next_openid=NEXT_OPENID
参数说明:
后端操作
我使用的是idea开发工具+spring boot+mybatis+mysql
1. 创建项目
2. pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<packaging>war</packaging>
<name>weixing</name>
<groupId>com.weixing</groupId>
<artifactId>weixing</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.2.RELEASE</version>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<shiro.version>1.3.2</shiro.version>
</properties>
<dependencies>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.2.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.27</version>
</dependency>
<dependency>
<groupId>net.sf.json-lib</groupId>
<artifactId>json-lib</artifactId>
<version>2.4</version>
<classifier>jdk15</classifier>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>me.chanjar</groupId>
<artifactId>weixin-java-tools</artifactId>
<version>1.0.2</version>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.1.0</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.3.2</version>
</dependency>
<dependency>
<groupId>com.jfinal</groupId>
<artifactId>jfinal-weixin</artifactId>
<version>1.9</version>
</dependency>
<dependency>
<groupId>com.jfinal</groupId>
<artifactId>jfinal</artifactId>
<version>3.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot </groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true </optional>
</dependency>
<!-- swagger依赖 -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.6.1</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.6.1</version>
</dependency>
<!-- 集成shiro 权限控制-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>${shiro.version}</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-web</artifactId>
<version>${shiro.version}</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>${shiro.version}</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>${shiro.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>springloaded</artifactId>
<version>1.2.5.RELEASE</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
</project>
- application.properties配置文件
在配置文件配置端口以及数据库信息
server.port=8081
server.tomcat.max-threads=1000
spring.output.ansi.enabled=DETECT
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/weixing?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&allowMultiQueries=true&useSSL=false
spring.datasource.username=root
spring.datasource.password=
mybatis.mapper-locations=classpath:mybatis/*.xml
mybatis.type-aliases-package=com.application.pojo
- 创建pojo
4.1AccessToken微信通用接口凭证
package com.application.pojo;
import java.util.Date;
/**
* 微信通用接口凭证
* Created by 13592 on 2017/6/26.
*/
public class AccessToken {
//获取到的凭证
private String token;
//凭证有效时间,单位:秒
private int expiresIn;
//当前时间
private Date time;
public String getToken() {
return token;
}
public void setToken(String token) {
this.token = token;
}
public int getExpiresIn() {
return expiresIn;
}
public void setExpiresIn(int expiresIn) {
this.expiresIn = expiresIn;
}
public Date getTime() {
return time;
}
public void setTime(Date time) {
this.time = time;
}
}
4.2UserList用户列表
package com.application.pojo;
import org.json.JSONArray;
/**
* 用户列表
* Created by 13592 on 2017/6/27.
*/
public class UserList {
//关注该公众账号的总用户数
private int total;
//拉取的OPENID个数,最大值为10000
private int count;
//列表数据,OPENID的列表
private JSONArray data;
//拉取列表的最后一个用户的OPENID
private String next_openid;
public int getTotal() {
return total;
}
public void setTotal(int total) {
this.total = total;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
public JSONArray getData() {
return data;
}
public void setData(JSONArray data) {
this.data = data;
}
public String getNext_openid() {
return next_openid;
}
public void setNext_openid(String next_openid) {
this.next_openid = next_openid;
}
}
- 常量类,用于配置接口以及一些固定的信息
5.1WechatApiUrlConstants微信常量API常量类
package com.application.scheduling;
/**
* 微信常量API常量类
* Created by 13592 on 2017/6/27.
*/
public class WechatApiUrlConstants {
//凭证获取
public final static String token_url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";
//用户列表
public final static String user_list_url = "https://api.weixin.qq.com/cgi-bin/user/get?access_token=ACCESS_TOKEN&next_openid=NEXT_OPENID";
//用户信息
public final static String user_data_url = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN";
//微信接口
public final static String weixing_url = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=ACCESS_TOKEN";
//第三方用户唯一凭证
public final static String appid = "wx8aae499a2";
//第三方用户唯一凭证密钥
public final static String secret = "075c76ea076a8";
//模板id
public final static String template_id = "WmDf6MhB6lgUk";
//详情连接
public final static String url = "http://www.baidu.com/";
//测试凭证
public final static String ce_appid = "wxe50a7d9ecf";
//测试密钥
public final static String ce_secret = "33ed74e6e1";
//测试模板id
public final static String ce_template_id = "RY2_Ga_Epv7o59pYhpTclXw";
//预览人员 燕之夜
public final static String preview_yaner = "ow-b4GR-LyAixQbu1_9pZX-Y";
- 工具类-htt请求/调用接口/时间计算等
6.1MyX509TrustManager微信请求-信任管理器
package com.application.util;
import javax.net.ssl.X509TrustManager;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
/**
* 微信请求-信任管理器
* Created by 13592 on 2017/6/26.
*/
public class MyX509TrustManager implements X509TrustManager{
/**
* 该方法检查客户端的证书,若不信任该证书则抛出异常。由于我们不需要对客户端进行认证,因此我们只需要执行默认的信任管理器的这个方法。
* JSSE中,默认的信任管理器类为TrustManager。
* @param x509Certificates
* @param s
* @throws CertificateException
*/
@Override
public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
}
/**
* 该方法检查服务器的证书,若不信任该证书同样抛出异常。通过自己实现该方法,可以使之信任我们指定的任何证书。
* 在实现该方法时,也可以简单的不做任何处理,即一个空的函数体,由于不会抛出异常,它就会信任任何证书。
* @param x509Certificates
* @param s
* @throws CertificateException
*/
@Override
public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
}
/**
* 返回受信任的X509证书数组。
* @return
*/
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
}
6.2AccessTokenUtil获取微信APPID和secret工具类
package com.application.util;
import com.application.pojo.AccessToken;
import com.application.pojo.UserData;
import com.application.pojo.UserList;
/**
* 获取微信APPID和secret工具类
* Created by 13592 on 2017/6/27.
*/
public class AccessTokenUtil {
public static AccessToken accessToken = new AccessToken();
public static UserData userData = new UserData();
public static UserList userList = new UserList();
}
6.3CommonUtil通用工具类/配置类
package com.application.util;
import com.application.from.MessageFrom;
import com.application.pojo.AccessToken;
import com.application.pojo.UserData;
import com.application.pojo.UserList;
import com.application.scheduling.WechatApiUrlConstants;
import net.sf.json.JSONObject;
import org.json.JSONArray;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Configuration;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.ConnectException;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
/**
* 通用工具类
* Created by 13592 on 2017/6/26.
*/
@Configuration
public class CommonUtil {
private static Logger log = LoggerFactory.getLogger(CommonUtil.class);
/**
* 发送https请求
*
* @param requestUrl 请求地址
* @param requestMethod 请求方式(GET、POST)
* @param outputStr 提交的数据
* @return JSONObject(通过JSONObject.get(key)的方式获取json对象的属性值)
*/
public static JSONObject httpsRequest(String requestUrl, String requestMethod, String outputStr) {
JSONObject jsonObject = null;
try {
// 创建SSLContext对象,并使用我们指定的信任管理器初始化
TrustManager[] tm = { new MyX509TrustManager() };
SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
sslContext.init(null, tm, new java.security.SecureRandom());
// 从上述SSLContext对象中得到SSLSocketFactory对象
SSLSocketFactory ssf = sslContext.getSocketFactory();
URL url = new URL(requestUrl);
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
conn.setSSLSocketFactory(ssf);
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setUseCaches(false);
// 设置请求方式(GET/POST)
conn.setRequestMethod(requestMethod);
// 当outputStr不为null时向输出流写数据
if (null != outputStr) {
OutputStream outputStream = conn.getOutputStream();
// 注意编码格式
outputStream.write(outputStr.getBytes("UTF-8"));
outputStream.close();
}
// 从输入流读取返回内容
InputStream inputStream = conn.getInputStream();
InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String str = null;
StringBuffer buffer = new StringBuffer();
while ((str = bufferedReader.readLine()) != null) {
buffer.append(str);
}
// 释放资源
bufferedReader.close();
inputStreamReader.close();
inputStream.close();
inputStream = null;
conn.disconnect();
jsonObject = JSONObject.fromObject(buffer.toString());
} catch (ConnectException ce) {
log.error("连接超时:{}", ce);
} catch (Exception e) {
log.error("https请求异常:{}", e);
}
return jsonObject;
}
/**
* 获取接口访问凭证
*
* @param appid 凭证
* @param appsecret 密钥
* @return
*/
public static AccessToken getToken(String appid, String appsecret) {
String requestUrl = WechatApiUrlConstants.token_url.replace("APPID", appid).replace("APPSECRET", appsecret);
// 发起GET请求获取凭证
JSONObject jsonObject = httpsRequest(requestUrl, "GET", null);
if (null != jsonObject) {
try {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
AccessTokenUtil.accessToken.setToken(jsonObject.getString("access_token"));
AccessTokenUtil.accessToken.setExpiresIn(jsonObject.getInt("expires_in"));
AccessTokenUtil.accessToken.setTime(dateFormat.parse(dateFormat.format(new Date())));
if(null != AccessTokenUtil.accessToken){
log.info("获取access_token成功,有效时长{}秒 token:{}", AccessTokenUtil.accessToken.getExpiresIn(), AccessTokenUtil.accessToken.getToken());
}
} catch (Exception e) {
AccessTokenUtil.accessToken = null;
log.error("{}", e);
log.error("获取token失败 errcode:{} errmsg:{}", jsonObject.getInt("errcode"), jsonObject.getString("errmsg"));
}
}
return AccessTokenUtil.accessToken;
}
/**
* 获取用户信息
* @param open 用户id
* @param token 调用接口凭证
* @return
*/
public static UserData getUser(List<String> open, String token){
for (int i = 0 ; i < open.size() ; i ++){
String requestUrl = WechatApiUrlConstants.user_data_url.replace("ACCESS_TOKEN",token).replace("OPENID",open.get(i));
//发起GET请求获取凭证
JSONObject jsonObject = httpsRequest(requestUrl,"GET",null);
if (null != jsonObject){
try {
AccessTokenUtil.userData.setSubscribe(jsonObject.getInt("subscribe"));
AccessTokenUtil.userData.setOpenid(jsonObject.getString("openid"));
AccessTokenUtil.userData.setNickname(jsonObject.getString("nickname"));
AccessTokenUtil.userData.setSex(jsonObject.getInt("sex"));
AccessTokenUtil.userData.setLanguage(jsonObject.getString("language"));
AccessTokenUtil.userData.setCity(jsonObject.getString("city"));
AccessTokenUtil.userData.setProvince(jsonObject.getString("province"));
AccessTokenUtil.userData.setCountry(jsonObject.getString("country"));
AccessTokenUtil.userData.setHeadimgurl(jsonObject.getString("headimgurl"));
AccessTokenUtil.userData.setSubscribe_time(jsonObject.getString("subscribe_time"));
AccessTokenUtil.userData.setUnionid(jsonObject.getString("unionid"));
AccessTokenUtil.userData.setRemark(jsonObject.getString("remark"));
AccessTokenUtil.userData.setGroupid(jsonObject.getInt("groupid"));
AccessTokenUtil.userData.setTagid_list(jsonObject.get("tagid_list"));
if (null != AccessTokenUtil.userData){
log.info("获取用户信息成功, token:{}",open.get(i), jsonObject.getString("nickname"));
System.out.println("用户id:"+open.get(i)+"用户姓名:"+jsonObject.getString("nickname"));
}else{
log.error("获取用户信息失败 errcode:{} errmsg:{}", jsonObject.getInt("errcode"), jsonObject.getString("errmsg"));
}
}catch (Exception e){
e.printStackTrace();
}
}
}
return AccessTokenUtil.userData;
}
/**
* 获取关注用户列表
* @param token 调用接口凭证
* @param openid 第一个拉取的OPENID
* @return
*/
public static UserList getUserList(String token,String openid){
String requestUrl = WechatApiUrlConstants.user_list_url.replace("ACCESS_TOKEN",token).replace("NEXT_OPENID","");
//发起GET请求获取凭证
JSONObject jsonObject = httpsRequest(requestUrl,"GET",null);
if (null != jsonObject){
try {
AccessTokenUtil.userList.setCount(jsonObject.getInt("count"));
AccessTokenUtil.userList.setNext_openid(jsonObject.getString("next_openid"));
AccessTokenUtil.userList.setTotal(jsonObject.getInt("total"));
JSONObject json1 = jsonObject.getJSONObject("data");
JSONArray json2 = new JSONArray(json1.get("openid").toString());
AccessTokenUtil.userList.setData(json2);
if (null != AccessTokenUtil.userList)
log.info("获取用户列表成功, token:{}", AccessTokenUtil.userList.getCount(), AccessTokenUtil.userList.getTotal());
else{
log.error("获取用户列表失败 errcode:{} errmsg:{}", jsonObject.getInt("errcode"), jsonObject.getString("errmsg"));
}
}catch (Exception e){
e.printStackTrace();
}
}
return AccessTokenUtil.userList;
}
/**
* 获取token的时间差
* @param time 获取时间
* @return
*/
public static Long dateDiff(Date time){
Date curretTime = new Date(System.currentTimeMillis());
long nd = 1000 * 24 * 60 * 60;// 一天的毫秒数
long nh = 1000 * 60 * 60;// 一小时的毫秒数
long nm = 1000 * 60;// 一分钟的毫秒数
long ns = 1000;// 一秒钟的毫秒数
long diff;
long day = 0;
long hour = 0;
long min = 0;
long sec = 0;
try {
diff = curretTime.getTime() - time.getTime();
day = diff / nd;// 计算差多少天
hour = diff % nd / nh + day * 24;// 计算差多少小时
min = diff % nd % nh / nm + day * 24 * 60;// 计算差多少分钟
sec = diff % nd % nh % nm / ns;// 计算差多少秒
// 输出结果
System.out.println("时间相差:" + day + "天" + (hour - day * 24) + "小时"
+ (min - day * 24 * 60) + "分钟" + sec + "秒。");
System.out.println("hour=" + hour + ",min=" + min);
} catch (Exception e) {
e.printStackTrace();
}
return hour;
}
/**
* 预览推送模板
* @param mf 模板信息
* @param openid 预览人员
* @param url 推送接口
*/
public static void reviewUser(MessageFrom mf, String openid,String url){
JSONObject json = new JSONObject();
json.put("touser", openid);//接收者wxName
json.put("template_id", WechatApiUrlConstants.ce_template_id);//消息模板
json.put("url", WechatApiUrlConstants.url);//填写url可查看详情
JSONObject dd = new JSONObject();
JSONObject dd2 = new JSONObject();
dd2.put("value", mf.getTitle_name());//消息提示
dd2.put("color", "#173177");
dd.put("first", dd2);
JSONObject cc2 = new JSONObject();
cc2.put("value", mf.getVulnerability_levels());//漏洞等级
cc2.put("color", "#173177");
dd.put("keyword1", cc2);
JSONObject ee2 = new JSONObject();
ee2.put("value", mf.getVulnerability_time());//漏洞时间
ee2.put("color", "#173177");
dd.put("keyword2", ee2);
JSONObject gg2 = new JSONObject();
gg2.put("value", mf.getVulnerabiliry_Overview());
gg2.put("color", "#173177");
dd.put("remark", gg2);
json.put("data", dd);
System.out.println(json.toString());
JSONObject js = CommonUtil.httpsRequest(url, "POST", json.toString());
System.out.println("js=="+js);
}
/**
* 全推送模板
* @param mf 模板信息
* @param openidList 全关注用户
* @param url 推送接口
*/
public static void push(MessageFrom mf,List<String> openidList,String url){
for (int i = 0 ; i < openidList.size(); i ++){
JSONObject json = new JSONObject();
json.put("touser", openidList.get(i));//接收者wxName
json.put("template_id", WechatApiUrlConstants.ce_template_id);//消息模板
json.put("url", WechatApiUrlConstants.url);//填写url可查看详情
JSONObject dd = new JSONObject();
JSONObject dd2 = new JSONObject();
dd2.put("value", mf.getTitle_name());//消息提示
dd2.put("color", "#173177");
dd.put("first", dd2);
JSONObject cc2 = new JSONObject();
cc2.put("value", mf.getVulnerability_levels());//漏洞等级
cc2.put("color", "#173177");
dd.put("keyword1", cc2);
JSONObject ee2 = new JSONObject();
ee2.put("value", mf.getVulnerability_time());//漏洞时间
ee2.put("color", "#173177");
dd.put("keyword2", ee2);
JSONObject gg2 = new JSONObject();
gg2.put("value", mf.getVulnerabiliry_Overview());
gg2.put("color", "#173177");
dd.put("remark", gg2);
json.put("data", dd);
System.out.println(json.toString());
JSONObject js = CommonUtil.httpsRequest(url, "POST", json.toString());
System.out.println("js=="+js);
}
}
}
- service
7.1AccessTokenService全局调用凭证的操作
package com.application.service;
import java.util.Date;
/**
* 全局调用凭证的操作
* Created by 13592 on 2017/6/27.
*/
public interface AccessTokenService {
/**
* 新增全局调用凭证信息
* @param token 全局调用凭证id
*/
void insertToken(String token);
/**
* 删除表中信息
* @return
*/
void deleteToken();
/**
* 查询全局调用凭证id
* @return
*/
String selectToken();
/**
* 查询新增时间
* @return
*/
Date selectTime();
}
7.1.1AccessTokenServiceImpl
package com.application.service.impl;
import com.application.mapper.AccessTokenMapper;
import com.application.pojo.AccessToken;
import com.application.service.AccessTokenService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Date;
/**
* Created by 13592 on 2017/6/27.
*/
@Service
public class AccessTokenServiceImpl implements AccessTokenService {
@Autowired
private AccessTokenMapper accessTokenMapper;
@Override
public void insertToken(String token){
AccessToken accessToken = new AccessToken();
Date curretTime = new Date(System.currentTimeMillis());
accessToken.setToken(token);
accessToken.setTime(curretTime);
accessTokenMapper.insertToken(accessToken);
}
@Override
public void deleteToken(){
accessTokenMapper.deleteToken();
}
@Override
public String selectToken(){
return accessTokenMapper.selectToken();
}
@Override
public Date selectTime(){return accessTokenMapper.selectTime();}
}
7.2PreviewService预览人员操作
package com.application.service;
import com.application.pojo.PreviewUser;
import java.util.List;
/**
* 预览人员操作
* Created by 13592 on 2017/6/29.
*/
public interface PreviewService {
/**
* 查询用户id列表
* @return
*/
List<String> getOpenid();
/**
* 新增预览用户信息
* @param previewUser
*/
void insertOpenid(PreviewUser previewUser);
/**
* 查询预览列表
* @return
*/
List<PreviewUser> previewList();
/**
* 通过微信名称查询预览用户id
* @param opename 微信名称
* @return
*/
String selectOpenid(String opename);
}
7.2.2PreviewServiceImpl
package com.application.service.impl;
import com.application.mapper.PreviewMapper;
import com.application.pojo.PreviewUser;
import com.application.service.PreviewService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* Created by 13592 on 2017/6/29.
*/
@Service
public class PreviewServiceImpl implements PreviewService{
@Autowired
private PreviewMapper previewMapper;
@Override
public List<String> getOpenid(){
List<String> openidList = previewMapper.getOpenid();
return openidList;
}
@Override
public void insertOpenid(PreviewUser previewUser){
try {
previewMapper.insertOpenid(previewUser);
}catch (Exception e){
e.printStackTrace();
}
}
@Override
public List<PreviewUser> previewList(){
return previewMapper.previewList();
}
@Override
public String selectOpenid(String openname){
String id = "";
try {
id = previewMapper.selectOpenid(openname);
}catch (Exception e){
e.printStackTrace();
}
return id;
}
}
- mapper层-完成持久化DAO层
使用MyBatis在我们通过xml集中配置SQL,并通过创建接口Mapper文件来完成持久化DAO层(mybatis内部使用的是动态代理,所以我们不需要自己编写实现类)。
8.1AccessTokenMapper
package com.application.mapper;
import com.application.pojo.AccessToken;
import java.util.Date;
/**
* Created by 13592 on 2017/6/27.
*/
public interface AccessTokenMapper {
void insertToken(AccessToken token);
void deleteToken();
String selectToken();
Date selectTime();
}
8.2PreviewMapper
package com.application.mapper;
import com.application.pojo.PreviewUser;
import java.util.List;
/**
* Created by 13592 on 2017/6/29.
*/
public interface PreviewMapper {
List<String> getOpenid();
void insertOpenid(PreviewUser previewUser);
List<PreviewUser> previewList();
String selectOpenid(String openname);
}
- form页面接受参数类
用于接受页面传过来的数据
9.1MessageFrom
package com.application.from;
/**
* Created by 13592 on 2017/6/28.
*/
public class MessageFrom {
//预览用户
private String preview_user;
//标题名称
private String title_name;
//漏洞等级
private String Vulnerability_levels;
//漏洞时间
private String Vulnerability_time;
//漏洞概要
private String Vulnerabiliry_Overview;
public String getPreview_user() {
return preview_user;
}
public void setPreview_user(String preview_user) {
this.preview_user = preview_user;
}
public String getTitle_name() {
return title_name;
}
public void setTitle_name(String title_name) {
this.title_name = title_name;
}
public String getVulnerability_levels() {
return Vulnerability_levels;
}
public void setVulnerability_levels(String vulnerability_levels) {
Vulnerability_levels = vulnerability_levels;
}
public String getVulnerability_time() {
return Vulnerability_time;
}
public void setVulnerability_time(String vulnerability_time) {
Vulnerability_time = vulnerability_time;
}
public String getVulnerabiliry_Overview() {
return Vulnerabiliry_Overview;
}
public void setVulnerabiliry_Overview(String vulnerabiliry_Overview) {
Vulnerabiliry_Overview = vulnerabiliry_Overview;
}
}
9.2PreviewUserForm
package com.application.from;
/**
* 页面预览人员
* Created by 13592 on 2017/6/30.
*/
public class PreviewUserForm {
//预览用户id
private String openid;
//预览用户名
private String name;
public String getOpenid() {
return openid;
}
public void setOpenid(String openid) {
this.openid = openid;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
- 使用swagger
10.1Swagger2
package com.application;
import com.google.common.base.Predicates;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.context.request.async.DeferredResult;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
/**
* 说明:
* 时间: 2017/3/28 11:32
*
* @author wimas
*/
@Configuration
@EnableSwagger2
public class Swagger2 {
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2).groupName("access")
.genericModelSubstitutes(DeferredResult.class)
.useDefaultResponseMessages(false)
.forCodeGeneration(true)
.pathMapping("/")// base,最终调用接口后会和paths拼接在一起s
.select()
.paths(Predicates.or(PathSelectors.regex("/access/.*")))//过滤的接口
.build()
.apiInfo(apiInfo());
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("微信模板推送")
.description("")
.version("1.0")
.build();
}
}
- controller控制类
11.1WechatController
package com.application.controller;
import com.application.from.MessageFrom;
import com.application.from.PreviewUserForm;
import com.application.pojo.AccessToken;
import com.application.pojo.PreviewUser;
import com.application.pojo.UserData;
import com.application.pojo.UserList;
import com.application.scheduling.WechatApiUrlConstants;
import com.application.service.AccessTokenService;
import com.application.service.PreviewService;
import com.application.util.CommonUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import java.util.*;
/**
* 微信推送信息
* Created by 13592 on 2017/6/26.
*/
@RestController
@RequestMapping("/access")
@Api(description = "微信模板推送")
public class WechatController {
@Autowired
private PreviewService previewService;
@Autowired
private AccessTokenService accessTokenService;
@ApiOperation(value = "模板推送")
@PostMapping(value = "/token")
@ApiImplicitParam(name = "mf", value = "模板信息", required = true, dataType = "MessageFrom")
@RequiresPermissions("access:token")
public void wxTuisong(@Valid @RequestBody MessageFrom mf){
AccessToken token = new AccessToken();
Date date = accessTokenService.selectTime();
Long time = getDiff(date);
if(time>=2){//时间间隔大于等于2个小时则重新取接口调用凭证
accessTokenService.deleteToken();
token = headtoken (WechatApiUrlConstants.appid,WechatApiUrlConstants.secret);//获取token
accessTokenService.insertToken(token.getToken());
}else{
token.setToken(accessTokenService.selectToken());
}
if(token.getToken()!=null){
UserList userList = getUserList(token.getToken(),"");
String url = WechatApiUrlConstants.weixing_url.replace("ACCESS_TOKEN", token.getToken());//转换为响应接口模式
List<String> previewUserList = previewService.getOpenid();//预览用户id列表
List<String> opeidList = new ArrayList<String>();//所有关注用户列表
for (int i = 0 ; i < userList.getData().length() ; i ++){
opeidList.add(userList.getData().get(i).toString());
}
List<String> list = new ArrayList<String>();
if (mf.getPreview_user()!= "" || !mf.getPreview_user().equals("string")){
for (int i = 0 ; i < previewUserList.size(); i ++){
if(mf.getPreview_user().equals(previewUserList.get(i))){
reviewUser(mf,previewUserList.get(i),url);
}
}
}else{
push(mf,opeidList,url);
}
}
}
@ApiOperation(value = "新增预览人员")
@PostMapping(value = "/insert")
@ApiImplicitParam(name = "puf", value = "模板信息", required = true, dataType = "PreviewUserForm")
@RequiresPermissions("access:insert")
public void insert(@Valid @RequestBody PreviewUserForm puf){
PreviewUser previewUser = new PreviewUser();
previewUser.setOpenid(puf.getOpenid());
previewUser.setOpenname(puf.getName());
previewService.insertOpenid(previewUser);
}
@ApiOperation(value = "查询预览列表")
@GetMapping(value = "/selectList")
@RequiresPermissions("access:selectList")
public List<PreviewUser> selectList(){
return previewService.previewList();
}
@ApiOperation(value = "查询预览id")
@GetMapping(value = "/selectOpenid/{openname}")
@RequiresPermissions("access:selectOpenid")
public String selectOpenid(@ApiParam(name = "openname",value = "用户名称",required = true) @PathVariable String openname){
return previewService.selectOpenid(openname);
}
/**
* 请求token
* @Description :
* @param
* @return
* ---------------
* @Author : My
* @CreateData : 2016-1-18
*/
public static AccessToken headtoken (String appId,String appSrecet){
AccessToken token = CommonUtil.getToken(appId, appSrecet);
return token;
}
/**
* 获取关注用户
* @param token 接口调用凭证
* @param openid
* @return
*/
public static UserList getUserList(String token,String openid){
UserList userList = CommonUtil.getUserList(token,openid);
return userList;
}
/**
* 时间获取
* @param time 获取时间
* @return
*/
public static Long getDiff(Date time){
CommonUtil commonUtil = new CommonUtil();
return commonUtil.dateDiff(time);
}
/**
* 获取用户信息
* @param openid 用户id
* @param token 接口调用凭证
* @return
*/
public static UserData userDate(List<String> openid,String token){
CommonUtil commonUtil = new CommonUtil();
return commonUtil.getUser(openid,token);
}
/**
* 预览推送模板
* @param mf 模板信息
* @param openid 用户id
* @param url 接口
*/
public static void reviewUser(MessageFrom mf, String openid,String url){
/* CommonUtil commonUtil = new CommonUtil();
commonUtil.reviewUser(mf, openid, url);*/
}
/**
* 全推送模板
* @param mf 模板信息
* @param openidList 全关注用户
* @param url 推送接口
*/
public static void push(MessageFrom mf,List<String> openidList,String url){
/* CommonUtil commonUtil = new CommonUtil();
commonUtil.push(mf, openidList, url);*/
}
public static void main(String[] args){
AccessToken token = new AccessToken();
// token = CommonUtil.getToken(APP_ID,SECRET);
WechatController wechatController = new WechatController();
CommonUtil commonUtil = new CommonUtil();
MessageFrom massages = new MessageFrom();
wechatController.wxTuisong(massages);
System.out.println("==================================================");
}
}
- mybatis.xml
12.1AccessTokenMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.application.mapper.AccessTokenMapper" >
<resultMap id="BaseResultMap" type="com.application.pojo.AccessToken">
<result column="access_token_name" property="token" jdbcType="VARCHAR"/>
<result column="access_token_time" property="time" jdbcType="TIMESTAMP"/>
</resultMap>
<insert id="insertToken" parameterType="com.application.pojo.AccessToken">
INSERT INTO weixing_access_token (
access_token_name,
access_token_time
)
VALUES
(
#{token,jdbcType=VARCHAR},#{time,jdbcType=TIMESTAMP})
</insert>
<delete id="deleteToken">
DELETE
FROM
weixing_access_token
WHERE
1 = 1
</delete>
<select id="selectToken" resultType="String">
SELECT
access_token_name
FROM
weixing_access_token
</select>
<select id="selectTime" resultType="Date">
SELECT
access_token_time
FROM
weixing_access_token
</select>
</mapper>
12.2PreviewMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.application.mapper.PreviewMapper" >
<resultMap id="BaseResultMap" type="com.application.pojo.PreviewUser">
<result column="openid" property="openid" jdbcType="VARCHAR"/>
<result column="openname" property="openname" jdbcType="VARCHAR"/>
</resultMap>
<select id="getOpenid" resultType="java.lang.String">
SELECT openid FROM review_user
</select>
<insert id="insertOpenid" parameterType="com.application.pojo.PreviewUser">
INSERT INTO review_user (openid, openname)
VALUES
(
#{openid,jdbcType=VARCHAR},#{openname,jdbcType=VARCHAR})
</insert>
<select id="previewList" resultMap="BaseResultMap" parameterType="com.application.pojo.PreviewUser">
SELECT * FROM review_user
</select>
<select id="selectOpenid" resultType="string" parameterType="string">
SELECT
openid
FROM
review_user
WHERE
openname = #{openname,jdbcType=VARCHAR}
</select>
</mapper>
- spring boot启动类
13.1Application
package com.application;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
/**
* Created by 13592 on 2017/6/27.
*/
@SpringBootApplication
@EnableCaching
@MapperScan(basePackages = “com.application.mapper”)
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
- 数据库
14.1review_user预览表
14.2weixing_access_token全局调用接口凭证信息表
- 启动Application
正常启动的情况
启动完毕后,在浏览器输入http://localhost:8081/swagger-ui.html
- 测试-输入模板消息
发送之后,因为填写了预览人,所以我会接受到这条推送信息
微信收到的模板
后端显示返回结果
在调用模板消息接口后,会返回JSON数据包。正常时的返回JSON数据包示例:
{
“errcode”:0,
“errmsg”:”ok”,
“msgid”:200228332
}