2 Commits

Author SHA1 Message Date
bamanker
12bbeaa39f add LICENSE.
Signed-off-by: bamanker <27054792@qq.com>
2023-11-13 15:18:59 +00:00
bamanker
f297aa823a update README.md.
Signed-off-by: bamanker <27054792@qq.com>
2023-11-13 15:17:09 +00:00
34 changed files with 745 additions and 1966 deletions

View File

@@ -1,3 +0,0 @@
*
!target/dailylove*
!Dockerfile

View File

@@ -1,170 +0,0 @@
name: Build Push and Deploy Image
on:
push:
#tag 触发
tags:
- 'v*'
# 分支触发
# branches:
# - main
workflow_dispatch: #手动构建h
#设置全局环境变量
env:
PATH: /opt/node/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
REGISTRY: ${{ secrets.DOCKER_REGISTRY }}
IMAGE_NAMESPACE: bamanker # todo 可以通过读取pom文件获取下面这些属性值
IMAGE_NAME: dailylove
APP_NAME: daily-love
# 构建 Job
jobs:
build:
runs-on: ubuntu-node22 # 如果host构建:linux_amd64
# container:
# image: swr.cn-north-4.myhuaweicloud.com/ddn-k8s/ghcr.io/catthehacker/ubuntu:act-latest
steps:
- name: Print system info 1
run: echo " The job was automatically triggered by a ${{ gitea.event_name }} event."
- name: Print system info 2
run: echo " This job is now running on a ${{ runner.os }} server hosted by Gitea!"
- name: Print system info 3
run: echo " The name of your branch is ${{ gitea.ref }} and your repository is ${{ gitea.repository }}."
- name: Print env
run: env && blkid
- name: Install dependencies
run: |
apt-get update &&
apt-get install -y gettext &&
apt-get install -y maven &&
apt-get install -y sudo &&
apt-get install -y iptables
- name: Set up Docker
uses: http://139.9.216.111:3000/bamanker/setup-docker-action@v4.6.0
with:
# 版本大于28会有兼容性问题
version: type=archive,channel=stable,version=v27.4.0
daemon-config: |
{
"registry-mirrors":["https://docker.1ms.run"],
"dns": ["8.8.8.8", "114.114.114.114"]
}
- name: Generate maven config
uses: http://139.9.216.111:3000/bamanker/maven-settings-action@v3.1.0
with:
mirrors: '[{"id": "alimaven", "name": "aliyun maven", "mirrorOf": "central", "url": "http://maven.aliyun.com/nexus/content/groups/public/"}]'
# - uses: http://localhost:3000/bamanker/setup-node@v6
# with:
# node-version: 24
# cache: 'npm'
# - run: node -v
# 下载仓库源码依赖node环境因此构建服务器本地需要下载安装node并设置环境变量
- name: Checkout repository code
#使用自定义仓库action
uses: http://139.9.216.111:3000/bamanker/checkout@v4
# 获取 TAG 并设置为环境变量
- name: Get version
id: get_version
# e.g. refs/tags/v1.0.0
run: |
echo "APP_TAG=${GITHUB_REF/refs\/tags\/v}" >> $GITHUB_ENV
# 检查 TAG 并传参
- name: Set envVar
id: set_envar
run: |
echo "The app version is $APP_TAG" && echo "tag=$APP_TAG" >> $GITHUB_OUTPUT &&
echo "now workspace: ${{ github.workspace }}"
# 为其他配置文件注入环境变量
- name: Inject envVar
run: |
envsubst < ./deployment-temp.yml > ./deployment.yml &&
cat ./deployment.yml
# 安装java环境
- name: Set up Java
uses: http://139.9.216.111:3000/bamanker/setup-graalvm@v1
with:
distribution: 'graalvm'
java-version: '25.0.1'
cache: 'maven'
# maven 构建
- name: Build with Maven
run: mvn clean native:compile -DskipTests -Pnative
# 登录镜像仓库,方便后续上传镜像
- name: Login to Docker Registry
uses: http://139.9.216.111:3000/bamanker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_PASSWORD }}
# # 获取时间戳
# - name: Get datetime
# id: datetime
# run: |
# echo "datetime=$(date '+%Y-%m-%d-%H-%M-%S')" >> $GITHUB_OUTPUT
# 构建并上传镜像
- name: Build and push Docker image
# uses: http://139.9.216.111:3000/bamanker/build-push-action@v4
# 获取上一步截取到的版本号,既 1.0.0
#只能这样接收
env:
TAG: ${{ steps.set_envar.outputs.tag }}
run: |
ls &&
docker build --file Dockerfile --tag ${{ env.REGISTRY }}/${{ env.IMAGE_NAMESPACE }}/${{ env.IMAGE_NAME }}:${{ env.TAG }} . &&
docker push ${{ env.REGISTRY }}/${{ env.IMAGE_NAMESPACE }}/${{ env.IMAGE_NAME }}:${{ env.TAG }}
# uses: http://139.9.216.111:3000/bamanker/docker-build-push@v5
# with:
# context: .
## platforms: linux/amd64
# file: Dockerfile
# push: true
# tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAMESPACE }}/${{ env.IMAGE_NAME }}:${{ env.TAG }}
#发布到 k8s
#安装 kubectl
- name: Setup kubectl
run: |
curl -LO "https://dl.k8s.io/release/v1.33.0/bin/linux/amd64/kubectl" &&
chmod +x kubectl &&
mv kubectl /usr/local/bin/
- name: Configure kubeconfig
# 假设您的 KUBE_CONFIG 秘密是 Base64 编码的 kubeconfig 文件内容
run: |
# 1. 创建 ~/.kube 目录
mkdir -p $HOME/.kube
# 2. 将 Base64 编码的 KUBE_CONFIG 秘密解码并写入默认配置文件
echo "${{ secrets.KUBE_CONFIG }}" | base64 -d > $HOME/.kube/config
# 3. 确保 kubectl 知道配置文件的位置 (可选, 但安全)
echo "KUBECONFIG=$HOME/.kube/config" >> $GITHUB_ENV
- name: Deploy with kubectl
run: |
kubectl apply -f ./deployment.yml
- name: k8s Check Pods Health
run: |
kubectl get pod -n default -l app=${{ env.APP_NAME }}
- name: k8s Update Deployment
run: |
kubectl rollout restart deployment ${{ env.APP_NAME }}

3
.gitignore vendored
View File

@@ -1,6 +1,6 @@
HELP.md
target/
.mvn/wrapper/maven-wrapper.jar
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/
@@ -31,4 +31,3 @@ build/
### VS Code ###
.vscode/
/mvn.log

11
.idea/.gitignore generated vendored
View File

@@ -1,11 +0,0 @@
# 默认忽略的文件
/shelf/
/workspace.xml
# 已忽略包含查询文件的默认文件夹
/queries/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml
# 基于编辑器的 HTTP 客户端请求
/httpRequests/
/.idea/

View File

@@ -1,5 +0,0 @@
FROM swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/ubuntu:jammy
LABEL maintainer="bamanker"
COPY target/dailylove /root/dailylove/
EXPOSE 13145
CMD /root/dailylove/dailylove -XX:StartFlightRecording='filename=recording.jfr,dumponexit=true,duration=10s'

12
LICENSE Normal file
View File

@@ -0,0 +1,12 @@
Copyright (c) 2023 bamanker
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.

230
README.md
View File

