1 Spring Boot 3.1.5
2 JDK 21
3 weixin-java-mp 4.5.0
4 fastjson 2.0.43
版本
<properties>
<java.version>21java.version>
<snakeyaml.version>2.2snakeyaml.version>
<jakarta.validation-api.version>3.0.2jakarta.validation-api.version>
<hibernate-validator.version>8.0.1.Finalhibernate-validator.version>
<weixin-java-mp.version>4.5.0weixin-java-mp.version>
<fastjson.version>2.0.43fastjson.version>
properties>
导入
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-configuration-processorartifactId>
<optional>trueoptional>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<optional>trueoptional>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
<dependency>
<groupId>jakarta.validationgroupId>
<artifactId>jakarta.validation-apiartifactId>
<version>${jakarta.validation-api.version}version>
dependency>
<dependency>
<groupId>org.hibernate.validatorgroupId>
<artifactId>hibernate-validatorartifactId>
<version>${hibernate-validator.version}version>
dependency>
<dependency>
<groupId>com.github.binarywanggroupId>
<artifactId>weixin-java-mpartifactId>
<version>${weixin-java-mp.version}version>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>fastjsonartifactId>
<version>${fastjson.version}version>
dependency>
dependencies>
@Slf4j
@SpringBootApplication
public class BaseWeixinMsgApplication {
public static void main(String[] args) {
SpringApplication.run(BaseWeixinMsgApplication.class, args);
log.info("启动成功!");
log.info(PushConfigure.getSecret());
log.info(PushConfigure.getAppId());
}
}
@Component
@ConfigurationProperties("wechat")
public class PushConfigure {
/**
* 微信公众平台的appID
*/
private static String appId;
/**
* 微信公众平台的appSecret
*/
private static String secret;
/**
* 天气查询的城市ID
*/
private static String districtId;
/**
* 应用AK
*/
private static String ak;
/**
* 纪念日
*/
private static String loveDate;
/**
* 生日
*/
private static String birthday;
/**
* 关注公众号的用户ID
*/
private static String userId;
/**
* 模板ID
*/
private static String templateId;
/**
* 天行数据apiKey
*/
private static String rainbowKey;
public static String getAppId() {
return appId;
}
public void setAppId(String appId) {
PushConfigure.appId = appId;
}
public static String getSecret() {
return secret;
}
public void setSecret(String secret) {
PushConfigure.secret = secret;
}
public static String getDistrictId() {
return districtId;
}
public void setDistrict_id(String district_id) {
PushConfigure.districtId = district_id;
}
public static String getAk() {
return ak;
}
public void setAk(String ak) {
PushConfigure.ak = ak;
}
public static String getLoveDate() {
return loveDate;
}
public void setLoveDate(String loveDate) {
PushConfigure.loveDate = loveDate;
}
public static String getBirthday() {
return birthday;
}
public void setBirthday(String birthday) {
PushConfigure.birthday = birthday;
}
public static String getUserId() {
return userId;
}
public void setUserId(String userId) {
PushConfigure.userId = userId;
}
public static String getTemplateId() {
return templateId;
}
public void setTemplateId(String templateId) {
PushConfigure.templateId = templateId;
}
public static String getRainbowKey() {
return rainbowKey;
}
public void setRainbowKey(String rainbowKey) {
PushConfigure.rainbowKey = rainbowKey;
}
}
@Data
public class Weather {
private String textDay;
private String textNight;
private String high;
private String low;
private String wcDay;
private String wdDay;
private String wcNight;
private String wdNight;
private String date;
private String week;
private String textNow;
private String temp;
private String city;
}
public class MemoryDayUtil {
private static final ThreadLocal<SimpleDateFormat> THREAD_LOCAL = new ThreadLocal<>();
/**
* 获取SimpleDateFormat
*/
private static SimpleDateFormat get() {
SimpleDateFormat sdf = THREAD_LOCAL.get();
if (sdf == null) {
sdf = new SimpleDateFormat("yyyy-MM-dd");
THREAD_LOCAL.set(sdf);
}
return sdf;
}
/**
* 计算两个时间差
*/
public static long getDatePoor(Date endDate, Date nowDate) {
long nd = 1000 * 24 * 60 * 60;
// 获得两个时间的毫秒时间差异
long diff = endDate.getTime() - nowDate.getTime();
// 计算差多少天
long day = diff / nd;
return day;
}
/**
* 计算天数
*/
public static long calculationLianAi(String date) {
SimpleDateFormat simpleDateFormat = get();
Date startDate = new Date();
try {
startDate = simpleDateFormat.parse(date);
} catch (ParseException e) {
e.printStackTrace();
}
return getDatePoor(new Date(), startDate);
}
/**
* 计算生日
*/
public static long calculationBirthday(String birthday) {
SimpleDateFormat simpleDateFormat = get();
Calendar cToday = Calendar.getInstance();
Calendar cBirth = Calendar.getInstance();
Date now = new Date();
try {
now = simpleDateFormat.parse(birthday);
} catch (ParseException e) {
e.printStackTrace();
}
cBirth.setTime(now);
cBirth.set(Calendar.YEAR, cToday.get(Calendar.YEAR));
int days;
if (cBirth.get(Calendar.DAY_OF_YEAR) < cToday.get(Calendar.DAY_OF_YEAR)) {
days = cToday.getActualMaximum(Calendar.DAY_OF_YEAR) - cToday.get(Calendar.DAY_OF_YEAR);
days += cBirth.get(Calendar.DAY_OF_YEAR);
} else {
days = cBirth.get(Calendar.DAY_OF_YEAR) - cToday.get(Calendar.DAY_OF_YEAR);
}
return days;
}
}
@Component
public class WeatherUtil {
public static Weather getWeather() {
RestTemplate restTemplate = new RestTemplate();
Map<String, String> map = new HashMap<>();
map.put("district_id", PushConfigure.getDistrictId());
map.put("ak", PushConfigure.getAk());
String res = restTemplate.getForObject("https://api.map.baidu.com/weather/v1/?district_id={district_id}&data_type=all&ak={ak}", String.class, map);
JSONObject json = JSONObject.parseObject(res);
if (json == null) {
//接口地址有误或者接口没调通
return null;
}
JSONArray forecasts = json.getJSONObject("result").getJSONArray("forecasts");
List<Weather> weathers = forecasts.toJavaList(Weather.class);
Weather weather = weathers.get(0);
JSONObject now = json.getJSONObject("result").getJSONObject("now");
JSONObject location = json.getJSONObject("result").getJSONObject("location");
weather.setTextNow(now.getString("text"));
weather.setTemp(now.getString("temp"));
weather.setCity(location.getString("city"));
return weather;
}
}
public class RainbowUtil {
public static String getRainbow() {
String httpUrl = "http://api.tianapi.com/caihongpi/index?key=" + PushConfigure.getRainbowKey();
BufferedReader reader = null;
String result = null;
StringBuilder stringBuilder = new StringBuilder();
try {
URL url = URL.of(URI.create(httpUrl), null);
// JDK 21 过期
// URL url = new URL(httpUrl);
HttpURLConnection connection = (HttpURLConnection) url
.openConnection();
connection.setRequestMethod("GET");
InputStream is = connection.getInputStream();
reader = new BufferedReader(new InputStreamReader(is, "UTF-8"));
String strRead = null;
while ((strRead = reader.readLine()) != null) {
stringBuilder.append(strRead);
stringBuilder.append("\r\n");
}
reader.close();
result = stringBuilder.toString();
} catch (Exception e) {
e.printStackTrace();
}
JSONObject jsonObject = JSONObject.parseObject(result);
if (jsonObject == null) {
return "";
}
JSONArray newslist = jsonObject.getJSONArray("newslist");
return newslist.getJSONObject(0).getString("content");
}
}
public class PushUtil {
/**
* 消息推送主要业务代码
*/
public static String push() {
//1,配置 // weixin-java-mp 4.5.0 版本使用该Config
WxMpDefaultConfigImpl wxStorage = new WxMpDefaultConfigImpl();
// weixin-java-mp 3.3.0 版本使用该Config
// WxMpInMemoryConfigStorage wxStorage = new WxMpInMemoryConfigStorage();
wxStorage.setAppId(PushConfigure.getAppId());
wxStorage.setSecret(PushConfigure.getSecret());
WxMpService wxMpService = new WxMpServiceImpl();
wxMpService.setWxMpConfigStorage(wxStorage);
// 推送消息
WxMpTemplateMessage templateMessage = WxMpTemplateMessage.builder()
.toUser(PushConfigure.getUserId())
.templateId(PushConfigure.getTemplateId())
.build();
// 配置你的信息
long loveDays = MemoryDayUtil.calculationLianAi(PushConfigure.getLoveDate());
long birthdays = MemoryDayUtil.calculationBirthday(PushConfigure.getBirthday());
Weather weather = WeatherUtil.getWeather();
if (weather == null) {
templateMessage.addData(new WxMpTemplateData("weather", "***", "#00FFFF"));
} else {
templateMessage.addData(new WxMpTemplateData("date", weather.getDate() + " " + weather.getWeek(), "#00BFFF"));
templateMessage.addData(new WxMpTemplateData("weather", weather.getTextNow(), "#00FFFF"));
templateMessage.addData(new WxMpTemplateData("low", weather.getLow() + "", "#173177"));
templateMessage.addData(new WxMpTemplateData("temp", weather.getTemp() + "", "#EE212D"));
templateMessage.addData(new WxMpTemplateData("high", weather.getHigh() + "", "#FF6347"));
templateMessage.addData(new WxMpTemplateData("city", weather.getCity() + "", "#173177"));
}
templateMessage.addData(new WxMpTemplateData("loveDays", loveDays + "", "#FF1493"));
templateMessage.addData(new WxMpTemplateData("birthdays", birthdays + "", "#FFA500"));
String remark = "亲爱的乖乖宝贝,早上好!记得要吃早餐哦,今天也要开心哦 =^_^= ";
if (loveDays % Constant.YEARDAYS == 0) {
remark = "\n今天是恋爱" + (loveDays / 365) + "周年纪念日!";
}
if (birthdays == 0) {
remark = "\n今天是生日,生日快乐呀!";
}
if (loveDays % Constant.YEARDAYS == 0 && birthdays == 0) {
remark = "\n今天是生日,也是恋爱" + (loveDays / 365) + "周年纪念日!";
}
templateMessage.addData(new WxMpTemplateData("remark", remark, "#FF1493"));
templateMessage.addData(new WxMpTemplateData("rainbow", RainbowUtil.getRainbow(), "#FF69B4"));
System.out.println(templateMessage.toJson());
try {
wxMpService.getTemplateMsgService().sendTemplateMsg(templateMessage);
} catch (Exception e) {
System.out.println("推送失败:" + e.getMessage());
return "推送失败:" + e.getMessage();
}
return "推送成功!";
}
}
@EnableScheduling
@Configuration
public class Task {
// 定时 早8点推送 0秒 0分 8时
//@Scheduled(cron = "0 0 8 * * ?")
// 定时 一个小时推送一次
@Scheduled(cron = "0 0 0/1 * * ?")
public void goodMorning() {
PushUtil.push();
}
}
@RestController
public class TestController {
@GetMapping("test")
public String test() {
return PushUtil.push();
}
}
这里自定义引入一下
@Configuration
public class WebDataBindConfig {
@Bean
ConfigurableWebBindingInitializer configurableWebBindingInitializer(){
return new ConfigurableWebBindingInitializer();
}
}
public class Constant {
public static final int YEARDAYS = 365;
}
#测试号信息中的appID
wechat.appId=
#测试号信息中的appsecret
wechat.secret=
#用户列表中的微信号id
wechat.userId=
#模板消息接口中模板ID
wechat.templateId=
#你查询天气城市的邮编
wechat.district_id=430300
#百度地图开放平台的AK
wechat.ak=
#在一起的时间
wechat.loveDate=2022-01-01
#生日
wechat.birthday=2003-12-05
#彩虹屁平台apiKey
wechat.rainbowKey=
参考文章 申请对应接口平台的权限
这里贴一下各个申请平台的地址:
微信公众平台: 微信公众平台
模板内容:
注意格式
:{{date.DATA}}
:{{remark.DATA}}
:{{city.DATA}} 的天气: {{weather.DATA}}
:最低气温: {{low.DATA }} 度
:最高气温: {{high.DATA }} 度
:今天是我们恋爱的第 {{loveDays.DATA}} 天
:距离宝宝的生日还有 {{birthdays.DATA}} 天
:{{rainbow.DATA}}
百度地图开放平台: 百度地图开放平台
天气服务接口:天气服务接口
创建应用:创建应用
注意:在 src/main/resources/application.properties 里面填写"应用AK"和"城市ID/行政代码",如上海浦东新区行政代码是310115
彩虹屁平台:彩虹屁平台
搜索一下彩虹屁申请对应的apiKey即可。
1 spring版本问题
需要自定义引入 ConfigurableWebBindingInitializer
见上面的问题
2 展示效果无彩色字体
微信公众号平台 2023年3月30日去除尾部/备注内容、自定义颜色、表情符号
关于规范公众号模板消息的再次公告
3 模板注意空格
可参考:模板消息