Commit baee6e33 authored by shiyu's avatar shiyu

公众号订阅

parent bf0c628f
package com.wwdz.ch.core.consts;
/**
* 公众号枚举
*/
public class OfficalAccountEnum {
/**
* 平台类型
*/
public enum PlatformTypeEnum {
WECHAT(1, "微信"),
ALIPAY(2, "支付宝"),
TIKTOK(3, "抖音"),
;
private int code;
private String des;
PlatformTypeEnum(int code, String des) {
this.code = code;
this.des = des;
}
public static String getNameByCode(int code) {
for (OfficalAccountEnum.PlatformTypeEnum platformTypeEnum : OfficalAccountEnum.PlatformTypeEnum.values()) {
if (code == platformTypeEnum.getCode()) {
return platformTypeEnum.getDes();
}
}
return null;
}
public int getCode() {
return code;
}
public String getDes() {
return des;
}
}
}
package com.wwdz.ch.db.dao;
import com.wwdz.ch.db.domain.OfficialAccountSubscribeRecord;
public interface OfficialAccountSubscribeRecordDao {
boolean insert(OfficialAccountSubscribeRecord officialAccountSubscribeRecord);
boolean update(OfficialAccountSubscribeRecord officialAccountSubscribeRecord);
boolean isExisted(String openid);
boolean isSubscribed(String openid);
}
package com.wwdz.ch.db.impl;
import com.wwdz.ch.db.dao.OfficialAccountSubscribeRecordDao;
import com.wwdz.ch.db.domain.OfficialAccountSubscribeRecord;
import com.wwdz.ch.db.domain.OfficialAccountSubscribeRecordExample;
import com.wwdz.ch.db.domain.OperateLog;
import com.wwdz.ch.db.mapper.OfficialAccountSubscribeRecordMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import java.util.Date;
@Repository
public class OfficialAccountSubscribeRecordDaoImpl implements OfficialAccountSubscribeRecordDao {
@Autowired
OfficialAccountSubscribeRecordMapper officialAccountSubscribeRecordMapper;
@Override
public boolean insert(OfficialAccountSubscribeRecord officialAccountSubscribeRecord) {
return officialAccountSubscribeRecordMapper.insert(officialAccountSubscribeRecord) > 0;
}
@Override
public boolean update(OfficialAccountSubscribeRecord officialAccountSubscribeRecord) {
OfficialAccountSubscribeRecordExample example = new OfficialAccountSubscribeRecordExample();
OfficialAccountSubscribeRecordExample.Criteria criteria = example.createCriteria();
criteria.andOpenidEqualTo(officialAccountSubscribeRecord.getOpenid());
return officialAccountSubscribeRecordMapper.updateByExampleSelective(officialAccountSubscribeRecord, example) > 0;
}
@Override
public boolean isExisted(String openid) {
OfficialAccountSubscribeRecordExample example = new OfficialAccountSubscribeRecordExample();
OfficialAccountSubscribeRecordExample.Criteria criteria = example.createCriteria();
criteria.andOpenidEqualTo(openid);
return officialAccountSubscribeRecordMapper.countByExample(example) > 0;
}
@Override
public boolean isSubscribed(String openid) {
OfficialAccountSubscribeRecordExample example = new OfficialAccountSubscribeRecordExample();
OfficialAccountSubscribeRecordExample.Criteria criteria = example.createCriteria();
criteria.andOpenidEqualTo(openid);
criteria.andEnabledEqualTo(1);
return officialAccountSubscribeRecordMapper.countByExample(example) > 0;
}
}
package com.wwdz.ch.db.mapper;
import com.wwdz.ch.db.domain.OfficialAccountSubscribeRecord;
import com.wwdz.ch.db.domain.OfficialAccountSubscribeRecordExample;
import java.util.List;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
@Mapper
public interface OfficialAccountSubscribeRecordMapper {
long countByExample(OfficialAccountSubscribeRecordExample example);
int deleteByExample(OfficialAccountSubscribeRecordExample example);
int deleteByPrimaryKey(Integer id);
int insert(OfficialAccountSubscribeRecord record);
int insertSelective(OfficialAccountSubscribeRecord record);
/**
* This method was generated by MyBatis Generator.
* This method corresponds to the database table official_account_subscribe_record
*
* @mbg.generated
* @project https://github.com/itfsw/mybatis-generator-plugin
*/
OfficialAccountSubscribeRecord selectOneByExample(OfficialAccountSubscribeRecordExample example);
/**
* This method was generated by MyBatis Generator.
* This method corresponds to the database table official_account_subscribe_record
*
* @mbg.generated
* @project https://github.com/itfsw/mybatis-generator-plugin
*/
OfficialAccountSubscribeRecord selectOneByExampleSelective(@Param("example") OfficialAccountSubscribeRecordExample example, @Param("selective") OfficialAccountSubscribeRecord.Column ... selective);
/**
* This method was generated by MyBatis Generator.
* This method corresponds to the database table official_account_subscribe_record
*
* @mbg.generated
* @project https://github.com/itfsw/mybatis-generator-plugin
*/
List<OfficialAccountSubscribeRecord> selectByExampleSelective(@Param("example") OfficialAccountSubscribeRecordExample example, @Param("selective") OfficialAccountSubscribeRecord.Column ... selective);
List<OfficialAccountSubscribeRecord> selectByExample(OfficialAccountSubscribeRecordExample example);
/**
* This method was generated by MyBatis Generator.
* This method corresponds to the database table official_account_subscribe_record
*
* @mbg.generated
* @project https://github.com/itfsw/mybatis-generator-plugin
*/
OfficialAccountSubscribeRecord selectByPrimaryKeySelective(@Param("id") Integer id, @Param("selective") OfficialAccountSubscribeRecord.Column ... selective);
OfficialAccountSubscribeRecord selectByPrimaryKey(Integer id);
int updateByExampleSelective(@Param("record") OfficialAccountSubscribeRecord record, @Param("example") OfficialAccountSubscribeRecordExample example);
int updateByExample(@Param("record") OfficialAccountSubscribeRecord record, @Param("example") OfficialAccountSubscribeRecordExample example);
int updateByPrimaryKeySelective(OfficialAccountSubscribeRecord record);
int updateByPrimaryKey(OfficialAccountSubscribeRecord record);
}
\ No newline at end of file
package com.wwdz.ch.wx.api;
import com.alibaba.fastjson.JSONObject;
import com.wwdz.ch.core.consts.OfficalAccountEnum;
import com.wwdz.ch.db.dao.UserDao;
import com.wwdz.ch.db.domain.OfficialAccountSubscribeRecord;
import com.wwdz.ch.db.domain.User;
import com.wwdz.ch.wx.api.aes.AesException;
import com.wwdz.ch.wx.api.aes.WXBizMsgCrypt;
import com.wwdz.ch.wx.util.StringUtil;
import com.xxdxxs.utils.JsonUtils;
import com.wwdz.ch.wx.service.OfficialAccountSubscribeRecordService;
import com.xxdxxs.utils.StringUtils;
import com.xxdxxs.utils.XmlUtils;
import org.dom4j.DocumentException;
......@@ -13,7 +15,6 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
......@@ -25,15 +26,14 @@ import java.util.*;
@RestController
@RequestMapping("/officialAccountCallback")
public class OfficialAccountController {
public class OfficialAccountCallbackController {
private static final Logger logger = LoggerFactory.getLogger(OfficialAccountController.class);
private static final Logger logger = LoggerFactory.getLogger(OfficialAccountCallbackController.class);
private final static String SUBSCRIBE_EVENT = "subscribe";
private final static String UNSUBSCRIBE_EVENT = "unsubscribe";
@Value("${dts.wx.officialaccount-token}")
private String OFFICIALACCOUNTTOKEN;
......@@ -46,10 +46,15 @@ public class OfficialAccountController {
@Value("${dts.wx.officialaccount-secret}")
private String APPSECRET;
@Autowired
OfficialAccountApi officialAccountApi;
@Autowired
OfficialAccountSubscribeRecordService officialAccountSubscribeRecordService;
@Autowired
UserDao userDao;
@RequestMapping(value ="/getNotice")
public Object getNotice(@RequestParam(required = false, name = "signature") String signature,
......@@ -72,17 +77,43 @@ public class OfficialAccountController {
output.write(by, 0, length);
}
String xmlInfo = new String(output.toByteArray(), "UTF-8");
logger.info("微信通知回调接口原文:{}", xmlInfo);
logger.info("微信公众号通知回调接口原文:{}", xmlInfo);
WXBizMsgCrypt wxBizMsgCrypt = new WXBizMsgCrypt(OFFICIALACCOUNTTOKEN, OFFICIALACCOUNTKEY, APPID);
String xmlStr = wxBizMsgCrypt.decryptXmlMsg(signature, timestamp, nonce, xmlInfo);
logger.info("微信公众号通知回调接口解密后内容:{}", xmlInfo);
List<Map<String, String>> list = XmlUtils.fromXml(xmlStr, "xml");
Map<String, String> contentMap = list.get(0);
String event = contentMap.get("Event");
if (SUBSCRIBE_EVENT.equals(event) || UNSUBSCRIBE_EVENT.equals(event)) {
String userOpenId = contentMap.get("FromUserName");
String createTime = contentMap.get("CreateTime");
Date date = new Date(createTime);
logger.info("openId:{}, event :{}, time:{}", userOpenId, event, date);
Date date = new Date(Long.valueOf(createTime));
logger.info("解析xml得到 openId:{}, event :{}, time:{}", userOpenId, event, date);
//新增或更新订阅记录
OfficialAccountSubscribeRecord officialAccountSubscribeRecord = new OfficialAccountSubscribeRecord();
officialAccountSubscribeRecord.setOpenid(userOpenId);
//查询有无历史订阅记录
boolean isExisted = officialAccountSubscribeRecordService.isExisted(userOpenId);
if (isExisted) {
if (SUBSCRIBE_EVENT.equals(event)) {
officialAccountSubscribeRecord.setEnabled(1);
} else {
officialAccountSubscribeRecord.setEnabled(0);
}
officialAccountSubscribeRecord.setUpdateTime(date);
officialAccountSubscribeRecordService.update(officialAccountSubscribeRecord);
} else {
//没有历史订阅记录,先根据openid查询手机号
User user = userDao.queryByOid(userOpenId);
if (user != null) {
officialAccountSubscribeRecord.setPhone(user.getMobile());
}
officialAccountSubscribeRecord.setCreateTime(date);
officialAccountSubscribeRecord.setUpdateTime(date);
officialAccountSubscribeRecord.setEnabled(1);
officialAccountSubscribeRecord.setPlatformType(OfficalAccountEnum.PlatformTypeEnum.WECHAT.getCode());
officialAccountSubscribeRecordService.insert(officialAccountSubscribeRecord);
}
}
} catch (Exception e) {
logger.error("微信公众号通知回调接口 error : {}", e);
......@@ -107,63 +138,27 @@ public class OfficialAccountController {
public static void main(String[] args) throws AesException, DocumentException {
String xml = "<xml><ToUserName><![CDATA[gh_075dfbc935ef]]></ToUserName>\n" +
"<FromUserName><![CDATA[oNPTN6QaVliZfKB53OzZRPBZr_r8]]></FromUserName>\n" +
"<CreateTime>1697165124</CreateTime>\n" +
"<MsgType><![CDATA[event]]></MsgType>\n" +
"<Event><![CDATA[subscribe]]></Event>\n" +
"<EventKey><![CDATA[]]></EventKey>\n" +
String xml = "<xml>\n" +
"<ToUserName><![CDATA[gh_075dfbc935ef]]></ToUserName>\n" +
"<Encrypt><![CDATA[tTfKN0RMPKKG1mvpwYS6aEt7FkHk+wgknt/y8ePwEwkKKuRxe9RV0ClGVtxDrJ35Ws12VGzAoQV3UB6oCQX+4NfjZBp2x/SRimCZrb9UVjL14PfMLEahELFFXgX7xvZP3RWJFSZHVXM1cizIhOGsffz0L9G0ohxmGx8NjZZZyJodocsThzdspiWHeQzsOOKB5g6czU4RdYWkrzVMGo/haPLHnxPps+ozBYaPp2Atqm8iFWRjs377FIWFjLbwnVUwdFE7PLkNi9JBsQzBakfRMui6IcjjStM3zyZQXRIpnGory5aaEbPts2iDaYCI+Pf7WPS+bo4Jp04KyDmxMOEf6iWP43VJ5tsrtGKpP2pFmnwZ9agTSNn6EPZocnLBIX6PUWBJSMi3j2PxJ93I+8rA2F+d63CmhNIEi9CXLFMZSSg=]]></Encrypt>\n" +
"</xml>";
WXBizMsgCrypt wxBizMsgCrypt = new WXBizMsgCrypt("Uu6GHYOiP1xJ6GaBMyXfnITufAGJTe3Q", "noeN1amYRvzrVmE2GnC5VnsIfgPEmv6bhX54wJOARlM", "wx7db8eb146a194083");
List<Map<String, String>> list = XmlUtils.fromXml(xml, "xml");
String xmlStr = wxBizMsgCrypt.decryptXmlMsg("150532dfbcfdaace820c0e98e34e919193fcca87", "1697175880", "2012082450", xml);
System.out.println(">>>>" +xmlStr);
List<Map<String, String>> list = XmlUtils.fromXml(xmlStr, "xml");
Map<String, String> contentMap = list.get(0);
System.out.println(contentMap.get("Event") + ">>" + contentMap.get("FromUserName") + ">>" + contentMap.get("CreateTime"));
String event = wxBizMsgCrypt.decrypt(contentMap.get("Event"));
String event = contentMap.get("Event");
if (SUBSCRIBE_EVENT.equals(event) || UNSUBSCRIBE_EVENT.equals(event)) {
String userOpenId = wxBizMsgCrypt.decrypt(contentMap.get("FromUserName"));
String createTime = wxBizMsgCrypt.decrypt(contentMap.get("CreateTime"));
Date date = new Date(createTime);
String userOpenId = contentMap.get("FromUserName");
String createTime = contentMap.get("CreateTime");
Date date = new Date(Long.valueOf(createTime));
System.out.println(userOpenId + ">>" + event + ">>" + date);
}
}
@RequestMapping(value ="/getSubscribeNotice", consumes = "text/xml")
public Object getSubscribeNotice(@RequestParam(required = false, name = "signature") String signature,
@RequestParam(required = false, name = "timestamp") String timestamp,
@RequestParam(required = false, name = "nonce") String nonce,
@RequestParam(required = false, name = "echostr") String echostr,
@RequestBody(required = false) String xmlInfo,
HttpServletResponse response) throws IOException {
try {
logger.info("接收公众号推送信息校验 -> appid: {}, signature:{}, timestamp:{}, nonce:{}, echostr : {}", APPID, signature, timestamp, nonce, echostr);
WXBizMsgCrypt wxBizMsgCrypt = new WXBizMsgCrypt(OFFICIALACCOUNTTOKEN, OFFICIALACCOUNTKEY, APPID);
if (StringUtils.hasLength(echostr)) {
return Long.valueOf(echostr.trim());
}
logger.info("公众号推送的消息原文 -> {}", xmlInfo);
String xmlStr = wxBizMsgCrypt.decryptMsg(signature, timestamp, nonce, xmlInfo);
logger.info("解密后获取公众号推送的信息内容 : {}", xmlStr);
List<Map<String, String>> list = XmlUtils.fromXml(xmlStr, "xml");
if (!CollectionUtils.isEmpty(list)) {
Map<String, String> contentMap = list.get(0);
String event = contentMap.get("Event");
if (SUBSCRIBE_EVENT.equals(event) || UNSUBSCRIBE_EVENT.equals(event)) {
String userOpenId = contentMap.get("FromUserName");
String createTime = contentMap.get("CreateTime");
Date date = new Date(createTime);
logger.info("openId:{}, event :{}, time:{}", userOpenId, event, date);
}
}
} catch (Exception e) {
logger.error("公众号推送信息error : {}", e);
}
return "success";
}
@RequestMapping(value ="/getToken")
public String getToken(){
......
......@@ -40,6 +40,7 @@ public class WebMvcConfiguration implements WebMvcConfigurer {
.excludePathPatterns("/*.html", "/**/*.html", "/**/*.css", "/**/*.js"
, "/wx/user/loginByWx", "/wx/user/loginByMobile", "/wx/user/loginRegCaptcha", "/wx/user/updateRegCaptcha", "/wx/user/login", "/wx/user/fillCode",
"/officialAccountCallback/**",
"/wx/officialAccount/**",
"/wx/item/**"
);
}
......
package com.wwdz.ch.wx.impl;
import com.wwdz.ch.core.type.Result;
import com.wwdz.ch.db.dao.OfficialAccountSubscribeRecordDao;
import com.wwdz.ch.db.domain.OfficialAccountSubscribeRecord;
import com.wwdz.ch.wx.service.OfficialAccountSubscribeRecordService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
@Service
public class OfficialAccountSubscribeRecordServiceImpl implements OfficialAccountSubscribeRecordService {
private static final Logger logger = LoggerFactory.getLogger(OfficialAccountSubscribeRecordServiceImpl.class);
private static final String OFFICAL_ACCOUNT_URL = "https://mp.weixin.qq.com/s/DEYZJMRnDKYkKxir6Gsx8w";
@Autowired
OfficialAccountSubscribeRecordDao officialAccountSubscribeRecordDao;
@Override
public Result insert(OfficialAccountSubscribeRecord officialAccountSubscribeRecord) {
try {
officialAccountSubscribeRecordDao.insert(officialAccountSubscribeRecord);
return Result.success();
} catch (Exception e) {
logger.error("新增公众号订阅记录出错:{}", e);
}
return Result.failed();
}
@Override
public Result update(OfficialAccountSubscribeRecord officialAccountSubscribeRecord) {
try {
officialAccountSubscribeRecordDao.update(officialAccountSubscribeRecord);
return Result.success();
} catch (Exception e) {
logger.error("新增公众号订阅记录出错:{}", e);
}
return Result.failed();
}
@Override
public boolean isExisted(String openid) {
return officialAccountSubscribeRecordDao.isExisted(openid);
}
@Override
public Result isSubscribed(String openid) {
try {
boolean flag = officialAccountSubscribeRecordDao.isSubscribed(openid);
Map<String, Object> map = new HashMap<>();
map.put("isSubscribed", flag);
map.put("url", OFFICAL_ACCOUNT_URL);
return Result.success(map);
} catch (Exception e) {
logger.error("isSubscribed error :{}", e);
}
return Result.failed();
}
}
......@@ -387,6 +387,18 @@ public class UserServiceImpl implements UserService {
}
}
@Override
public Result queryUserInfo(UserRequestDto dto) {
try {
User user = userDao.queryById(dto.getUserId());
return Result.success(user);
} catch (Exception e) {
logger.error("查询用户信息失败", e);
}
return Result.failed("查询用户信息失败");
}
@Override
public Result guestUserInfo(UserRequestDto dto, HttpServletRequest request) {
try {
......
package com.wwdz.ch.wx.service;
import com.wwdz.ch.core.type.Result;
import com.wwdz.ch.db.domain.OfficialAccountSubscribeRecord;
public interface OfficialAccountSubscribeRecordService {
Result insert(OfficialAccountSubscribeRecord officialAccountSubscribeRecord);
Result update(OfficialAccountSubscribeRecord officialAccountSubscribeRecord);
/**
* 是否有历史订阅记录
* @param openid
* @return
*/
boolean isExisted(String openid);
/**
* 是否关注过公众号
* @param openid
* @return
*/
Result isSubscribed(String openid);
}
......@@ -80,6 +80,15 @@ public interface UserService {
*/
Result userInfo(HttpServletRequest request);
/**
* 查询用户信息
*
* @param dto
* @return
*/
Result queryUserInfo(UserRequestDto dto);
/**
* 查询用户信息
*
......
package com.wwdz.ch.wx.web;
import com.alibaba.fastjson.JSON;
import com.wwdz.ch.core.consts.ResultCode;
import com.wwdz.ch.core.type.Result;
import com.wwdz.ch.db.domain.User;
import com.wwdz.ch.wx.entity.request.UserRequestDto;
import com.wwdz.ch.wx.service.OfficialAccountSubscribeRecordService;
import com.wwdz.ch.wx.service.UserService;
import io.swagger.annotations.ApiOperation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/wx/officialAccount")
public class OfficialAccountController {
private static final Logger logger = LoggerFactory.getLogger(OfficialAccountController.class);
@Autowired
OfficialAccountSubscribeRecordService officialAccountSubscribeRecordService;
@Autowired
UserService userService;
@ApiOperation(value = "判断用户是否关注过公众号")
@PostMapping("/isSubscribed")
public Result isSubscribed(@RequestBody UserRequestDto dto) {
logger.info("【请求开始】判断用户是否关注过公众号,请求参数:{}", JSON.toJSONString(dto));
if (StringUtils.isEmpty(dto.getUserId())) {
return Result.failed(ResultCode.PARAM_ERROR);
}
Result<User> result = userService.queryUserInfo(dto);
String openid = null;
if (result.getSuccess() && result.getData() != null) {
openid = result.getData().getWeixinOpenid();
}
if (openid == null) {
return Result.failed("该用户没有记录下openid");
}
return officialAccountSubscribeRecordService.isSubscribed(openid);
}
}
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