Java发送微信模板消息
微信模板消息如果在小程序实现是比较简单的,但是有些业务必须后台实现。所以只要拿到prepay_id 或者fromId就可以了
1. 添加模板
进入微信公众平台小程序 添加自定义模板
https://mp.weixin.qq.com/wxopen/authprofile
查看官方文档
https://developers.weixin.qq.com/miniprogram/dev/api/sendTemplateMessage.html
注意这里的form_id,表单提交场景下,为 submit 事件带上的 formId;支付场景下,为本次支付的 prepay_id,由于业务中prepay_id比较好拿就是用prepay_id了,注意一个坑就是接受模板消息者必须使用他的prepay_id,而且只能用三次。
2. 编程
- 为了方便创建了一张表来保存prepay_id。此步骤可以省略,直接代码写死也是可以的
CREATE TABLE `wx_user_prepayid` (
`id` int(20) NOT NULL AUTO_INCREMENT,
`userId` varchar(50) DEFAULT NULL COMMENT '用户id',
`prepayId` varchar(50) DEFAULT NULL COMMENT '支付id',
`fromId` varchar(50) DEFAULT NULL COMMENT 'fromId提交表单id',
`openId` varchar(50) DEFAULT NULL COMMENT 'openId',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=695 DEFAULT CHARSET=utf8
- 代码
由于比较懒就直接把业务中的代码贴出来了,有需要自己改下 ,这里用的是mybatisPlus
如果省略的创建数据库步骤直接把下面打注释的拿来用就好了。
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dlc.lzsharebed.entity.WxUserPrepayid;
import com.dlc.lzsharebed.mapper.WxUserPrepayidMapper;
import com.dlc.lzsharebed.service.IWxUserPrepayidService;
import com.dlc.lzsharebed.utils.SendTemplateMessage;
import com.github.pagehelper.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
/**
* @author jijl
* @since 2018-12-05
*/
@Service
@Slf4j
public class WxUserPrepayidServiceImpl extends ServiceImpl<WxUserPrepayidMapper, WxUserPrepayid> implements IWxUserPrepayidService {
@Override
public void send(String userId,String endDate) {
log.info("---发送消息 userId:{}",userId);
log.info("--发送消息 endDate:{}",userId);
QueryWrapper queryWrapper = new QueryWrapper();
queryWrapper.eq("userId", userId);
queryWrapper.orderByDesc("id");
WxUserPrepayid wxUserPrepayid = selectOne(queryWrapper);
if(wxUserPrepayid!=null){
String fromId = wxUserPrepayid.getPrepayId();
String optionId = wxUserPrepayid.getOpenId();
//template_id 根据实际来 TODO
String template_id = "template_id ";
String keyword2 = endDate;
//AppId根据实际来 TODO
String wx_SpAppId= "AppId";
//Secrect根据实际来 TODO
String wx_SpSecrect= "Secrect";
//发送微信模板消息
SendTemplateMessage.sendMessage(fromId, optionId, template_id,keyword2,wx_SpAppId,wx_SpSecrect);
}
//发送微信模板消息测试
// String fromId = "wx05143135971766cee0cb40da0499151483";
// String optionId = "oBBqp5baIEPSoqisRVGNjrXRJaEM";
// String template_id = "template_id ";
// String keyword2 = "2018年9月30日16:33:44";
// String wx_SpAppId= "wx_SpAppId";
// String wx_SpSecrect= "wx_SpSecrect";
// SendTemplateMessage.sendMessage(fromId, optionId, template_id,keyword2,wx_SpAppId,wx_SpSecrect);
}
}
这个类写的是不规范的,但是功能可以实现的有强迫症的同学可以改下
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.*;
import java.util.HashMap;
import java.util.Map;
/**
* @auther: jijl
* @Date: Create in 2018/11/12
* @Description: 发送小程序模板消息
**/
@Data
@Slf4j
public class SendTemplateMessage {
/**
* 接收者(用户)的 openid
*/
private String touser;
/**
* 所需下发的模板消息的id
*/
private String template_id;
/**
* 点击模板卡片后的跳转页面,仅限本小程序内的页面。支持带参数,(示例index?foo=bar)。该字段不填则模板无跳转。
*/
private String page;
/**
* 表单提交场景下,为 submit 事件带上的 formId;支付场景下,为本次支付的 prepay_id
*/
private String form_id;
/**
* 模板内容,不填则下发空模板
*/
private Map<String, Object> data;
/**
* 模板需要放大的关键词,不填则默认无放大
*/
private String emphasis_keyword;
/**
* 发送模板消息sendTemplateMessage
* 小程序模板消息,发送服务通知
*
* @param touser 接收者(用户)的 openid
* @param template_id 所需下发的模板消息的id
* @param page 点击模板卡片后的跳转页面,仅限本小程序内的页面。支持带参数,(示例index?foo=bar)。该字段不填则模板无跳转。
* @param formid 表单提交场景下,为 submit 事件带上的 formId;支付场景下,为本次支付的 prepay_id
* @return
*/
public static JSONObject sendTemplateMessage(String touser, String template_id, String page, String formid, Map<String, Object> map, String accessToken) {
SendTemplateMessage sendTemplateMessage = new SendTemplateMessage();
//拼接数据
sendTemplateMessage.setTouser(touser);
sendTemplateMessage.setTemplate_id(template_id);
sendTemplateMessage.setPage(page);
sendTemplateMessage.setForm_id(formid);
sendTemplateMessage.setData(map);
sendTemplateMessage.setEmphasis_keyword("");
String json = JSONObject.toJSONString(sendTemplateMessage);
log.info("##模版发送JSON数据: " + json);
String ret = SendTemplateMessage.sendPost("https://api.weixin.qq.com/cgi-bin/message/wxopen/template/send?access_token=" + accessToken, json);
return JSON.parseObject(ret);
}
/**
* 发送post请求 json格式
*
* @param url
* @param param
* @return
*/
public static String sendPost(String url, String param) {
PrintWriter out = null;
BufferedReader in = null;
String result = "";
try {
URL realUrl = new URL(url);
// 打开和URL之间的连接
URLConnection conn = realUrl.openConnection();
// 设置通用的请求属性
conn.setRequestProperty("Accept", "application/json");
conn.setRequestProperty("Content-Type", "application/json");
// 发送POST请求必须设置如下两行
conn.setDoOutput(true);
conn.setDoInput(true);
// 获取URLConnection对象对应的输出流
out = new PrintWriter(conn.getOutputStream());
// 发送请求参数
out.print(param);
// flush输出流的缓冲
out.flush();
// 定义BufferedReader输入流来读取URL的响应
in = new BufferedReader(
new InputStreamReader(conn.getInputStream()));
String line;
while ((line = in.readLine()) != null) {
result += line;
}
} catch (Exception e) {
System.out.println("发送 POST 请求出现异常!" + e);
e.printStackTrace();
}
//使用finally块来关闭输出流、输入流
finally {
try {
if (out != null) {
out.close();
}
if (in != null) {
in.close();
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
return result;
}
public static void sendMessage(String fromId, String optionId, String template_id,String keyword2,String wx_SpAppId,String wx_SpSecrect) {
Map<String, Object> stringObjectMap = new HashMap<>();
Map<String, Object> map1 = new HashMap<>();
map1.put("value", "尊敬的用户,您的订单即将超时,请及时关锁!");
Map<String, Object> map2 = new HashMap<>();
map2.put("value", keyword2);
stringObjectMap.put("keyword1", map1);
stringObjectMap.put("keyword2", map2);
System.out.println(JSONObject.toJSONString(stringObjectMap));
JSONObject js = sendTemplateMessage(optionId, template_id, "pages/index/main", fromId, stringObjectMap, accessToken( wx_SpAppId, wx_SpSecrect));
log.info("发送微信消息结果:{}", js);
}
public static String accessToken(String wx_SpAppId,String wx_SpSecrect) {
String urlValue = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" +wx_SpAppId+ "&secret="+wx_SpSecrect;
log.info("请求accessToken地址:{}", urlValue);
StringBuffer result = new StringBuffer();
try {
URL url = new URL(urlValue);
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setDoOutput(true);
con.setRequestMethod("GET");
con.setRequestProperty("Content-Type", "text/xml; charset=UTF-8");
con.connect();
log.info("HTTP状态码={}", con.getResponseCode());
BufferedReader inn = new BufferedReader(new InputStreamReader(con.getInputStream(), "UTF-8"));
String value = inn.readLine().trim();
while (value != null) {
if (!"".equals(value)) {
result.append(value.trim() + "\n");
}
value = inn.readLine();
}
inn.close();
} catch (ProtocolException e) {
e.printStackTrace();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
Map respStr = JSONObject.parseObject(result.toString());
log.info("请求accessToken结果:{}", respStr);
return String.valueOf(respStr.get("access_token"));
}
}