Compare commits

..
13 Commits
Author SHA1 Message Date
wonder e6111188c1 ✨Feat: 菜单板块 2025-10-26 16:34:16 +08:00
wonder ea8c18b18b ✨Feat: 垂钓板块 2025-10-26 16:21:31 +08:00
wonder 5ddf362834 ✨Feat: 耕种板块 2025-10-26 16:18:33 +08:00
wonder dbee3a5b12 ✨Feat: 实现菜单推送 2025-10-26 16:07:38 +08:00
wonder 2372b7ebae 🔧Chore: 部分代码补充 2025-10-26 15:32:39 +08:00
wonder d4afe0e923 ✨Feat: 完成天气卡片 2025-10-26 14:35:08 +08:00
wonder d76deecb3d ♻️Refactor: 优化目录层次结构 2025-10-26 14:12:25 +08:00
wonder c4b5927d9d ✨Feat: 实现天气消息卡片 2025-10-26 13:58:28 +08:00
wonder db41860804 ✨Feat: 接入获取天气接口 2025-10-26 11:31:21 +08:00
wonder de0d0060c6 🔧Chore: 补充部分注释、综合优化修改 2025-10-26 10:27:23 +08:00
wonder df4a138159 🔄Update: 点击菜单事件监听 2025-10-25 21:09:05 +08:00
wonder c50c876a53 ✨Feat: 完成 Lark 简单消息接收 2025-10-25 20:40:54 +08:00
wonder b900377f4f 🐛Fix: 脚本部署主启动类配置问题 2025-10-25 20:17:08 +08:00
28 changed files with 752 additions and 105 deletions
+9 -10
View File
@@ -74,16 +74,15 @@
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.4.1</version>
<configuration>
<archive>
<manifest>
<mainClass>com.wonderland.stardewvalley.Application</mainClass>
</manifest>
</archive>
</configuration>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
@@ -1,5 +1,6 @@
package com.wonderland.stardewvalley;
import com.wonderland.stardewvalley.util.lark.EventListener;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@@ -7,5 +8,6 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
EventListener.listen();
}
}
@@ -0,0 +1,27 @@
package com.wonderland.stardewvalley.common.constant;
import lombok.Getter;
@Getter
public class BackGroundConstant {
public static final String BACKGROUND_SPRING = "春天";
public static final String BACKGROUND_SUMMER = "夏天";
public static final String BACKGROUND_AUTUMN = "秋天";
public static final String BACKGROUND_WINTER = "冬天";
public static final String BACKGROUND_SPRING_DESCRIPTION = "“春种一粒粟,秋收万颗子”\n" +
"耕种 收获提升,户外活动(节日)比例增加";
public static final String BACKGROUND_SUMMER_DESCRIPTION = "“日复一日的劳作,是生活的底色”\n" +
"钓鱼 收获提升,室内活动(节日)比例增加";
public static final String BACKGROUND_AUTUMN_DESCRIPTION = "“收获的喜悦,也伴随着失去的阵痛”\n" +
"耕种 收获提升,户外活动(节日)比例增加,随机事件大幅增加";
public static final String BACKGROUND_WINTER_DESCRIPTION = "“寒冷的季节,也是心灵的沉淀”\n" +
"作息 影响健康值幅度增加,室内活动(节日)比例增加";
public static final String BACKGROUND_WEATHER = "【要求】请根据传入的今日数据,采用符合的语气,emjoy和符号,带一点想象,用简洁的语句,描述一下想象中的风景,体感,并附带一点小Tips。\n" +
"【输出格式】今天的星露谷....(控制在30字)\\nTips。\n" +
"【输出示例】\n" +
"今天的星露谷天气阴沉,气温舒适,北风轻轻吹拂,风力微弱,湿度较高,仿佛连空气都带着一丝凉意。这种天气最适合在家中泡一杯热茶,或者在庭院里摆上几张藤椅,享受难得的宁静。\n" +
"Tips:可以尝试在这样的天气里种植一些耐阴植物,比如蕨类或苔藓,为你的农场增添一抹绿意哦!\uD83D\uDE09\uD83C\uDF31";
}
@@ -0,0 +1,15 @@
package com.wonderland.stardewvalley.common.constant;
import lombok.Getter;
@Getter
public enum CityCode {
WuHan("420100");
private final String code;
CityCode(String code){
this.code = code;
}
}
@@ -1,8 +1,8 @@
package com.wonderland.stardewvalley.constant;
package com.wonderland.stardewvalley.common.constant;
public class GuideConstant {
final public static String GUIDE = "\uD83C\uDF31 在这个名为“如果人生是星露谷”的世界中,玩家扮演的是一位现实世界中的普通人 ,在某种“精神投射”或“虚拟现实”中,进入了一个与《星露谷物语》相似的模拟世界。这个世界并非简单的幻想乡,而是对现实生活的重构与映射 ,玩家通过在现实世界中“种田、打工、探索、运动”等行为,影响游戏中的生活节奏与心理状态。\n" +
final public static String GUIDE = "\uD83C\uDF31 在这个名为“如果人生是星露谷”的世界中,玩家扮演的是一位现实世界中的普通人 ,在某种“精神投射”或“虚拟现实”中,进入了一个与《星露谷物语》相似的模拟世界。这个世界并非简单的幻想乡,而是对现实生活的重构与映射 ,玩家通过在现实世界中“工作、探索、运动”等行为,影响游戏中的生活节奏与心理状态。\n" +
"\n" +
"\uD83C\uDFAE 游戏说明:\n" +
"\uD83C\uDF06 车水马龙的街道,拥挤的人潮,在这充满快节奏的水泥森林里,人们被巨大的压力裹挟着,疲惫不堪,宛若行尸走肉。改不完的稿子,数不完的ddl,望不到头的前路,许久没体会过的放松....生活什么时变得这么累了\n" +
@@ -1,4 +1,4 @@
package com.wonderland.stardewvalley.constant;
package com.wonderland.stardewvalley.common.constant;
public class LarkConstant {
@@ -1,6 +1,8 @@
package com.wonderland.stardewvalley.exception;
package com.wonderland.stardewvalley.common.exception;
/**
* 运行时异常封装为业务异常
*/
public class BusinessException extends RuntimeException{
private final int code;
@@ -1,17 +1,16 @@
package com.wonderland.stardewvalley.exception;
package com.wonderland.stardewvalley.common.exception;
import lombok.Getter;
/**
* 错误码
*/
@Getter
public enum ErrorCode {
SUCCESS(0, "ok"),
PARAMS_ERROR(40000, "请求参数错误"),
NOT_LOGIN_ERROR(40100, "未登录"),
NO_AUTH_ERROR(40101, "无权限"),
NOT_FOUND_ERROR(40400, "请求数据不存在"),
FORBIDDEN_ERROR(40300, "禁止访问"),
SYSTEM_ERROR(50000, "系统内部异常"),
OPERATION_ERROR(50001, "操作失败");
@@ -1,6 +1,8 @@
package com.wonderland.stardewvalley.exception;
package com.wonderland.stardewvalley.common.exception;
/**
* 根据条件抛出异常
*/
public class ThrowUtils {
public static void throwIf(boolean condition, RuntimeException runtimeException) {
@@ -1,12 +0,0 @@
package com.wonderland.stardewvalley.constant;
import lombok.Getter;
@Getter
public class BackGroundConstant {
private static final String BACKGROUND_SPRING = "春天";
private static final String BACKGROUND_SUMMER = "夏天";
private static final String BACKGROUND_AUTUMN = "秋天";
private static final String BACKGROUND_WINTER = "冬天";
}
@@ -1,9 +1,9 @@
package com.wonderland.stardewvalley.controller;
import com.wonderland.stardewvalley.ai.ChatUtil;
import com.wonderland.stardewvalley.service.ai.ChatUtil;
import com.wonderland.stardewvalley.entity.AIChatRequest;
import com.wonderland.stardewvalley.entity.BaseResponse;
import com.wonderland.stardewvalley.util.ResultUtil;
import com.wonderland.stardewvalley.util.response.ResultUtil;
import jakarta.annotation.Resource;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
@@ -1,7 +1,7 @@
package com.wonderland.stardewvalley.controller;
import com.wonderland.stardewvalley.entity.BaseResponse;
import com.wonderland.stardewvalley.util.ResultUtil;
import com.wonderland.stardewvalley.util.response.ResultUtil;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@@ -1,9 +1,9 @@
package com.wonderland.stardewvalley.controller;
import com.wonderland.stardewvalley.constant.GuideConstant;
import com.wonderland.stardewvalley.common.constant.GuideConstant;
import com.wonderland.stardewvalley.entity.BaseResponse;
import com.wonderland.stardewvalley.lark.LarkUtil;
import com.wonderland.stardewvalley.util.ResultUtil;
import com.wonderland.stardewvalley.util.lark.LarkUtil;
import com.wonderland.stardewvalley.util.response.ResultUtil;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@@ -2,6 +2,9 @@ package com.wonderland.stardewvalley.entity;
import lombok.Data;
/**
* 封装 AI 请求:背景信息 + 内容
*/
@Data
public class AIChatRequest {
private String backGround;
@@ -1,7 +1,7 @@
package com.wonderland.stardewvalley.entity;
import com.wonderland.stardewvalley.exception.ErrorCode;
import com.wonderland.stardewvalley.common.exception.ErrorCode;
import lombok.Data;
import java.io.Serializable;
@@ -0,0 +1,16 @@
package com.wonderland.stardewvalley.entity.game;
import lombok.Builder;
import lombok.Data;
@Data
@Builder
public class Weather {
private String weather;
private String temperature;
private String windPower;
private String windDirection;
private String reportTime;
private String humidity;
private String content;
}
@@ -0,0 +1,20 @@
package com.wonderland.stardewvalley.handle;
import com.wonderland.stardewvalley.entity.game.Weather;
import com.wonderland.stardewvalley.util.lark.LarkUtil;
import com.wonderland.stardewvalley.util.weather.WeatherUtil;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Component;
@Component
public class WeatherHandle {
@Resource
private LarkUtil larkUtil;
public void sendCard() throws Exception {
Weather weather = WeatherUtil.getWeather();
larkUtil.sendWeatherCard(weather);
}
}
@@ -1,60 +0,0 @@
package com.wonderland.stardewvalley.lark;
import cn.hutool.core.util.IdUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.gson.JsonParser;
import com.lark.oapi.Client;
import com.lark.oapi.core.utils.Jsons;
import com.lark.oapi.service.im.v1.model.CreateMessageReq;
import com.lark.oapi.service.im.v1.model.CreateMessageReqBody;
import com.lark.oapi.service.im.v1.model.CreateMessageResp;
import com.wonderland.stardewvalley.constant.LarkConstant;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.nio.charset.StandardCharsets;
@Slf4j
@Service
public class LarkUtil {
// SDK 使用文档:https://open.feishu.cn/document/uAjLw4CM/ukTMukTMukTM/server-side-sdk/java-sdk-guide/preparations
// 复制该 Demo 后, 需要将 "YOUR_APP_ID", "YOUR_APP_SECRET" 替换为自己应用的 APP_ID, APP_SECRET.
// 以下示例代码默认根据文档示例值填充,如果存在代码问题,请在 API 调试台填上相关必要参数后再复制代码使用
public static void sendText(String content) throws Exception {
// 构建client
Client client = Client.newBuilder(LarkConstant.APP_ID, LarkConstant.APP_SECRET).build();
// 组装文本 JSON
ObjectMapper mapper = new ObjectMapper();
ObjectNode node = mapper.createObjectNode();
node.put("text", content);
log.info("[Lark] 发送消息:{}", node.toString());
// 创建请求对象
CreateMessageReq req = CreateMessageReq.newBuilder()
.receiveIdType("open_id")
.createMessageReqBody(CreateMessageReqBody.newBuilder()
.receiveId(LarkConstant.USER_OPEN_ID)
.msgType("text")
.content(node.toString())
.uuid(IdUtil.randomUUID())
.build())
.build();
// 发起请求
CreateMessageResp resp = client.im().v1().message().create(req);
// 处理服务端错误
if(!resp.success()) {
System.out.println(String.format("code:%s,msg:%s,reqId:%s, resp:%s",
resp.getCode(), resp.getMsg(), resp.getRequestId(), Jsons.createGSON(true, false).toJson(JsonParser.parseString(new String(resp.getRawResponse().getBody(), StandardCharsets.UTF_8)))));
return;
}
// 业务数据处理
System.out.println(Jsons.DEFAULT.toJson(resp.getData()));
}
}
@@ -0,0 +1,21 @@
package com.wonderland.stardewvalley.lark.card;
import lombok.Getter;
@Getter
public enum CardTemplate {
CARD_TEMPLATE_WEATHER("AAqxas5etOJDx", "1.0.5"),
CARD_TEMPLATE_FARM("AAqxaYo9rbXPa", "1.0.8"),
CARD_TEMPLATE_FISH("AAqxauQ2FQuSF", "1.0.4"),
CARD_TEMPLATE_MINE("AAqxarffytU2e", "1.0.4"),
CARD_TEMPLATE_HELP("AAqxaCRidel6g", "1.0.5"),
CARD_TEMPLATE_LUCK("AAqxaScwjaUB3", "1.0.2");
private String cardId;
private String version;
CardTemplate(String cardId, String version) {
this.cardId = cardId;
this.version = version;
}
}
@@ -1,6 +1,5 @@
package com.wonderland.stardewvalley.ai;
package com.wonderland.stardewvalley.service.ai;
import jakarta.annotation.Resource;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.stereotype.Service;
@@ -0,0 +1,25 @@
package com.wonderland.stardewvalley.util.bean;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
@Component
public class SpringContextUtil implements ApplicationContextAware {
private static ApplicationContext context;
public static <T> T getBean(Class<T> beanClass) {
return context.getBean(beanClass);
}
public static <T> T getBean(String name, Class<T> beanClass) {
return context.getBean(name, beanClass);
}
public static Object getBean(String name) {
return context.getBean(name);
}
@Override
public void setApplicationContext(ApplicationContext appContext) throws BeansException {
context = appContext;
}
}
@@ -0,0 +1,61 @@
package com.wonderland.stardewvalley.util.lark;
import com.lark.oapi.core.utils.Jsons;
import com.lark.oapi.event.EventDispatcher;
import com.lark.oapi.service.application.ApplicationService;
import com.lark.oapi.service.application.v6.model.P2BotMenuV6;
import com.lark.oapi.service.im.ImService;
import com.lark.oapi.service.im.v1.model.P2MessageReceiveV1;
import com.lark.oapi.ws.Client;
import com.wonderland.stardewvalley.common.constant.LarkConstant;
import com.wonderland.stardewvalley.handle.WeatherHandle;
import com.wonderland.stardewvalley.util.bean.SpringContextUtil;
public class EventListener {
// onP2MessageReceiveV1 为接收消息 v2.0;onCustomizedEvent 内的 message 为接收消息 v1.0。
private static final EventDispatcher EVENT_HANDLER = EventDispatcher.newBuilder("", "")
.onP2MessageReceiveV1(new ImService.P2MessageReceiveV1Handler() {
@Override
public void handle(P2MessageReceiveV1 event) throws Exception {
System.out.printf("[ onP2MessageReceiveV1 access ], data: %s\n", Jsons.DEFAULT.toJson(event.getEvent()));
}
})
// 首次使用应用
// .onCustomizedEvent("p2p_chat_create", new CustomEventHandler() {
// @Override
// public void handle(EventReq event) throws Exception {
// System.out.printf("[ onCustomizedEvent access ], type: message, data: %s\n", new String(event.getBody(), StandardCharsets.UTF_8));
// }
// })
// 监听点击菜单事件
.onP2BotMenuV6(new ApplicationService.P2BotMenuV6Handler() {
@Override
public void handle(P2BotMenuV6 event) throws Exception {
String eventKey = event.getEvent().getEventKey();
if (eventKey.equals("weather")) {
WeatherHandle weatherHandle = SpringContextUtil.getBean(WeatherHandle.class);
weatherHandle.sendCard();
} else if (eventKey.equals("farm")) {
LarkUtil.sendFarmCard();
} else if (eventKey.equals("fish")) {
LarkUtil.sendFishCard();
} else if (eventKey.equals("mine")) {
LarkUtil.sendMineCard();
} else if (eventKey.equals("help")) {
LarkUtil.sendHelpCard();
} else if (eventKey.equals("luck")) {
LarkUtil.sendLuckCard();
}
System.out.printf("[ onP2BotMenuV6 access ], data: %s\n", Jsons.DEFAULT.toJson(event.getEvent()));
}
})
.build();
public static void listen() {
Client cli = new Client.Builder(LarkConstant.APP_ID, LarkConstant.APP_SECRET)
.eventHandler(EVENT_HANDLER)
.build();
cli.start();
}
}
@@ -0,0 +1,402 @@
package com.wonderland.stardewvalley.util.lark;
import cn.hutool.core.util.IdUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.gson.JsonParser;
import com.lark.oapi.Client;
import com.lark.oapi.core.utils.Jsons;
import com.lark.oapi.service.im.v1.model.CreateMessageReq;
import com.lark.oapi.service.im.v1.model.CreateMessageReqBody;
import com.lark.oapi.service.im.v1.model.CreateMessageResp;
import com.wonderland.stardewvalley.common.constant.BackGroundConstant;
import com.wonderland.stardewvalley.common.constant.LarkConstant;
import com.wonderland.stardewvalley.entity.game.Weather;
import com.wonderland.stardewvalley.lark.card.CardTemplate;
import com.wonderland.stardewvalley.service.ai.ChatUtil;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
@Slf4j
@Service
public class LarkUtil {
// SDK 使用文档:https://open.feishu.cn/document/uAjLw4CM/ukTMukTMukTM/server-side-sdk/java-sdk-guide/preparations
// 复制该 Demo 后, 需要将 "YOUR_APP_ID", "YOUR_APP_SECRET" 替换为自己应用的 APP_ID, APP_SECRET.
// 以下示例代码默认根据文档示例值填充,如果存在代码问题,请在 API 调试台填上相关必要参数后再复制代码使用
@Resource
private ChatUtil chatUtil;
/**
* 发送简单的文本消息
* @param content 发送的内容
* @throws Exception 异常
*/
public static void sendText(String content) throws Exception {
// 构建client
Client client = Client.newBuilder(LarkConstant.APP_ID, LarkConstant.APP_SECRET).build();
// 组装文本 JSON
ObjectMapper mapper = new ObjectMapper();
ObjectNode node = mapper.createObjectNode();
node.put("text", content);
log.info("[Lark] 发送消息:{}", node.toString());
// 创建请求对象
CreateMessageReq req = CreateMessageReq.newBuilder()
.receiveIdType("open_id")
.createMessageReqBody(CreateMessageReqBody.newBuilder()
.receiveId(LarkConstant.USER_OPEN_ID)
.msgType("text")
.content(node.toString())
.uuid(IdUtil.randomUUID())
.build())
.build();
// 发起请求
CreateMessageResp resp = client.im().v1().message().create(req);
// 处理服务端错误
if(!resp.success()) {
System.out.println(String.format("code:%s,msg:%s,reqId:%s, resp:%s",
resp.getCode(), resp.getMsg(), resp.getRequestId(), Jsons.createGSON(true, false).toJson(JsonParser.parseString(new String(resp.getRawResponse().getBody(), StandardCharsets.UTF_8)))));
return;
}
// 业务数据处理
System.out.println(Jsons.DEFAULT.toJson(resp.getData()));
}
public void sendWeatherCard(Weather weather) throws Exception {
// 构建client
Client client = Client.newBuilder(LarkConstant.APP_ID, LarkConstant.APP_SECRET).build();
// 生成uuid
String uuid = IdUtil.randomUUID().toString();
// 卡片参数
// String textParam = JSONUtil.toJsonStr(weather);
// log.info(textParam);
// 构建卡片:对于不同的卡片,只需要给出不同的 模板id 版本号 变量字段
String content = chatUtil.doChat(BackGroundConstant.BACKGROUND_WEATHER, weather.toString());
weather.setContent(content);
log.info("[LarkUtil] Set Content via LLM: {}", content);
Map<String, Object> templateData = new HashMap<>();
templateData.put("template_id", CardTemplate.CARD_TEMPLATE_WEATHER.getCardId());
templateData.put("template_version_name", CardTemplate.CARD_TEMPLATE_WEATHER.getVersion());
templateData.put("template_variable", weather);
// String jsonCardContent = Jsons.DEFAULT.toJson(templateData);
Map<String, Object> jsonContent = new HashMap<>();
jsonContent.put("data", templateData);
jsonContent.put("type", "template");
String json = Jsons.DEFAULT.toJson(jsonContent);
log.info(json);
// 创建请求对象
CreateMessageReq req = CreateMessageReq.newBuilder()
.receiveIdType("open_id")
.createMessageReqBody(CreateMessageReqBody.newBuilder()
.receiveId(LarkConstant.USER_OPEN_ID)
.msgType("interactive")
.content(json)
.uuid(uuid)
.build())
.build();
// 发起请求
CreateMessageResp resp = client.im().v1().message().create(req);
// 处理服务端错误
if(!resp.success()) {
System.out.println(String.format("code:%s,msg:%s,reqId:%s, resp:%s",
resp.getCode(), resp.getMsg(), resp.getRequestId(), Jsons.createGSON(true, false).toJson(JsonParser.parseString(new String(resp.getRawResponse().getBody(), StandardCharsets.UTF_8)))));
return;
}
// 业务数据处理
System.out.println(Jsons.DEFAULT.toJson(resp.getData()));
}
public static void sendFarmCard() throws Exception {
// 构建client
Client client = Client.newBuilder(LarkConstant.APP_ID, LarkConstant.APP_SECRET).build();
// 生成uuid
String uuid = IdUtil.randomUUID().toString();
// 卡片参数
// String textParam = JSONUtil.toJsonStr(weather);
// log.info(textParam);
// 构建卡片:对于不同的卡片,只需要给出不同的 模板id 版本号 变量字段
Map<String, Object> templateData = new HashMap<>();
templateData.put("template_id", CardTemplate.CARD_TEMPLATE_FARM.getCardId());
templateData.put("template_version_name", CardTemplate.CARD_TEMPLATE_FARM.getVersion());
// templateData.put("template_variable", "");
// String jsonCardContent = Jsons.DEFAULT.toJson(templateData);
Map<String, Object> jsonContent = new HashMap<>();
jsonContent.put("data", templateData);
jsonContent.put("type", "template");
String json = Jsons.DEFAULT.toJson(jsonContent);
log.info(json);
// 创建请求对象
CreateMessageReq req = CreateMessageReq.newBuilder()
.receiveIdType("open_id")
.createMessageReqBody(CreateMessageReqBody.newBuilder()
.receiveId(LarkConstant.USER_OPEN_ID)
.msgType("interactive")
.content(json)
.uuid(uuid)
.build())
.build();
// 发起请求
CreateMessageResp resp = client.im().v1().message().create(req);
// 处理服务端错误
if(!resp.success()) {
System.out.println(String.format("code:%s,msg:%s,reqId:%s, resp:%s",
resp.getCode(), resp.getMsg(), resp.getRequestId(), Jsons.createGSON(true, false).toJson(JsonParser.parseString(new String(resp.getRawResponse().getBody(), StandardCharsets.UTF_8)))));
return;
}
// 业务数据处理
System.out.println(Jsons.DEFAULT.toJson(resp.getData()));
}
public static void sendFishCard() throws Exception {
// 构建client
Client client = Client.newBuilder(LarkConstant.APP_ID, LarkConstant.APP_SECRET).build();
// 生成uuid
String uuid = IdUtil.randomUUID().toString();
// 卡片参数
// String textParam = JSONUtil.toJsonStr(weather);
// log.info(textParam);
// 构建卡片:对于不同的卡片,只需要给出不同的 模板id 版本号 变量字段
Map<String, Object> templateData = new HashMap<>();
templateData.put("template_id", CardTemplate.CARD_TEMPLATE_FISH.getCardId());
templateData.put("template_version_name", CardTemplate.CARD_TEMPLATE_FISH.getVersion());
// templateData.put("template_variable", "");
// String jsonCardContent = Jsons.DEFAULT.toJson(templateData);
Map<String, Object> jsonContent = new HashMap<>();
jsonContent.put("data", templateData);
jsonContent.put("type", "template");
String json = Jsons.DEFAULT.toJson(jsonContent);
log.info(json);
// 创建请求对象
CreateMessageReq req = CreateMessageReq.newBuilder()
.receiveIdType("open_id")
.createMessageReqBody(CreateMessageReqBody.newBuilder()
.receiveId(LarkConstant.USER_OPEN_ID)
.msgType("interactive")
.content(json)
.uuid(uuid)
.build())
.build();
// 发起请求
CreateMessageResp resp = client.im().v1().message().create(req);
// 处理服务端错误
if(!resp.success()) {
System.out.println(String.format("code:%s,msg:%s,reqId:%s, resp:%s",
resp.getCode(), resp.getMsg(), resp.getRequestId(), Jsons.createGSON(true, false).toJson(JsonParser.parseString(new String(resp.getRawResponse().getBody(), StandardCharsets.UTF_8)))));
return;
}
// 业务数据处理
System.out.println(Jsons.DEFAULT.toJson(resp.getData()));
}
public static void sendMineCard() throws Exception {
// 构建client
Client client = Client.newBuilder(LarkConstant.APP_ID, LarkConstant.APP_SECRET).build();
// 生成uuid
String uuid = IdUtil.randomUUID().toString();
// 卡片参数
// String textParam = JSONUtil.toJsonStr(weather);
// log.info(textParam);
// 构建卡片:对于不同的卡片,只需要给出不同的 模板id 版本号 变量字段
Map<String, Object> templateData = new HashMap<>();
templateData.put("template_id", CardTemplate.CARD_TEMPLATE_MINE.getCardId());
templateData.put("template_version_name", CardTemplate.CARD_TEMPLATE_MINE.getVersion());
// templateData.put("template_variable", "");
// String jsonCardContent = Jsons.DEFAULT.toJson(templateData);
Map<String, Object> jsonContent = new HashMap<>();
jsonContent.put("data", templateData);
jsonContent.put("type", "template");
String json = Jsons.DEFAULT.toJson(jsonContent);
log.info(json);
// 创建请求对象
CreateMessageReq req = CreateMessageReq.newBuilder()
.receiveIdType("open_id")
.createMessageReqBody(CreateMessageReqBody.newBuilder()
.receiveId(LarkConstant.USER_OPEN_ID)
.msgType("interactive")
.content(json)
.uuid(uuid)
.build())
.build();
// 发起请求
CreateMessageResp resp = client.im().v1().message().create(req);
// 处理服务端错误
if(!resp.success()) {
System.out.println(String.format("code:%s,msg:%s,reqId:%s, resp:%s",
resp.getCode(), resp.getMsg(), resp.getRequestId(), Jsons.createGSON(true, false).toJson(JsonParser.parseString(new String(resp.getRawResponse().getBody(), StandardCharsets.UTF_8)))));
return;
}
// 业务数据处理
System.out.println(Jsons.DEFAULT.toJson(resp.getData()));
}
public static void sendHelpCard() throws Exception {
// 构建client
Client client = Client.newBuilder(LarkConstant.APP_ID, LarkConstant.APP_SECRET).build();
// 生成uuid
String uuid = IdUtil.randomUUID().toString();
// 卡片参数
// String textParam = JSONUtil.toJsonStr(weather);
// log.info(textParam);
// 构建卡片:对于不同的卡片,只需要给出不同的 模板id 版本号 变量字段
Map<String, Object> templateData = new HashMap<>();
templateData.put("template_id", CardTemplate.CARD_TEMPLATE_HELP.getCardId());
templateData.put("template_version_name", CardTemplate.CARD_TEMPLATE_HELP.getVersion());
// templateData.put("template_variable", "");
// String jsonCardContent = Jsons.DEFAULT.toJson(templateData);
Map<String, Object> jsonContent = new HashMap<>();
jsonContent.put("data", templateData);
jsonContent.put("type", "template");
String json = Jsons.DEFAULT.toJson(jsonContent);
log.info(json);
// 创建请求对象
CreateMessageReq req = CreateMessageReq.newBuilder()
.receiveIdType("open_id")
.createMessageReqBody(CreateMessageReqBody.newBuilder()
.receiveId(LarkConstant.USER_OPEN_ID)
.msgType("interactive")
.content(json)
.uuid(uuid)
.build())
.build();
// 发起请求
CreateMessageResp resp = client.im().v1().message().create(req);
// 处理服务端错误
if(!resp.success()) {
System.out.println(String.format("code:%s,msg:%s,reqId:%s, resp:%s",
resp.getCode(), resp.getMsg(), resp.getRequestId(), Jsons.createGSON(true, false).toJson(JsonParser.parseString(new String(resp.getRawResponse().getBody(), StandardCharsets.UTF_8)))));
return;
}
// 业务数据处理
System.out.println(Jsons.DEFAULT.toJson(resp.getData()));
}
public static void sendLuckCard() throws Exception {
// 构建client
Client client = Client.newBuilder(LarkConstant.APP_ID, LarkConstant.APP_SECRET).build();
// 生成uuid
String uuid = IdUtil.randomUUID().toString();
// 卡片参数
// String textParam = JSONUtil.toJsonStr(weather);
// log.info(textParam);
// 构建卡片:对于不同的卡片,只需要给出不同的 模板id 版本号 变量字段
Map<String, Object> templateData = new HashMap<>();
templateData.put("template_id", CardTemplate.CARD_TEMPLATE_LUCK.getCardId());
templateData.put("template_version_name", CardTemplate.CARD_TEMPLATE_LUCK.getVersion());
// templateData.put("template_variable", "");
// String jsonCardContent = Jsons.DEFAULT.toJson(templateData);
Map<String, Object> jsonContent = new HashMap<>();
jsonContent.put("data", templateData);
jsonContent.put("type", "template");
String json = Jsons.DEFAULT.toJson(jsonContent);
log.info(json);
// 创建请求对象
CreateMessageReq req = CreateMessageReq.newBuilder()
.receiveIdType("open_id")
.createMessageReqBody(CreateMessageReqBody.newBuilder()
.receiveId(LarkConstant.USER_OPEN_ID)
.msgType("interactive")
.content(json)
.uuid(uuid)
.build())
.build();
// 发起请求
CreateMessageResp resp = client.im().v1().message().create(req);
// 处理服务端错误
if(!resp.success()) {
System.out.println(String.format("code:%s,msg:%s,reqId:%s, resp:%s",
resp.getCode(), resp.getMsg(), resp.getRequestId(), Jsons.createGSON(true, false).toJson(JsonParser.parseString(new String(resp.getRawResponse().getBody(), StandardCharsets.UTF_8)))));
return;
}
// 业务数据处理
System.out.println(Jsons.DEFAULT.toJson(resp.getData()));
}
}
@@ -1,9 +1,12 @@
package com.wonderland.stardewvalley.util;
package com.wonderland.stardewvalley.util.response;
import com.wonderland.stardewvalley.entity.BaseResponse;
import com.wonderland.stardewvalley.exception.ErrorCode;
import com.wonderland.stardewvalley.common.exception.ErrorCode;
/**
* 返回统一的格式
*/
public class ResultUtil {
public static <T> BaseResponse<T> success(T data) {
@@ -0,0 +1,69 @@
package com.wonderland.stardewvalley.util.weather;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.wonderland.stardewvalley.common.constant.CityCode;
import com.wonderland.stardewvalley.entity.game.Weather;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@Service
@Slf4j
public class WeatherUtil {
/**
* 参考文档: https://lbs.amap.com/api/webservice/guide/api/weatherinfo
* URL 格式: https://restapi.amap.com/v3/weather/weatherInfo?parameters
*
*/
private static final String API_BASE_URL = "https://restapi.amap.com/v3/weather/weatherInfo";
private static final String API_SECRET = "d0f5599ac19a5e4553ba68cd1781d2df";
private static String createUrl() {
StringBuffer stringBuffer = new StringBuffer();
String url = stringBuffer
.append(API_BASE_URL)
.append("?key=")
.append(API_SECRET)
.append("&city=")
.append(CityCode.WuHan.getCode())
.append("&extensions=base")
.toString();
log.info("[Weather] URL: {}", url);
return url;
}
public static Weather getWeather() {
String url = createUrl();
String ans = HttpUtil.get(url);
log.info("[Weather] Response: {}", ans);
// TODO 封装为需要的对象
JSONObject obj = JSONUtil.parseObj(ans);
log.info("[Weather] Obj: {}", obj);
// 检查返回状态码
String status = obj.getStr("status");
if (!"1".equals(status)) {
String info = obj.getStr("info", "Unknown Error");
String errorCode = obj.getStr("infocode", "N/A");
log.error("[Weather] Request failed with code: {}, error: {}", errorCode, info);
return null;
}
// 获取天气信息数组
JSONObject weatherData = obj.getJSONArray("lives").getJSONObject(0);
Weather weather = Weather.builder()
.weather(weatherData.getStr("weather"))
.temperature(weatherData.getStr("temperature"))
.windDirection(weatherData.getStr("winddirection"))
.windPower(weatherData.getStr("windpower"))
.reportTime(weatherData.getStr("reporttime"))
.humidity(weatherData.getStr("humidity"))
.build();
log.info("[Weather] Prepared: {}", weather);
return weather;
}
}
@@ -0,0 +1,19 @@
package com.wonderland.stardewvalley.ai;
import com.wonderland.stardewvalley.common.constant.BackGroundConstant;
import com.wonderland.stardewvalley.service.ai.ChatUtil;
import jakarta.annotation.Resource;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class ChatUtilTest {
@Resource
private ChatUtil chatUtil;
@Test
void doChat() {
System.out.println(chatUtil.doChat(BackGroundConstant.BACKGROUND_SPRING + BackGroundConstant.BACKGROUND_SPRING_DESCRIPTION, "根据背景给出春天的特点,不需要输出背景以外的信息"));
}
}
@@ -1,9 +1,18 @@
package com.wonderland.stardewvalley.lark;
import com.wonderland.stardewvalley.entity.game.Weather;
import com.wonderland.stardewvalley.util.weather.WeatherUtil;
import com.wonderland.stardewvalley.util.lark.LarkUtil;
import jakarta.annotation.Resource;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class LarkUtilTest {
@Resource
private LarkUtil larkUtil;
@Test
void sendText() throws Exception {
LarkUtil.sendText("\uD83C\uDF31 在这个名为“如果人生是星露谷”的世界中,玩家扮演的是一位现实世界中的普通人 ,在某种“精神投射”或“虚拟现实”中,进入了一个与《星露谷物语》相似的模拟世界。这个世界并非简单的幻想乡,而是对现实生活的重构与映射 ,玩家通过在现实世界中“种田、打工、探索、运动”等行为,影响游戏中的生活节奏与心理状态。\n" +
@@ -15,4 +24,10 @@ class LarkUtilTest {
"\n" +
"\uD83C\uDF3E 放下城市的喧嚣,放下心里的压力,拿起一杆锄头,和我们一起,去往一个叫“星露谷”的地方吧。");
}
@Test
void sendWeatherCard() throws Exception {
Weather weather = WeatherUtil.getWeather();
larkUtil.sendWeatherCard(weather);
}
}
@@ -0,0 +1,20 @@
package com.wonderland.stardewvalley.util;
import com.wonderland.stardewvalley.entity.game.Weather;
import com.wonderland.stardewvalley.util.weather.WeatherUtil;
import jakarta.annotation.Resource;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class WeatherUtilTest {
@Resource
private WeatherUtil weatherUtil;
@Test
void getWeather() {
Weather weather = weatherUtil.getWeather();
System.out.println(weather);
}
}