本文主要实现给不同的用户推动不同的问候模板
准备工作
申请微信公众平台的测试号
申请微信测试公众号
创建成功后,可以看到appid和appsecret,这个后面认证时需要
申请模板
可自行修改
今天是:{{now.DATA}} 不管那一天,每一天都是想你的一天
当前城市:{{city.DATA}}
今天的天气:{{text.DATA}}
最低气温:{{low.DATA}} 度
最高气温:{{high.DATA}} 度
今天是我们想恋的第:{{scq_day.DATA}} 天
距你的生日还有:{{bir_day.DATA}} 天
{{daily_english_cn.DATA}}
{{daily_english_en.DATA}}
新建成功后,记得保存模板Id后续有用
扫描关注该测试公众号
扫码关注后,记录微信号,后续推送通知用
申请百度天气
申请百度天气
完成认证后,创建一个应用,保存ak
申请天行数据的接口
申请天行数据
- 申请彩虹屁
- 申请每日一句
记得保存申请接口的key
开发工作
技术栈
- springboot 2.7.5
- swagger 3.0
- mysql 8.x
- spring data jpa
- openfeign
依赖
<?xml version="1.0" encoding="UTF-8"?><projectxmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.zhao</groupId><artifactId>daily-weather</artifactId><version>1.0.0</version><name>daily-weather</name><description>微信用户推送消息</description><properties><java.version>1.8</java.version><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><spring-boot.version>2.7.5</spring-boot.version><swagger.version>3.0.0</swagger.version><knife4j.version>3.0.3</knife4j.version><fastjson.version>2.0.15</fastjson.version><openfeign.version>3.1.3</openfeign.version><hutools.version>5.7.5</hutools.version></properties><dependencies><!--hutools--><dependency><groupId>cn.hutool</groupId><artifactId>hutool-core</artifactId><version>${hutools.version}</version></dependency><!--fastjson--><dependency><groupId>com.alibaba.fastjson2</groupId><artifactId>fastjson2</artifactId><version>${fastjson.version}</version></dependency><!--open feign--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId><version>${openfeign.version}</version></dependency><!--weixin-java-mp--><dependency><groupId>com.github.binarywang</groupId><artifactId>weixin-java-mp</artifactId><version>3.3.0</version></dependency><!--lombok--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><!--swagger--><dependency><groupId>io.springfox</groupId><artifactId>springfox-boot-starter</artifactId><version>${swagger.version}</version></dependency><!--换掉默认皮肤--><dependency><groupId>com.github.xiaoymin</groupId><artifactId>knife4j-spring-boot-starter</artifactId><version>${knife4j.version}</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope><exclusions><exclusion><groupId>org.junit.vintage</groupId><artifactId>junit-vintage-engine</artifactId></exclusion></exclusions></dependency></dependencies><dependencyManagement><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>${spring-boot.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.8.1</version><configuration><source>1.8</source><target>1.8</target><encoding>UTF-8</encoding></configuration></plugin><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><version>2.3.7.RELEASE</version><configuration><mainClass>com.zhao.wechat.DailyWeatherApplication</mainClass></configuration><executions><execution><id>repackage</id><goals><goal>repackage</goal></goals></execution></executions></plugin></plugins></build></project>
配置文件
server:
port: 43310
# 微信配置
tencent:
wechat:
appId: 微信appid
appSecret: 微信appSecret
# 模板消息集合
templatelist:
- type: 1
templateId: 微信模板id
- type: 2
templateId: 微信模板id
- type: 3
templateId: 微信模板id
# 百度天气配置
baidu:
server: https://api.map.baidu.com
ak: 百度数据的ak
# 天行数据
tianxin:
server: http://api.tianapi.com
key: 天行数据的key
spring:
mvc:
pathmatch:
matching-strategy: ant_path_matcher
datasource:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://ip:3306/库名?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
username: root
password: 564929
hikari:
minimum-idle: 5
# 空闲连接存活最大时间,默认600000(10分钟)
idle-timeout: 180000
# 连接池最大连接数,默认是10
maximum-pool-size: 10
# 此属性控制从池返回的连接的默认自动提交行为,默认值:true
auto-commit: true
# 连接池名称
pool-name: MyHikariCP
# 此属性控制池中连接的最长生命周期,值0表示无限生命周期,默认1800000即30分钟
max-lifetime: 1800000
# 数据库连接超时时间,默认30秒,即30000
connection-timeout: 30000
connection-test-query: SELECT 1
jpa:
show-sql: true # 默认false,在日志里显示执行的sql语句
database: mysql
database-platform: org.hibernate.dialect.MySQL5Dialect
hibernate:
ddl-auto: update #指定为update,每次启动项目检测表结构有变化的时候会新增字段,表不存在时会 新建,如果指定create,则每次启动项目都会清空数据并删除表,再新建
naming:
#指定jpa的自动表生成策略,驼峰自动映射为下划线格式7
implicit-strategy: org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyJpaImpl
#physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
# 日志
#logging:
# config: classpath:logback-spring-dev.xml
统一数据封装
packagecom.zhao.wechat.advice;importcom.fasterxml.jackson.core.JsonProcessingException;importcom.fasterxml.jackson.databind.ObjectMapper;importcom.zhao.wechat.common.Result;importlombok.extern.slf4j.Slf4j;importorg.springframework.core.MethodParameter;importorg.springframework.http.MediaType;importorg.springframework.http.converter.HttpMessageConverter;importorg.springframework.http.server.ServerHttpRequest;importorg.springframework.http.server.ServerHttpResponse;importorg.springframework.web.bind.annotation.RestControllerAdvice;importorg.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;/**
* 对前端响应结果统一封装
*/@Slf4j@RestControllerAdvice(basePackages ={"com.zhao.wechat.rest"})publicclassApiResponseAdviceimplementsResponseBodyAdvice<Object>{/**
* 打印统一请求响应规范
*/ApiResponseAdvice(){
log.info("启动请求统一响应规范... ...");}/**
* 判断是否需要对返回值进行封装
* @param returnType the return type
* @param converterType the selected converter type
* @return
*/@Overridepublicbooleansupports(MethodParameter returnType,Class<?extendsHttpMessageConverter<?>> converterType){// 如果返回的结果是Result.class类型就不用封装if(returnType.getParameterType().equals(Result.class)){returnfalse;}returntrue;}/**
* 对返回前端的值统一封装
* @param body the body to be written
* @param returnType the return type of the controller method
* @param selectedContentType the content type selected through content negotiation
* @param selectedConverterType the converter type selected to write to the response
* @param request the current request
* @param response the current response
* @return
*/@OverridepublicObjectbeforeBodyWrite(Object body,MethodParameter returnType,MediaType selectedContentType,Class<?extendsHttpMessageConverter<?>> selectedConverterType,ServerHttpRequest request,ServerHttpResponse response){if(returnType.getParameterType().equals(String.class)){// 如果是String类需要特殊处理ObjectMapper objectMapper =newObjectMapper();try{// 设置响应数据格式为json
response.getHeaders().add("content-type","application/json;charset=UTF-8");return objectMapper.writeValueAsString(Result.success(body));}catch(JsonProcessingException e){thrownewRuntimeException(e);}}returnResult.success(body);}}
工程结构
用户controller
packagecom.zhao.wechat.rest;importcom.zhao.wechat.domain.UserInfo;importcom.zhao.wechat.service.UserInfoService;importio.swagger.annotations.Api;importio.swagger.annotations.ApiOperation;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.data.domain.Page;importorg.springframework.data.domain.Pageable;importorg.springframework.data.web.PageableDefault;importorg.springframework.web.bind.annotation.*;importjava.util.List;/**
* 用户信息管理视图层
*/@RestController@RequestMapping("/userInfo")@Api(tags ="用户信息管理")publicclassUserInfoRest{@AutowiredprivateUserInfoService userInfoService;/**
* 分页获取所有的用户
* @return
*/@ApiOperation(value ="分页获取所有的用户")@PostMapping("/queryPage")publicPage<UserInfo>queryUserPage(@PageableDefaultPageable pageable){Page<UserInfo> userInfos = userInfoService.queryUserPage(pageable.getPageNumber(), pageable.getPageSize());return userInfos;}/**
* 添加或者修改用户
*/@ApiOperation(value ="添加或者修改用户")@PostMapping("/saveOrUpdate")publicvoidsaveOrUpdate(@RequestBodyUserInfo userInfo){
userInfoService.saveOrUpdate(userInfo);}/**
* 删除用户
*/@ApiOperation(value ="删除用户")@DeleteMapping("/delete")publicvoiddeleteUserById(@RequestParam("id")Long id){
userInfoService.deleteUserById(id);}}
调用第三方接口
packagecom.zhao.wechat.remote;importcom.zhao.wechat.remote.param.TianXinParam;importorg.springframework.cloud.openfeign.FeignClient;importorg.springframework.cloud.openfeign.SpringQueryMap;importorg.springframework.http.MediaType;importorg.springframework.web.bind.annotation.GetMapping;/**
* 第三方接口天行数据
*/@FeignClient(value ="TianDataRemoteClient",url ="${tianxin.server}")publicinterfaceTianDataRemoteClient{/**
* 获取彩虹屁
*/@GetMapping(value ="/caihongpi/index",
consumes ={MediaType.APPLICATION_JSON_VALUE},
produces ={MediaType.APPLICATION_JSON_VALUE})StringqueryRainbow(@SpringQueryMapTianXinParam tianXinParam);/**
* 获取优美的句子
*/@GetMapping(value ="/ensentence/index",
consumes ={MediaType.APPLICATION_JSON_VALUE},
produces ={MediaType.APPLICATION_JSON_VALUE})StringqueryEnsentence(@SpringQueryMapTianXinParam tianXinParam);}
推送微信数据
packagecom.zhao.wechat.service;importcn.hutool.core.date.DatePattern;importcn.hutool.core.date.DateUnit;importcn.hutool.core.date.DateUtil;importcn.hutool.core.util.StrUtil;importcom.alibaba.fastjson2.JSON;importcom.zhao.wechat.config.WechatConfig;importcom.zhao.wechat.config.WechatTemplate;importcom.zhao.wechat.config.WechatTemplateList;importcom.zhao.wechat.domain.*;importcom.zhao.wechat.remote.BaiduWeatherRemoteClient;importcom.zhao.wechat.remote.TianDataRemoteClient;importcom.zhao.wechat.remote.param.BaiduWeatherParam;importcom.zhao.wechat.remote.param.TianXinParam;importlombok.extern.slf4j.Slf4j;importme.chanjar.weixin.common.error.WxErrorException;importme.chanjar.weixin.mp.api.WxMpInMemoryConfigStorage;importme.chanjar.weixin.mp.api.WxMpService;importme.chanjar.weixin.mp.api.impl.WxMpServiceImpl;importme.chanjar.weixin.mp.bean.template.WxMpTemplateData;importme.chanjar.weixin.mp.bean.template.WxMpTemplateMessage;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.beans.factory.annotation.Value;importorg.springframework.stereotype.Service;importorg.springframework.util.CollectionUtils;importjava.time.format.DateTimeFormatter;importjava.util.Calendar;importjava.util.Date;importjava.util.List;importjava.util.Objects;@Slf4j@ServicepublicclassPushDailyWechatImplimplementsPushDailyWechat{@AutowiredprivateUserInfoService userInfoService;@AutowiredprivateBaiduWeatherRemoteClient baiduWeatherRemoteClient;@AutowiredprivateTianDataRemoteClient tianDataRemoteClient;/** 微信配置类 **/@AutowiredprivateWechatConfig wechatConfig;/** 模板列表**/@AutowiredprivateWechatTemplateList wechatTemplateList;/** ak **/@Value("${baidu.ak}")privateString ak;/** key **/@Value("${tianxin.key}")privateString key;/**
* 给不同的用户推送消息
*/@OverridepublicvoidpushWechat()throwsWxErrorException{// 获取用户列表List<UserInfo> userInfoList = userInfoService.listUserInfo();if(!CollectionUtils.isEmpty(userInfoList)){// 根据用户的type类型和模板type进行匹配for(UserInfo userInfo : userInfoList){for(WechatTemplate template : wechatTemplateList.getTemplatelist()){if(userInfo.getType().equals(template.getType())){this.wechatData(userInfo.getWechatId(), template.getTemplateId(),userInfo);}}}}}/**
* 封装微信数据
* @param wechatId
* @param templateId
*/privatevoidwechatData(String wechatId,String templateId,UserInfo userInfo)throwsWxErrorException{// 创建配置信息WxMpInMemoryConfigStorage wxStorage =newWxMpInMemoryConfigStorage();
wxStorage.setAppId(wechatConfig.getAppId());
wxStorage.setSecret(wechatConfig.getAppSecret());WxMpService wxMpService =newWxMpServiceImpl();
wxMpService.setWxMpConfigStorage(wxStorage);// 创建模板信息WxMpTemplateMessage templateMessage =WxMpTemplateMessage.builder().toUser(wechatId).templateId(templateId).build();// 获取天气预报信息BaiduWeatherParam baiduWeatherParam =BaiduWeatherParam.builder().district_id(userInfo.getDistrictId()).data_type("all").ak(this.ak).build();String queryWeather = baiduWeatherRemoteClient.queryWeather(baiduWeatherParam);
log.info("查询的百度天气信息为:{}",queryWeather);BaiduNowWeather baiduNowWeather =ApiResponse.parseBaiduNowData(queryWeather,BaiduNowWeather.class);List<BaiduForecastsWeather> baiduForecastsWeatherList =ApiResponse.parseBaiduForecastsData(queryWeather,BaiduForecastsWeather.class);
log.info("baiduNowWeather:{},baiduForecastsWeather:{}",baiduNowWeather,baiduForecastsWeatherList);// 获取彩虹屁TianXinParam tianXinParam =TianXinParam.builder().key(this.key).build();String queryRainbow = tianDataRemoteClient.queryRainbow(tianXinParam);List<TianRainbow> rainbowList =ApiResponse.parseTianData(queryRainbow,TianRainbow.class);// 获取每日一句String queryEnsentence = tianDataRemoteClient.queryEnsentence(tianXinParam);List<TianEnsentence> tianEnsentenceList =ApiResponse.parseTianData(queryEnsentence,TianEnsentence.class);// 封装模板数据
templateMessage.addData(newWxMpTemplateData("now",this.pareDateNow(baiduForecastsWeatherList.get(0)),"#FFB6C1"));
templateMessage.addData(newWxMpTemplateData("city",userInfo.getCity(),"#B95EA6"));
templateMessage.addData(newWxMpTemplateData("text",baiduNowWeather.getText(),"#173177"));
templateMessage.addData(newWxMpTemplateData("high",baiduForecastsWeatherList.get(0).getHigh(),"#87cefa"));
templateMessage.addData(newWxMpTemplateData("low",baiduForecastsWeatherList.get(0).getLow(),"#FF6347"));
templateMessage.addData(newWxMpTemplateData("scq_day",this.calScqDate(userInfo),"#FF1493"));
templateMessage.addData(newWxMpTemplateData("bir_day",this.calBirData(userInfo),"#FF00FF"));
templateMessage.addData(newWxMpTemplateData("daily_english_cn",rainbowList.get(0).getContent(),"#800080"));
templateMessage.addData(newWxMpTemplateData("daily_english_en",tianEnsentenceList.get(0).getEn(),"#FFA500"));
log.info("发送的消息为:{}",JSON.toJSONString(templateMessage));
wxMpService.getTemplateMsgService().sendTemplateMsg(templateMessage);}/**
* 计算想认识/想恋日期
* @return
*/privateStringcalScqDate(UserInfo userInfo){// 获取第一次想认识的时间if(Objects.nonNull(userInfo)){Date scqTime = userInfo.getScqTime();// 计算时间差long between =DateUtil.between(scqTime,DateUtil.date(),DateUnit.DAY);returnString.valueOf(between);}return"";}/**
* 计算生日
* @param userInfo
* @return
*/privateStringcalBirData(UserInfo userInfo){// 获取用户的出生日期if(Objects.nonNull(userInfo)){Date birTime = userInfo.getBirTime();// 今日日期Calendar today =Calendar.getInstance();// 出生日期Calendar birthDay =Calendar.getInstance();// 设置生日
birthDay.setTime(birTime);// 修改为本年int bir;
birthDay.set(Calendar.YEAR,today.get(Calendar.YEAR));if(birthDay.get(Calendar.DAY_OF_YEAR)< today.get(Calendar.DAY_OF_YEAR)){// 生日已经过了,计算明年的
bir = today.getActualMaximum(Calendar.DAY_OF_YEAR)- today.get(Calendar.DAY_OF_YEAR);
bir += birthDay.get(Calendar.DAY_OF_YEAR);}else{// 生日还没过
bir = birthDay.get(Calendar.DAY_OF_YEAR)- today.get(Calendar.DAY_OF_YEAR);}returnString.valueOf(bir);}return"";}/**
* 拼接今日时间
* @return
*/privateStringpareDateNow(BaiduForecastsWeather baiduForecastsWeather){// 获取当前日期String now =DateUtil.format(DateUtil.date(),DatePattern.CHINESE_DATE_PATTERN);// 获取星期几String week = baiduForecastsWeather.getWeek();return now+" "+week;}}
定时任务
packagecom.zhao.wechat.job;importcom.zhao.wechat.service.PushDailyWechat;importme.chanjar.weixin.common.error.WxErrorException;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.scheduling.annotation.Scheduled;importorg.springframework.stereotype.Component;/**
* 推送消息到用户定时任务
*/@ComponentpublicclassPushWechatJob{@AutowiredprivatePushDailyWechat pushDailyWechat;/**
* 每天早上7点推送到微信
* @throws WxErrorException
*/@Scheduled(cron ="0 30 7 1/1 * ? ")voiddoJob()throwsWxErrorException{
pushDailyWechat.pushWechat();}}
效果
推送到微信
版权归原作者 stevezhao6 所有, 如有侵权,请联系我们删除。