微信开发文档:
接口调用请求说明
http请求方式: POST
https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=ACCESS_TOKEN
各消息类型所需的JSON数据包如下:
发送文本消息
{
"touser":"OPENID",
"msgtype":"text",
"text":
{
"content":"Hello World"
}
}
创建封装实体类:
import java.util.Map;
/**
* 客户接口消息发送实体
*
* @author
* @date 2018-2-6 11:00:30
*/
public class TestMessage {
//openid
private String touser;
//消息类型
private String msgtype;
//消息内容
private Map text ;
public String getTouser() {
return touser;
}
public void setTouser(String touser) {
this.touser = touser;
}
public String getMsgtype() {
return msgtype;
}
public void setMsgtype(String msgtype) {
this.msgtype = msgtype;
}
public Map getText() {
return text;
}
public void setText(Map text) {
this.text = text;
}
}
后台controller代码:
/**
* 状态修改为测试中
*
* @param id 要测试的ID
* @param request
* @return 内容展示页面
*/
@ResponseBody
@RequestMapping(value = "/service/test", method = RequestMethod.PUT)
public ResponseVO ContentTest(Long id, HttpServletRequest request) {
ResponseVO vo=new ResponseVO();
if(id!=null){
//根据接收的ID查询相应的内容实体
WeixinContent weixinContent = weixinContentService.selectById(id);
//判断查询到的对象的合法性
if (weixinContent!=null&&(weixinContent.getState() == 1||weixinContent.getState()==4)) {
//修改内容实体状态为测试中
weixinContent.setState(2);
//将内容实体进行保存操作
weixinContentService.updateById(weixinContent);
//获得内容静态页面的访问路径
String templatesUrl= weixinContent.getTemplatesUrl();
//拼接访问的完整路径
String saveUrl =fileuploadPrefix + "/" + templatesUrl;
//获得内容信息标题
String title = weixinContent.getTitle();
//拼接发送的消息内容
String content="你好!标题("+title+")点我测试";
//创建微信用户查询条件
Wrapper wrapper=new EntityWrapper<>();
wrapper.where("tagid_list={0}","[101]");
//获得满足条件的集合
List weixinUsers = weixinUserService.selectList(wrapper);
//遍历用户集合调用业务层进行消息发送
for (WeixinUser weixinUser : weixinUsers) {
String openid = weixinUser.getOpenid();
//调用业务层进行发送消息
wxContentTextService.contentTest(openid,content);
}
vo.setSuccess(true);
} else {
//不是未测试状态所以不能进行状态修改
vo.setSuccess(false);
}
}
return vo;
}
后台service代码:
/**
*
* 菜单信息 服务实现类
*
*
* @author
* @date 2018/01/15
*/
@Service
public class WxContentTextService {
private static Logger log = LoggerFactory.getLogger(WxContentTextService.class);
/**
* 客服接口给用户发送消息接口
*/
public static String content_openid="https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=ACCESS_TOKEN";
@Autowired
private TokenFeignService tokenFeignService;
@Autowired
private WeixinPortalService weixinPortalService;
/**
*
* @param openid openid
* @param saveUrl 静态页面访问地址
* @return
*/
public ResponseVO contentTest(String openid,String saveUrl){
//获得令牌
String accessToken = tokenFeignService.getToken();
//创建返回实体对象
ResponseVO vo = new ResponseVO();
//替换token
String url=content_openid.replace("ACCESS_TOKEN", accessToken);
TestMessage testMessage=new TestMessage();
//设置消息的类型
testMessage.setMsgtype("text");
//设置要发送的openid集合
testMessage.setTouser(openid);
//创建集合
Map map=new HashMap<>();
//设置发送内容
map.put("content",saveUrl);
testMessage.setText(map);
//将测试消息对象转成json
String jsonTestMessage = JSONObject.toJSONString(testMessage);
//调用接口进行发送
JSONObject jsonObject = httpRequest(url, "POST", jsonTestMessage);
log.error("分组群发消息失败 errcode:{" + jsonObject.getInteger("errcode")+"} " +
"errmsg:{"+jsonObject.getString("errmsg")+"} ");
Integer errcode = jsonObject.getInteger("errcode");
String errorCodeText = ErrorCodeText.errorMsg(errcode);
if (errcode == 0){
vo.setSuccess(true);
}else{
vo.setSuccess(false);
}
vo.setCode(errcode);
vo.setText(errorCodeText);
return vo;
}
}
获取token的业务层:
import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
/**
* 进行请求分发
*
*/
@FeignClient(value = "weixin-2")
public interface TokenFeignService {
/**
* 进行token请求
* @param
* @return
*/
@RequestMapping(value = "/getToken",method = RequestMethod.GET)
String getToken();
}
微信请求工具类utils
public class WeixinHttpUtil {
private static Logger log = LoggerFactory.getLogger(WeixinHttpUtil.class);
/**
* 描述: 发起https请求并获取结果
* @param requestUrl 请求地址
* @param requestMethod 请求方式(GET、POST)
* @param outputStr 提交的数据
* @return JSONObject(通过JSONObject.get(key)的方式获取json对象的属性值)
*/
public static JSONObject httpRequest(String requestUrl, String requestMethod, String outputStr) {
JSONObject jsonObject = null;
StringBuffer buffer = new StringBuffer();
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 httpUrlConn = (HttpsURLConnection) url.openConnection();
httpUrlConn.setSSLSocketFactory(ssf);
httpUrlConn.setDoOutput(true);
httpUrlConn.setDoInput(true);
httpUrlConn.setUseCaches(false);
// 设置请求方式(GET/POST)
httpUrlConn.setRequestMethod(requestMethod);
if ("GET".equalsIgnoreCase(requestMethod))
{httpUrlConn.connect();}
// 当有数据需要提交时
if (null != outputStr) {
OutputStream outputStream = httpUrlConn.getOutputStream();
// 注意编码格式,防止中文乱码
outputStream.write(outputStr.getBytes("UTF-8"));
outputStream.close();
}
// 将返回的输入流转换成字符串
InputStream inputStream = httpUrlConn.getInputStream();
InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String str = null;
while ((str = bufferedReader.readLine()) != null) {
buffer.append(str);
}
bufferedReader.close();
inputStreamReader.close();
// 释放资源
inputStream.close();
inputStream = null;
httpUrlConn.disconnect();
jsonObject = JSONObject.parseObject(buffer.toString());
} catch (ConnectException ce) {
log.error("Weixin server connection timed out.");
} catch (Exception e) {
log.error("https request error:{}", e);
}
return jsonObject;
}
}
应网友要求贴出获取token部分代码,首先要配置公众号相关配置
1.IP白名单
2.配置开发模式
3.在自己配置的白名单服务器就可以获取token,根据自己配置的服务器接口就可以监听所有公众号的操作,从而得到操作用户信息和具体操作内容
3.1这个就是通过springCloud远程调用获取token接口
@Controller @RequestMapping("") public class WeixinTokenController { @Autowired private WeixinAccessTokenTask weixinAccessTokenTask; @RequestMapping("getToken") @ResponseBody public String getToken(){ AccessToken token = weixinAccessTokenTask.getLastAccessToken(); return token.getAccessToken(); } }
3.2具体获取token业务
@Component public class WeixinAccessTokenTask implements ApplicationListener { protected final static Logger logger = LoggerFactory.getLogger(WeixinAccessTokenTask.class); private static boolean isStart = false; /** * 微信Access_Token刷新地址 */ private String uri = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET"; /** * 存放Access_Token的标识符 */ private String tokenKey = "WEIXIN_ACCESS_TOKEN"; /** * 最近一次的Access_Token */ private AccessToken lastAccessToken; /** * 微信分配的appID */ @Value("${app.id}") private String appID; /** * 微信分配的appsecret */ @Value("${app.secrect}") private String appsecrect; private long lastRunTime; /** * 刷新Access_Token * @return boolean 刷新是否成功 */ @Scheduled(cron="0 0/5 * * * ?") public boolean refresh(){ boolean refresh = this.refresh(false); //重置最后一次定时器运行时间 lastRunTime = System.currentTimeMillis(); return refresh; } /** * 刷新Access_Token * @param forced 是否强制 * @return boolean 刷新是否成功 */ public boolean refresh(boolean forced){ if(!(forced || this.isNeedRefresh())){ return false; } try { AccessToken token = this.getWeixinAccessToken(); //把token存入lastAccessToken,便于下次检验token是否有效 lastAccessToken = token; return true; } catch (IOException e){ e.printStackTrace(); } return false; } /** * 请求微信接口获取最新的access_token信息 * @return AccessToken */ public AccessToken getWeixinAccessToken() throws IOException{ String uri = this.uri.replace("APPID", this.getAppID()).replace("APPSECRET", this.getAppsecrect()); URL url = new URL(uri); HttpURLConnection conn = null; BufferedReader reader = null; StringBuffer buffer = new StringBuffer(); try{ conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod("GET"); conn.connect(); reader = new BufferedReader(new InputStreamReader(conn.getInputStream())); String line; while ((line = reader.readLine()) != null) { buffer.append(line); } }finally { if(reader != null){ reader.close(); } if(conn != null){ conn.disconnect(); } } //返回的参数是json格式 JSONObject jsonObject = JSONObject.parseObject(buffer.toString()); AccessToken token = new AccessToken(); if (!jsonObject.containsKey("access_token")) {//如果没拿到token,肯定发生了问题,打印错误日志 logger.info(jsonObject.toJSONString()); } String accessToken = jsonObject.getString("access_token"); String expiresInStr = jsonObject.getString("expires_in"); int expiresIn = Integer.parseInt(expiresInStr); token.setAccessToken(accessToken); token.setExpiresIn(expiresIn); //设置token的更新时间 token.setUpdateTime(new Date()); logger.info("最新的token>>>> "+ AesUtil.aesEncrypt(accessToken)); return token; } /** * 是否需要刷新 * * @return boolean 判断是否需要刷新 */ private boolean isNeedRefresh(){ AccessToken token = this.getLastAccessToken(); /*如果上次会话不存在,肯定是需要刷新缓存的*/ if(null == token){ return true; } //当前系统时间 long now = System.currentTimeMillis(); //此次运行和上次运行的时间间隔,5min long interval = now - this.lastRunTime; //上次token的更新时间 long lastTimeMillis = this.getLastTimeMillis(); //此处在微信规定7200秒的基础上减去1800秒,即度过1h30m的时间,就认为token已失效,以此保证token的有效性 int expiresIn = 5400*1000; /*如果时间间隔不足以支撑到下次运算时的超时时间,则会话会在本次被刷新*/ // logger.info("判断是否需要刷新开始---------"); // logger.info(" 此时此刻 now ---------" + now); // logger.info("此次运行和上次运行的时间间隔 interval ---------" + interval); // logger.info(" 上次token的更新时间 lastTimeMillis ---------" + lastTimeMillis); // logger.info(" token有效期 expiresIn ---------" + expiresIn); // logger.info("计算表达式(lastTimeMillis + expiresIn) <= (now + interval)---------" + ((lastTimeMillis + expiresIn) <= (now + interval))); if((lastTimeMillis + expiresIn) <= (now + interval)){ return true; } return false; } private String getAppID() { return appID; } public void setAppID(String appID) { this.appID = appID; } private String getAppsecrect() { return appsecrect; } public void setAppsecrect(String appsecrect) { this.appsecrect = appsecrect; } public AccessToken getLastAccessToken(){ if(this.lastAccessToken == null){ return null; } return this.lastAccessToken; } //获得token有效期的时间戳 private long getLastTimeMillis(){ AccessToken token = this.getLastAccessToken(); Date updateTime = token.getUpdateTime(); if(updateTime == null){ return 0L; } long millis = updateTime.getTime(); return millis; } @Override public void onApplicationEvent(ApplicationEvent applicationEvent) { if (!isStart) { isStart = true; logger.info("启动token刷新服务.........."); this.refresh(); } } }