@@ -1,194 +1,36 @@
# dailyLove
## 公众号每日问候推送系统
一个基于 Spring Boot 4 和响应式编程的微信公众号每日问候推送系统,可定时推送天气、节日、纪念日等个性化信息。
## 功能特性
- **定时推送**每日早上7:30推送早安问候晚上22:00推送晚安问候
- **天气信息**:实时获取并推送当地天气情况
- **纪念日提醒**:自动计算恋爱纪念日、结婚纪念日及生日倒计时
- **节日祝福**:支持农历节日和节气提醒
- **个性化内容**:彩虹话、每日一言、贴心小提示等
- **响应式架构**:使用 WebFlux 和 WebClient 实现高性能异步处理
- **配置灵活**:支持外部配置和环境变量
## 技术栈
- **后端框架**Spring Boot 4.x
- **响应式编程**Spring WebFlux + WebClient
- **JSON处理**Jackson 3
- **工具库**Hutool
- **构建工具**Maven
- **JDK版本**JDK 25
- **原生镜像**GraalVM Native Image
## 快速开始
### 环境要求
- JDK 25+
- Maven 3.6+
- 微信公众平台账号
- 天行数据API密钥
### 配置说明
`application.yml` 中配置以下参数:
```yaml
# 微信相关配置
wechat:
app-id: "your-app-id" # 微信公众号AppID
app-secret: "your-app-secret" # 微信公众号AppSecret
open-id: "user-open-id" # 接收推送的用户OpenID
template-id-morning: "template-id-for-morning" # 早安模板消息ID
template-id-night: "template-id-for-night" # 晚安模板消息ID
# 天行数据API配置
daily-love:
data:
tianxin-key: "your-tianxin-api-key" # 天行数据API密钥
city-id: "101270106" # 城市ID
girl-birthday: "1995-06-28" # 女方生日
boy-birthday: "1995-03-30" # 男方生日
cat-birthday: "2022-10-23" # 宠物生日
love-day: "2022-07-16" # 恋爱纪念日
wedding-day: "2025-10-08" # 结婚纪念日
```
### 启动应用
```bash
# 编译项目
mvn clean package
# 运行应用
java -jar target/dailylove.jar
# 或使用Maven运行
mvn spring-boot:run
```
## 项目结构
```
src/
├── main/
│ ├── java/com/bamanker/dailylove/
│ │ ├── config/ # 配置类
│ │ ├── controller/ # 控制器
│ │ ├── domain/ # 数据模型
│ │ ├── service/ # 业务服务
│ │ ├── utils/ # 工具类
│ │ └── DailyLoveApplication.java
│ └── resources/
│ └── application.yml # 应用配置
└── test/
```
## 核心功能模块
### 1. 推送控制器
- [PushDailyController](file:///D:/myWork/dailyLove/src/main/java/com/bamanker/dailylove/controller/PushDailyController.java):处理早安/晚安推送逻辑
- 支持 `/pushMorning``/pushNight` 接口手动触发推送
### 2. 定时任务
- [PushTask](file:///D:/myWork/dailyLove/src/main/java/com/bamanker/dailylove/config/PushTask.java):配置定时推送任务
- Cron表达式`0 30 7 * * ?` (早上7:30) 和 `0 0 22 * * ?` (晚上22:00)
### 3. 外部服务调用
- 使用 WebClient 调用微信API获取访问令牌
- 调用天行数据API获取天气、彩虹话、每日一言等信息
## 配置项说明
| 配置项 | 描述 | 示例 |
| --------------------------- | -------------------- | ----------- |
| wechat.app-id | 微信公众号AppID | wx123456789 |
| wechat.app-secret | 微信公众号AppSecret | abc123... |
| wechat.open-id | 接收消息的用户OpenID | oABC123... |
| daily-love.data.tianxin-key | 天行数据API密钥 | 123abc... |
| daily-love.data.city-id | 城市ID | 101270106 |
## 自定义推送内容
系统会根据以下情况进行智能提醒:
- **恋爱纪念日**:显示恋爱天数及特殊纪念日提醒
- **生日提醒**:推送生日倒计时
- **节日祝福**:农历节日、节气等
- **天气预报**:当日/次日天气情况
- **个性化内容**:彩虹话、每日一言等
## 部署方式
### Docker部署
```bash
# 构建Docker镜像
docker build -t dailylove .
# 运行容器
docker run -d -p 13145:13145 --name dailylove dailylove
```
### 原生镜像部署
项目支持GraalVM原生镜像构建启动速度更快
```bash
# 构建原生镜像
./mvnw native:compile -Pnative
# 运行原生镜像
./target/dailylove
```
## 更新日志
### **v3.1.1-native**
- 优化了响应式编程实现,避免阻塞操作
· 移除了 PushDailyController 中的 .block() 阻塞操作
· 重构了异步数据处理逻辑,使用 Mono.zip 并发获取多个数据源
· 改善了错误处理机制
- 重构了配置管理,使用@ConfigurationProperties替代静态字段
· 创建了 DailyLoveProperties 类使用 @ConfigurationProperties 注解
· 更新了配置文件结构,使用更清晰的层次结构
· 添加了环境变量支持,提高了配置的灵活性
- 修复了定时任务失效问题
· 启用了 PushTask 定时任务类,使用 @Component 注解
· 添加了日志记录以便跟踪任务执行
- 改进了错误处理,增加全局异常处理器
· 创建了专门的 PushException 异常类
· 更新了全局异常处理器 GlobalExceptionHandler
· 在关键位置添加了错误映射和处理
- 增强了配置文件,支持环境变量
· 更新了 application.yml 文件,采用新的配置结构
· 添加了日志级别配置
· 为配置项提供了默认值和环境变量支持
### **v2.4.0-native**
- 升级到Spring Boot 4
- 使用WebClient替代OpenFeign
- 支持原生镜像构建
## 贡献指南
1. Fork 本仓库
2. 创建功能分支 (`git checkout -b feature/AmazingFeature`)
3. 提交更改 (`git commit -m 'Add some AmazingFeature'`)
4. 推送到分支 (`git push origin feature/AmazingFeature`)
5. 开启 Pull Request
## 许可证
此项目采用 MIT 许可证。
# dailyLove
#### 介绍
#### 软件架构
软件架构说明
#### 安装教程
1. xxxx
2. xxxx
3. xxxx
#### 使用说明
1. xxxx
2. xxxx
3. xxxx
#### 参与贡献
1. Fork 本仓库
2. 新建 Feat_xxx 分支
3. 提交代码
4. 新建 Pull Request
#### 特技
1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md
2. Gitee 官方博客 [blog.gitee.com](https://blog.gitee.com)
3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解 Gitee 上的优秀开源项目
4. [GVP](https://gitee.com/gvp) 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目
5. Gitee 官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help)
6. Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)

View File

@@ -1,101 +0,0 @@
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: $APP_NAME # 标签 用于选择器
version: $APP_TAG
name: $APP_NAME # Deployment名称
namespace: default # 一定要写名称空间
spec:
progressDeadlineSeconds: 600
replicas: 1 # 副本数 1个 pod
revisionHistoryLimit: 2
selector:
matchLabels:
app: $APP_NAME # 选择器 匹配 pod 标签
strategy:
rollingUpdate:
maxSurge: 50%
maxUnavailable: 50%
type: RollingUpdate
template:
metadata:
labels:
app: $APP_NAME # pod 标签
version: $APP_TAG
spec:
imagePullSecrets:
- name: dockerhub-id #提前在项目下配置访问私有镜像仓库的账号密码
containers:
- name: $APP_NAME # 容器名称
image: $REGISTRY/$IMAGE_NAMESPACE/$IMAGE_NAME:$APP_TAG # 镜像地址
imagePullPolicy: Always
# 存活探针配置
livenessProbe: # 存活探针:失败意味着应用彻底挂了,需要重启来恢复
httpGet:
path: /actuator/health/liveness # 探针路径
port: 13145 # 探针端口
scheme: HTTP # 协议
initialDelaySeconds: 20 # 容器启动后延迟 xx秒开始检查
periodSeconds: 10 # 每隔 15秒检查一次
timeoutSeconds: 5 # 10秒未返回结果则超时
# successThreshold: 1 # 成功 1 次就认定为健康
failureThreshold: 3 # 探测失败后的重试次数,当达到这个次数后就判定结果为失败,重启容器
#就绪探针配置
readinessProbe:
httpGet:
path: /actuator/health/readiness # 探针路径
port: 13145 # 探针端口
scheme: HTTP # 协议
initialDelaySeconds: 10 # 容器启动后等 30 秒再开始检查
periodSeconds: 5 # 每 5 秒检查一次,比存活探针频繁
timeoutSeconds: 5 # 超时时间 3 秒
# successThreshold: 1 # 成功 1 次就认为就绪
failureThreshold: 2 # 失败 3 次才认为未就绪,会从负载均衡摘掉
# 启动探针配置(可选,启动慢的应用必须配)
# startupProbe:
# httpGet:
# path: /actuator/health/liveness # 用存活探针的路径
# port: 13145
# scheme: HTTP
# initialDelaySeconds: 0 # 立即开始检查
# periodSeconds: 5 # 每 5 秒检查一次
# timeoutSeconds: 3 # 超时时间 3 秒
# successThreshold: 1 # 成功 1 次就认为启动完成
# failureThreshold: 30 # 失败 30 次150 秒)才认为启动失败
# 生命周期钩子,优雅关闭
lifecycle:
preStop:
sleep:
seconds: 10 #容器停止前先等 10 秒,让流量切走
ports:
- containerPort: 13145 # 应用端口
protocol: TCP
# 资源限制
resources:
limits:
cpu: 99m # 最多 0.1核 CPU
memory: 65Mi # 最多 65m 内存
# 环境变量配置
env:
- name: TZ
value: "Asia/Shanghai"
---
apiVersion: v1
kind: Service
metadata:
labels:
app: $APP_NAME
name: $APP_NAME
namespace: default
spec:
type: NodePort
externalTrafficPolicy: Local
ports:
- name: http
protocol: TCP
port: 13145
nodePort: 30045
selector:
app: $APP_NAME

182
pom.xml
View File

@@ -5,37 +5,22 @@
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>4.0.1</version>
<version>2.4.3</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<url/>
<licenses>
<license/>
</licenses>
<developers>
<developer/>
</developers>
<scm>
<connection/>
<developerConnection/>
<tag/>
<url/>
</scm>
<groupId>com.bamanker</groupId>
<artifactId>dailylove</artifactId>
<version>v3.1.4-native</version>
<name>dailylove</name>
<description>dailylove-forK8S</description>
<artifactId>dailyLove</artifactId>
<version>0.1.3</version>
<name>dailyLove</name>
<description>dailyLove</description>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>25</java.version>
<maven.compiler.source>25</maven.compiler.source>
<maven.compiler.target>25</maven.compiler.target>
<spring-boot.version>4.0.1</spring-boot.version>
<spring-cloud.version>2023.0.0</spring-cloud.version>
<hutool.version>5.8.25</hutool.version>
<docker.private.repository>registry.cn-chengdu.aliyuncs.com/bamanker</docker.private.repository>
<java.version>1.8</java.version>
<fastjson.version>2.0.21</fastjson.version>
<openfeign.version>3.1.5</openfeign.version>
<nacos.version>2021.1</nacos.version>
<hutool.version>5.8.10</hutool.version>
</properties>
<dependencies>
<dependency>
@@ -43,141 +28,62 @@
<artifactId>hutool-core</artifactId>
<version>${hutool.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
<version>3.1.5</version>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<version>${nacos.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
<version>${nacos.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<version>${openfeign.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2</artifactId>
<version>${fastjson.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- 如果需要显式指定 Jackson 3 -->
<dependency>
<groupId>tools.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring Boot Configuration Processor -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
<!-- Spring Boot Actuator提供健康检查端点 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<finalName>dailylove</finalName>
<!--指定filtering=true.maven的占位符解析表达式就可以用于它里面的文件-->
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.graalvm.buildtools</groupId>
<artifactId>native-maven-plugin</artifactId>
<!--为本机映像程序添加配置,生成的配置文件位于
META-INF/native-image/groupID/artifactID/native-image.properties
也可以手动配置-->
<configuration>
<mainClass>com.bamanker.dailylove.DailyLoveApplication</mainClass>
<buildArgs>
<!--开启dashboard-->
<!-- <arg>-H:DashboardDump=dailylove -H:+DashboardAll</arg>-->
<buildArg>-H:+ReportExceptionStackTraces</buildArg>
<!--生成诊断报告-->
<buildArg>-H:+PrintAnalysisCallTree</buildArg>
<!--开启监控代理-->
<buildArg>--enable-monitoring=jfr,heapdump,jvmstat</buildArg>
<!-- <arg>&#45;&#45;pgo</arg>-->
<!---Ob: 快速构建模式,编译快但性能差点,适合开发调试-->
<buildArg>-Ob</buildArg>
<!-- <buildArg>&#45;&#45;gc=G1</buildArg>-->
<!-- <arg>-march=native</arg>-->
<!-- <arg>-H:+BuildReport</arg>-->
</buildArgs>
<!--启动详细输出-->
<verbose>true</verbose>
<!--配置jvm参数-->
<!-- <jvmArgs>
</jvmArgs>-->
<!--<agent>
<enabled>true</enabled>
<options>
<option>experimental-class-loader-support</option>
</options>
</agent>-->
</configuration>
</plugin>
<plugin>
<!--支持yaml读取pom的参数-->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<configuration>
<encoding>UTF-8</encoding>
<delimiters>
<delimiter>@</delimiter>
</delimiters>
<useDefaultDelimiters>false</useDefaultDelimiters>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<release>25</release>
<annotationProcessors>
<annotationProcessor>lombok.launch.AnnotationProcessorHider$AnnotationProcessor
</annotationProcessor>
</annotationProcessors>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@@ -1,35 +1,18 @@
package com.bamanker.dailylove;
import com.bamanker.dailylove.config.DailyLoveConfigure;
import com.bamanker.dailylove.config.DailyLoveProperties;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.scheduling.annotation.EnableScheduling;
/**
* @descriptions 启动类
* @author bamanker
* @date 2026/1/13 23:42
*/
@SpringBootApplication
@EnableFeignClients
//开启定时任务
@EnableScheduling
public class DailyLoveApplication implements ApplicationListener<ApplicationReadyEvent> {
public class DailyLoveApplication {
public static void main(String[] args) {
SpringApplication.run(DailyLoveApplication.class, args);
}
/**
* 应用启动完成后执行
*/
@Override
public void onApplicationEvent(ApplicationReadyEvent event) {
ConfigurableApplicationContext applicationContext = event.getApplicationContext();
DailyLoveProperties properties = applicationContext.getBean(DailyLoveProperties.class);
DailyLoveConfigure.initialize(properties);
}
}

View File

@@ -1,141 +0,0 @@
package com.bamanker.dailylove.config;
import cn.hutool.core.util.ClassUtil;
import jakarta.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
/**
* 反射将所有项目类扫描加入到服务, 大力出奇迹的操作,感觉不太合适,不过先让服务跑起来
*
* @author bamanker
*/
@Component
public class ClassReflectConfig {
static boolean begin = true;
@Value("${scanclass}")
private Boolean scanclass;
private final ThreadPoolTaskExecutor executorService;
public ClassReflectConfig(ThreadPoolTaskExecutor executorService) {
this.executorService = executorService;
}
@PostConstruct
public void init() {
if (scanclass) {
System.err.println("配置文件下 scanclass 开启了生成反射类");
} else {
System.err.println("配置文件下 scanclass 关闭了生成反射类");
}
synchronized (ClassReflectConfig.class) {
if (begin && scanclass) {
begin = false;
executorService.submit(() -> {
// {
// // 先抓取上一次的文件,生成
// try {
// BufferedReader utf8Reader = ResourceUtil
// .getUtf8Reader("classpath:/META-INF/native-image/reflect-config.json");
// String res = utf8Reader.lines().collect(Collectors.joining());
// List object = ProJsonUtil.toObject(res, List.class);
// for (Object object2 : object) {
// try {
// Map object22 = (Map) object2;
// handlerClass(Class.forName(ProMapUtil.getStr(object22, "name")));
// } catch (Exception e) {
// }
// }
// } catch (Exception e) {
// log.error("生成文件异常", e);
// }
// }
{
// 扫描系统第二级开始的包
String packageName = ClassReflectConfig.class.getPackageName();
String proPackageName = packageName.substring(0,
packageName.indexOf(".", packageName.indexOf(".") + 1));
// 可以在这个地方,添加除了服务以外其他的包,将会加入反射,以供graalvm生成配置
List<String> asList = Arrays.asList(proPackageName);
for (String spn : asList) {
try {
Set<Class<?>> doScan = ClassUtil.scanPackage(spn);
for (Class clazz : doScan) {
handlerClass(clazz);
}
} catch (Throwable e) {
e.printStackTrace();
}
}
}
// handlerClass(RedisMessageListenerContainer.class);
});
}
}
}
private void handlerClass(Class clazz) {
if (clazz.equals(ClassReflectConfig.class)) {
// 跳过自己,避免形成循环
return;
}
executorService.submit(() -> {
try {
System.err.println("反射注入:" + clazz.getName());
// 生成所有的构造器
Constructor[] declaredConstructors = clazz.getDeclaredConstructors();
// 找到无参构造器然后实例化
Constructor declaredConstructor = clazz.getDeclaredConstructor();
declaredConstructor.setAccessible(true);
Object newInstance = declaredConstructor.newInstance();
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {
try {
// 实例化成功,那么调用一下
method.setAccessible(true);
// graalvm必须需要声明方法
method.invoke(newInstance);
} catch (Throwable e) {
}
}
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
try {
field.setAccessible(true);
field.getType();
String name = field.getName();
field.get(newInstance);
} catch (Throwable e) {
}
}
System.err.println("反射注入完成:" + clazz.getName());
} catch (Throwable e) {
}
});
}
}

View File

@@ -1,36 +1,14 @@
package com.bamanker.dailylove.config;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Component;
/**
* @descriptions 配置类适配器,用于兼容旧代码
* @author bamanker
* @date 2026/1/8 12:12
*/
@Component
@RequiredArgsConstructor
@RefreshScope
public class DailyLoveConfigure {
private final DailyLoveProperties properties;
// 微信相关配置
public static String App_ID;
public static String App_Secret;
public static String Open_ID;
public static String Template_ID_Morning;
public static String Template_ID_Night;
// 数据相关配置
public static String City_ID;
public static String TianXin_Key;
public static String Boy_Birthday;
public static String Girl_Birthday;
public static String Cat_Birthday;
public static String Love_Day;
public static String Wedding_Day;
// 颜色配置
// public static String Access_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={0}&secret={1}";
// public static String Send_URL = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token={0}";
public static String Color_quality;
public static String Color_morning;
public static String Color_chineseDate;
@@ -49,50 +27,184 @@ public class DailyLoveConfigure {
public static String Color_bbir;
public static String Color_cbir;
public static String Color_loveDay;
public static String Color_weddingDay;
public static String Color_remark;
public static String Color_Top;
// 初始化静态变量
public static void initialize(DailyLoveProperties properties) {
// 微信相关配置
App_ID = properties.getWechat().getAppId();
App_Secret = properties.getWechat().getAppSecret();
Open_ID = properties.getWechat().getOpenId();
Template_ID_Morning = properties.getWechat().getTemplateIdMorning();
Template_ID_Night = properties.getWechat().getTemplateIdNight();
// 数据相关配置
City_ID = properties.getData().getCityId();
TianXin_Key = properties.getData().getTianxinKey();
Boy_Birthday = properties.getData().getBoyBirthday();
Girl_Birthday = properties.getData().getGirlBirthday();
Cat_Birthday = properties.getData().getCatBirthday();
Love_Day = properties.getData().getLoveDay();
Wedding_Day = properties.getData().getWeddingDay();
// 颜色配置
DailyLoveProperties.Wechat.Colors colors = properties.getWechat().getColors();
Color_quality = colors.getQuality();
Color_morning = colors.getMorning();
Color_chineseDate = colors.getChineseDate();
Color_festival = colors.getFestival();
Color_night = colors.getNight();
Color_tomorrow = colors.getTomorrow();
Color_Now = colors.getNow();
Color_city = colors.getCity();
Color_weather = colors.getWeather();
Color_minTem = colors.getMinTem();
Color_maxTem = colors.getMaxTem();
Color_tips = colors.getTips();
Color_dailyCn = colors.getDailyCn();
Color_dailyEn = colors.getDailyEn();
Color_gbir = colors.getGbir();
Color_bbir = colors.getBbir();
Color_cbir = colors.getCbir();
Color_loveDay = colors.getLoveDay();
Color_weddingDay = colors.getWeddingDay();
Color_remark = colors.getRemark();
Color_Top = colors.getTop();
@Value("${wechat.color.tomorrow:null}")
public void setColor_tomorrow(String color_tomorrow) {
Color_tomorrow = color_tomorrow;
}
@Value("${wechat.color.quality:null}")
public void setColor_quality(String color_quality) {
Color_quality = color_quality;
}
@Value("${wechat.color.morning:null}")
public void setColor_morning(String color_morning) {
Color_morning = color_morning;
}
@Value("${wechat.color.chineseDate:null}")
public void setColor_chineseDate(String color_chineseDate) {
Color_chineseDate = color_chineseDate;
}
@Value("${wechat.color.festival:null}")
public void setColor_festival(String color_festival) {
Color_festival = color_festival;
}
@Value("${wechat.color.night:null}")
public void setColor_night(String color_night) {
Color_night = color_night;
}
@Value("${wechat.color.city:null}")
public void setColor_city(String color_city) {
Color_city = color_city;
}
@Value("${wechat.color.weather:null}")
public void setColor_weather(String color_weather) {
Color_weather = color_weather;
}
@Value("${wechat.color.minTem:null}")
public void setColor_minTem(String color_minTem) {
Color_minTem = color_minTem;
}
@Value("${wechat.color.maxTem:null}")
public void setColor_maxTem(String color_maxTem) {
Color_maxTem = color_maxTem;
}
@Value("${wechat.color.tips:null}")
public void setColor_tips(String color_tips) {
Color_tips = color_tips;
}
@Value("${wechat.color.dailyCn:null}")
public void setColor_dailyCn(String color_dailyCn) {
Color_dailyCn = color_dailyCn;
}
@Value("${wechat.color.dailyEn:null}")
public void setColor_dailyEn(String color_dailyEn) {
Color_dailyEn = color_dailyEn;
}
@Value("${wechat.color.gbir:null}")
public void setColor_gbir(String color_gbir) {
Color_gbir = color_gbir;
}
@Value("${wechat.color.bbir:null}")
public void setColor_bbir(String color_bbir) {
Color_bbir = color_bbir;
}
@Value("${wechat.color.cbir:null}")
public void setColor_cbir(String color_cbir) {
Color_cbir = color_cbir;
}
@Value("${wechat.color.loveDay:null}")
public void setColor_loveDay(String color_loveDay) {
Color_loveDay = color_loveDay;
}
@Value("${wechat.color.remark:null}")
public void setColor_remark(String color_remark) {
Color_remark = color_remark;
}
@Value("${wechat.color.now:null}")
public void setColor_Now(String color_Now) {
Color_Now = color_Now;
}
public static String App_ID;
@Value("${wechat.app-id}")
public void setAppID(String AppID) {
App_ID = AppID;
}
public static String App_Secret;
@Value("${wechat.app-secret}")
public void setAppSecret(String AppSecret) {
App_Secret = AppSecret;
}
public static String Open_ID;
@Value("${wechat.open-id}")
public void setOpenID(String OpenID) {
Open_ID = OpenID;
}
public static String Template_ID_Morning;
@Value("${wechat.template-id-morning}")
public void setTemplateIDMorning(String templateIDMorning) {
Template_ID_Morning = templateIDMorning;
}
public static String Template_ID_Night;
@Value("${wechat.template-id-night}")
public void setTemplateIDNight(String templateIDNight) {
Template_ID_Night = templateIDNight;
}
public static String City_ID;
@Value("${DL.city-id}")
public void setCity_ID(String city_ID) {
City_ID = city_ID;
}
public static String Color_Top = null;
@Value("${wechat.color.top}")
public void setColor_Top(String colorTop) {
Color_Top = colorTop;
}
public static String TianXin_Key;
@Value("${DL.tianxin-key}")
public void setTianXin_Key(String tianXin_Key) {
TianXin_Key = tianXin_Key;
}
public static String Boy_Birthday;
@Value("${DL.boy-birthday}")
public void setBoyBirthday(String BoyBirthday) {
Boy_Birthday = BoyBirthday;
}
public static String Girl_Birthday;
@Value("${DL.girl-birthday}")
public void setGirlBirthday(String GirlBirthday) {
Girl_Birthday = GirlBirthday;
}
public static String Cat_Birthday;
@Value("${DL.cat-birthday}")
public void setCatBirthday(String CatBirthday) {
Cat_Birthday = CatBirthday;
}
public static String Love_Day;
@Value("${DL.love-day}")
public void setLoveDay(String LoveDay) {
Love_Day = LoveDay;
}
}

View File

@@ -1,128 +0,0 @@
package com.bamanker.dailylove.config;
import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* @descriptions 配置类
* @author bamanker
* @date 2026/1/13 23:31
*/
@Setter
@Getter
@Component
@ConfigurationProperties(prefix = "daily-love")
public class DailyLoveProperties {
// Getters and Setters for DailyLoveProperties
private Wechat wechat = new Wechat();
private Data data = new Data();
public static class Wechat {
private String appId;
private String appSecret;
private String openId;
private String templateIdMorning;
private String templateIdNight;
private Colors colors = new Colors();
public static class Colors {
private String quality = "#000000";
private String morning = "#FF69B4";
private String chineseDate = "#FF69B4";
private String festival = "#FF69B4";
private String night = "#FF69B4";
private String tomorrow = "#000000";
private String now = "#000000";
private String city = "#000000";
private String weather = "#000000";
private String minTem = "#000000";
private String maxTem = "#000000";
private String tips = "#000000";
private String dailyCn = "#000000";
private String dailyEn = "#000000";
private String gbir = "#FF69B4";
private String bbir = "#FF69B4";
private String cbir = "#FF69B4";
private String loveDay = "#FF69B4";
private String weddingDay = "#FF69B4";
private String remark = "#FF69B4";
private String top = "#FF69B4";
// Getters and Setters for Colors
public String getQuality() { return quality; }
public void setQuality(String quality) { this.quality = quality; }
public String getMorning() { return morning; }
public void setMorning(String morning) { this.morning = morning; }
public String getChineseDate() { return chineseDate; }
public void setChineseDate(String chineseDate) { this.chineseDate = chineseDate; }
public String getFestival() { return festival; }
public void setFestival(String festival) { this.festival = festival; }
public String getNight() { return night; }
public void setNight(String night) { this.night = night; }
public String getTomorrow() { return tomorrow; }
public void setTomorrow(String tomorrow) { this.tomorrow = tomorrow; }
public String getNow() { return now; }
public void setNow(String now) { this.now = now; }
public String getCity() { return city; }
public void setCity(String city) { this.city = city; }
public String getWeather() { return weather; }
public void setWeather(String weather) { this.weather = weather; }
public String getMinTem() { return minTem; }
public void setMinTem(String minTem) { this.minTem = minTem; }
public String getMaxTem() { return maxTem; }
public void setMaxTem(String maxTem) { this.maxTem = maxTem; }
public String getTips() { return tips; }
public void setTips(String tips) { this.tips = tips; }
public String getDailyCn() { return dailyCn; }
public void setDailyCn(String dailyCn) { this.dailyCn = dailyCn; }
public String getDailyEn() { return dailyEn; }
public void setDailyEn(String dailyEn) { this.dailyEn = dailyEn; }
public String getGbir() { return gbir; }
public void setGbir(String gbir) { this.gbir = gbir; }
public String getBbir() { return bbir; }
public void setBbir(String bbir) { this.bbir = bbir; }
public String getCbir() { return cbir; }
public void setCbir(String cbir) { this.cbir = cbir; }
public String getLoveDay() { return loveDay; }
public void setLoveDay(String loveDay) { this.loveDay = loveDay; }
public String getWeddingDay() { return weddingDay; }
public void setWeddingDay(String weddingDay) { this.weddingDay = weddingDay; }
public String getRemark() { return remark; }
public void setRemark(String remark) { this.remark = remark; }
public String getTop() { return top; }
public void setTop(String top) { this.top = top; }
}
// Getters and Setters for Wechat
public String getAppId() { return appId; }
public void setAppId(String appId) { this.appId = appId; }
public String getAppSecret() { return appSecret; }
public void setAppSecret(String appSecret) { this.appSecret = appSecret; }
public String getOpenId() { return openId; }
public void setOpenId(String openId) { this.openId = openId; }
public String getTemplateIdMorning() { return templateIdMorning; }
public void setTemplateIdMorning(String templateIdMorning) { this.templateIdMorning = templateIdMorning; }
public String getTemplateIdNight() { return templateIdNight; }
public void setTemplateIdNight(String templateIdNight) { this.templateIdNight = templateIdNight; }
public Colors getColors() { return colors; }
public void setColors(Colors colors) { this.colors = colors; }
}
@Setter
@Getter
public static class Data {
// Getters and Setters for Data
private String cityId;
private String tianxinKey;
private String boyBirthday;
private String girlBirthday;
private String catBirthday;
private String loveDay;
private String weddingDay;
}
}

View File

@@ -0,0 +1,15 @@
package com.bamanker.dailylove.config;
import feign.Logger;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class FeignConfig
{
@Bean
Logger.Level feignLoggerLevel()
{
return Logger.Level.FULL;
}
}

View File

@@ -1,36 +1,24 @@
package com.bamanker.dailylove.config;
import com.bamanker.dailylove.controller.PushDailyController;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
/**
* @descriptions 定时任务类
* @author bamanker
* @date 2026/1/13 23:33
*/
@Component
@Slf4j
public class PushTask {
final
@Autowired
PushDailyController pushDailyController;
public PushTask(PushDailyController pushDailyController) {
this.pushDailyController = pushDailyController;
}
//每日 早上7.30,晚上22点 定时推送
@Scheduled(cron = "0 30 7 * * ?")
public void scheduledPushMorning(){
log.info("开始执行早安推送任务...");
pushDailyController.pushMorning();
}
@Scheduled(cron = "0 0 22 * * ?")
public void scheduledPushNight(){
log.info("开始执行晚安推送任务...");
pushDailyController.pushNight();
}
}

View File

@@ -1,58 +0,0 @@
package com.bamanker.dailylove.config;
import io.netty.handler.logging.LogLevel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.netty.http.client.HttpClient;
import reactor.netty.transport.logging.AdvancedByteBufFormat;
/**
* @author bamanker
* @descriptions webclent 配置类
* @date 2026/1/12 17:33
*/
@Configuration
@Slf4j
public class WebClientConfig {
HttpClient httpClient = HttpClient.create().wiretap("reactor.netty.http.client.HttpClient",
LogLevel.DEBUG,
AdvancedByteBufFormat.TEXTUAL);
/**
* 创建WebClient Bean
*/
@Bean
public WebClient wechatWebClient() {
return WebClient.builder()
.clientConnector(new ReactorClientHttpConnector(httpClient))
.filter((request, next) -> {
log.info("wechatRequest: {}", request.url());
return next.exchange(request);
})
// 基础URL
.baseUrl("https://api.weixin.qq.com/cgi-bin")
// 默认请求头
.defaultHeader("User-Agent", "WebFlux-Client")
.build();
}
@Bean
public WebClient dateRemoteClient() {
return WebClient.builder()
.clientConnector(new ReactorClientHttpConnector(httpClient))
.filter((request, next) -> {
log.info("tianxingRequest: {}", request.url());
return next.exchange(request);
})
.baseUrl("https://apis.tianapi.com")
.defaultHeader("User-Agent", "WebFlux-Client")
.build();
}
}

View File

@@ -2,288 +2,244 @@ package com.bamanker.dailylove.controller;
import cn.hutool.core.date.ChineseDate;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson2.JSONObject;
import com.bamanker.dailylove.config.DailyLoveConfigure;
import com.bamanker.dailylove.domain.DataItem;
import com.bamanker.dailylove.domain.ResultVo;
import com.bamanker.dailylove.domain.TianXinReqParam;
import com.bamanker.dailylove.domain.Weather;
import com.bamanker.dailylove.exception.PushException;
import com.bamanker.dailylove.service.DataRemoteService;
import com.bamanker.dailylove.service.WechatRequestService;
import com.bamanker.dailylove.domain.*;
import com.bamanker.dailylove.service.DataRemoteClient;
import com.bamanker.dailylove.service.WechatRequestClient;
import com.bamanker.dailylove.utils.DataUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aot.hint.annotation.RegisterReflectionForBinding;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;
import reactor.util.function.Tuple4;
import tools.jackson.databind.JsonNode;
import tools.jackson.databind.json.JsonMapper;
import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.util.Date;
import java.util.function.Function;
/**
* @author bamanker
* @descriptions 推送控制器
* @date 2026/1/8 12:04
*/
@RestController
@Slf4j
@RestController
public class PushDailyController {
final
JsonMapper mapper;
@Resource
DataRemoteClient dataRemoteClient;
final
DataRemoteService dataRemoteService;
final
WechatRequestService wechatRequestService;
public PushDailyController(JsonMapper mapper, DataRemoteService dataRemoteService, WechatRequestService wechatRequestService) {
this.mapper = mapper;
this.dataRemoteService = dataRemoteService;
this.wechatRequestService = wechatRequestService;
}
@Resource
WechatRequestClient wechatRequestClient;
/**
* 推送晚安
*
* @return
*/
@GetMapping("/pushNight")
@RegisterReflectionForBinding(Weather.class)
public Mono<String> pushNight() {
public String pushNight() {
ResultVo resultVo = ResultVo.initializeResultVo(DailyLoveConfigure.Open_ID,
DailyLoveConfigure.Template_ID_Night,
DailyLoveConfigure.Color_Top);
// 封装获取天气信息请求参数
TianXinReqParam param1 = new TianXinReqParam();
param1.setKey(DailyLoveConfigure.TianXin_Key);
param1.setCity(DailyLoveConfigure.City_ID);
param1.setType("7");
String weatherResp = dataRemoteClient.getWeather(param1);
JSONObject weatherJson = JSONObject.parseObject(weatherResp).getJSONArray("result").getJSONObject(0).getJSONArray("list").getJSONObject(1);
String city = JSONObject.parseObject(weatherResp).getJSONArray("result").getJSONObject(0).getString("area");
Weather weather = weatherJson.toJavaObject(Weather.class);
// 获取农历和节日信息
ChineseDate chineseDate = new ChineseDate(DateUtil.parseDate(LocalDate.now().toString()));
resultVo.setAttribute("tomorrow", new DataItem(weather.getDate() + " " + weather.getWeek(), DailyLoveConfigure.Color_tomorrow));
resultVo.setAttribute("city", new DataItem(city, DailyLoveConfigure.Color_city));
resultVo.setAttribute("weather", new DataItem(weather.getWeather(), DailyLoveConfigure.Color_weather));
resultVo.setAttribute("min_temperature", new DataItem(weather.getLowest(), DailyLoveConfigure.Color_minTem));
resultVo.setAttribute("max_temperature", new DataItem(weather.getHighest(), DailyLoveConfigure.Color_maxTem));
resultVo.setAttribute("quality", new DataItem(weather.getVis(), DailyLoveConfigure.Color_quality));
TianXinReqParam param2 = new TianXinReqParam();
param2.setKey(DailyLoveConfigure.TianXin_Key);
String tipsResp = dataRemoteClient.getTips(param2);
String tips = JSONObject.parseObject(tipsResp).getJSONArray("result").getJSONObject(0).getString("content");
resultVo.setAttribute("tips", new DataItem(tips, DailyLoveConfigure.Color_tips));
String nightResp = dataRemoteClient.getNight(param2);
String night = JSONObject.parseObject(nightResp).getJSONArray("result").getJSONObject(0).getString("content");
resultVo.setAttribute("night", new DataItem(night, DailyLoveConfigure.Color_night));
String rainbowResp = dataRemoteClient.getRainbow(param2);
String rainbow = JSONObject.parseObject(rainbowResp).getJSONArray("result").getJSONObject(0).getString("content");
resultVo.setAttribute("rainbow", new DataItem(rainbow, DailyLoveConfigure.Color_dailyCn));
// String englishResp = dataRemoteClient.getDailyEnglish(param2);
// String english = JSONObject.parseObject(englishResp).getJSONArray("result").getJSONObject(0).getString("en");
// resultVo.setAttribute("daily_english_en", new DataItem(english, DailyLoveConfigure.Color_dailyEn));
ChineseDate chineseDate = new ChineseDate(DateUtil.parseDate(weather.getDate()));
String festival = chineseDate.getFestivals();
String term = chineseDate.getTerm();
resultVo.setAttribute("lunar", new DataItem(chineseDate.toString(), DailyLoveConfigure.Color_chineseDate));
resultVo.setAttribute("festival", new DataItem(festival + " " + term, DailyLoveConfigure.Color_festival));
// 计算各种日期
int girlBirthdays = DataUtils.getBirthdays(DailyLoveConfigure.Girl_Birthday) - 1;
int boyBirthdays = DataUtils.getChineseBirthdays(DailyLoveConfigure.Boy_Birthday) - 1;
int catBirthdays = DataUtils.getBirthdays(DailyLoveConfigure.Cat_Birthday) - 1;
int loveDays = DataUtils.getDayDiff(DailyLoveConfigure.Love_Day) + 1;
int weddingDays = DataUtils.getDayDiff(DailyLoveConfigure.Wedding_Day) + 1;
log.info("gbir_days:{}, bbir_days:{}, cbir_days:{}, love_days:{}, wedding_days:{}",
girlBirthdays, boyBirthdays, catBirthdays, loveDays, weddingDays);
int girlBirthdays = DataUtils.getBirthdays(DailyLoveConfigure.Girl_Birthday);
log.debug("gbir_day:{}", girlBirthdays);
resultVo.setAttribute("gbir_day", new DataItem(girlBirthdays - 1 + "", DailyLoveConfigure.Color_gbir));
int boyBirthdays = DataUtils.getChineseBirthdays(DailyLoveConfigure.Boy_Birthday);
log.debug("bbir_day:{}", boyBirthdays);
resultVo.setAttribute("bbir_day", new DataItem(boyBirthdays - 1 + "", DailyLoveConfigure.Color_bbir));
int catBirthdays = DataUtils.getBirthdays(DailyLoveConfigure.Cat_Birthday);
log.debug("cbir_day:{}", catBirthdays);
resultVo.setAttribute("cbir_day", new DataItem(catBirthdays - 1 + "", DailyLoveConfigure.Color_cbir));
String words = "普通的一天";
// 设置提醒文字
String words;
if (DataUtils.getBirthdays(DailyLoveConfigure.Love_Day) == 1) {
words = "明天是恋爱周年纪念日!永远爱你~mua";
} else if ((DataUtils.getDayDiff(DailyLoveConfigure.Love_Day)) % 100 == 99) {
} else if ((DataUtils.getLoveDays(DailyLoveConfigure.Love_Day)) % 100 == 1) {
words = "明天是恋爱百日纪念日!提前庆祝哦~";
} else if (DataUtils.getBirthdays(DailyLoveConfigure.Wedding_Day) == 1) {
words = "明天是结婚周年纪念日!提前庆祝哦~";
} else if (girlBirthdays == 1) {
words = "明天是lili大宝贝的生日啦";
} else if (boyBirthdays == 1) {
words = "明天是菘菘的生日!别忘了哦~";
words = "明天是ss的生日!别忘了哦~";
} else if (catBirthdays == 1) {
words = "明天是小离谱的生日!别忘了小鱼干!";
} else {
words = "普通的一天";
}
// 同时获取多个数据源
Mono<String> weatherRespMono = dataRemoteService.getWeather(param1.getKey(), param1.getCity(), param1.getType());
Mono<String> tipsMono = dataRemoteService.getTips(param1.getKey(), param1.getCity(), param1.getType());
Mono<String> nightMono = dataRemoteService.getNight(param1.getKey(), param1.getCity(), param1.getType());
Mono<String> rainbowMono = dataRemoteService.getRainbow(param1.getKey(), param1.getCity(), param1.getType());
resultVo.setAttribute("words", new DataItem(words, DailyLoveConfigure.Color_remark));
// 组合所有异步操作
return Mono.zip(weatherRespMono, tipsMono, nightMono, rainbowMono)
.onErrorMap(throwable -> new PushException("获取晚安推送数据失败: " + throwable.getMessage(), throwable))
.flatMap(tuple -> {
String weatherResp = tuple.getT1();
String tipsResp = tuple.getT2();
String nightResp = tuple.getT3();
String rainbowResp = tuple.getT4();
int loveDays = DataUtils.getLoveDays(DailyLoveConfigure.Love_Day);
log.debug("love_day:{}", loveDays);
resultVo.setAttribute("love_day", new DataItem(loveDays + 1 + "", DailyLoveConfigure.Color_loveDay));
try {
// 解析天气数据
String city = mapper.readTree(weatherResp).get("result").get("area").asString();
var weatherData = mapper.readTree(weatherResp).get("result").get("list").get(1);
Weather weather = mapper.treeToValue(weatherData, Weather.class);
log.debug("resultVo:{}", resultVo);
WechatTokenParam wechatTokenParam = new WechatTokenParam();
wechatTokenParam.setAppid(DailyLoveConfigure.App_ID);
wechatTokenParam.setSecret(DailyLoveConfigure.App_Secret);
// 解析其他数据
String tips = mapper.readTree(tipsResp).get("result").get("content").asString();
String nightContent = mapper.readTree(nightResp).get("result").get("content").asString();
String rainbowContent = mapper.readTree(rainbowResp).get("result").get("content").asString();
String accessTokenResp = wechatRequestClient.getAccessToken(wechatTokenParam);
log.debug("accessTokenJson:{}", accessTokenResp);
String token = JSONObject.parseObject(accessTokenResp).getString("access_token");
String responseStr = wechatRequestClient.sendMsg(resultVo, token);
return responseStr;
// 创建结果对象
ResultVo resultVo = ResultVo.initializeResultVo(DailyLoveConfigure.Open_ID,
DailyLoveConfigure.Template_ID_Night,
DailyLoveConfigure.Color_Top);
// 设置各项数据
resultVo.setAttribute("city", new DataItem(city, DailyLoveConfigure.Color_city));
resultVo.setAttribute("tomorrow", new DataItem(weather.getDate() + " " + weather.getWeek(), DailyLoveConfigure.Color_tomorrow));
resultVo.setAttribute("weather", new DataItem(weather.getWeather(), DailyLoveConfigure.Color_weather));
resultVo.setAttribute("min_temperature", new DataItem(weather.getLowest(), DailyLoveConfigure.Color_minTem));
resultVo.setAttribute("max_temperature", new DataItem(weather.getHighest(), DailyLoveConfigure.Color_maxTem));
resultVo.setAttribute("quality", new DataItem(weather.getVis(), DailyLoveConfigure.Color_quality));
resultVo.setAttribute("tips", new DataItem(tips, DailyLoveConfigure.Color_tips));
resultVo.setAttribute("night", new DataItem(nightContent, DailyLoveConfigure.Color_night));
resultVo.setAttribute("rainbow", new DataItem(rainbowContent, DailyLoveConfigure.Color_dailyCn));
resultVo.setAttribute("lunar", new DataItem(chineseDate.toString(), DailyLoveConfigure.Color_chineseDate));
resultVo.setAttribute("festival", new DataItem(festival + " " + term, DailyLoveConfigure.Color_festival));
resultVo.setAttribute("gbir_day", new DataItem(girlBirthdays + "", DailyLoveConfigure.Color_gbir));
resultVo.setAttribute("bbir_day", new DataItem(boyBirthdays + "", DailyLoveConfigure.Color_bbir));
resultVo.setAttribute("cbir_day", new DataItem(catBirthdays + "", DailyLoveConfigure.Color_cbir));
resultVo.setAttribute("words", new DataItem(words, DailyLoveConfigure.Color_remark));
resultVo.setAttribute("love_day", new DataItem(loveDays + "", DailyLoveConfigure.Color_loveDay));
resultVo.setAttribute("wedding_day", new DataItem(weddingDays + "", DailyLoveConfigure.Color_weddingDay));
log.info("推送消息: {}", resultVo);
// 获取微信访问令牌并发送消息
return wechatRequestService.getAccessToken("client_credential", DailyLoveConfigure.App_ID, DailyLoveConfigure.App_Secret)
.onErrorMap(throwable -> new PushException("获取微信访问令牌失败: " + throwable.getMessage(), throwable))
.map(tokenResp -> mapper.readTree(tokenResp).get("access_token").asString())
.flatMap(accessToken -> wechatRequestService.sendMsg(accessToken, resultVo)
.doOnNext(this::printPushLog)
.onErrorMap(throwable -> new PushException("发送微信消息失败: " + throwable.getMessage(), throwable)))
.doOnSuccess(response -> log.info("推送结果: {}", response));
} catch (Exception e) {
log.error("处理晚安推送数据时发生错误", e);
return Mono.error(new PushException("处理晚安推送数据时发生错误", e));
}
});
}
/**
* 推送早安
*/
@GetMapping("/pushMorning")
@RegisterReflectionForBinding(Weather.class)
public Mono<String> pushMorning() {
// 获取天气信息
public String pushMorning() {
TianXinReqParam param1 = new TianXinReqParam();
param1.setKey(DailyLoveConfigure.TianXin_Key);
param1.setCity(DailyLoveConfigure.City_ID);
param1.setType("7");
param1.setType("1");
String weatherResp = dataRemoteClient.getWeather(param1);
// 获取农历和节日信息
ChineseDate chineseDate = new ChineseDate(DateUtil.parseDate(LocalDate.now().toString()));
Weather weather = JSONObject.parseObject(weatherResp).getJSONArray("result").getJSONObject(0).toJavaObject(Weather.class);
ResultVo resultVo = ResultVo.initializeResultVo(DailyLoveConfigure.Open_ID,
DailyLoveConfigure.Template_ID_Morning,
DailyLoveConfigure.Color_Top);
resultVo.setAttribute("now", new DataItem(weather.getDate() + " " + weather.getWeek(), DailyLoveConfigure.Color_Now));
resultVo.setAttribute("city", new DataItem(weather.getArea(), DailyLoveConfigure.Color_city));
resultVo.setAttribute("weather", new DataItem(weather.getWeather(), DailyLoveConfigure.Color_weather));
resultVo.setAttribute("min_temperature", new DataItem(weather.getLowest(), DailyLoveConfigure.Color_minTem));
resultVo.setAttribute("max_temperature", new DataItem(weather.getHighest(), DailyLoveConfigure.Color_maxTem));
resultVo.setAttribute("quality", new DataItem(weather.getQuality(), DailyLoveConfigure.Color_quality));
TianXinReqParam param2 = new TianXinReqParam();
param2.setKey(DailyLoveConfigure.TianXin_Key);
// String tipsResp = dataRemoteClient.getTips(param2);
// String tips = JSONObject.parseObject(tipsResp).getJSONArray("result").getJSONObject(0).getString("content");
// resultVo.setAttribute("tips", new DataItem(tips, DailyLoveConfigure.Color_tips));
String morningResp = dataRemoteClient.getMorning(param2);
String morning = JSONObject.parseObject(morningResp).getJSONArray("result").getJSONObject(0).getString("content");
resultVo.setAttribute("morning", new DataItem(morning, DailyLoveConfigure.Color_morning));
String rainbowResp = dataRemoteClient.getRainbow(param2);
String rainbow = JSONObject.parseObject(rainbowResp).getJSONArray("result").getJSONObject(0).getString("content");
resultVo.setAttribute("rainbow", new DataItem(rainbow, DailyLoveConfigure.Color_dailyCn));
// String englishResp = dataRemoteClient.getDailyEnglish(param2);
// String english = JSONObject.parseObject(englishResp).getJSONArray("result").getJSONObject(0).getString("en");
// resultVo.setAttribute("daily_english_en", new DataItem(english, DailyLoveConfigure.Color_dailyEn));
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
Date date = new Date();
String currentTime = dateFormat.format(date);
ChineseDate chineseDate = new ChineseDate(DateUtil.parseDate(currentTime));
String festival = chineseDate.getFestivals();
String term = chineseDate.getTerm();
resultVo.setAttribute("lunar", new DataItem(chineseDate.toString(), DailyLoveConfigure.Color_chineseDate));
resultVo.setAttribute("festival", new DataItem(festival + " " + term, DailyLoveConfigure.Color_festival));
// 计算各种日期
int girlBirthdays = DataUtils.getBirthdays(DailyLoveConfigure.Girl_Birthday);
log.debug("gbir_day:{}", girlBirthdays);
resultVo.setAttribute("gbir_day", new DataItem(girlBirthdays + "", DailyLoveConfigure.Color_gbir));
int boyBirthdays = DataUtils.getChineseBirthdays(DailyLoveConfigure.Boy_Birthday);
log.debug("bbir_day:{}", boyBirthdays);
resultVo.setAttribute("bbir_day", new DataItem(boyBirthdays + "", DailyLoveConfigure.Color_bbir));
int catBirthdays = DataUtils.getBirthdays(DailyLoveConfigure.Cat_Birthday);
int loveDays = DataUtils.getDayDiff(DailyLoveConfigure.Love_Day);
int weddingDays = DataUtils.getDayDiff(DailyLoveConfigure.Wedding_Day);
log.debug("cbir_day:{}", catBirthdays);
resultVo.setAttribute("cbir_day", new DataItem(catBirthdays + "", DailyLoveConfigure.Color_cbir));
log.info("gbir_days:{}, bbir_days:{}, cbir_days:{}, love_days:{}, wedding_days:{}",
girlBirthdays, boyBirthdays, catBirthdays, loveDays, weddingDays);
String words = "普通的一天";
// 设置提醒文字
String words;
if (DataUtils.getBirthdays(DailyLoveConfigure.Love_Day) == 0) {
words = "今天是恋爱周年纪念日!永远爱你~mua";
} else if ((DataUtils.getDayDiff(DailyLoveConfigure.Love_Day)) % 100 == 0) {
} else if ((DataUtils.getLoveDays(DailyLoveConfigure.Love_Day)) % 100 == 0) {
words = "今天是恋爱百日纪念日!永远爱你~";
} else if (DataUtils.getBirthdays(DailyLoveConfigure.Wedding_Day) == 0) {
words = "今天是结婚周年纪念日!永远爱你~";
} else if (girlBirthdays == 0) {
words = "今天是lili宝贝的生日生日快乐哟~";
} else if (boyBirthdays == 0) {
words = "今天是菘菘的生日!别忘了好好爱他~";
words = "今天是ss的生日!别忘了好好爱他~";
} else if (catBirthdays == 0) {
words = "今天是小离谱的生日!别忘了小鱼干!";
} else {
words = "普通的一天";
}
// 同时获取多个数据源
Mono<String> weatherRespMono = dataRemoteService.getWeather(param1.getKey(), param1.getCity(), param1.getType());
Mono<String> tipsMono = dataRemoteService.getTips(param1.getKey(), param1.getCity(), param1.getType());
Mono<String> morningMono = dataRemoteService.getMorning(param1.getKey(), param1.getCity(), param1.getType());
Mono<String> rainbowMono = dataRemoteService.getRainbow(param1.getKey(), param1.getCity(), param1.getType());
resultVo.setAttribute("words", new DataItem(words, DailyLoveConfigure.Color_remark));
// 组合所有异步操作
return Mono.zip(weatherRespMono, tipsMono, morningMono, rainbowMono)
.onErrorMap(throwable -> new PushException("获取早安推送数据失败: " + throwable.getMessage(), throwable))
.flatMap(tuple -> {
String weatherResp = tuple.getT1();
String tipsResp = tuple.getT2();
String morningResp = tuple.getT3();
String rainbowResp = tuple.getT4();
int loveDays = DataUtils.getLoveDays(DailyLoveConfigure.Love_Day);
log.debug("love_day:{}", loveDays);
resultVo.setAttribute("love_day", new DataItem(loveDays + "", DailyLoveConfigure.Color_loveDay));
try {
// 解析天气数据
String city = mapper.readTree(weatherResp).get("result").get("area").asString();
var weatherData = mapper.readTree(weatherResp).get("result").get("list").get(0);
Weather weather = mapper.treeToValue(weatherData, Weather.class);
log.debug("resultVo:{}", resultVo);
WechatTokenParam wechatTokenParam = new WechatTokenParam();
wechatTokenParam.setAppid(DailyLoveConfigure.App_ID);
wechatTokenParam.setSecret(DailyLoveConfigure.App_Secret);
// 解析其他数据
String tips = mapper.readTree(tipsResp).get("result").get("content").asString();
String morningContent = mapper.readTree(morningResp).get("result").get("content").asString();
String rainbowContent = mapper.readTree(rainbowResp).get("result").get("content").asString();
String accessTokenResp = wechatRequestClient.getAccessToken(wechatTokenParam);
log.debug("accessTokenJson:{}", accessTokenResp);
String token = JSONObject.parseObject(accessTokenResp).getString("access_token");
String responseStr = wechatRequestClient.sendMsg(resultVo, token);
return responseStr;
// 创建结果对象
ResultVo resultVo = ResultVo.initializeResultVo(DailyLoveConfigure.Open_ID,
DailyLoveConfigure.Template_ID_Morning,
DailyLoveConfigure.Color_Top);
// 设置各项数据
resultVo.setAttribute("city", new DataItem(city, DailyLoveConfigure.Color_city));
resultVo.setAttribute("now", new DataItem(weather.getDate() + " " + weather.getWeek(), DailyLoveConfigure.Color_Now));
resultVo.setAttribute("weather", new DataItem(weather.getWeather(), DailyLoveConfigure.Color_weather));
resultVo.setAttribute("min_temperature", new DataItem(weather.getLowest(), DailyLoveConfigure.Color_minTem));
resultVo.setAttribute("max_temperature", new DataItem(weather.getHighest(), DailyLoveConfigure.Color_maxTem));
resultVo.setAttribute("quality", new DataItem(weather.getVis(), DailyLoveConfigure.Color_quality));
resultVo.setAttribute("tips", new DataItem(tips, DailyLoveConfigure.Color_tips));
resultVo.setAttribute("morning", new DataItem(morningContent, DailyLoveConfigure.Color_morning));
resultVo.setAttribute("rainbow", new DataItem(rainbowContent, DailyLoveConfigure.Color_dailyCn));
resultVo.setAttribute("lunar", new DataItem(chineseDate.toString(), DailyLoveConfigure.Color_chineseDate));
resultVo.setAttribute("festival", new DataItem(festival + " " + term, DailyLoveConfigure.Color_festival));
resultVo.setAttribute("gbir_day", new DataItem(girlBirthdays + "", DailyLoveConfigure.Color_gbir));
resultVo.setAttribute("bbir_day", new DataItem(boyBirthdays + "", DailyLoveConfigure.Color_bbir));
resultVo.setAttribute("cbir_day", new DataItem(catBirthdays + "", DailyLoveConfigure.Color_cbir));
resultVo.setAttribute("words", new DataItem(words, DailyLoveConfigure.Color_remark));
resultVo.setAttribute("love_day", new DataItem(loveDays + "", DailyLoveConfigure.Color_loveDay));
resultVo.setAttribute("wedding_day", new DataItem(weddingDays + "", DailyLoveConfigure.Color_weddingDay));
log.info("推送消息: {}", resultVo);
// 获取微信访问令牌并发送消息
return wechatRequestService.getAccessToken("client_credential", DailyLoveConfigure.App_ID, DailyLoveConfigure.App_Secret)
.onErrorMap(throwable -> new PushException("获取微信访问令牌失败: " + throwable.getMessage(), throwable))
.map(tokenResp -> mapper.readTree(tokenResp).get("access_token").asString())
.flatMap(accessToken -> wechatRequestService.sendMsg(accessToken, resultVo)
.doOnNext(PushDailyController.this::printPushLog)
.onErrorMap(throwable -> new PushException("发送微信消息失败: " + throwable.getMessage(), throwable)))
.doOnSuccess(response -> log.info("推送结果: {}", response));
} catch (Exception e) {
log.error("处理早安推送数据时发生错误", e);
return Mono.error(new PushException("处理早安推送数据时发生错误", e));
}
});
}
/**
* @descriptions 打印 error日志
* @author bamanker
* @date 2026/1/13 23:47
* 打印 response log
*
* @param responseStr
*/
private void printPushLog(String responseStr) {
JsonNode jsonNode = mapper.readTree(responseStr);
String msgCode = jsonNode.get("errcode").asString();
String msgContent = jsonNode.get("errmsg").asString();
JSONObject jsonObject = JSONObject.parseObject(responseStr);
String msgCode = jsonObject.getString("errcode");
String msgContent = jsonObject.getString("errmsg");
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("[ " + dateFormat.format(new Date()) + " ] : messageCode=" + msgCode + ",messageContent=" + msgContent);
}
}
}

View File

@@ -1,27 +0,0 @@
package com.bamanker.dailylove.controller;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author bamanker
*/
@Slf4j
@RestController
public class TestController {
/**
* 处理GET请求的测试方法。
*
* @return 返回一个字符串,内容为"test ok!!!!!!!!",用于验证功能的正常运行。
*/
@GetMapping("/test")
public String test(){
return "test ok!!!!!!!!";
}
}

View File

@@ -4,11 +4,6 @@ import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @descriptions 数据项
* @author bamanker
* @date 2026/1/13 23:36
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@@ -16,8 +11,4 @@ public class DataItem {
private String value;
private String color;
}

View File

@@ -1,17 +0,0 @@
package com.bamanker.dailylove.domain;
import lombok.Data;
/**
* @descriptions 错误响应类
* @author bamanker
* @date 2026/1/13 23:36
*/
@Data
public class ErrorResponse {
private Integer code;
private String message;
private Long timestamp;
}

View File

@@ -6,11 +6,6 @@ import lombok.NoArgsConstructor;
import java.util.HashMap;
/**
* @descriptions 结果集
* @author bamanker
* @date 2026/1/13 23:36
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@@ -29,10 +24,11 @@ public class ResultVo {
return new ResultVo(_touser,_template_id,_topcolor,_data);
}
public void setAttribute(String key, DataItem item){
public ResultVo setAttribute(String key, DataItem item){
if(this.data==null) {
this.data = new HashMap<String,DataItem>();
}
this.data.put(key,item);
return this;
}
}

View File

@@ -4,12 +4,6 @@ import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @descriptions 天行请求参数
* @author bamanker
* @date 2026/1/13 23:37
*/
@Builder
@Data
@AllArgsConstructor

View File

@@ -4,11 +4,6 @@ import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @descriptions 天气实体类
* @author bamanker
* @date 2026/1/13 23:30
*/
@Data
@AllArgsConstructor
@NoArgsConstructor

View File

@@ -4,11 +4,6 @@ import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @descriptions 微信 token 参数
* @author bamanker
* @date 2026/1/13 23:37
*/
@Data
@AllArgsConstructor
@NoArgsConstructor

View File

@@ -1,71 +0,0 @@
package com.bamanker.dailylove.exception;
import com.bamanker.dailylove.domain.ErrorResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
/**
* @descriptions 全局异常处理器
* @author bamanker
* @date 2026/1/13 23:38
*/
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
/**
* 处理推送异常
*/
@ExceptionHandler(PushException.class)
public ResponseEntity<ErrorResponse> handlePushException(PushException e) {
log.error("推送服务异常: {}", e.getMessage(), e);
ErrorResponse error = new ErrorResponse();
error.setCode(HttpStatus.INTERNAL_SERVER_ERROR.value());
error.setMessage(e.getMessage());
error.setTimestamp(System.currentTimeMillis());
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(error);
}
/**
* 处理运行时异常
*/
@ExceptionHandler(RuntimeException.class)
public ResponseEntity<ErrorResponse> handleRuntimeException(RuntimeException e) {
log.error("运行时异常: {}", e.getMessage(), e);
ErrorResponse error = new ErrorResponse();
error.setCode(HttpStatus.INTERNAL_SERVER_ERROR.value());
error.setMessage(e.getMessage());
error.setTimestamp(System.currentTimeMillis());
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(error);
}
/**
* 处理一般异常
*/
@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handleGeneralException(Exception e) {
log.error("系统异常: {}", e.getMessage(), e);
ErrorResponse error = new ErrorResponse();
error.setCode(HttpStatus.INTERNAL_SERVER_ERROR.value());
error.setMessage("系统内部错误,请稍后重试");
error.setTimestamp(System.currentTimeMillis());
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(error);
}
/**
* 处理参数异常
*/
@ExceptionHandler(IllegalArgumentException.class)
public ResponseEntity<ErrorResponse> handleIllegalArgumentException(IllegalArgumentException e) {
log.warn("参数错误: {}", e.getMessage(), e);
ErrorResponse error = new ErrorResponse();
error.setCode(HttpStatus.BAD_REQUEST.value());
error.setMessage("参数错误: " + e.getMessage());
error.setTimestamp(System.currentTimeMillis());
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(error);
}
}

View File

@@ -1,16 +0,0 @@
package com.bamanker.dailylove.exception;
/**
* @descriptions 推送异常
* @author bamanker
* @date 2026/1/13 23:38
*/
public class PushException extends RuntimeException {
public PushException(String message) {
super(message);
}
public PushException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@@ -0,0 +1,44 @@
package com.bamanker.dailylove.service;
import com.bamanker.dailylove.domain.TianXinReqParam;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.cloud.openfeign.SpringQueryMap;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
/**
* 天行数据第三方接口
* @author baman
*/
@Component
@FeignClient(value = "TianXinDataRemoteClient",url = "${tianxin.server}")
public interface DataRemoteClient {
@GetMapping(value = "/tianqi/index",
consumes = {MediaType.APPLICATION_JSON_VALUE},
produces = {MediaType.APPLICATION_JSON_VALUE})
String getWeather(@SpringQueryMap TianXinReqParam param);
@GetMapping(value = "/caihongpi/index",
consumes = {MediaType.APPLICATION_JSON_VALUE},
produces = {MediaType.APPLICATION_JSON_VALUE})
String getRainbow(@SpringQueryMap TianXinReqParam param);
@GetMapping(value = "/ensentence/index",
consumes = {MediaType.APPLICATION_JSON_VALUE},
produces = {MediaType.APPLICATION_JSON_VALUE})
String getDailyEnglish(@SpringQueryMap TianXinReqParam param);
@GetMapping(value = "/qiaomen/index",
consumes = {MediaType.APPLICATION_JSON_VALUE},
produces = {MediaType.APPLICATION_JSON_VALUE})
String getTips(@SpringQueryMap TianXinReqParam param);
@GetMapping(value = "/zaoan/index",
consumes = {MediaType.APPLICATION_JSON_VALUE},
produces = {MediaType.APPLICATION_JSON_VALUE})
String getMorning(@SpringQueryMap TianXinReqParam param);
@GetMapping(value = "/wanan/index",
consumes = {MediaType.APPLICATION_JSON_VALUE},
produces = {MediaType.APPLICATION_JSON_VALUE})
String getNight(@SpringQueryMap TianXinReqParam param);
}

View File

@@ -1,94 +0,0 @@
package com.bamanker.dailylove.service;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;
/**
* @descriptions 远程数据服务
* @author bamanker
* @date 2026/1/13 23:38
*/
@Service
public class DataRemoteService {
final
WebClient webClient;
public DataRemoteService(@Qualifier("dateRemoteClient") WebClient dataRemoteService) {
this.webClient = dataRemoteService;
}
public Mono<String> getWeather(String key, String city, String type) {
return webClient.get()
.uri(uriBuilder -> uriBuilder
.path("/tianqi/index")
.queryParam("key", key)
.queryParam("city", city)
.queryParam("type", type)
.build())
.retrieve()
.bodyToMono(String.class);
}
public Mono<String> getRainbow(String key, String city, String type) {
return webClient.get()
.uri(uriBuilder -> uriBuilder
.path("/caihongpi/index")
.queryParam("key", key)
.queryParam("city", city)
.queryParam("type", type)
.build())
.retrieve()
.bodyToMono(String.class);
}
public Mono<String> getDailyEnglish(String key, String city, String type) {
return webClient.get()
.uri(uriBuilder -> uriBuilder
.path("/ensentence/index")
.queryParam("key", key)
.queryParam("city", city)
.queryParam("type", type)
.build())
.retrieve()
.bodyToMono(String.class);
}
public Mono<String> getTips(String key, String city, String type) {
return webClient.get()
.uri(uriBuilder -> uriBuilder
.path("/qiaomen/index")
.queryParam("key", key)
.queryParam("city", city)
.queryParam("type", type)
.build())
.retrieve()
.bodyToMono(String.class);
}
public Mono<String> getMorning(String key, String city, String type) {
return webClient.get()
.uri(uriBuilder -> uriBuilder
.path("/zaoan/index")
.queryParam("key", key)
.queryParam("city", city)
.queryParam("type", type)
.build())
.retrieve()
.bodyToMono(String.class);
}
public Mono<String> getNight(String key, String city, String type) {
return webClient.get()
.uri(uriBuilder -> uriBuilder
.path("/wanan/index")
.queryParam("key", key)
.queryParam("city", city)
.queryParam("type", type)
.build())
.retrieve()
.bodyToMono(String.class);
}
}

View File

@@ -0,0 +1,21 @@
package com.bamanker.dailylove.service;
import com.bamanker.dailylove.domain.ResultVo;
import com.bamanker.dailylove.domain.WechatTokenParam;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.cloud.openfeign.SpringQueryMap;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
@Component
@FeignClient(value = "WechatRequestClient", url = "https://api.weixin.qq.com/cgi-bin")
public interface WechatRequestClient {
@GetMapping("/token")
String getAccessToken(@SpringQueryMap WechatTokenParam param);
@PostMapping("/message/template/send?access_token={token}")
String sendMsg(ResultVo resultVo, @RequestParam("token") String token);
}

View File

@@ -1,44 +0,0 @@
package com.bamanker.dailylove.service;
import com.bamanker.dailylove.domain.ResultVo;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;
/**
* @descriptions 微信请求服务
* @author bamanker
* @date 2026/1/13 23:38
*/
@Service
public class WechatRequestService {
final
WebClient webClient;
public WechatRequestService(@Qualifier("wechatWebClient") WebClient dateRemoteWebClient) {
this.webClient = dateRemoteWebClient;
}
public Mono<String> getAccessToken(String grant_type,String appid,String secret){
return webClient.get()
.uri(uriBuilder -> uriBuilder
.path("/token")
.queryParam("grant_type", grant_type)
.queryParam("appid", appid)
.queryParam("secret", secret)
.build())
.retrieve()
.bodyToMono(String.class);
}
public Mono<String> sendMsg(String token, ResultVo resultVo){
return webClient.post()
.uri("/message/template/send?access_token={token}", token)
.bodyValue(resultVo)
.retrieve()
.bodyToMono(String.class);
}
}

View File

@@ -5,28 +5,21 @@ import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import com.bamanker.dailylove.config.DailyLoveConfigure;
import lombok.extern.slf4j.Slf4j;
import org.bouncycastle.util.Strings;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
import java.util.Calendar;
import java.util.Date;
/**
* @author bamanker
* @descriptions 日期工具类
* @date 2026/1/13 23:39
*/
@Slf4j
public class DataUtils {
/**
* 计算农历生日天数
*
* @param birthday
* @return int
* @descriptions 计算农历生日天数
* @author bamanker
* @date 2026/1/13 23:39
* @return
*/
public static int getChineseBirthdays(String birthday) {
//获取输入的生日
@@ -35,33 +28,32 @@ public class DataUtils {
ChineseDate chineseBir = new ChineseDate(DateUtil.parseDate(DailyLoveConfigure.Boy_Birthday));
log.info("生日的农历日期是:{}", chineseBir);
//截取日、月
// String[] strings = Strings.split(boyBirthday, '-');
String[] strings = Strings.split(boyBirthday, '-');
int chineseMonth = chineseBir.getMonth();
int chineseDay = chineseBir.getDay();
//获取当前日期的年
Calendar dateToday = Calendar.getInstance();
int todayYear = dateToday.get(Calendar.YEAR);
//把生日的年改为今年,方便计算
ChineseDate chineseDate = new ChineseDate(todayYear, chineseMonth, chineseDay, false);
ChineseDate chineseDate = new ChineseDate(todayYear, chineseMonth, chineseDay,false);
//农历日期对应的阳历日期
int gregorianDay = chineseDate.getGregorianDay();
//计算时间差
long days = haveThisDay(chineseMonth, chineseDay, dateToday, todayYear, chineseDate, gregorianDay);
// log.info("days:{}", days);
log.info("days:{}", days);
return (int) days;
}
/**
* 需要递归计算日期差
*
* @param chineseMonth 农历月
* @param chineseDay 农历日
* @param dateToday 今天的日期类
* @param todayYear 当前的年
* @param chineseDate 组装的待计算的新日期
* @param gregorianDay 判断是否存在农历日期的参数,-1代表今年不存在这个农历日期
* @return long 计算好的天数
* @descriptions 递归计算日期差
* @author bamanker
* @date 2026/1/13 23:39
* @return 计算好的天数
*/
private static long haveThisDay(int chineseMonth, int chineseDay, Calendar dateToday, int todayYear, ChineseDate chineseDate, int gregorianDay) {
//判断当前年份是否存在农历日对应的阳历日
@@ -97,11 +89,10 @@ public class DataUtils {
}
/**
* 计算生日天数 days
*
* @param birthday
* @return int
* @descriptions 计算生日天数
* @author bamanker
* @date 2026/1/13 23:40
* @return
*/
public static int getBirthdays(String birthday) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
@@ -117,7 +108,8 @@ public class DataUtils {
dateBirth.set(Calendar.YEAR, dateToday.get(Calendar.YEAR));
if (dateBirth.get(Calendar.DAY_OF_YEAR) < dateToday.get(Calendar.DAY_OF_YEAR)) {
// 生日已经过了,要算明年的了
days = (dateToday.getActualMaximum(Calendar.DAY_OF_YEAR) - dateToday.get(Calendar.DAY_OF_YEAR)) + dateBirth.get(Calendar.DAY_OF_YEAR);
days = (dateToday.getActualMaximum(Calendar.DAY_OF_YEAR) - dateToday.get(Calendar.DAY_OF_YEAR))
+ dateBirth.get(Calendar.DAY_OF_YEAR);
} else {
// 生日还没过
days = dateBirth.get(Calendar.DAY_OF_YEAR) - dateToday.get(Calendar.DAY_OF_YEAR);
@@ -130,16 +122,21 @@ public class DataUtils {
}
/**
* @param startDay
* @return int
* @descriptions 计算日期差
* @author bamanker
* @date 2026/1/13 23:41
* 计算恋爱天数 days
*
* @param loveday
* @return
*/
public static int getDayDiff(String startDay) {
public static int getLoveDays(String loveday) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
int days = 0;
try {
long time = System.currentTimeMillis() - dateFormat.parse(loveday).getTime();
days = (int) (time / (24 * 60 * 60 * 1000));
LocalDate dateNow = LocalDate.now();
LocalDate dateStart = LocalDate.parse(startDay);
return (int) ChronoUnit.DAYS.between(dateStart, dateNow);
} catch (ParseException e) {
e.printStackTrace();
}
return days;
}
}

View File

@@ -1,83 +0,0 @@
server:
port: 13145
spring:
application:
name: dailyLove
cloud:
refresh:
enabled: false
# 新的配置结构
daily-love:
wechat:
app-id: ${WECHAT_APP_ID:wxba68702957f8b93e}
app-secret: ${WECHAT_APP_SECRET:834078bb149409bfca4fe693ea7c4c1c}
# ME: oo5bL6bK_4TC0tb-Wa5oiugTPVeQ
#LILI: oo5bL6QafHJa9zQNYKS0fIhFC0zM
open-id: ${WECHAT_OPEN_ID:oo5bL6bK_4TC0tb-Wa5oiugTPVeQ}
template-id-morning: ${WECHAT_TEMPLATE_ID_MORNING:dWNAL-ZOzpBhnByFoTamt9DlJQYLB5z3ldKLvQstyU4}
template-id-night: ${WECHAT_TEMPLATE_ID_NIGHT:oraLiXC-8740stYc1a7mpzUFHiAIRaM3JikqibZ2grE}
colors:
quality: '#99CC66'
morning: '#FFFF99'
chineseDate: '#99CC66'
festival: '#FF6666'
night: '#006699'
tomorrow: '#99CCCC'
now: '#99CCCC'
city: ""
weather: '#66CCCC'
minTem: '#0066CC'
maxTem: '#FF0033'
tips: ""
dailyCn: '#993366'
dailyEn: '#CC99CC'
gbir: '#FF3399'
bbir: '#FF3399'
cbir: '#FF3399'
loveDay: '#FF3399'
weddingDay: '#FF3399'
remark: '#FF6666'
top: '#FF0000'
data:
city-id: ${CITY_ID:101270106}
tianxin-key: ${TIANXIN_KEY:72fbbb9e75e338ea6a240e83972f287c}
girl-birthday: ${GIRL_BIRTHDAY:1995-06-28}
boy-birthday: ${BOY_BIRTHDAY:1995-03-30}
cat-birthday: ${CAT_BIRTHDAY:2022-10-23}
love-day: ${LOVE_DAY:2022-07-16}
wedding-day: ${WEDDING_DAY:2025-10-08}
# 外部服务配置
apis:
tianxin:
server: https://apis.tianapi.com
logging:
level:
com.bamanker.dailylove: INFO
reactor.netty.http.client: DEBUG
org.springframework.web.reactive.function.client: DEBUG
scanclass: false
# Actuator 配置
management:
# 端点配置
endpoints:
web:
exposure:
# 暴露健康端点,生产环境要慎重,别把敏感信息暴露了
include: health,info
# 健康端点配置
endpoint:
health:
# 显示详细的健康信息,方便调试
# 生产环境建议设为 when-authorized需要认证才能看详情
show-details: always
# 开启探针支持,这个必须设置
probes:
enabled: true
# 在主端口上也暴露探针路径
# 这样 K8s 探针可以直接访问应用端口,不用单独配置 management 端口
add-additional-paths: true

View File

@@ -0,0 +1,68 @@
server:
port: 13145
spring:
profiles:
active: prob
application:
name: dailyLove
cloud:
nacos:
config:
server-addr: ${url.nacos} # nacos地址配置中心
file-extension: yaml
group: Group1
discovery:
#持久化实例 ture为临时实例 false为持久化实例 临时实例发生异常直接剔除, 而持久化实例等待恢复
ephemeral: true
#注册中心地址
server-addr: ${url.nacos}
url:
nacos: 127.0.0.1:8848
DL:
tianxin-key: 72fbbb9e75e338ea6a240e83972f287c
city-id: 101270106
girl-birthday: 1995-06-28
boy-birthday: 1995-3-30
love-day: 2022-07-16
cat-birthday: 2022-10-23
wechat:
app-id: wxba68702957f8b93e
app-secret: 834078bb149409bfca4fe693ea7c4c1c
#ME: oo5bL6bK_4TC0tb-Wa5oiugTPVeQ
#LILI: oo5bL6QafHJa9zQNYKS0fIhFC0zM
open-id: oo5bL6QafHJa9zQNYKS0fIhFC0zM
template-id-morning: 1yx1fahCs923nOmMh0_KLWN0nXGKd8_pHQrfpdMblrQ
template-id-night: QG-5NBX-jip46ulGVsaE3Uhl30GUxvNmtKOxwMHFkx0
color:
now: '#99CCCC'
tomorrow: '#99CCCC'
chineseDate: '#99CC66'
top: '#FF0000'
weather: '#66CCCC'
minTem: '#0066CC'
maxTem: '#FF0033'
dailyCn: '#993366'
dailyEn: '#CC99CC'
gbir: '#FF3399'
bbir: '#FF3399'
cbir: '#FF3399'
loveDay: '#FF3399'
remark: '#FF6666'
city: ""
tips: ""
quality: '#99CC66'
festival: '#FF6666'
morning: '#FFFF99'
night: '#006699'
tianxin:
server: https://apis.tianapi.com
logging:
level:
com.bamanker.dailylove.service: debug #指定openfeign日志以什么级别监控哪个接口可多个

View File

@@ -1,316 +1,150 @@
package com.bamanker.dailylove;
import com.bamanker.dailylove.service.DataRemoteService;
import com.bamanker.dailylove.service.WechatRequestService;
import jakarta.annotation.Resource;
import cn.hutool.core.date.ChineseDate;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson2.JSONObject;
import com.bamanker.dailylove.config.DailyLoveConfigure;
import com.bamanker.dailylove.domain.TianXinReqParam;
import com.bamanker.dailylove.domain.Weather;
import com.bamanker.dailylove.service.DataRemoteClient;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.bouncycastle.util.Strings;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import tools.jackson.databind.json.JsonMapper;
import javax.annotation.Resource;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
@SpringBootTest
@Slf4j
class DailyLoveApplicationTests {
//
// @Resource
// DataRemoteClient dataRemoteClient;
@Resource
DataRemoteService dataRemoteService;
DataRemoteClient dataRemoteClient;
@Resource
WechatRequestService wechatRequestService;
String remark = "";
@Autowired
JsonMapper mapper;
@Test
void test4(){
log.info("mark: {}",205%100);
}
@Test
void test3() {
//
// String remark = "❤";
//
// @Test
// void test4(){
// log.info("mark: {}",205%100);
//
// }
// @Test
// void test3() {
//
//
// //获取输入的生日
// String boyBirthday = DailyLoveConfigure.Boy_Birthday;
// //获取农历生日
// ChineseDate chineseBir = new ChineseDate(DateUtil.parseDate(DailyLoveConfigure.Boy_Birthday));
// log.info("生日的农历日期是:{}", chineseBir);
// //截取日、月
// String[] strings = Strings.split(boyBirthday, '-');
// int chineseMonth = chineseBir.getMonth();
// int chineseDay = chineseBir.getDay();
// //获取当前日期的年
// Calendar dateToday = Calendar.getInstance();
// int todayYear = dateToday.get(Calendar.YEAR);
// //把生日的年改为今年,方便计算
// ChineseDate chineseDate = new ChineseDate(todayYear, chineseMonth, chineseDay,false);
// //农历日期对应的阳历日期
// int gregorianDay = chineseDate.getGregorianDay();
// //计算时间差
// long days = haveThisDay(chineseMonth, chineseDay, dateToday, todayYear, chineseDate, gregorianDay);
// log.info("days:{}", days);
//
// }
//
// /**
// * 需要递归计算日期差
// *
// * @param chineseMonth 农历月
// * @param chineseDay 农历日
// * @param dateToday 今天的日期类
// * @param todayYear 当前的年
// * @param chineseDate 组装的待计算的新日期
// * @param gregorianDay 判断是否存在农历日期的参数,-1代表今年不存在这个农历日期
// * @return 计算好的天数
// */
// private static long haveThisDay(int chineseMonth, int chineseDay, Calendar dateToday, int todayYear, ChineseDate chineseDate, int gregorianDay) {
// //判断当前年份是否存在农历日对应的阳历日
// while (gregorianDay == -1) {
// //不存在,计算明年
// todayYear += 1;
// chineseDate = new ChineseDate(todayYear, chineseMonth, chineseDay, false);
// gregorianDay = chineseDate.getGregorianDay();
// }
// //存在
// //将农历日期改为阳历日期
// Calendar gregorianbir = chineseDate.getGregorianCalendar();
// //判断这个日期是否和今年是同一年
// if (todayYear == dateToday.get(Calendar.YEAR)) {
// //是同一年,判断这一天过了没
// if (gregorianbir.get(Calendar.DAY_OF_YEAR) < dateToday.get(Calendar.DAY_OF_YEAR)) {
// //这一天过了,计算明年
// todayYear += 1;
// chineseDate = new ChineseDate(todayYear, chineseMonth, chineseDay, false);
// gregorianDay = chineseDate.getGregorianDay();
// //递归计算下一年是否存在对应的阳历日
// return haveThisDay(chineseMonth, chineseDay, dateToday, todayYear, chineseDate, gregorianDay);
// }
// //没有过,直接计算
// }
// //不是同一年,直接计算
// Date time = dateToday.getTime();
// log.info("当前的日期是:{}", time);
// Date time1 = gregorianbir.getTime();
// log.info("下一个生日的日期:{}", time1);
// return DateUtil.between(dateToday.getTime(), gregorianbir.getTime(), DateUnit.DAY);
// }
//
// @Test
// void test2() {
//
// ResultVo resultVo = ResultVo.initializeResultVo(DailyLoveConfigure.Open_ID,
// DailyLoveConfigure.Template_ID_Night,
// DailyLoveConfigure.Color_Top);
//
// TianXinReqParam param1 = new TianXinReqParam();
// param1.setKey(DailyLoveConfigure.TianXin_Key);
// param1.setCity(DailyLoveConfigure.City_ID);
// param1.setType("7");
// Mono<String> weatherRespMono = dataRemoteService.getWeather(param1.getKey(), param1.getCity(), param1.getType());
// Mono<ResultVo> resultVoMono1 = weatherRespMono
// .map(respJson -> mapper.readTree(respJson)
// .get("result")
// .get("area")
// .toString())
// .flatMap(city -> {
// resultVo.setAttribute("city", new DataItem(city, DailyLoveConfigure.Color_city));
// return Mono.just(resultVo);
// });
// Mono<ResultVo> resultVoMono2 = weatherRespMono
// .map(respJson -> mapper.readTree(respJson)
// .get("result")
// .get("list")
// .get(1))
// .map(respJson -> mapper.treeToValue(respJson, Weather.class))
// .flatMap(weather -> {
// resultVo.setAttribute("tomorrow", new DataItem(weather.getDate() + " " + weather.getWeek(), DailyLoveConfigure.Color_tomorrow));
// resultVo.setAttribute("weather", new DataItem(weather.getWeather(), DailyLoveConfigure.Color_weather));
// resultVo.setAttribute("min_temperature", new DataItem(weather.getLowest(), DailyLoveConfigure.Color_minTem));
// resultVo.setAttribute("max_temperature", new DataItem(weather.getHighest(), DailyLoveConfigure.Color_maxTem));
// resultVo.setAttribute("quality", new DataItem(weather.getVis(), DailyLoveConfigure.Color_quality));
// return Mono.just(resultVo);
// });
//// Mono<Tuple2<ResultVo, ResultVo>> zip = Mono.zip(resultVoMono1, resultVoMono);
//
//
// TianXinReqParam param2 = new TianXinReqParam();
// param2.setKey(DailyLoveConfigure.TianXin_Key);
//
// Mono<ResultVo> resultVoMono3 = dataRemoteService.getTips(param2.getKey(), param2.getCity(), param2.getType())
// .map(respJson -> mapper.readTree(respJson)
// .get("result")
// .get("content").asString())
// .flatMap(tips -> {
// resultVo.setAttribute("tips", new DataItem(tips, DailyLoveConfigure.Color_tips));
// return Mono.just(resultVo);
// });
// Mono<ResultVo> resultVoMono4 = dataRemoteService.getNight(param2.getKey(), param2.getCity(), param2.getType())
// .map(respJson -> mapper.readTree(respJson)
// .get("result")
// .get("content").asString())
// .flatMap(night -> {
// resultVo.setAttribute("night", new DataItem(night, DailyLoveConfigure.Color_night));
// return Mono.just(resultVo);
// });
// Mono<ResultVo> resultVoMono5 = dataRemoteService.getRainbow(param2.getKey(), param2.getCity(), param2.getType())
// .map(respJson -> mapper.readTree(respJson)
// .get("result")
// .get("content").asString())
// .flatMap(rainbow -> {
// resultVo.setAttribute("rainbow", new DataItem(rainbow, DailyLoveConfigure.Color_dailyCn));
// return Mono.just(resultVo);
// });
//
// Mono<ResultVo> resultVoMono = Mono.zip(resultVoMono1, resultVoMono2, resultVoMono3, resultVoMono4, resultVoMono5)
// .flatMap(new Function<Tuple5<ResultVo, ResultVo, ResultVo, ResultVo, ResultVo>, Mono<? extends ResultVo>>() {
// @Override
// public Mono<? extends ResultVo> apply(Tuple5<ResultVo, ResultVo, ResultVo, ResultVo, ResultVo> tuple) {
// return Mono.just(tuple.getT1());
// }
// });
//
// ChineseDate chineseDate = new ChineseDate(DateUtil.parseDate(LocalDate.now().toString()));
// String festival = chineseDate.getFestivals();
// String term = chineseDate.getTerm();
// resultVo.setAttribute("lunar", new DataItem(chineseDate.toString(), DailyLoveConfigure.Color_chineseDate));
// resultVo.setAttribute("festival", new DataItem(festival + " " + term, DailyLoveConfigure.Color_festival));
//
//
// int girlBirthdays = DataUtils.getBirthdays(DailyLoveConfigure.Girl_Birthday);
// log.info("gbir_days:{}", girlBirthdays);
// resultVo.setAttribute("gbir_day", new DataItem(girlBirthdays - 1 + "", DailyLoveConfigure.Color_gbir));
//
// int boyBirthdays = DataUtils.getChineseBirthdays(DailyLoveConfigure.Boy_Birthday);
// log.info("bbir_days:{}", boyBirthdays);
// resultVo.setAttribute("bbir_day", new DataItem(boyBirthdays - 1 + "", DailyLoveConfigure.Color_bbir));
//
// int catBirthdays = DataUtils.getBirthdays(DailyLoveConfigure.Cat_Birthday);
// log.info("cbir_days:{}", catBirthdays);
// resultVo.setAttribute("cbir_day", new DataItem(catBirthdays - 1 + "", DailyLoveConfigure.Color_cbir));
//
// String words = "普通的一天";
//
// if (DataUtils.getBirthdays(DailyLoveConfigure.Love_Day) == 1) {
// words = "明天是恋爱周年纪念日!永远爱你~mua";
// } else if ((DataUtils.getDayDiff(DailyLoveConfigure.Love_Day)) % 100 == 99) {
// words = "明天是恋爱百日纪念日!提前庆祝哦~";
// } else if (DataUtils.getBirthdays(DailyLoveConfigure.Wedding_Day) == 1) {
// words = "明天是结婚周年纪念日!提前庆祝哦~";
// } else if (girlBirthdays == 1) {
// words = "明天是lili大宝贝的生日啦";
// } else if (boyBirthdays == 1) {
// words = "明天是菘菘的生日!别忘了哦~";
// } else if (catBirthdays == 1) {
// words = "明天是小离谱的生日!别忘了小鱼干!";
// }
//
// resultVo.setAttribute("words", new DataItem(words, DailyLoveConfigure.Color_remark));
//
// int loveDays = DataUtils.getDayDiff(DailyLoveConfigure.Love_Day);
// log.info("love_days:{}", loveDays);
// resultVo.setAttribute("love_day", new DataItem(loveDays + 1 + "", DailyLoveConfigure.Color_loveDay));
//
// int weddingDays = DataUtils.getDayDiff(DailyLoveConfigure.Wedding_Day);
// log.info("wedding_days:{}", weddingDays);
// resultVo.setAttribute("wedding_day", new DataItem(weddingDays + 1 + "", DailyLoveConfigure.Color_weddingDay));
//
// resultVoMono.flatMap(new Function<ResultVo, Mono<?>>() {
// @Override
// public Mono<?> apply(ResultVo resultVo) {
// return Mono.just(resultVo);
// }
// }).log().block();
//
// WechatTokenParam param3 = new WechatTokenParam();
// param3.setAppid(DailyLoveConfigure.App_ID);
// param3.setSecret(DailyLoveConfigure.App_Secret);
//
// String accessToken = wechatRequestService.getAccessToken(param3.getGrant_type(), param3.getAppid(), param3.getSecret())
// .map(respJson -> {
// return mapper.readTree(respJson)
// .get("access_token").asString();
// }).log().block();
// wechatRequestService.sendMsg(accessToken, resultVo).log().block();
//获取输入的生日
String boyBirthday = DailyLoveConfigure.Boy_Birthday;
//获取农历生日
ChineseDate chineseBir = new ChineseDate(DateUtil.parseDate(DailyLoveConfigure.Boy_Birthday));
log.info("生日的农历日期是:{}", chineseBir);
//截取日、月
String[] strings = Strings.split(boyBirthday, '-');
int chineseMonth = chineseBir.getMonth();
int chineseDay = chineseBir.getDay();
//获取当前日期的年
Calendar dateToday = Calendar.getInstance();
int todayYear = dateToday.get(Calendar.YEAR);
//把生日的年改为今年,方便计算
ChineseDate chineseDate = new ChineseDate(todayYear, chineseMonth, chineseDay,false);
//农历日期对应的阳历日期
int gregorianDay = chineseDate.getGregorianDay();
//计算时间差
long days = haveThisDay(chineseMonth, chineseDay, dateToday, todayYear, chineseDate, gregorianDay);
log.info("days:{}", days);
}
/**
* 需要递归计算日期差
*
* @param chineseMonth 农历月
* @param chineseDay 农历日
* @param dateToday 今天的日期类
* @param todayYear 当前的年
* @param chineseDate 组装的待计算的新日期
* @param gregorianDay 判断是否存在农历日期的参数,-1代表今年不存在这个农历日期
* @return 计算好的天数
*/
private static long haveThisDay(int chineseMonth, int chineseDay, Calendar dateToday, int todayYear, ChineseDate chineseDate, int gregorianDay) {
//判断当前年份是否存在农历日对应的阳历日
while (gregorianDay == -1) {
//不存在,计算明年
todayYear += 1;
chineseDate = new ChineseDate(todayYear, chineseMonth, chineseDay, false);
gregorianDay = chineseDate.getGregorianDay();
}
//存在
//将农历日期改为阳历日期
Calendar gregorianbir = chineseDate.getGregorianCalendar();
//判断这个日期是否和今年是同一年
if (todayYear == dateToday.get(Calendar.YEAR)) {
//是同一年,判断这一天过了没
if (gregorianbir.get(Calendar.DAY_OF_YEAR) < dateToday.get(Calendar.DAY_OF_YEAR)) {
//这一天过了,计算明年
todayYear += 1;
chineseDate = new ChineseDate(todayYear, chineseMonth, chineseDay, false);
gregorianDay = chineseDate.getGregorianDay();
//递归计算下一年是否存在对应的阳历日
return haveThisDay(chineseMonth, chineseDay, dateToday, todayYear, chineseDate, gregorianDay);
}
//没有过,直接计算
}
//不是同一年,直接计算
Date time = dateToday.getTime();
log.info("当前的日期是:{}", time);
Date time1 = gregorianbir.getTime();
log.info("下一个生日的日期:{}", time1);
return DateUtil.between(dateToday.getTime(), gregorianbir.getTime(), DateUnit.DAY);
}
@Test
void test2() {
TianXinReqParam param1 = new TianXinReqParam();
param1.setKey(DailyLoveConfigure.TianXin_Key);
param1.setCity(DailyLoveConfigure.City_ID);
param1.setType("7");
String weatherJson = dataRemoteClient.getWeather(param1);
log.info("weather:{}", weatherJson);
JSONObject resWeather = JSONObject.parseObject(weatherJson);
JSONObject result = resWeather.getJSONArray("result").getJSONObject(0).getJSONArray("list").getJSONObject(2);
log.info("----result----:{}", result);
Weather weather = result.toJavaObject(Weather.class);
log.info("weather:{}", weather);
ChineseDate chineseDate = new ChineseDate(DateUtil.parseDate(weather.getDate()));
System.out.println("--------------55555----------"+weather.getDate());
System.out.println("------------------------"+chineseDate);
// String tips = mapper.readTree(tipsResp).get("result").get("content").asString();
}
// log.info("weather:{}", weatherResp);
// JsonNode weatherJson = mapper.readTree(weatherResp).get("result").get("list").get(1);
// System.out.println("-----------------------------");
// System.out.println(weatherJson);
// String city = mapper.readTree(weatherResp).get("result").get("area").asString();
// System.out.println("-----------------------------");
// System.out.println(city);
// Weather weather = mapper.treeToValue(weatherJson, Weather.class);
// System.out.println("-----------------------------");
// System.out.println(weather);
//
// resultVo.setAttribute("tomorrow", new DataItem(weather.getDate() + " " + weather.getWeek(), DailyLoveConfigure.Color_tomorrow));
// resultVo.setAttribute("city", new DataItem(city, DailyLoveConfigure.Color_city));
// resultVo.setAttribute("weather", new DataItem(weather.getWeather(), DailyLoveConfigure.Color_weather));
// resultVo.setAttribute("min_temperature", new DataItem(weather.getLowest(), DailyLoveConfigure.Color_minTem));
// resultVo.setAttribute("max_temperature", new DataItem(weather.getHighest(), DailyLoveConfigure.Color_maxTem));
// resultVo.setAttribute("quality", new DataItem(weather.getVis(), DailyLoveConfigure.Color_quality));
//
// System.out.println("-----------------------------");
// System.out.println(resultVo);
@Test
void test1() {
int loveDays = getLoveDays("2021-07-16");
log.info("-------------------------------{}", loveDays);
}
// TianXinReqParam param2 = new TianXinReqParam();
// param2.setKey(DailyLoveConfigure.TianXin_Key);
//
// String tipsResp = dataRemoteClient.getTips(param2);
// String tips = mapper.readTree(tipsResp).get("result").get("content").asString();
//
// System.out.println("-----------------------------");
// System.out.println(tips);
//
// TianXinReqParam param1 = new TianXinReqParam();
// param1.setKey(DailyLoveConfigure.TianXin_Key);
// param1.setCity(DailyLoveConfigure.City_ID);
// param1.setType("1");
// String weatherResp = dataRemoteClient.getWeather(param1);
// JsonNode weatherJson = mapper.readTree(weatherResp).get("result");
// Weather weather = mapper.treeToValue(weatherJson, Weather.class);
//
// System.out.println("-----------------------------");
// System.out.println(weather);
public static int getLoveDays(String loveday) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
int days = 0;
try {
long time = System.currentTimeMillis() - dateFormat.parse(loveday).getTime();
days = (int) (time / (24 * 60 * 60 * 1000));
// log.info("----result----:{}", result);
} catch (ParseException e) {
e.printStackTrace();
}
return days;
}
//}
//
//
// @Test
// void test1() {
// int weddingDays = DataUtils.getWeddingDays("2025-10-08");
// log.info("wedding_days:{}", weddingDays);
// }
//
// public static int getLoveDays(String loveday) {
// SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
// int days = 0;
// try {
// long time = System.currentTimeMillis() - dateFormat.parse(loveday).getTime();
// days = (int) (time / (24 * 60 * 60 * 1000));
//
// } catch (ParseException e) {
// e.printStackTrace();
// }
// return days;
// }
//
// @Test
// void contextLoads() {
@Test
void contextLoads() {
// TianXinReqParam param1 = new TianXinReqParam();
// param1.setKey(DailyLoveConfigure.TianXin_Key);
// param1.setCity(DailyLoveConfigure.City_ID);
@@ -367,6 +201,6 @@ class DailyLoveApplicationTests {
// log.info("resultVo:{}", resultVo);
}
}
//}
}