diff --git a/.gitignore b/.gitignore index 1b5050f..f41242f 100644 --- a/.gitignore +++ b/.gitignore @@ -25,3 +25,5 @@ /Gateway/src/main/resources/application-test.yml /ResourceManager/src/main/resources/application-test.yml /ResourceManager/src/main/resources/bootstrap-test.yml +/WXEngine/src/main/resources/bootstrap-test.yml +/WXEngine/src/main/resources/application-test.yml diff --git a/WXEngine/pom.xml b/WXEngine/pom.xml new file mode 100644 index 0000000..bfb73af --- /dev/null +++ b/WXEngine/pom.xml @@ -0,0 +1,177 @@ + + + 4.0.0 + + cn.crtech.cloud.wxengine + WXEngine + 1.0.1 + + + + cn.crtech.cloud.dependencies + Dependencies + 1.0.1 + + + + + + 8 + 8 + 1.8 + UTF-8 + + 1.0.1 + 1.14.3 + 6.4.0.jre8 + 4.3.0 + 4.2.0 + + + + + org.springframework.boot + spring-boot-starter-web + + + + + com.alibaba.cloud + spring-cloud-starter-alibaba-nacos-discovery + + + + org.springframework.boot + spring-boot-starter-test + test + + + org.junit.vintage + junit-vintage-engine + + + + + + junit + junit + test + + + + org.springframework.boot + spring-boot-test + + + + org.springframework + spring-test + + + + org.apache.commons + commons-lang3 + + + + + org.springframework.cloud + spring-cloud-starter-openfeign + + + + org.springframework.cloud + spring-cloud-starter-loadbalancer + + + + redis.clients + jedis + + + + org.projectlombok + lombok + true + + + + cn.crtech.cloud.common + Common + ${common.version} + + + + org.jsoup + jsoup + ${jsoup.version} + + + + com.microsoft.sqlserver + mssql-jdbc + ${mssql.version} + runtime + + + + + com.github.binarywang + weixin-java-mp + ${wx.mp.version} + + + com.google.guava + guava + + + commons-io + commons-io + + + + + + + com.github.binarywang + weixin-java-miniapp + ${normal.wx.version} + + + + + com.github.binarywang + weixin-java-cp + ${normal.wx.version} + + + + + com.github.binarywang + weixin-java-pay + ${normal.wx.version} + + + + + com.github.binarywang + weixin-java-open + ${normal.wx.version} + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + true + -Dfile.encoding=UTF-8 + + + + + diff --git a/WXEngine/src/main/java/cn/crtech/cloud/wxengine/WXEngineApplcation.java b/WXEngine/src/main/java/cn/crtech/cloud/wxengine/WXEngineApplcation.java new file mode 100644 index 0000000..7cda8e0 --- /dev/null +++ b/WXEngine/src/main/java/cn/crtech/cloud/wxengine/WXEngineApplcation.java @@ -0,0 +1,37 @@ +package cn.crtech.cloud.wxengine; + +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +//微服务启动时使用 begin + +@EnableDiscoveryClient +@SpringBootApplication +@EnableTransactionManagement +@MapperScan("cn.crtech.cloud.wxengine.mapper") +public class WXEngineApplcation { + public static void main(String[] args) { + SpringApplication.run(WXEngineApplcation.class, args); + } +} + +//微服务启动时使用 end + +//使用launcher启动时使用 begin +//launcher.NacosConfig @Component需要放开 +// +//@SpringBootApplication +//@MapperScan("cn.crtech.cloud.resmanager.mapper") +//public class ResmanagerApplcation extends SpringBootServletInitializer { +// @Override +// protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { +// return application.sources(ResmanagerApplcation.class); +// } +//} + +//使用launcher启动时使用 end + + diff --git a/WXEngine/src/main/java/cn/crtech/cloud/wxengine/config/DataSourceConfiguration.java b/WXEngine/src/main/java/cn/crtech/cloud/wxengine/config/DataSourceConfiguration.java new file mode 100644 index 0000000..05cd519 --- /dev/null +++ b/WXEngine/src/main/java/cn/crtech/cloud/wxengine/config/DataSourceConfiguration.java @@ -0,0 +1,34 @@ +package cn.crtech.cloud.wxengine.config; + +import cn.crtech.cloud.common.utils.EncryptUtil; +import com.alibaba.druid.pool.DruidDataSource; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import javax.sql.DataSource; +import java.util.Objects; + +@Configuration +public class DataSourceConfiguration { + @Autowired + private DataSourceProperties properties; + + @Bean + public DataSource dataSource() throws Exception { + DruidDataSource dataSource = new DruidDataSource(); + dataSource.setDbType("mysql"); + dataSource.setUrl(properties.getUrl()); + dataSource.setUsername(new String(Objects.requireNonNull(EncryptUtil.decrypt(EncryptUtil.parseHexStr2Byte(properties.getUsername()), "THIS SHALL NOT BE SEEN.")))); + dataSource.setPassword(new String(Objects.requireNonNull(EncryptUtil.decrypt(EncryptUtil.parseHexStr2Byte(properties.getPassword()), "THIS SHALL NOT BE SEEN.")))); + dataSource.setInitialSize(5); + dataSource.setMinIdle(1); + dataSource.setMinEvictableIdleTimeMillis(10000L); + dataSource.setMaxActive(100); + dataSource.setMaxWait(60000L); + dataSource.setValidationQuery("SELECT 'x'"); + dataSource.setFilters("stat, wall"); + return dataSource; + } +} diff --git a/WXEngine/src/main/java/cn/crtech/cloud/wxengine/config/RedisRepositoryConfig.java b/WXEngine/src/main/java/cn/crtech/cloud/wxengine/config/RedisRepositoryConfig.java new file mode 100644 index 0000000..3a156ae --- /dev/null +++ b/WXEngine/src/main/java/cn/crtech/cloud/wxengine/config/RedisRepositoryConfig.java @@ -0,0 +1,30 @@ +package cn.crtech.cloud.wxengine.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.repository.configuration.EnableRedisRepositories; +import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; +import org.springframework.data.redis.serializer.StringRedisSerializer; + +/** + * Redis相关配置 + */ +@Configuration +@EnableRedisRepositories +public class RedisRepositoryConfig { + @Bean + public RedisTemplate redisTemplate(RedisConnectionFactory connectionFactory) { + RedisTemplate redisTemplate = new RedisTemplate<>(); + redisTemplate.setConnectionFactory(connectionFactory); + StringRedisSerializer stringRedisSerializer = new StringRedisSerializer(); + redisTemplate.setKeySerializer(stringRedisSerializer); + redisTemplate.setHashKeySerializer(stringRedisSerializer); + Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class); + redisTemplate.setValueSerializer(jackson2JsonRedisSerializer); + redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer); + redisTemplate.afterPropertiesSet(); + return redisTemplate; + } +} diff --git a/WXEngine/src/main/java/cn/crtech/cloud/wxengine/config/WxMpConfig.java b/WXEngine/src/main/java/cn/crtech/cloud/wxengine/config/WxMpConfig.java new file mode 100644 index 0000000..d5b8c4a --- /dev/null +++ b/WXEngine/src/main/java/cn/crtech/cloud/wxengine/config/WxMpConfig.java @@ -0,0 +1,79 @@ +package cn.crtech.cloud.wxengine.config; + +import cn.crtech.cloud.wxengine.mapper.WxMpMapper; +import cn.crtech.cloud.wxengine.pojo.WxMp; +import cn.crtech.cloud.wxengine.pojo.WxMpTemp; +import cn.hutool.core.collection.CollectionUtil; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl; +import me.chanjar.weixin.mp.config.impl.WxMpDefaultConfigImpl; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; + +import javax.annotation.PostConstruct; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@Data +@Slf4j +@Configuration +public class WxMpConfig { + @Autowired + private WxMpMapper wxMpMapper; + + private Map wxMpMap; + + private Map wxMpServiceList; + + @PostConstruct + public void initWxConfig() { + this.initWxMp(); + } + + public void initWxMp() { + wxMpServiceList = new HashMap<>(); + wxMpMap = new HashMap<>(); + List list = wxMpMapper.getWxMpByList(1); + if (!CollectionUtil.isEmpty(list)) { + list.forEach(item -> { + WxMpService wxMpService = new WxMpServiceImpl(); + WxMpDefaultConfigImpl wxMpConfigStorage = new WxMpDefaultConfigImpl(); + wxMpConfigStorage.setAppId(item.getAppId()); + wxMpConfigStorage.setSecret(item.getAppSecret()); + wxMpConfigStorage.setToken(item.getAppToken()); + wxMpConfigStorage.setAesKey(item.getAppAeskey()); + wxMpService.setWxMpConfigStorage(wxMpConfigStorage); + wxMpServiceList.put(item.getAppId(), wxMpService); + item.getWxMpTempMap().putAll(item.getWxMpTemps().stream().collect(Collectors.toMap(WxMpTemp::getTypeCode, WxMpTemp -> WxMpTemp))); + wxMpMap.put(item.getAppId(), item); + }); + log.info("公众号配置缓存成功!"); + } else { + log.error("公众号配置数据为空,系统缓存失败!"); + } + } + + /** + * 获取对应公众号的配置信息 + * + * @param appId + * @return + */ + public WxMp getWxMp(String appId) { + return wxMpMap.get(appId); + } + + /** + * 获取对应公众号的wxMpService + * + * @param appId + * @return + */ + public WxMpService getWxMpService(String appId) { + return wxMpServiceList.get(appId); + } +} diff --git a/WXEngine/src/main/java/cn/crtech/cloud/wxengine/controller/WeiXinAPIController.java b/WXEngine/src/main/java/cn/crtech/cloud/wxengine/controller/WeiXinAPIController.java new file mode 100644 index 0000000..e559ad1 --- /dev/null +++ b/WXEngine/src/main/java/cn/crtech/cloud/wxengine/controller/WeiXinAPIController.java @@ -0,0 +1,113 @@ +package cn.crtech.cloud.wxengine.controller; + +import cn.crtech.cloud.wxengine.config.WxMpConfig; +import cn.crtech.cloud.wxengine.pojo.WxMp; +import cn.crtech.cloud.wxengine.serveice.WxMpAccessService; +import lombok.extern.slf4j.Slf4j; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.Date; + +@RestController +@RequestMapping("/api") +@Slf4j +public class WeiXinAPIController { + @Autowired + private WxMpAccessService wxMpAccessService; + + @Autowired + private WxMpConfig wxMpConfig; + + /** + * 公众号消息接入 + * + * @param signature 消息签名 + * @param timestamp 时间戳 + * @param nonce 随机字符串 + * @param echostr 加密内容 + * @return + */ + @GetMapping("/message/{appId}") + @ResponseBody + public String message(@PathVariable("appId") String appId, + @RequestParam("signature") String signature, + @RequestParam("timestamp") String timestamp, + @RequestParam("nonce") String nonce, + @RequestParam("echostr") String echostr) { + WxMp wxMp = wxMpConfig.getWxMp(appId); + if (wxMp == null) { + log.error("系统没有此公众号({})配置", appId); + return "公众号配置信息异常"; + } + + if (StringUtils.isAnyBlank(signature, timestamp, nonce, echostr)) { + throw new IllegalArgumentException("请求参数非法,请核实!"); + } + WxMpService wxMpService = wxMpConfig.getWxMpService(appId); + if (wxMpService == null) { + log.error("公众号配置信息异常"); + return "公众号配置信息异常!"; + } + + if (wxMpService.checkSignature(timestamp, nonce, signature)) { + return echostr; + } + + log.error("验证失败"); + log.info("\n微信公众号消息服务中心接收消息: \nsignature:[{}] \ntimestamp:[{}] \nnonce:[{}] \nechostr:[{}]", + signature, timestamp, nonce, echostr); + return ""; + } + + /** + * 公众号消息处理 + * + * @param requestBody 消息内容 + * @param signature 消息签名 + * @param timestamp 时间戳 + * @param nonce 随机字符串 + * @param openid 发送方openid + * @param encType 加密方式 + * @param msgSignature 消息加密串 + * @return + */ + @PostMapping("/message/{appId}") + @ResponseBody + public String message(@RequestBody String requestBody, + @PathVariable("appId") String appId, + @RequestParam("signature") String signature, + @RequestParam("timestamp") String timestamp, + @RequestParam("nonce") String nonce, + @RequestParam("openid") String openid, + @RequestParam("encrypt_type") String encType, + @RequestParam("msg_signature") String msgSignature) { + WxMp wxMp = wxMpConfig.getWxMp(appId); + if (wxMp == null) { + log.error("系统没有此公众号({})配置", appId); + return "公众号配置信息异常"; + } + + Date start = new Date(); + WxMpService wxMpService = wxMpConfig.getWxMpService(appId); + if (wxMpService == null) { + log.error("公众号配置信息异常"); + return "公众号配置信息异常!"; + } + + if (encType == null) { + WxMpXmlMessage inMessage = WxMpXmlMessage.fromXml(requestBody); + log.info("花费时间 ==> {}", new Date().getTime() - start.getTime()); + return wxMpAccessService.dealCenter(appId, wxMpService, inMessage); + } else if ("aes".equalsIgnoreCase(encType)) { + WxMpXmlMessage inMessage = WxMpXmlMessage.fromEncryptedXml(requestBody, wxMpService.getWxMpConfigStorage(), + timestamp, nonce, msgSignature); + log.info("花费时间 ==> {}", new Date().getTime() - start.getTime()); + return wxMpAccessService.dealCenter(appId, wxMpService, inMessage); + } + return ""; + } +} diff --git a/WXEngine/src/main/java/cn/crtech/cloud/wxengine/mapper/WxMpMapper.java b/WXEngine/src/main/java/cn/crtech/cloud/wxengine/mapper/WxMpMapper.java new file mode 100644 index 0000000..fec51c7 --- /dev/null +++ b/WXEngine/src/main/java/cn/crtech/cloud/wxengine/mapper/WxMpMapper.java @@ -0,0 +1,19 @@ +package cn.crtech.cloud.wxengine.mapper; + +import cn.crtech.cloud.wxengine.pojo.WxMp; +import org.apache.ibatis.annotations.Param; +import org.springframework.stereotype.Repository; +import tk.mybatis.mapper.common.Mapper; + +import java.util.List; +import java.util.Map; + +/** + * Created by rxy on 2023-03-02 10:48:14 + */ +@Repository +public interface WxMpMapper extends Mapper { + List listWxMpByPage(Map params); + + List getWxMpByList(@Param("status") int status); +} diff --git a/WXEngine/src/main/java/cn/crtech/cloud/wxengine/mapper/WxMpTempMapper.java b/WXEngine/src/main/java/cn/crtech/cloud/wxengine/mapper/WxMpTempMapper.java new file mode 100644 index 0000000..e6a75a5 --- /dev/null +++ b/WXEngine/src/main/java/cn/crtech/cloud/wxengine/mapper/WxMpTempMapper.java @@ -0,0 +1,16 @@ +package cn.crtech.cloud.wxengine.mapper; + +import cn.crtech.cloud.wxengine.pojo.WxMpTemp; +import org.springframework.stereotype.Repository; +import tk.mybatis.mapper.common.Mapper; + +import java.util.List; +import java.util.Map; + +/** + * Created by rxy on 2023-03-02 10:49:03 + */ +@Repository +public interface WxMpTempMapper extends Mapper { + List listWxMpTempByPage(Map params); +} diff --git a/WXEngine/src/main/java/cn/crtech/cloud/wxengine/pojo/WxMp.java b/WXEngine/src/main/java/cn/crtech/cloud/wxengine/pojo/WxMp.java new file mode 100644 index 0000000..57d189b --- /dev/null +++ b/WXEngine/src/main/java/cn/crtech/cloud/wxengine/pojo/WxMp.java @@ -0,0 +1,53 @@ +package cn.crtech.cloud.wxengine.pojo; + +import cn.crtech.cloud.common.annotation.DataExportAnnotation; +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; + +import javax.persistence.*; +import java.io.Serializable; +import java.util.*; + +/** + * Created by rxy on 2023-03-02 10:48:14 + */ +@Data +@Table(name = "cr_wx_mp") +@DataExportAnnotation("微信公众号配置") +public class WxMp implements Serializable { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @DataExportAnnotation("") + private Integer id; + @Column(name = "gzh_name") + @DataExportAnnotation("公众号名称") + private String gzhName; + @Column(name = "app_id") + @DataExportAnnotation("应用id") + private String appId; + @Column(name = "app_secret") + @DataExportAnnotation("公众号授权秘钥") + private String appSecret; + @Column(name = "app_token") + @DataExportAnnotation("公众号授权解码token") + private String appToken; + @Column(name = "app_aeskey") + @DataExportAnnotation("公众号授权解码key") + private String appAeskey; + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + @Column(name = "created") + @DataExportAnnotation("创建时间") + private Date created; + @Column(name = "status") + @DataExportAnnotation("状态 0删除 1停用 2启用 ") + private Integer status; + @Column(name = "concat") + @DataExportAnnotation("服务器是否接通 0未接入 1接入成功") + private Integer concat; + + @Transient + private List wxMpTemps = new ArrayList<>(); + + @Transient + private Map wxMpTempMap = new HashMap<>(); +} diff --git a/WXEngine/src/main/java/cn/crtech/cloud/wxengine/pojo/WxMpTemp.java b/WXEngine/src/main/java/cn/crtech/cloud/wxengine/pojo/WxMpTemp.java new file mode 100644 index 0000000..fbe38af --- /dev/null +++ b/WXEngine/src/main/java/cn/crtech/cloud/wxengine/pojo/WxMpTemp.java @@ -0,0 +1,41 @@ +package cn.crtech.cloud.wxengine.pojo; + +import java.util.Date; +import java.math.BigDecimal; +import cn.crtech.cloud.common.annotation.DataExportAnnotation; +import com.fasterxml.jackson.annotation.JsonFormat; +import java.io.Serializable; +import lombok.*; +import javax.persistence.*; + +/** + * Created by rxy on 2023-03-02 10:49:03 + */ +@Data +@Table(name = "cr_wx_mp_temp") +@DataExportAnnotation("微信公众号模板配置") +public class WxMpTemp implements Serializable { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @DataExportAnnotation("主键") + private Integer id; + @Column(name = "wx_mp_id") + @DataExportAnnotation("微信公众号id") + private Integer wxMpId; + @Column(name = "mp_temp") + @DataExportAnnotation("模板id") + private String mpTemp; + @Column(name = "temp_url") + @DataExportAnnotation("模板url") + private String tempUrl; + @Column(name = "type_code") + @DataExportAnnotation("类型id 关联字典") + private String typeCode; + @Column(name = "status") + @DataExportAnnotation("0 禁用 1启用") + private Integer status; + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + @Column(name = "created") + @DataExportAnnotation("创建时间") + private Date created; +} diff --git a/WXEngine/src/main/java/cn/crtech/cloud/wxengine/serveice/AbstractBuilder.java b/WXEngine/src/main/java/cn/crtech/cloud/wxengine/serveice/AbstractBuilder.java new file mode 100644 index 0000000..312ea8c --- /dev/null +++ b/WXEngine/src/main/java/cn/crtech/cloud/wxengine/serveice/AbstractBuilder.java @@ -0,0 +1,15 @@ +package cn.crtech.cloud.wxengine.serveice; + +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage; +import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage; + +/** + * desc + * + * @Author: TYP + * @Date: 2022-06-10 10:46 + */ +public abstract class AbstractBuilder { + public abstract WxMpXmlOutMessage build(String content, WxMpXmlMessage wxMessage, WxMpService service); +} diff --git a/WXEngine/src/main/java/cn/crtech/cloud/wxengine/serveice/BaseService.java b/WXEngine/src/main/java/cn/crtech/cloud/wxengine/serveice/BaseService.java new file mode 100644 index 0000000..e2a04a3 --- /dev/null +++ b/WXEngine/src/main/java/cn/crtech/cloud/wxengine/serveice/BaseService.java @@ -0,0 +1,50 @@ +package cn.crtech.cloud.wxengine.serveice; + +import cn.crtech.cloud.common.dto.Result; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; +import tk.mybatis.mapper.common.Mapper; + +import java.util.Map; + +public abstract class BaseService { + public abstract Mapper getMapper(); + + @Transactional(propagation = Propagation.REQUIRED) + public Result add(T obj) { + getMapper().insert(obj); + return Result.success(obj, "操作成功!"); + } + + @Transactional(propagation = Propagation.REQUIRED) + public Result update(T obj) { + getMapper().updateByPrimaryKeySelective(obj); + return Result.success(obj, "操作成功!"); + } + + @Transactional(propagation = Propagation.REQUIRED) + public Result deleteById(int id) { + getMapper().deleteByPrimaryKey(id); + return Result.success(id, "操作成功!"); + } + + @Transactional(propagation = Propagation.REQUIRED) + public Result delete(T obj) { + getMapper().delete(obj); + return Result.success(obj, "操作成功!"); + } + + + public T getById(int id) { + return (T) getMapper().selectByPrimaryKey(id); + } + + public T getById(String id) { + return (T) getMapper().selectByPrimaryKey(id); + } + + public abstract Result listByPage(Map params); + + public abstract Result listByParams(Map params); + +} diff --git a/WXEngine/src/main/java/cn/crtech/cloud/wxengine/serveice/WxMpAccessService.java b/WXEngine/src/main/java/cn/crtech/cloud/wxengine/serveice/WxMpAccessService.java new file mode 100644 index 0000000..78e44f3 --- /dev/null +++ b/WXEngine/src/main/java/cn/crtech/cloud/wxengine/serveice/WxMpAccessService.java @@ -0,0 +1,113 @@ +package cn.crtech.cloud.wxengine.serveice; + +import lombok.extern.slf4j.Slf4j; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.kefu.WxMpKefuMessage; +import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage; +import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Map; + +/** + * 微信公众号事件处理 实现层 + */ + +@Slf4j +@Service +public class WxMpAccessService { + /** + * 消息/事件处理中心 + * + * @param wxMpService + * @param inMessage + * @return + */ + @Transactional(rollbackFor = Exception.class) + public String dealCenter(String appId, WxMpService wxMpService, WxMpXmlMessage inMessage) { + if (!StringUtils.isEmpty(inMessage.getEvent())) { + return this.eventCenter(appId, wxMpService, inMessage, inMessage.getEvent()); + } else { + // todo 消息处理 + String msgType = inMessage.getMsgType(); + // msgType = text 主动推送 + WxMpXmlOutMessage build = new WxMpTextBuilder().build("123456", inMessage, wxMpService); + System.out.println("回复消息 ==> \n" + build.toXml()); + return build.toXml(); + } + } + + /** + * 事件处理中心 + * + * @param wxMpService + * @param inMessage + * @param eventName + * @return + */ + private String eventCenter(String appId, WxMpService wxMpService, WxMpXmlMessage inMessage, String eventName) { + String reply = ""; + String wxOpenId = inMessage.getFromUser(); + + switch (eventName) { + case "subscribe": + String content = "超然静配欢迎您的关注!"; + reply = new WxMpTextBuilder().build(content, inMessage, wxMpService).toXml(); + break; + case "unsubscribe": + + break; + case "SCAN": + log.info("公众号({})用户({})扫码事件接收", appId, wxOpenId); + break; + case "CLICK": + reply = eventKeyCenter(appId, wxMpService, inMessage, inMessage.getEventKey()); + break; + default: + reply = ""; + } + return reply; + } + + private String eventKeyCenter(String appId, WxMpService wxMpService, WxMpXmlMessage inMessage, String eventKey) { + String reply = ""; + switch (eventKey) { + case "click_get_kf_url": + // todo 测试用 售前客服 待其他关系库完善后再进行处理 + break; + case "click_get_kf_url_back": + // 售后客服 + break; + default: + break; + } + return reply; + } + + /** + * 主动发送消息接口 + * + * @param sendMsg 发送内容 包括content以及消息接收方 + * @param wxMpService 对应的发送服务 + * @return + */ + public Boolean sendMsg(Map sendMsg, WxMpService wxMpService) { + String content = sendMsg.get("content").toString(); + String toUser = sendMsg.get("toUser").toString(); + + WxMpKefuMessage wxMpKefuMessage = new WxMpKefuMessage(); + wxMpKefuMessage.setContent(content); + wxMpKefuMessage.setToUser(toUser); + wxMpKefuMessage.setMsgType("text"); + + try { + return wxMpService.getKefuService().sendKefuMessage(wxMpKefuMessage); + } catch (WxErrorException e) { + log.error("主动发送消息失败 , 原因 ==> {}", e.getMessage()); + return false; + } + } +} diff --git a/WXEngine/src/main/java/cn/crtech/cloud/wxengine/serveice/WxMpService.java b/WXEngine/src/main/java/cn/crtech/cloud/wxengine/serveice/WxMpService.java new file mode 100644 index 0000000..cb3add3 --- /dev/null +++ b/WXEngine/src/main/java/cn/crtech/cloud/wxengine/serveice/WxMpService.java @@ -0,0 +1,49 @@ +package cn.crtech.cloud.wxengine.serveice; + +import cn.crtech.cloud.common.dto.Result; +import cn.crtech.cloud.wxengine.mapper.WxMpMapper; +import cn.crtech.cloud.wxengine.pojo.WxMp; +import com.github.pagehelper.PageHelper; +import com.github.pagehelper.PageInfo; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import tk.mybatis.mapper.common.Mapper; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * Created by rxy on 2023-03-02 10:48:14 + */ +@Service +@Transactional(readOnly = true) +public class WxMpService extends BaseService { + @Autowired + WxMpMapper wxMpMapper; + + @Override + public Mapper getMapper() { + return wxMpMapper; + } + + @Override + public Result listByPage(Map params) { + List data; + if(params != null){ + PageHelper.startPage( params ); + data = wxMpMapper.listWxMpByPage(params); + }else{ + data = new ArrayList<>(); + } + PageInfo page = new PageInfo( data ); + return Result.success(page); + } + + @Override + public Result listByParams(Map params) { + return null; + } + +} diff --git a/WXEngine/src/main/java/cn/crtech/cloud/wxengine/serveice/WxMpTempService.java b/WXEngine/src/main/java/cn/crtech/cloud/wxengine/serveice/WxMpTempService.java new file mode 100644 index 0000000..8b9de8f --- /dev/null +++ b/WXEngine/src/main/java/cn/crtech/cloud/wxengine/serveice/WxMpTempService.java @@ -0,0 +1,49 @@ +package cn.crtech.cloud.wxengine.serveice; + +import cn.crtech.cloud.common.dto.Result; +import cn.crtech.cloud.wxengine.mapper.WxMpTempMapper; +import cn.crtech.cloud.wxengine.pojo.WxMpTemp; +import com.github.pagehelper.PageHelper; +import com.github.pagehelper.PageInfo; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import tk.mybatis.mapper.common.Mapper; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * Created by rxy on 2023-03-02 10:49:03 + */ +@Service +@Transactional(readOnly = true) +public class WxMpTempService extends BaseService { + @Autowired + WxMpTempMapper wxMpTempMapper; + + @Override + public Mapper getMapper() { + return wxMpTempMapper; + } + + @Override + public Result listByPage(Map params) { + List data; + if (params != null) { + PageHelper.startPage(params); + data = wxMpTempMapper.listWxMpTempByPage(params); + } else { + data = new ArrayList<>(); + } + PageInfo page = new PageInfo(data); + return Result.success(page); + } + + @Override + public Result listByParams(Map params) { + return null; + } + +} diff --git a/WXEngine/src/main/java/cn/crtech/cloud/wxengine/serveice/WxMpTextBuilder.java b/WXEngine/src/main/java/cn/crtech/cloud/wxengine/serveice/WxMpTextBuilder.java new file mode 100644 index 0000000..69e10bd --- /dev/null +++ b/WXEngine/src/main/java/cn/crtech/cloud/wxengine/serveice/WxMpTextBuilder.java @@ -0,0 +1,23 @@ +package cn.crtech.cloud.wxengine.serveice; + +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage; +import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage; +import me.chanjar.weixin.mp.bean.message.WxMpXmlOutTextMessage; + +/** + * 微信公众号文本消息创建工具类 + * + * @Author: TYP + * @Date: 2022-06-10 10:47 + */ +public class WxMpTextBuilder extends AbstractBuilder { + @Override + public WxMpXmlOutMessage build(String content, WxMpXmlMessage wxMessage, + WxMpService service) { + WxMpXmlOutTextMessage m = WxMpXmlOutMessage.TEXT().content(content) + .fromUser(wxMessage.getToUser()).toUser(wxMessage.getFromUser()) + .build(); + return m; + } +} diff --git a/WXEngine/src/main/java/cn/crtech/cloud/wxengine/utils/CodeUtils.java b/WXEngine/src/main/java/cn/crtech/cloud/wxengine/utils/CodeUtils.java new file mode 100644 index 0000000..3612736 --- /dev/null +++ b/WXEngine/src/main/java/cn/crtech/cloud/wxengine/utils/CodeUtils.java @@ -0,0 +1,22 @@ +package cn.crtech.cloud.wxengine.utils; + +import java.text.SimpleDateFormat; +import java.util.Date; + +public class CodeUtils { + private static byte[] lock = new byte[0]; + + private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssss"); + + // 位数,默认是8位 + private final static long w = 5; + + public static String createID(String Prefix) { + long r = 0; + synchronized (lock) { + r = (long) ((Math.random() + 1) * w); + } + + return Prefix + sdf.format(new Date()) + String.valueOf(r).substring(1); + } +} diff --git a/WXEngine/src/main/resources/application-dev.yml b/WXEngine/src/main/resources/application-dev.yml new file mode 100644 index 0000000..ef6b747 --- /dev/null +++ b/WXEngine/src/main/resources/application-dev.yml @@ -0,0 +1,37 @@ +server: + port: 2001 + servlet: + encoding: + charset: utf-8 + enabled: true + force: true +spring: + servlet: + multipart: + max-file-size: 50MB + max-request-size: 50MB + jackson: + date-format: yyyy-MM-dd HH:mm:ss + time-zone: GMT+8 + redis: + database: 0 + port: 6379 + host: localhost + password: +mybatis: + mapper-locations: classpath*:/mapper/*Mapper.xml + type-aliases-package: cn.crtech.cloud.common.pojo.general,cn.crtech.cloud.common.dto.general + #配置驼峰下划线 + configuration: + map-underscore-to-camel-case: true +logging: + config: classpath:logback.xml + file: + path: logs/crtech-service-wxengine.log + level: + cn.crtech.cloud.customer: debug +weixin: + appid: wxc74a3f37e8bdfbed # 设置微信公众号的appid + secret: bd58cb0e336efbed8faf907931d2d974 # 设置微信公众号的app corpSecret + token: Crtech # 设置微信公众号的token + aes-token: yHEUfbxwnmKcjRnMQBWekDo9QvGfHCkC0IRrlbNpg5H # 设置微信公众号的EncodingAESKey diff --git a/WXEngine/src/main/resources/application-prod.yml b/WXEngine/src/main/resources/application-prod.yml new file mode 100644 index 0000000..e438c1e --- /dev/null +++ b/WXEngine/src/main/resources/application-prod.yml @@ -0,0 +1,40 @@ +server: + port: 8087 + servlet: + encoding: + charset: utf-8 + enabled: true + force: true +spring: + servlet: + multipart: + max-file-size: 50MB + max-request-size: 50MB + jackson: + date-format: yyyy-MM-dd HH:mm:ss + time-zone: GMT+8 + redis: + database: 0 + port: 6397 + host: chaoran.crtech.cn + password: +mybatis: + mapper-locations: classpath*:/mapper/*Mapper.xml + type-aliases-package: cn.crtech.cloud.common.pojo.customer,cn.crtech.cloud.common.dto.customer + #配置驼峰下划线 + configuration: + map-underscore-to-camel-case: true +logging: + config: classpath:logback.xml + file: + path: logs/crtech-service-customer.log + level: + cn.crtech.cloud.customer: debug +wx: + mp: + domain: http://crcloud.crtech.cn/client +LingKaiSMS: + CorpID: CRTECH00002 + Pwd: crtech + domain: https://mb345.com/ws/BatchSend2.aspx + diff --git a/WXEngine/src/main/resources/bootstrap-dev.yml b/WXEngine/src/main/resources/bootstrap-dev.yml new file mode 100644 index 0000000..4e1725c --- /dev/null +++ b/WXEngine/src/main/resources/bootstrap-dev.yml @@ -0,0 +1,13 @@ +spring: + application: + name: crtech-cloud-wxengine # 项目名称尽量用小写 + cloud: + nacos: + discovery: + server-addr: localhost:8848 + datasource: + url: jdbc:mysql://chaoran.crtech.cn:9803/cr_cloud_general_dev?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true + username: 406EB1CDA013F64723B971DBD68B8511 + password: 086B2FA5626018DE67E865D13134D67B9BC1AEBE46D471A439DECA0725908C65 + + diff --git a/WXEngine/src/main/resources/bootstrap-prod.yml b/WXEngine/src/main/resources/bootstrap-prod.yml new file mode 100644 index 0000000..d34e188 --- /dev/null +++ b/WXEngine/src/main/resources/bootstrap-prod.yml @@ -0,0 +1,13 @@ +spring: + application: + name: crtech-cloud-wxengine # 项目名称尽量用小写 + cloud: + nacos: + discovery: + server-addr: http://chaoran.crtech.cn:28848 + datasource: + url: jdbc:mysql://chaoran.crtech.cn:9803/cr_cloud_customer?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true&allowMultiQueries=true + username: 406EB1CDA013F64723B971DBD68B8511 + password: 086B2FA5626018DE67E865D13134D67B9BC1AEBE46D471A439DECA0725908C65 + + diff --git a/WXEngine/src/main/resources/bootstrap.yml b/WXEngine/src/main/resources/bootstrap.yml new file mode 100644 index 0000000..76d483d --- /dev/null +++ b/WXEngine/src/main/resources/bootstrap.yml @@ -0,0 +1,5 @@ +spring: + profiles: + active: dev + + diff --git a/WXEngine/src/main/resources/logback.xml b/WXEngine/src/main/resources/logback.xml new file mode 100644 index 0000000..9cde327 --- /dev/null +++ b/WXEngine/src/main/resources/logback.xml @@ -0,0 +1,56 @@ + + + + + + logs/crtech-service-wxengine.%d{yyyy-MM-dd}.log + + + + + %d{yyyy-MM-dd_HH:mm:ss} %logger{18} -%msg%n + + + + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + 0 + 1000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/WXEngine/src/main/resources/mapper/WxMpMapper.xml b/WXEngine/src/main/resources/mapper/WxMpMapper.xml new file mode 100644 index 0000000..1eef0dc --- /dev/null +++ b/WXEngine/src/main/resources/mapper/WxMpMapper.xml @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + a.id,a.gzh_name,a.app_id,a.app_secret,a.app_token,a.app_aeskey,a.created,a.status + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/WXEngine/src/main/resources/mapper/WxMpTempMapper.xml b/WXEngine/src/main/resources/mapper/WxMpTempMapper.xml new file mode 100644 index 0000000..200bf14 --- /dev/null +++ b/WXEngine/src/main/resources/mapper/WxMpTempMapper.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + a.id,a.wx_mp_id,a.mp_temp,a.type_code,a.status,a.created + + + +