1、微信公众平台申请模板消息
登录微信公众平台对自己的公众号添加模板消息:微信公众平台
后面的代码是通过模板ID来进行绑定的。
2、发模板消息关键代码
微信公众号文档:文档地址
其中需要获取access_token:获取access_token-文档地址
测试公众号申请:申请地址
文档有完整的说明,现在可以找到很多代码的例子,如:
String token = saveAndFlushAccessTokenUtil.getToken();
String postUrl = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=" + token;
JSONObject jsonObject = new JSONObject();
jsonObject.put("touser", "接受用户的openid"); // openid
jsonObject.put("template_id", "模板id");
jsonObject.put("url", "跳转路径");
JSONObject data = new JSONObject();
JSONObject first = new JSONObject();
first.put("value", "hello");
first.put("color", "#173177");
JSONObject keyword1 = new JSONObject();
keyword1.put("value", "hello");
keyword1.put("color", "#173177");
JSONObject keyword2 = new JSONObject();
keyword2.put("value", "hello");
keyword2.put("color", "#173177");
JSONObject keyword3 = new JSONObject();
keyword3.put("value", "hello");
keyword3.put("color", "#173177");
JSONObject remark = new JSONObject();
remark.put("value", "hello");
remark.put("color", "#173177");
data.put("first",first);
data.put("keyword1",keyword1);
data.put("keyword2",keyword2);
data.put("keyword3",keyword3);
data.put("remark",remark);
jsonObject.put("data", data);
String string = HttpClientUtils.sendPostJson(postUrl, jsonObject.toJSONString()); //发送模板消息的工具方法
JSONObject result = JSON.parseObject(string);
int errcode = result.getIntValue("errcode");
if(errcode == 0){
// 发送成功
System.out.println("发送成功");
} else {
// 发送失败
System.out.println("发送失败");
}
3、高级通用版本:使用WxMpService、AOP、自定义注解的方式实现推送模板消息
使用的框架:
后端:jeecgboot
前端:uniapp
使用自定义注解,利用AOP写一个切面类调用发送消息方法,然后在需要模板消息的地方可可使用自定义注解来实现发送模板消息
@Aspect :AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,
通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术.AOP是OOP的延续,
是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。
利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,
提高程序的可重用性,同时提高了开发的效率。
WxMpService:微信公众号API的Service.用来请求微信服务器。
1、微信模板消息推送接口类
【完整代码】
import org.jeecg.common.wx.vo.WxMsgType;
import java.lang.annotation.*;
/**
* 微信模板消息推送
*/
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface WxMessage {
/**
* 需要接收消息的用户名
*/
String useranme() default "";
/**
* 主表id
*/
String tableId() default "";
/**
* 消息模板类型
*
* @return
*/
WxMsgType type() default WxMsgType.INDEX;
}
2、微信模板消息类
【完整代码】
@Data
@Builder
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = false)
public class WxMsgVo implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 主表id
*/
private String tableId;
/**
* 用户登录名
*/
private String username;
}
3、微信消息切面:
【完整代码】
@Slf4j
@Aspect
@Component
@RequiredArgsConstructor(onConstructor_ = @Autowired)
public class WxMsgAspect {
private final WxMsgService wxMsgService;
/**
* 切入点
*
* @annotation() 注解切入
*/
@Pointcut("@annotation(org.jeecg.common.wx.api.WxMessage)")
public void pointcut() {
}
/**
* 通知 - 环绕
* 可在切入目标执行前后自定义通知行为
*
* @param joinPoint
* @return
* @throws Throwable
*/
@Around("pointcut()")
public Object around(ProceedingJoinPoint joinPoint) {
Object result = null;
try {
log.info("【@WxMessage】 环绕-前:@Around {}");
result = joinPoint.proceed();
log.info("【@WxMessage】 环绕-后:@Around {}");
} catch (Exception e) {
e.printStackTrace();
} catch (Throwable throwable) {
throwable.printStackTrace();
}
return result;
}
/**
* 通知 - 前置
* 在切入目标之前调用
*
* @param joinPoint
*/
@Before("pointcut()")
public void before(JoinPoint joinPoint) {
log.info("【@WxMessage】 前置:@Before {}");
}
/**
* 通知 - 后置
* 在切入目标正常切入结束之后调用,异常不调用
*
* @param joinPoint 连接点
* @param result 切入点返回值
*/
@AfterReturning(value = "pointcut()", returning = "result")
public void afterReturning(JoinPoint joinPoint, Object result) {
try {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
//判断方法上是否有该注解
boolean annotationPresent = method.isAnnotationPresent(WxMessage.class);
if (annotationPresent) {
//获取注解属性值
WxMessage annotation = method.getAnnotation(WxMessage.class);
if (method.getName().equals("execute")) { //定时任务
wxMsgService.sendMessage(null, annotation.type());
} else {
Result<Object> res = (Result<Object>) result;
if (res.isSuccess()) {
//解析spel 表达式
String tableId = SpelUtil.analysisSpel(annotation.tableId(), joinPoint);
String useranme = SpelUtil.analysisSpel(annotation.useranme(), joinPoint);
WxMsgVo wxmsg = WxMsgVo.builder().tableId(tableId).username(useranme).build();
//调用发送消息方法
wxMsgService.sendMessage(wxmsg, annotation.type());
}
}
}
log.info("【@WxMessage】 后置:@AfterReturning {}");
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 通知 - 后置
* 在切入目标结束之后调用,正常/异常 都调用
*
* @param joinPoint
*/
@After("pointcut()")
public void after(JoinPoint joinPoint) {
log.info("【@WxMessage】 后置:@After {}");
}
/**
* 通知 - 异常
* 在切入目标异常调用
*
* @param joinPoint 连接点
* @param err 异常
*/
@AfterThrowing(value = "pointcut()", throwing = "err")
public void afterThrowing(JoinPoint joinPoint, Exception err) {
log.error("【@WxMessage】 异常:@AfterThrowing msg:{}", err.getMessage());
}
}
4、发送消息方法抽象类:
【完整代码】
public interface WxMsgService {
void sendMessage(WxMsgVo wxMsgVo, WxMsgType type) throws WxErrorException;
}
5、发送消息方法抽象实现类
【关键代码】
@Service
@RequiredArgsConstructor(onConstructor_ = @Autowired)
public class WxMsgServiceImpl implements WxMsgService {
@Override
public void sendMessage(WxMsgVo wxMsgVo, WxMsgType type) throws WxErrorException {
switch (type) {
//不同的类型调用不同的方法
default:
break;
}
}
//举例一个方法
private void approvalFlow(WxMsgVo wxMsgVo) {
String eventId = wxMsgVo.getTableId();
//获取流程信息
JSONObject obj = workFlowApi.getFlowInfoByEvent(eventId);
String createName = obj.getString("createName");
String flowName = obj.getString("flowName");
String toUser = obj.getString("toUser");
String createTime = DateUtil.format(obj.getDate("createTime"), DatePattern.NORM_DATETIME_MINUTE_PATTERN);
if(StringUtils.isNotEmpty(toUser)){
try {
WxMpTemplateMessage data = WxMpTemplateMessage.builder()
.toUser(接受模板消息的人的openid)
.url(点击模板消息跳转地址))
.templateId(模板id)
.data(Arrays.asList(
//流程编号
new WxMpTemplateData("keyword1", eventId),
//流程名称
new WxMpTemplateData("keyword2", flowName),
//流程标题
new WxMpTemplateData("keyword3", "标题"),
//申请人
new WxMpTemplateData("keyword4", createName),
//申请时间
new WxMpTemplateData("keyword5", createTime),
//备注
new WxMpTemplateData("remark", "")
)).build();
wxService.getTemplateMsgService().sendTemplateMsg(data);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
6、在需要发送模板消息的方法上添加 @WxMessage的注解
【完整代码】
@ApiOperation(value = "开票申请-添加", notes = "开票申请-添加")
@PostMapping(value = "/add")
@WxMessage(type = WxMsgType.FLOW_APPRAVAL, tableId = "#appInvoice.id")
public Result<?> add(@RequestBody AppInvoice appInvoice) {
return Result.OK("添加成功!");
}
7、结果演示为:
此博客主要用来记录,若其中有错误,或有更好的实现方式,欢迎评论区留言,互相学习。