Commit d9e410fe by 吕明尚

微信公众号平台API对接,模版消息对接

parent 704564d9
......@@ -31,6 +31,11 @@ wx:
token: coujio
aesKey: zf8vTHbI0ZDPTkkCXHEuwh9EbtVtOn6n4vQjMb9OFrS
msgDataFormat: XML
#微信公众号配置
official:
account:
appId: wx687cc62ee62ef19a
appSecret: 1422a30daf21584f657f042ffc152fec
tiktok:
appId: awt50u5zommqxkl9
appSecret: c567551e0c4ce1db4f985d0233025d8d
......
......@@ -31,6 +31,11 @@ wx:
token: coujio
aesKey: zf8vTHbI0ZDPTkkCXHEuwh9EbtVtOn6n4vQjMb9OFrS
msgDataFormat: XML
#微信公众号配置
official:
account:
appId: wx687cc62ee62ef19a
appSecret: 1422a30daf21584f657f042ffc152fec
tiktok:
appId: awt50u5zommqxkl9
appSecret: c567551e0c4ce1db4f985d0233025d8d
......
......@@ -31,6 +31,11 @@ wx:
token: coujio
aesKey: zf8vTHbI0ZDPTkkCXHEuwh9EbtVtOn6n4vQjMb9OFrS
msgDataFormat: XML
#微信公众号配置
official:
account:
appId: wx687cc62ee62ef19a
appSecret: 1422a30daf21584f657f042ffc152fec
tiktok:
appId: awt50u5zommqxkl9
appSecret: c567551e0c4ce1db4f985d0233025d8d
......
package share.common.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Data
@Component
@ConfigurationProperties(prefix = "wx.official.account")
public class OfficialAccountConfig {
private String appId;
private String appSecret;
}
......@@ -238,6 +238,11 @@ public class WeChatConstants {
public static final String WECHAT_PUBLIC_JS_TICKET_URL = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token={}&type=jsapi";
/** 公众号发送模板消息的url */
public static final String WECHAT_PUBLIC_SEND_TEMPLATE_URL = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token={}";
//微信公众号的获取用户列表
public static final String WECHAT_PUBLIC_USER_GET_URL = "https://api.weixin.qq.com/cgi-bin/user/get?access_token={}}&next_openid={}";
/** 公众号获取自定义菜单配置的url */
public static final String WECHAT_PUBLIC_MENU_GET_URL = "https://api.weixin.qq.com/cgi-bin/menu/get?access_token={}";
/** 公众号创建自定义菜单的url */
......
......@@ -3,7 +3,15 @@ package share.common.enums;
public enum MessageReminderEnum {
RESERVER("预约成功通知", "UkvsRnZkZB_w3MqXPbRhi4jEk8ML4N9PWT3rnd3Bhxg", "若因事迟到,迟到部分时间不延期不退还"),
START("订单开始通知", "K8fbcKVq46w9o7Ekpesn70wK3mYjXqdSfFUth4AufqU", "您的凑角房间使用订单即将开始"),
END("订单结单通知", "HB2_moQRQrXC2cKw6zE08FF8UZJ5ue1h_qXZhvOkacc", "您的房间使用时间还剩15分钟");
END("订单结单通知", "HB2_moQRQrXC2cKw6zE08FF8UZJ5ue1h_qXZhvOkacc", "您的房间使用时间还剩15分钟"),
//保洁工单派单通知
CLEANING("保洁工单派单通知", "7kiyzMNnnUuUbwPFBEram0_Q9dL-oo-QkarE127LuDk", "您有新的保洁工单,请及时处理"),
//订单预订成功通知
ORDER_RESERVE("订单预订成功通知", "E0kv7x8f6S5UIWzrowrVliQN0cIES8nGz9Cy8Z3jJ8k", "您的预订订单已成功提交,请等待审核"),
;
private String name;
private String value;
......
......@@ -30,6 +30,15 @@ public enum OrderTypeEnum {
return null;
}
public static String getNameByCode(Integer code) {
for (OrderTypeEnum type : OrderTypeEnum.values()) {
if (type.code.compareTo(code) == 0) {
return type.name;
}
}
return null;
}
public static OrderTypeEnum getEnumByValue(String value){
if(StringUtils.isNotBlank(value)) {
for (OrderTypeEnum type : OrderTypeEnum.values()) {
......
......@@ -32,6 +32,15 @@ public enum PlatformTypeEnum {
this.name = name;
}
public static String getNameByCode(Integer code) {
for (PlatformTypeEnum type : PlatformTypeEnum.values()) {
if (type.code.compareTo(code) == 0) {
return type.name;
}
}
return null;
}
PlatformTypeEnum() {
}
}
package share.web.controller.common;
import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaSubscribeMessage;
import cn.hutool.core.date.LocalDateTimeUtil;
import lombok.AllArgsConstructor;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import share.common.core.domain.R;
import share.common.enums.MessageReminderEnum;
import share.system.config.WxMaProperties;
import share.system.domain.vo.SendTemplateMessageItemVo;
......@@ -20,9 +18,7 @@ import share.system.domain.vo.TemplateMessageVo;
import share.system.service.WechatNewService;
import share.system.util.WXMsgPushUtils;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
......@@ -152,4 +148,10 @@ public class WxMsgPushController {
// }
}
@GetMapping("/public/accessToken")
public R<String> getAccessToken() {
return R.ok(wechatNewService.getPublicAccessToken());
}
}
......@@ -32,9 +32,10 @@ wx:
aesKey: zf8vTHbI0ZDPTkkCXHEuwh9EbtVtOn6n4vQjMb9OFrS
msgDataFormat: JSON
#微信公众号配置
officialAccount:
ppid: wxdd170b8783edf7a0
secret: 7339f117e858
official:
account:
appId: wx687cc62ee62ef19a
appSecret: 1422a30daf21584f657f042ffc152fec
tiktok:
......
......@@ -31,6 +31,11 @@ wx:
token: coujio
aesKey: zf8vTHbI0ZDPTkkCXHEuwh9EbtVtOn6n4vQjMb9OFrS
msgDataFormat: JSON
#微信公众号配置
official:
account:
appId: wx687cc62ee62ef19a
appSecret: 1422a30daf21584f657f042ffc152fec
tiktok:
appId: awt50u5zommqxkl9
appSecret: c567551e0c4ce1db4f985d0233025d8d
......
......@@ -31,6 +31,11 @@ wx:
token: coujio
aesKey: zf8vTHbI0ZDPTkkCXHEuwh9EbtVtOn6n4vQjMb9OFrS
msgDataFormat: JSON
#微信公众号配置
official:
account:
appId: wx687cc62ee62ef19a
appSecret: 1422a30daf21584f657f042ffc152fec
tiktok:
appId: awt50u5zommqxkl9
appSecret: c567551e0c4ce1db4f985d0233025d8d
......
......@@ -41,6 +41,10 @@ public class SConsumerToken implements Serializable {
@ApiModelProperty(value = "登录ip")
private String loginIp;
@ApiModelProperty(value = "公众号OpenId")
private String openId;
@ApiModelProperty(value = "用户公众平台UnionID")
private String unionId;
}
package share.system.domain.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import java.util.HashMap;
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@ApiModel(value = "OfficialAccountTemplate对象", description = "微信模板发送类")
public class OfficialAccountTemplate {
@ApiModelProperty(value = "OPENID", required = true)
private String touser;
@ApiModelProperty(value = "模板ID", required = true)
private String template_id;
@ApiModelProperty(value = "跳小程序所需数据,不需跳小程序可不用传该数据")
private String miniprogram;
@ApiModelProperty(value = "所需跳转到的小程序appid", required = true)
private String appid;
@ApiModelProperty(value = "所需跳转到小程序的具体页面路径")
private String pagepath;
@ApiModelProperty(value = "发送内容")
private HashMap<String, SendTemplateMessageItemVo> data;
}
......@@ -14,7 +14,7 @@ import java.util.HashMap;
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@ApiModel(value="SendTemplateMessageVo对象", description="微信模板发送类")
@ApiModel(value = "SendTemplateMessageVo对象", description = "小程序模板发送类")
public class TemplateMessageVo {
@ApiModelProperty(value = "OPENID", required = true)
private String touser;
......
package share.system.domain.vo;
import io.swagger.annotations.ApiModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import java.util.List;
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@ApiModel(value = "WeChatAccessTokenVo", description = "公众号用户列表")
public class UserOpenIdVo {
private Integer total;
private Integer count;
private List<String> data;
private String next_openid;
}
......@@ -87,8 +87,11 @@ public interface WechatNewService {
* @param templateMessage 模板消息对象
* @return 是否发送成功
*/
Boolean sendPublicTemplateMessage(TemplateMessageVo templateMessage);
Boolean sendPublicTemplateMessage(OfficialAccountTemplate templateMessage);
Boolean sendPublicTemplateMessage(SOrder byOrderNo, MessageReminderEnum messageReminderEnum);
UserOpenIdVo getWechatUSERList();
/**
* 微信小程序发送订阅消息
* @param templateMessage 消息对象
......@@ -98,6 +101,7 @@ public interface WechatNewService {
Boolean sendMiniSubscribeMessage(SOrder byOrderNo, MessageReminderEnum messageReminderEnum);
/**
* 获取微信公众号自定义菜单配置
* (使用本自定义菜单查询接口可以获取默认菜单和全部个性化菜单信息)
......
......@@ -24,6 +24,7 @@ import share.common.utils.DateUtil;
import share.common.utils.wx.WxUtil;
import share.system.domain.SConsumer;
import share.system.domain.SConsumerToken;
import share.system.domain.vo.FrontTokenComponent;
import share.system.domain.vo.WeChatMiniAuthorizeVo;
import share.system.domain.vo.WeChatPhoneNumberVo;
import share.system.mapper.SConsumerMapper;
......@@ -31,10 +32,12 @@ import share.system.request.RegisterThirdSConsumerRequest;
import share.system.request.WxBindingPhoneRequest;
import share.system.request.WxRegisterPhoneRequest;
import share.system.response.LoginResponse;
import share.system.service.*;
import share.system.domain.vo.FrontTokenComponent;
import share.system.service.SConsumerCenterService;
import share.system.service.SConsumerService;
import share.system.service.SConsumerTokenService;
import share.system.service.WechatNewService;
import java.util.*;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
/**
......@@ -102,6 +105,10 @@ public class SConsumerCenterServiceImpl extends ServiceImpl<SConsumerMapper, SCo
logger.error(StrUtil.format("小程序登录生成token失败,uid={}", sConsumer.getId()));
e.printStackTrace();
}
if (StringUtils.isEmpty(sConsumerToken.getUnionId())) {
sConsumerToken.setUnionId(response.getUnionId());
sConsumerTokenService.updateById(sConsumerToken);
}
loginResponse.setType("login");
loginResponse.setUid(sConsumer.getId());
loginResponse.setNikeName(sConsumer.getNickName());
......
......@@ -1071,6 +1071,15 @@ public class SOrderServiceImpl extends ServiceImpl<SOrderMapper, SOrder> impleme
Optional<SOrder> lastOrderOp = orderList.stream().max(Comparator.comparing(SOrder::getPreEndDate));
SOrder lastOrder = lastOrderOp.orElse(null);
if (Objects.nonNull(lastOrder) && Objects.nonNull(lastOrder.getEndDate())) {
SCleanRecords sCleanRecords = cleanRecordsService.lastCleanByRoomId(lastOrder.getRoomId());
if (ObjectUtils.isEmpty(sCleanRecords)) {
return;
}
if (sCleanRecords.getStatus().compareTo(CleaningStatusEnum.CLEANED.getCode()) == 0
&& sCleanRecords.getEndDate().compareTo(lastOrder.getEndDate()) > 0
&& sCleanRecords.getEndDate().compareTo(request.getPreStartDate()) < 0) {
return;
}
if (request.getOrderType().equals(OrderTypeEnum.RESERVER.getCode())) {
if (!(DateUtils.addMinutes(lastOrder.getEndDate(), Constants.ROOM_LOCK_DELAY_MINUTE).compareTo(request.getPreStartDate()) < 0)) {
throw new BaseException("下单时间已被预定!");
......@@ -1083,15 +1092,6 @@ public class SOrderServiceImpl extends ServiceImpl<SOrderMapper, SOrder> impleme
if (lastOrder.getConsumerId().equals(user.getId())) {
return;
}
SCleanRecords sCleanRecords = cleanRecordsService.lastCleanByRoomId(lastOrder.getRoomId());
if (ObjectUtils.isEmpty(sCleanRecords)) {
return;
}
if(sCleanRecords.getStatus().compareTo(CleaningStatusEnum.CLEANED.getCode())==0
&&sCleanRecords.getEndDate().compareTo(lastOrder.getEndDate())>0
&&sCleanRecords.getEndDate().compareTo(request.getPreStartDate())<0){
return;
}
}
throw new BaseException("下单时间已被预定!");
}
......
package share.system.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.codec.binary.Base64;
......@@ -17,15 +15,19 @@ import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import share.common.config.OfficialAccountConfig;
import share.common.config.WeChatConfig;
import share.common.constant.PayConstants;
import share.common.constant.WeChatConstants;
import share.common.core.redis.RedisUtil;
import share.common.enums.MessageReminderEnum;
import share.common.utils.http.RestTemplateUtil;
import share.common.enums.OrderTypeEnum;
import share.common.enums.PlatformTypeEnum;
import share.common.exception.base.BaseException;
import share.common.utils.BaseUtil;
import share.common.utils.XmlUtil;
import share.common.utils.http.RestTemplateUtil;
import share.system.domain.*;
import share.system.domain.vo.*;
import share.system.response.WeChatJsSdkConfigResponse;
......@@ -55,6 +57,8 @@ public class WechatNewServiceImpl implements WechatNewService {
@Autowired
private RestTemplateUtil restTemplateUtil;
@Autowired
private OfficialAccountConfig officialAccountConfig;
@Autowired
private WechatPayInfoService wechatPayInfoService;
......@@ -71,6 +75,9 @@ public class WechatNewServiceImpl implements WechatNewService {
@Autowired
private ISRoomService roomService;
@Autowired
private ISConsumerCouponService sConsumerCouponService;
@Value("${wechat.miniprogram_state}")
private String miniprogramState;
......@@ -84,13 +91,13 @@ public class WechatNewServiceImpl implements WechatNewService {
Object accessToken = redisUtil.get(WeChatConstants.REDIS_WECAHT_PUBLIC_ACCESS_TOKEN_KEY);
return accessToken.toString();
}
String appId = weChatConfig.getAppId();
String appId = officialAccountConfig.getAppId();
if (StrUtil.isBlank(appId)) {
throw new BaseException("微信公众号appId未设置");
throw new BaseException("微信小程序appId未设置");
}
String secret = weChatConfig.getAppSecret();
String secret = officialAccountConfig.getAppSecret();
if (StrUtil.isBlank(secret)) {
throw new BaseException("微信公众号secret未设置");
throw new BaseException("微信小程序secret未设置");
}
WeChatAccessTokenVo accessTokenVo = getAccessToken(appId, secret, "public");
// 缓存accessToken
......@@ -502,7 +509,7 @@ public class WechatNewServiceImpl implements WechatNewService {
* @return 是否发送成功
*/
@Override
public Boolean sendPublicTemplateMessage(TemplateMessageVo templateMessage) {
public Boolean sendPublicTemplateMessage(OfficialAccountTemplate templateMessage) {
String accessToken = getPublicAccessToken();
String url = StrUtil.format(WeChatConstants.WECHAT_PUBLIC_SEND_TEMPLATE_URL, accessToken);
JSONObject jsonData = JSONObject.parseObject(JSONObject.toJSONString(templateMessage));
......@@ -520,6 +527,7 @@ public class WechatNewServiceImpl implements WechatNewService {
return Boolean.TRUE;
}
/**
* 微信小程序发送订阅消息
*
......@@ -563,6 +571,65 @@ public class WechatNewServiceImpl implements WechatNewService {
return Boolean.TRUE;
}
/**
* 微信公众号发送模板消息
*/
@Override
public Boolean sendPublicTemplateMessage(SOrder byOrderNo, MessageReminderEnum messageReminderEnum) {
OfficialAccountTemplate officialAccountTemplate = new OfficialAccountTemplate();
officialAccountTemplate.setAppid(weChatConfig.getAppId());
String pagepath = "/pages/orderResult/orderResult?orderNo=" + byOrderNo.getOrderNo();
officialAccountTemplate.setPagepath(pagepath);
HashMap<String, SendTemplateMessageItemVo> data = new HashMap<>();
SStore sStore = storeService.getById(byOrderNo.getStoreId());
SRoomVo sRoomVo = roomService.selectSRoomById(byOrderNo.getRoomId());
//拼接开始和结束时间
Date preStartDate = byOrderNo.getPreStartDate();
Date preEndDate = byOrderNo.getPreEndDate();
//转字符串
String preStartDateStr = DateUtil.format(preStartDate, DatePattern.NORM_DATETIME_MINUTE_FORMATTER);
String preEndDateStr = DateUtil.format(preEndDate, DatePattern.NORM_DATETIME_MINUTE_FORMATTER);
String date = preStartDateStr + "~" + preEndDateStr;
String msg = "实付金额" + byOrderNo.getPayPrice() + "元";
if (!ObjectUtils.isEmpty(byOrderNo.getCouponId())) {
SConsumerCoupon byId = sConsumerCouponService.getById(byOrderNo.getCouponId());
msg = msg + ",优惠券类型为" + PlatformTypeEnum.getNameByCode(byId.getPlatformType());
}
if (messageReminderEnum.equals(MessageReminderEnum.CLEANING)) {
officialAccountTemplate.setTemplate_id(MessageReminderEnum.CLEANING.getValue());
//预约店铺
data.put("thing2", new SendTemplateMessageItemVo("武汉" + sStore.getName()));
//预约包间
data.put("thing3", new SendTemplateMessageItemVo(sRoomVo.getName()));
//预约时间
data.put("time1", new SendTemplateMessageItemVo(preEndDateStr));
} else if (messageReminderEnum.equals(MessageReminderEnum.ORDER_RESERVE)) {
officialAccountTemplate.setTemplate_id(MessageReminderEnum.ORDER_RESERVE.getValue());
//门店名称
data.put("thing2", new SendTemplateMessageItemVo("武汉" + sStore.getName() + "(" + sRoomVo.getName() + ")"));
//预订时间
data.put("time4", new SendTemplateMessageItemVo(date));
//联系电话
data.put("phone_number8", new SendTemplateMessageItemVo(byOrderNo.getConsumerPhone()));
//订单状态
data.put("phrase11", new SendTemplateMessageItemVo(OrderTypeEnum.getNameByCode(byOrderNo.getOrderType())));
//商品名称
data.put("thing21", new SendTemplateMessageItemVo(msg));
}
return sendPublicTemplateMessage(officialAccountTemplate);
}
@Override
public UserOpenIdVo getWechatUSERList() {
String accessToken = getMiniAccessToken();
String url = StrUtil.format(WeChatConstants.WECHAT_PUBLIC_USER_GET_URL, accessToken, "");
JSONObject data = restTemplateUtil.getData(url);
if (ObjectUtil.isNull(data)) {
throw new BaseException("微信平台接口异常,没任何数据返回!");
}
return JSONObject.parseObject(data.toJSONString(), UserOpenIdVo.class);
}
@Override
public Boolean sendMiniSubscribeMessage(SOrder byOrderNo, MessageReminderEnum messageReminderEnum) {
//发送模板消息 预约提醒到期
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment