diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..a39dcad --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/dataSources.xml b/.idea/dataSources.xml new file mode 100644 index 0000000..2f8893c --- /dev/null +++ b/.idea/dataSources.xml @@ -0,0 +1,12 @@ + + + + + mysql.8 + true + com.mysql.cj.jdbc.Driver + jdbc:mysql://120.26.251.180:3326/vv_assistant + $ProjectFileDir$ + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..aa00ffa --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..1030d73 --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,14 @@ + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000..105ce2d --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..42f83d9 --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Maven__com_vaadin_external_google_android_json_0_0_20131108_vaadin1.xml b/.idea/libraries/Maven__com_vaadin_external_google_android_json_0_0_20131108_vaadin1.xml new file mode 100644 index 0000000..b8581a6 --- /dev/null +++ b/.idea/libraries/Maven__com_vaadin_external_google_android_json_0_0_20131108_vaadin1.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Maven__jakarta_activation_jakarta_activation_api_1_2_2.xml b/.idea/libraries/Maven__jakarta_activation_jakarta_activation_api_1_2_2.xml new file mode 100644 index 0000000..be90656 --- /dev/null +++ b/.idea/libraries/Maven__jakarta_activation_jakarta_activation_api_1_2_2.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Maven__jakarta_annotation_jakarta_annotation_api_1_3_5.xml b/.idea/libraries/Maven__jakarta_annotation_jakarta_annotation_api_1_3_5.xml new file mode 100644 index 0000000..cba9dd2 --- /dev/null +++ b/.idea/libraries/Maven__jakarta_annotation_jakarta_annotation_api_1_3_5.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Maven__jakarta_xml_bind_jakarta_xml_bind_api_2_3_3.xml b/.idea/libraries/Maven__jakarta_xml_bind_jakarta_xml_bind_api_2_3_3.xml new file mode 100644 index 0000000..04213f7 --- /dev/null +++ b/.idea/libraries/Maven__jakarta_xml_bind_jakarta_xml_bind_api_2_3_3.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Maven__org_apache_logging_log4j_log4j_to_slf4j_2_17_2.xml b/.idea/libraries/Maven__org_apache_logging_log4j_log4j_to_slf4j_2_17_2.xml new file mode 100644 index 0000000..a4f1650 --- /dev/null +++ b/.idea/libraries/Maven__org_apache_logging_log4j_log4j_to_slf4j_2_17_2.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Maven__org_apiguardian_apiguardian_api_1_1_2.xml b/.idea/libraries/Maven__org_apiguardian_apiguardian_api_1_1_2.xml new file mode 100644 index 0000000..6ac1c42 --- /dev/null +++ b/.idea/libraries/Maven__org_apiguardian_apiguardian_api_1_1_2.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Maven__org_hamcrest_hamcrest_2_2.xml b/.idea/libraries/Maven__org_hamcrest_hamcrest_2_2.xml new file mode 100644 index 0000000..6b5496f --- /dev/null +++ b/.idea/libraries/Maven__org_hamcrest_hamcrest_2_2.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Maven__org_junit_jupiter_junit_jupiter_5_8_2.xml b/.idea/libraries/Maven__org_junit_jupiter_junit_jupiter_5_8_2.xml new file mode 100644 index 0000000..4f367e7 --- /dev/null +++ b/.idea/libraries/Maven__org_junit_jupiter_junit_jupiter_5_8_2.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Maven__org_junit_jupiter_junit_jupiter_api_5_8_2.xml b/.idea/libraries/Maven__org_junit_jupiter_junit_jupiter_api_5_8_2.xml new file mode 100644 index 0000000..8e50783 --- /dev/null +++ b/.idea/libraries/Maven__org_junit_jupiter_junit_jupiter_api_5_8_2.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Maven__org_junit_jupiter_junit_jupiter_engine_5_8_2.xml b/.idea/libraries/Maven__org_junit_jupiter_junit_jupiter_engine_5_8_2.xml new file mode 100644 index 0000000..fc8291b --- /dev/null +++ b/.idea/libraries/Maven__org_junit_jupiter_junit_jupiter_engine_5_8_2.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Maven__org_junit_jupiter_junit_jupiter_params_5_8_2.xml b/.idea/libraries/Maven__org_junit_jupiter_junit_jupiter_params_5_8_2.xml new file mode 100644 index 0000000..4b3ffb1 --- /dev/null +++ b/.idea/libraries/Maven__org_junit_jupiter_junit_jupiter_params_5_8_2.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Maven__org_junit_platform_junit_platform_commons_1_8_2.xml b/.idea/libraries/Maven__org_junit_platform_junit_platform_commons_1_8_2.xml new file mode 100644 index 0000000..181d095 --- /dev/null +++ b/.idea/libraries/Maven__org_junit_platform_junit_platform_commons_1_8_2.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Maven__org_junit_platform_junit_platform_engine_1_8_2.xml b/.idea/libraries/Maven__org_junit_platform_junit_platform_engine_1_8_2.xml new file mode 100644 index 0000000..5f3aebe --- /dev/null +++ b/.idea/libraries/Maven__org_junit_platform_junit_platform_engine_1_8_2.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Maven__org_objenesis_objenesis_3_2.xml b/.idea/libraries/Maven__org_objenesis_objenesis_3_2.xml new file mode 100644 index 0000000..6613def --- /dev/null +++ b/.idea/libraries/Maven__org_objenesis_objenesis_3_2.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Maven__org_opentest4j_opentest4j_1_2_0.xml b/.idea/libraries/Maven__org_opentest4j_opentest4j_1_2_0.xml new file mode 100644 index 0000000..fbc1b16 --- /dev/null +++ b/.idea/libraries/Maven__org_opentest4j_opentest4j_1_2_0.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Maven__org_skyscreamer_jsonassert_1_5_1.xml b/.idea/libraries/Maven__org_skyscreamer_jsonassert_1_5_1.xml new file mode 100644 index 0000000..56582d6 --- /dev/null +++ b/.idea/libraries/Maven__org_skyscreamer_jsonassert_1_5_1.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Maven__org_slf4j_jul_to_slf4j_1_7_36.xml b/.idea/libraries/Maven__org_slf4j_jul_to_slf4j_1_7_36.xml new file mode 100644 index 0000000..5d5c14b --- /dev/null +++ b/.idea/libraries/Maven__org_slf4j_jul_to_slf4j_1_7_36.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Maven__org_slf4j_slf4j_api_1_7_36.xml b/.idea/libraries/Maven__org_slf4j_slf4j_api_1_7_36.xml new file mode 100644 index 0000000..2d759c1 --- /dev/null +++ b/.idea/libraries/Maven__org_slf4j_slf4j_api_1_7_36.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..c6f03cc --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,12 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml new file mode 100644 index 0000000..2b63946 --- /dev/null +++ b/.idea/uiDesigner.xml @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/vvPkAssistant.iml b/.idea/vvPkAssistant.iml new file mode 100644 index 0000000..d0876a7 --- /dev/null +++ b/.idea/vvPkAssistant.iml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/HELP.md b/HELP.md new file mode 100644 index 0000000..0e0c676 --- /dev/null +++ b/HELP.md @@ -0,0 +1,20 @@ +# Getting Started + +### Reference Documentation + +For further reference, please consider the following sections: + +* [Official Apache Maven documentation](https://maven.apache.org/guides/index.html) +* [Spring Boot Maven Plugin Reference Guide](https://docs.spring.io/spring-boot/docs/2.6.13/maven-plugin/reference/html/) +* [Create an OCI image](https://docs.spring.io/spring-boot/docs/2.6.13/maven-plugin/reference/html/#build-image) +* [Spring Web](https://docs.spring.io/spring-boot/docs/2.6.13/reference/htmlsingle/#web) + +### Guides + +The following guides illustrate how to use some features concretely: + +* [Building a RESTful Web Service](https://spring.io/guides/gs/rest-service/) +* [Serving Web Content with Spring MVC](https://spring.io/guides/gs/serving-web-content/) +* [Building REST services with Spring](https://spring.io/guides/tutorials/rest/) +* [Accessing data with MySQL](https://spring.io/guides/gs/accessing-data-mysql/) + diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..63cf238 --- /dev/null +++ b/pom.xml @@ -0,0 +1,150 @@ + + + 4.0.0 + com.vv.pk.assistant + vvPkAssistant + 0.0.1 + vvPkAssistant + vvPkAssistant + + 1.8 + UTF-8 + UTF-8 + 2.7.12 + + + + org.springframework.boot + spring-boot-starter-web + + + + com.mysql + mysql-connector-j + runtime + + + + org.projectlombok + lombok + true + + + + org.springframework.boot + spring-boot-starter-test + test + + + + ch.qos.logback + logback-classic + 1.2.13 + + + + ch.qos.logback + logback-core + 1.2.13 + + + + + com.baomidou + mybatis-plus-boot-starter + 3.5.6 + + + + org.springframework.boot + spring-boot-configuration-processor + true + + + + com.fasterxml.jackson.core + jackson-core + 2.15.0 + + + + + com.squareup.okhttp3 + okhttp + 4.9.3 + + + + + com.google.code.gson + gson + 2.8.9 + + + + + org.apache.logging.log4j + log4j-api + 2.20.0 + + + + org.apache.logging.log4j + log4j-core + 2.20.0 + + + + + com.qcloud + cos_api + 5.6.227 + + + + + + + org.springframework.boot + spring-boot-dependencies + ${spring-boot.version} + pom + import + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + 1.8 + 1.8 + UTF-8 + + + + org.springframework.boot + spring-boot-maven-plugin + ${spring-boot.version} + + vvpkassistant.Application + false + + + + repackage + + repackage + + + + + + + + diff --git a/src/main/java/vvpkassistant/Anchors/AnchorDao.java b/src/main/java/vvpkassistant/Anchors/AnchorDao.java new file mode 100644 index 0000000..cfa0d9f --- /dev/null +++ b/src/main/java/vvpkassistant/Anchors/AnchorDao.java @@ -0,0 +1,22 @@ +package vvpkassistant.Anchors; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; + +import java.util.List; + +@Mapper +public interface AnchorDao extends BaseMapper { + + // 根据用户id和主播id查询数据 + @Select("select count(*) from anchors where anchor_id = #{anchorId} and create_user_id = #{userId}") + int selectAnchorWithAnchorIdAndUserId(@Param("anchorId") String anchorId, @Param("userId") int userId); + + // 查询属于我的主播列表 + @Select("select * from anchors where create_user_id = #{userId} order by id desc") + List selectMyAnchor(@Param("userId") Integer userId); + + +} diff --git a/src/main/java/vvpkassistant/Anchors/AnchorModel.java b/src/main/java/vvpkassistant/Anchors/AnchorModel.java new file mode 100644 index 0000000..9c0f8ef --- /dev/null +++ b/src/main/java/vvpkassistant/Anchors/AnchorModel.java @@ -0,0 +1,18 @@ +package vvpkassistant.Anchors; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +@Data +@TableName("anchors") +public class AnchorModel { + @TableId(type = IdType.AUTO) + private Integer id; + private String anchorId; // 主播id + private String headerIcon; // 主播头像 + private Integer gender; // 主播性别 + private String country; // 主播国家 + private Integer createUserId; // 创建者的用户id +} diff --git a/src/main/java/vvpkassistant/Anchors/AnchorsController.java b/src/main/java/vvpkassistant/Anchors/AnchorsController.java new file mode 100644 index 0000000..83ca82b --- /dev/null +++ b/src/main/java/vvpkassistant/Anchors/AnchorsController.java @@ -0,0 +1,78 @@ +package vvpkassistant.Anchors; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import vvpkassistant.Data.ResponseData; +import vvpkassistant.Data.ResponseInfo; +import vvpkassistant.pk.PkRecordDao; + +import java.util.List; +import java.util.Map; + +@RestController +@RequestMapping("anchor") +public class AnchorsController { + + @Autowired + private AnchorDao anchorDao; + + @Autowired + private PkRecordDao recordDao; + + // 添加新主播 + @PostMapping("add") + public ResponseData addNewAnchor(@RequestBody AnchorModel model) { + //查询是否存在重复主播 + int r = anchorDao.selectAnchorWithAnchorIdAndUserId(model.getAnchorId(), model.getCreateUserId()); + if (r != 0) { + return ResponseData.error(ResponseInfo.ERROR,"该主播已存在"); + } + int insert = anchorDao.insert(model); + return insert == 1 ? ResponseData.success("") : ResponseData.error(ResponseInfo.ERROR,"添加失败"); + } + + // 查询我的主播列表 + @PostMapping("list") + public ResponseData myAnchorList(@RequestBody Map map) { + Integer userId = map.get("id"); + List anchorModels = anchorDao.selectMyAnchor(userId); + return ResponseData.success(anchorModels); + } + + // 删除我的主播 + @PostMapping("deleteMyAnchor") + public ResponseData deleteMyAnchor(@RequestBody Map map) { + Integer id = map.get("id"); + AnchorModel anchorModel = anchorDao.selectById(id); + try { + String anchorId = anchorModel.getAnchorId(); + // 根据主播id查询该主播是否存在pk记录 + int i = recordDao.existsPkRecordByAnchor(anchorId); + if (i > 0) { + return ResponseData.error(ResponseInfo.ERROR,"该主播已有pk记录。无法删除"); + } + int r = anchorDao.deleteById(id); + return r == 1 ? ResponseData.success("") : ResponseData.error(ResponseInfo.ERROR,null); + } catch (Exception e) { + return ResponseData.error(ResponseInfo.ERROR,"非法数据,操作失败"); + } + } + + // 更新主播信息 + @PostMapping("updateAnchorInfo") + public ResponseData updateAnchorInfo(@RequestBody AnchorModel model) { + // 查询该主播是否存在记录 + int i = recordDao.existsPkRecordByAnchor(model.getAnchorId()); + if (i > 0) { + return ResponseData.error(ResponseInfo.ERROR,"该主播已有pk记录。无法修改信息"); + } + int r = anchorDao.updateById(model); + return r == 1 ? ResponseData.success("") : ResponseData.error(ResponseInfo.ERROR,null); + } + + + +} diff --git a/src/main/java/vvpkassistant/Application.java b/src/main/java/vvpkassistant/Application.java new file mode 100644 index 0000000..8336a0b --- /dev/null +++ b/src/main/java/vvpkassistant/Application.java @@ -0,0 +1,12 @@ +package vvpkassistant; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class Application { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } + +} diff --git a/src/main/java/vvpkassistant/CoinRecords/CoinRecords.java b/src/main/java/vvpkassistant/CoinRecords/CoinRecords.java new file mode 100644 index 0000000..854888e --- /dev/null +++ b/src/main/java/vvpkassistant/CoinRecords/CoinRecords.java @@ -0,0 +1,31 @@ +package vvpkassistant.CoinRecords; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +@Data +@TableName("coin_records") +public class CoinRecords { + + @TableId(type = IdType.AUTO) + private Integer id; // 主键 + private String info; // 具体信息 + private Integer userId; // 用户id + private int time; // 时间 + private Integer number; // 变更数量 + private Integer status; // 0 减少 1 增加 + + + public CoinRecords() {} + + // 遍历构造 + public CoinRecords(String info, Integer userId, Integer number, Integer time, Integer status) { + this.info = info; + this.userId = userId; + this.number = number; + this.time = time; + this.status = status; + } + +} diff --git a/src/main/java/vvpkassistant/CoinRecords/CoinRecordsDao.java b/src/main/java/vvpkassistant/CoinRecords/CoinRecordsDao.java new file mode 100644 index 0000000..8f5a327 --- /dev/null +++ b/src/main/java/vvpkassistant/CoinRecords/CoinRecordsDao.java @@ -0,0 +1,14 @@ +package vvpkassistant.CoinRecords; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; +import java.util.List; + +@Mapper +public interface CoinRecordsDao extends BaseMapper { + + @Select("select * from coin_records where user_id = #{userId} order by id desc limit #{page} , #{size}") + List fetchMyPointsData(@Param("userId") Integer userId, @Param("page") Integer page, @Param("size") Integer size); +} diff --git a/src/main/java/vvpkassistant/Data/ResponseData.java b/src/main/java/vvpkassistant/Data/ResponseData.java new file mode 100644 index 0000000..a4b1c06 --- /dev/null +++ b/src/main/java/vvpkassistant/Data/ResponseData.java @@ -0,0 +1,36 @@ +package vvpkassistant.Data; +import lombok.Data; +import org.springframework.lang.Nullable; + +@Data +public class ResponseData { + + // 状态码 + T data = null; + public String msg; + public Integer code; + + ResponseData() {} + + // 成功的返回方法 + public static ResponseData success(@Nullable T param) { + ResponseInfo info = ResponseInfo.SUCCESS; + ResponseData data = new ResponseData<>(); + data.setData(param); + data.setCode(info.getCode()); + data.setMsg(info.getDesc()); + return data; + } + + // 返回错误的方法 + public static ResponseData error(ResponseInfo info, @Nullable String msg) { + ResponseData data = new ResponseData<>(); + data.msg = msg != null ? msg : info.getDesc(); + data.code = info.getCode(); + data.data = null; + return data; + } + + + +} diff --git a/src/main/java/vvpkassistant/Data/ResponseInfo.java b/src/main/java/vvpkassistant/Data/ResponseInfo.java new file mode 100644 index 0000000..b86a0cc --- /dev/null +++ b/src/main/java/vvpkassistant/Data/ResponseInfo.java @@ -0,0 +1,26 @@ +package vvpkassistant.Data; + +public enum ResponseInfo { + + // 成功 + SUCCESS(200, "操作成功"), + ERROR(1001, "操作失败"); + + private final int code; // 状态码 + private final String desc; // 描述 + + // 构造方法(默认是private) + ResponseInfo(int code, String desc) { + this.code = code; + this.desc = desc; + } + + // Getter方法 + public int getCode() { + return code; + } + + public String getDesc() { + return desc; + } +} diff --git a/src/main/java/vvpkassistant/Data/WxChatParam.java b/src/main/java/vvpkassistant/Data/WxChatParam.java new file mode 100644 index 0000000..6503c85 --- /dev/null +++ b/src/main/java/vvpkassistant/Data/WxChatParam.java @@ -0,0 +1,15 @@ +package vvpkassistant.Data; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +@Data +@Component +@ConfigurationProperties("chat") +public class WxChatParam { + private String appId; + private String appKey; +} + + diff --git a/src/main/java/vvpkassistant/Data/WxParam.java b/src/main/java/vvpkassistant/Data/WxParam.java new file mode 100644 index 0000000..8a9c762 --- /dev/null +++ b/src/main/java/vvpkassistant/Data/WxParam.java @@ -0,0 +1,8 @@ +package vvpkassistant.Data; +import lombok.Data; + +@Data +public class WxParam { + public String appId = "wx0af70c44ad1939e9"; + public String secret = "3c9a1d2cadbb402a5ec935d090695be9"; +} diff --git a/src/main/java/vvpkassistant/FunctionConfig/FunctionConfigController.java b/src/main/java/vvpkassistant/FunctionConfig/FunctionConfigController.java new file mode 100644 index 0000000..b8babc4 --- /dev/null +++ b/src/main/java/vvpkassistant/FunctionConfig/FunctionConfigController.java @@ -0,0 +1,57 @@ +package vvpkassistant.FunctionConfig; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; +import vvpkassistant.Data.ResponseData; +import vvpkassistant.Data.ResponseInfo; + +@RestController +@RequestMapping("config") +public class FunctionConfigController { + + @Autowired + private FunctionConfigMapper configMapper; + + // 获取所有配置 + @GetMapping("getAllConfig") + public ResponseData getAllConfig() { + return ResponseData.success(FunctionConfigHolder.CONFIGS); + } + + // 更新配置项内容 + @PostMapping("updateConfigValue") + public ResponseData updateConfigValue(@RequestBody FunctionConfigModel model) { + // 1. 更新数据库 + configMapper.updateById(model); + // 2. 更新内存 + FunctionConfigHolder.CONFIGS.removeIf(c -> model.getFunctionName().equals(c.getFunctionName())); + FunctionConfigHolder.CONFIGS.add(model); + return ResponseData.success(""); + } + + @PostMapping("add") + public ResponseData addNewConfig(@RequestBody FunctionConfigModel newModel) { + String name = newModel.getFunctionName(); + boolean isDuplicate = FunctionConfigHolder.CONFIGS.stream() + .anyMatch(config -> name.equals(config.getFunctionName())); + if (isDuplicate) { + return ResponseData.error(ResponseInfo.ERROR,"配置名称重复"); + }else { + configMapper.insert(newModel); + FunctionConfigHolder.CONFIGS.add(newModel); + return ResponseData.success(""); + } + } + + @PostMapping("deleteConfigById") + public ResponseData deleteConfigById(@RequestBody FunctionConfigModel model) { + int i = configMapper.deleteById(model); + if (i == 1) { + FunctionConfigHolder.CONFIGS.removeIf(c -> model.getId().equals(c.getId())); + return ResponseData.success(""); + }else { + return ResponseData.error(ResponseInfo.ERROR,null); + } + } + + +} diff --git a/src/main/java/vvpkassistant/FunctionConfig/FunctionConfigHolder.java b/src/main/java/vvpkassistant/FunctionConfig/FunctionConfigHolder.java new file mode 100644 index 0000000..8aabfe7 --- /dev/null +++ b/src/main/java/vvpkassistant/FunctionConfig/FunctionConfigHolder.java @@ -0,0 +1,42 @@ +package vvpkassistant.FunctionConfig; +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.PostConstruct; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; + +@Component +@RequiredArgsConstructor +public class FunctionConfigHolder { + // 线程安全的全局配置容器 + static final List CONFIGS = new CopyOnWriteArrayList<>(); + + @Autowired + private FunctionConfigMapper configMapper; + + /** + * 启动时加载所有配置到内存 + */ + @PostConstruct + public void init() { + List dbConfigs = configMapper.selectList(null); + CONFIGS.clear(); + CONFIGS.addAll(dbConfigs); + System.out.println("已加载 "+CONFIGS.size()+" 条功能配置"); + } + + /** + * 按功能名获取配置值 + */ + public static String getValue(String functionName) { + return CONFIGS.stream() + .filter(c -> functionName.equals(c.getFunctionName())) + .findFirst() + .map(FunctionConfigModel::getFunctionValue) + .orElse(null); + } + +} diff --git a/src/main/java/vvpkassistant/FunctionConfig/FunctionConfigMapper.java b/src/main/java/vvpkassistant/FunctionConfig/FunctionConfigMapper.java new file mode 100644 index 0000000..e5e6401 --- /dev/null +++ b/src/main/java/vvpkassistant/FunctionConfig/FunctionConfigMapper.java @@ -0,0 +1,10 @@ +package vvpkassistant.FunctionConfig; + + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface FunctionConfigMapper extends BaseMapper { + +} diff --git a/src/main/java/vvpkassistant/FunctionConfig/FunctionConfigModel.java b/src/main/java/vvpkassistant/FunctionConfig/FunctionConfigModel.java new file mode 100644 index 0000000..925a7fc --- /dev/null +++ b/src/main/java/vvpkassistant/FunctionConfig/FunctionConfigModel.java @@ -0,0 +1,15 @@ +package vvpkassistant.FunctionConfig; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +@Data +@TableName("function_configuration") +public class FunctionConfigModel { + @TableId(type = IdType.AUTO) + private Integer id; // 主键 + private String functionName; // 功能名称 + private String functionValue; // 设置的值 +} diff --git a/src/main/java/vvpkassistant/SystemMessage/SystemMessage.java b/src/main/java/vvpkassistant/SystemMessage/SystemMessage.java new file mode 100644 index 0000000..4dd7082 --- /dev/null +++ b/src/main/java/vvpkassistant/SystemMessage/SystemMessage.java @@ -0,0 +1,14 @@ +package vvpkassistant.SystemMessage; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import lombok.Data; + +@Data +public class SystemMessage { + @TableId(type = IdType.AUTO) + private Integer id; // 主键 + private String content; // 内容 + private String title; // 标题 + private String time; // 创建时间 +} diff --git a/src/main/java/vvpkassistant/SystemMessage/SystemMessageController.java b/src/main/java/vvpkassistant/SystemMessage/SystemMessageController.java new file mode 100644 index 0000000..7e90e3e --- /dev/null +++ b/src/main/java/vvpkassistant/SystemMessage/SystemMessageController.java @@ -0,0 +1,49 @@ +package vvpkassistant.SystemMessage; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import vvpkassistant.Data.ResponseData; +import vvpkassistant.Tools.VVTools; + +import java.util.List; +import java.util.Map; + +@RestController +@RequestMapping("systemMessage") +public class SystemMessageController { + + @Autowired + private SystemMessageDao messageDao; + + // 获取列表 + @PostMapping("list") + public ResponseData messageList(@RequestBody Map map) { + Integer page = map.get("page"); + Integer size = map.get("size"); + List systemMessages = messageDao.messageList(page * size, size); + return ResponseData.success(systemMessages); + } + + // 增加 + @PostMapping("add") + public ResponseData createNewMessage(@RequestBody SystemMessage message) { + message.setTime(VVTools.getCurrentTime("yyyy-MM-dd HH:mm")); + return ResponseData.success(messageDao.insert(message)); + } + + // 修改 + @PostMapping("update") + public ResponseData updateMessage(@RequestBody SystemMessage message) { + return ResponseData.success(messageDao.updateById(message)); + } + + // 删除 + @PostMapping("delete") + public ResponseData delete(@RequestBody SystemMessage message) { + return ResponseData.success(messageDao.deleteById(message)); + } + +} diff --git a/src/main/java/vvpkassistant/SystemMessage/SystemMessageDao.java b/src/main/java/vvpkassistant/SystemMessage/SystemMessageDao.java new file mode 100644 index 0000000..73e559c --- /dev/null +++ b/src/main/java/vvpkassistant/SystemMessage/SystemMessageDao.java @@ -0,0 +1,18 @@ +package vvpkassistant.SystemMessage; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; + +import java.util.List; + +@Mapper +public interface SystemMessageDao extends BaseMapper { + + // 查询消息列表 + @Select("select * from system_message order by id desc limit #{page} , #{size}") + List messageList(@Param("page")Integer page, @Param("size") Integer size); + + +} diff --git a/src/main/java/vvpkassistant/Tools/COSSigner.java b/src/main/java/vvpkassistant/Tools/COSSigner.java new file mode 100644 index 0000000..bfb19f3 --- /dev/null +++ b/src/main/java/vvpkassistant/Tools/COSSigner.java @@ -0,0 +1,276 @@ +package vvpkassistant.Tools;/* + * Copyright 2010-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + + * According to cos feature, we modify some class,comment, field name, etc. + */ + + +import static com.qcloud.cos.auth.COSSignerConstants.LINE_SEPARATOR; +import static com.qcloud.cos.auth.COSSignerConstants.Q_AK; +import static com.qcloud.cos.auth.COSSignerConstants.Q_HEADER_LIST; +import static com.qcloud.cos.auth.COSSignerConstants.Q_KEY_TIME; +import static com.qcloud.cos.auth.COSSignerConstants.Q_SIGNATURE; +import static com.qcloud.cos.auth.COSSignerConstants.Q_SIGN_ALGORITHM_KEY; +import static com.qcloud.cos.auth.COSSignerConstants.Q_SIGN_ALGORITHM_VALUE; +import static com.qcloud.cos.auth.COSSignerConstants.Q_SIGN_TIME; +import static com.qcloud.cos.auth.COSSignerConstants.Q_URL_PARAM_LIST; + +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.TreeMap; + +import com.qcloud.cos.Headers; +import com.qcloud.cos.auth.AnonymousCOSCredentials; +import com.qcloud.cos.auth.COSCredentials; +import com.qcloud.cos.auth.COSSessionCredentials; +import com.qcloud.cos.exception.CosClientException; +import com.qcloud.cos.http.CosHttpRequest; +import com.qcloud.cos.http.HttpMethodName; +import com.qcloud.cos.internal.CosServiceRequest; +import com.qcloud.cos.utils.UrlEncoderUtils; + +import org.apache.commons.codec.digest.DigestUtils; +import org.apache.commons.codec.digest.HmacUtils; + +public class COSSigner { + private static Set needSignedHeaderSet = new HashSet<>(); + private Boolean isCIWorkflowRequest = false; + // Time offset between local and server + private int localTimeDelta = 0; + static { + needSignedHeaderSet.add("cache-control"); + needSignedHeaderSet.add("content-disposition"); + needSignedHeaderSet.add("content-encoding"); + needSignedHeaderSet.add("content-length"); + needSignedHeaderSet.add("content-md5"); + needSignedHeaderSet.add("content-type"); + needSignedHeaderSet.add("expect"); + needSignedHeaderSet.add("expires"); + needSignedHeaderSet.add("host"); + needSignedHeaderSet.add("if-match"); + needSignedHeaderSet.add("if-modified-since"); + needSignedHeaderSet.add("if-none-match"); + needSignedHeaderSet.add("if-unmodified-since"); + needSignedHeaderSet.add("origin"); + needSignedHeaderSet.add("range"); + needSignedHeaderSet.add("transfer-encoding"); + needSignedHeaderSet.add(Headers.PIC_OPERATIONS.toLowerCase()); + } + + private boolean isAnonymous(COSCredentials cred) { + return cred instanceof AnonymousCOSCredentials; + } + + public void sign(CosHttpRequest request, COSCredentials cred, Date expiredTime) { + if (isAnonymous(cred)) { + return; + } + + String authoriationStr = + buildAuthorizationStr(request.getHttpMethod(), request.getResourcePath(), + request.getHeaders(), request.getParameters(), cred, expiredTime, true); + + request.addHeader(Headers.COS_AUTHORIZATION, authoriationStr); + if (cred instanceof COSSessionCredentials) { + request.addHeader(Headers.SECURITY_TOKEN, + ((COSSessionCredentials) cred).getSessionToken()); + } + } + + public String buildPostObjectSignature(String secretKey, String keyTime, String policy) { + String signKey = HmacUtils.hmacSha1Hex(secretKey, keyTime); + String stringToSign = DigestUtils.sha1Hex(policy); + return HmacUtils.hmacSha1Hex(signKey, stringToSign); + } + + public String buildAuthorizationStr(HttpMethodName methodName, String resouce_path, + COSCredentials cred, + Date expiredTime) { + Date startTime = new Date(); + return buildAuthorizationStr(methodName, resouce_path, new HashMap<>(), new HashMap<>(), cred, startTime, expiredTime, true); + } + + public String buildAuthorizationStr(HttpMethodName methodName, String resouce_path, + Map headerMap, Map paramMap, COSCredentials cred, + Date expiredTime) { + Date startTime = new Date(); + return buildAuthorizationStr(methodName, resouce_path, headerMap, paramMap, + cred, startTime, expiredTime,true); + } + + public String buildAuthorizationStr(HttpMethodName methodName, String resouce_path, + Map headerMap, Map paramMap, COSCredentials cred, + Date expiredTime, Boolean signHost) { + Date startTime = new Date(); + return buildAuthorizationStr(methodName, resouce_path, headerMap, paramMap, + cred, startTime, expiredTime, signHost); + } + + public String buildAuthorizationStr(HttpMethodName methodName, String resouce_path, + Map headerMap, Map paramMap, COSCredentials cred, + Date startTime, Date expiredTime, Boolean signHost) { + if (isAnonymous(cred)) { + return null; + } + //万象工作流接口会出现uri带问号的情况 例如 /workflow/xxxxxx?active 这种情况?后面的参数不参与鉴权 + if (isCIWorkflowRequest){ + resouce_path = resouce_path.split("\\?")[0]; + } + + Map signHeaders = buildSignHeaders(headerMap, signHost); + // 签名中的参数和http 头部 都要进行字符串排序 + //对请求中的参数和http头部进行处理:对key先urlencode再小写处理,对value进行urlencode处理; + //生成 key 到 value 的映射 Map,根据key按照字典序排序 + TreeMap encodedSortedSignHeaders = buildEncodeSortedMemberMap(signHeaders); + TreeMap encodedSortedParams = buildEncodeSortedMemberMap(paramMap); + + //生成keylist + String qHeaderListStr = buildSignMemberStr(encodedSortedSignHeaders); + String qUrlParamListStr = buildSignMemberStr(encodedSortedParams); + + String qKeyTimeStr, qSignTimeStr; + qKeyTimeStr = qSignTimeStr = buildTimeStr(startTime, expiredTime); + String signKey = HmacUtils.hmacSha1Hex(cred.getCOSSecretKey(), qKeyTimeStr); + String formatMethod = methodName.toString().toLowerCase(); + String formatUri = resouce_path; + String formatParameters = formatMapToStr(encodedSortedParams); + String formatHeaders = formatMapToStr(encodedSortedSignHeaders); + + String formatStr = new StringBuilder().append(formatMethod).append(LINE_SEPARATOR) + .append(formatUri).append(LINE_SEPARATOR).append(formatParameters) + .append(LINE_SEPARATOR).append(formatHeaders).append(LINE_SEPARATOR).toString(); + String hashFormatStr = DigestUtils.sha1Hex(formatStr); + String stringToSign = new StringBuilder().append(Q_SIGN_ALGORITHM_VALUE) + .append(LINE_SEPARATOR).append(qSignTimeStr).append(LINE_SEPARATOR) + .append(hashFormatStr).append(LINE_SEPARATOR).toString(); + String signature = HmacUtils.hmacSha1Hex(signKey, stringToSign); + + String authoriationStr = new StringBuilder().append(Q_SIGN_ALGORITHM_KEY).append("=") + .append(Q_SIGN_ALGORITHM_VALUE).append("&").append(Q_AK).append("=") + .append(cred.getCOSAccessKeyId()).append("&").append(Q_SIGN_TIME).append("=") + .append(qSignTimeStr).append("&").append(Q_KEY_TIME).append("=").append(qKeyTimeStr) + .append("&").append(Q_HEADER_LIST).append("=").append(qHeaderListStr).append("&") + .append(Q_URL_PARAM_LIST).append("=").append(qUrlParamListStr).append("&") + .append(Q_SIGNATURE).append("=").append(signature).toString(); + return authoriationStr; + } + + public boolean needSignedHeader(String header) { + return needSignedHeaderSet.contains(header) || header.startsWith("x-cos-"); + } + + private Map buildSignHeaders(Map originHeaders, Boolean signHost) { + Boolean hasHost = false; + Map signHeaders = new HashMap<>(); + for (Entry headerEntry : originHeaders.entrySet()) { + String key = headerEntry.getKey().toLowerCase(); + + if (key.equals("host")) { + hasHost = true; + } + + if(needSignedHeader(key)) { + String value = headerEntry.getValue(); + signHeaders.put(key, value); + } + } + + if (!hasHost && signHost) { + String msg = String.format("buildAuthorization missing header: host. %s", originHeaders); + throw new CosClientException(msg); + } + + return signHeaders; + } + + private TreeMap buildEncodeSortedMemberMap(Map signElements){ + TreeMap encodeSortedSignElements = new TreeMap<>(); + + for (Entry header : signElements.entrySet()) { + if (header.getKey() == null) { + continue; + } + String encodeLowerKey = UrlEncoderUtils.encode(header.getKey().trim()).toLowerCase(); + String value = ""; + if (header.getValue()!=null){ + value = header.getValue().trim(); + } + String encodeValue = UrlEncoderUtils.encode(value); + encodeSortedSignElements.put(encodeLowerKey, encodeValue); + } + return encodeSortedSignElements; + } + + private String buildSignMemberStr(Map signHeaders) { + StringBuilder strBuilder = new StringBuilder(); + boolean seenOne = false; + for (String key : signHeaders.keySet()) { + if (!seenOne) { + seenOne = true; + } else { + strBuilder.append(";"); + } + strBuilder.append(key); + } + return strBuilder.toString(); + } + + private String formatMapToStr(Map kVMap) { + StringBuilder strBuilder = new StringBuilder(); + boolean seeOne = false; + for (Entry entry : kVMap.entrySet()) { + String key = entry.getKey(); + String value = entry.getValue(); + if (!seeOne) { + seeOne = true; + } else { + strBuilder.append("&"); + } + strBuilder.append(key).append("=").append(value); + } + return strBuilder.toString(); + } + + private String buildTimeStr(Date startTime, Date endTime) { + StringBuilder strBuilder = new StringBuilder(); + long startTimestamp = startTime.getTime() / 1000 + localTimeDelta; + long endTimestamp = endTime.getTime() / 1000 + localTimeDelta; + strBuilder.append(startTimestamp).append(";").append(endTimestamp); + return strBuilder.toString(); + } + + public static Set getNeedSignedHeaderSet() { + return needSignedHeaderSet; + } + + public static void setNeedSignedHeaderSet(Set needSignedHeaderSet) { + COSSigner.needSignedHeaderSet = needSignedHeaderSet; + } + + public void setCIWorkflowRequest(Boolean CIRequest) { + isCIWorkflowRequest = CIRequest; + } + + public int getLocalTimeDelta() { + return localTimeDelta; + } + + public void setLocalTimeDelta(int localTimeDelta) { + this.localTimeDelta = localTimeDelta; + } +} \ No newline at end of file diff --git a/src/main/java/vvpkassistant/Tools/LogUtil.java b/src/main/java/vvpkassistant/Tools/LogUtil.java new file mode 100644 index 0000000..b6cad23 --- /dev/null +++ b/src/main/java/vvpkassistant/Tools/LogUtil.java @@ -0,0 +1,38 @@ +package vvpkassistant.Tools; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +public class LogUtil { + // 获取 Logger 实例 + private static final Logger logger = LogManager.getLogger(LogUtil.class); + + // 封装不同级别的日志方法 + public static void trace(String message) { + logger.trace(message); + } + + public static void debug(String message) { + logger.debug(message); + } + + public static void info(String message) { + logger.info(message); + } + + public static void warn(String message) { + logger.warn(message); + } + + public static void error(String message) { + logger.error(message); + } + + public static void fatal(String message) { + logger.fatal(message); + } + + // 记录异常信息 + public static void error(String message, Throwable throwable) { + logger.error(message, throwable); + } +} diff --git a/src/main/java/vvpkassistant/Tools/OkHttpUtils.java b/src/main/java/vvpkassistant/Tools/OkHttpUtils.java new file mode 100644 index 0000000..87148f5 --- /dev/null +++ b/src/main/java/vvpkassistant/Tools/OkHttpUtils.java @@ -0,0 +1,151 @@ +package vvpkassistant.Tools; + +import com.google.gson.Gson; +import okhttp3.*; +import org.springframework.lang.Nullable; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +/** + * OkHttp + Gson 封装工具类 + * 功能: + * 1. 支持 GET/POST 请求 + * 2. 自动处理 JSON 转换(请求和响应) + * 3. 支持 Form 表单和 JSON Body 传参 + * 4. 可自定义超时时间和请求头 + */ +public class OkHttpUtils { + private static final OkHttpClient client; + private static final Gson gson = new Gson(); + private static final MediaType JSON = MediaType.parse("application/json; charset=utf-8"); + + // 初始化 OkHttpClient(可自定义超时时间) + static { + client = new OkHttpClient.Builder() + .connectTimeout(10, TimeUnit.SECONDS) // 连接超时 + .readTimeout(10, TimeUnit.SECONDS) // 读取超时 + .build(); + } + + // ------------------- GET 请求 ------------------- + /** + * GET 请求(返回字符串) + */ + public static String get(String url, Map params, Map headers) throws IOException { + Request request = buildGetRequest(url, params, headers); + return executeRequest(request); + } + + /** + * GET 请求(直接返回 Java 对象) + */ + public static T get(String url, Map params, Map headers, @Nullable Class clazz) throws IOException { + String json = get(url, params, headers); + return gson.fromJson(json, clazz); + } + + // ------------------- POST 请求 ------------------- + /** + * POST 请求(支持 Form 表单或 JSON Body,返回字符串) + * + * @param url 请求地址 + * @param data 请求数据(Map 或其他对象) + * @param headers 请求头 + * @param isForm 是否为 Form 表单提交 + * @return 响应字符串 + */ + public static String post(String url, Object data, Map headers, boolean isForm) throws IOException { + Request request = buildPostRequest(url, data, headers, isForm); + return executeRequest(request); + } + + /** + * POST 请求(直接返回 Java 对象) + * + * @param url 请求地址 + * @param data 请求数据(Map 或其他对象) + * @param headers 请求头 + * @param isForm 是否为 Form 表单提交 + * @param clazz 返回的对象类型 + * @return 响应的 Java 对象 + */ + public static T post(String url, Object data, Map headers, boolean isForm, Class clazz) throws IOException { + String json = post(url, data, headers, isForm); + return gson.fromJson(json, clazz); + } + + // ------------------- 私有方法 ------------------- + // 构建 GET 请求 + private static Request buildGetRequest(String url, Map params, Map headers) { + HttpUrl.Builder urlBuilder = HttpUrl.parse(url).newBuilder(); + if (params != null) { + params.forEach(urlBuilder::addQueryParameter); + } + Request.Builder builder = new Request.Builder().url(urlBuilder.build()); + addHeaders(builder, headers); + return builder.build(); + } + + // 构建 POST 请求 + private static Request buildPostRequest(String url, Object data, Map headers, boolean isForm) { + RequestBody requestBody; + + if (isForm) { + // Form 表单提交 + if (!(data instanceof Map)) { + throw new IllegalArgumentException("Form data must be of type Map"); + } + FormBody.Builder formBuilder = new FormBody.Builder(); + ((Map) data).forEach(formBuilder::add); + requestBody = formBuilder.build(); + + // 设置默认的 Content-Type 为 application/x-www-form-urlencoded + if (headers == null) { + headers = new HashMap<>(); // 初始化为空的 HashMap + headers.put("Content-Type", "application/x-www-form-urlencoded"); + } else if (!headers.containsKey("Content-Type")) { + headers.put("Content-Type", "application/x-www-form-urlencoded"); + } + } else { + // JSON Body 提交 + String json = gson.toJson(data); + requestBody = RequestBody.create(json, JSON); + + // 设置默认的 Content-Type 为 application/json + if (headers == null) { + headers = new HashMap<>(); // 初始化为空的 HashMap + headers.put("Content-Type", "application/json"); + } else if (!headers.containsKey("Content-Type")) { + headers.put("Content-Type", "application/json"); + } + } + + Request.Builder builder = new Request.Builder().url(url).post(requestBody); + addHeaders(builder, headers); + return builder.build(); + } + + // 添加请求头 + private static void addHeaders(Request.Builder builder, Map headers) { + if (headers != null) { + headers.forEach(builder::addHeader); + } + } + + // 执行请求并返回响应字符串 + private static String executeRequest(Request request) throws IOException { + try (Response response = client.newCall(request).execute()) { + if (!response.isSuccessful()) { + throw new IOException("Request failed: " + response.code() + ", " + response.message()); + } + ResponseBody responseBody = response.body(); + if (responseBody == null) { + throw new IOException("Response body is null"); + } + return responseBody.string(); + } + } +} diff --git a/src/main/java/vvpkassistant/Tools/VVRequester.java b/src/main/java/vvpkassistant/Tools/VVRequester.java new file mode 100644 index 0000000..47a644d --- /dev/null +++ b/src/main/java/vvpkassistant/Tools/VVRequester.java @@ -0,0 +1,194 @@ +package vvpkassistant.Tools; + +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.google.gson.reflect.TypeToken; +import lombok.SneakyThrows; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import vvpkassistant.Data.WxChatParam; +import vvpkassistant.Data.WxParam; +import vvpkassistant.User.UserModel; + +import java.io.BufferedReader; +import java.io.DataOutputStream; +import java.io.InputStreamReader; +import java.lang.reflect.Type; +import java.net.HttpURLConnection; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.util.*; +import java.util.Map; + +// 请求接口类 +@Component +public class VVRequester { + +// @Autowired +// private WxChatParam wxChatParam; + + // 登录小程序 + @SneakyThrows + public Map loginApp(String code) { + WxParam wx = new WxParam(); + Map requestMap = new HashMap<>(); + requestMap.put("appid",wx.getAppId()); + requestMap.put("secret", wx.getSecret()); + requestMap.put("js_code", code); + requestMap.put("grant_type", "authorization_code"); + Map data = OkHttpUtils.get("https://api.weixin.qq.com/sns/jscode2session",requestMap, null, Map.class); + return data; + } + + // 获取accessToken + @SneakyThrows + private String getAccessToken() { + WxParam wx = new WxParam(); + String requestUrl = "https://api.weixin.qq.com/cgi-bin/token"; + Map requestParam = new HashMap<>(); + requestParam.put("grant_type","client_credential"); + requestParam.put("appid",wx.getAppId()); + requestParam.put("secret",wx.getSecret()); + + Map result = OkHttpUtils.get(requestUrl, requestParam, null, Map.class); + String access_token = result.get("access_token").toString(); + return access_token; + } + + // 查询手机号 + @SneakyThrows + public String queryPhoneNumber(String code) { + + String requestUrl = "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=" + getAccessToken(); + Map param = new HashMap<>(); + param.put("code",code); + + // 将 Map 转换为 JSON 字符串 + Gson gson = new Gson(); + String jsonParam = gson.toJson(param); + + // 使用 OkHttpUtils 发送 POST 请求 + Map result = requestWeChatApi(requestUrl,"POST", jsonParam); + String phoneNumber = ""; + if (result.containsKey("phone_info")) { + String jsonString = new Gson().toJson(result); + JsonObject jsonObject = JsonParser.parseString(jsonString).getAsJsonObject(); + phoneNumber = jsonObject.getAsJsonObject("phone_info").get("phoneNumber").getAsString(); + } + return phoneNumber; + } + + + // 创建聊天账号 +// @SneakyThrows +// public Integer createChatAccount(UserModel userModel , String usersig) { +// long number = randomNumber(); +// +// String requestUrl = "https://console.tim.qq.com/v4/im_open_login_svc/account_import?sdkappid=" + wxChatParam.getAppId() + "&identifier=administrator&usersig=" + usersig + "&random=" + number + "&contenttype=json"; +// +// // 设置头像 +// String icon = "https://vv-1317974657.cos.ap-shanghai.myqcloud.com/headerIcon/" + userModel.getHeaderIcon(); +// +// Map requestParam = new HashMap<>(); +// requestParam.put("UserID",String.valueOf(userModel.getId())); +// requestParam.put("Nick",userModel.getNickName()); +// requestParam.put("FaceUrl",icon); +// +// Map result = OkHttpUtils.post(requestUrl,requestParam,null,false, Map.class); +// Integer errorCode = Integer.valueOf(result.get("ErrorCode").toString().split("\\.")[0]); +// System.out.println(result); +// return errorCode; +// } + + // 更新聊天账号的昵称和头像 +// @SneakyThrows +// public Integer updateChatAccountInfo(Map map) { +// +// Map param = new HashMap<>(); +// param.put("From_Account",map.get("id").toString()); +// List> list = new ArrayList<>(); +// +// Map nickNameMap = new HashMap<>(); +// nickNameMap.put("Tag","Tag_Profile_IM_Nick"); +// nickNameMap.put("value", map.get("nickName").toString()); +// +// Map imageMap = new HashMap<>(); +// imageMap.put("Tag","Tag_Profile_IM_Image"); +// imageMap.put("value", map.get("icon").toString()); +// +// list.add(nickNameMap); +// list.add(imageMap); +// param.put("ProfileItem", list); +// +// String userSig = map.get("usersig").toString(); +// +// long number = randomNumber(); +// +// String requestUrl = "https://console.tim.qq.com/v4/profile/portrait_set?sdkappid=" + wxChatParam.getAppId() + "&identifier=administrator&usersig=" + userSig + "&random=" + number + "&contenttype=json"; +// +// Map result = OkHttpUtils.post(requestUrl, param, null, false, Map.class); +// +// Integer errorCode = Integer.valueOf(result.get("ErrorCode").toString().split("\\.")[0]); +// return errorCode; +// } + + // 获取一个32位的无符号整数 + private long randomNumber() { + return (long) (Math.random() * (4294967295L + 1)); // 生成 0 到 4294967295 范围的随机数 + } + + + //请求微信API + public Map requestWeChatApi(String requestUrl, String method, String postParams) { + try { + URL url = new URL(requestUrl); + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + + // 根据方法类型设置属性 + if ("POST".equalsIgnoreCase(method)) { + conn.setRequestMethod("POST"); + // 设置请求头,假设我们发送的是表单数据 + conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded; application/json;"); + conn.setDoOutput(true); // 需要输出 + + // 写入参数 + try (DataOutputStream wr = new DataOutputStream(conn.getOutputStream())) { + if (postParams != null) { + wr.write(postParams.getBytes(StandardCharsets.UTF_8)); + wr.flush(); + } + } + } else { // 对于其他请求方法,如GET + conn.setRequestMethod(method); + } + + int responseCode = conn.getResponseCode(); + + if (responseCode == HttpURLConnection.HTTP_OK) { + BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream())); + String inputLine; + StringBuilder response = new StringBuilder(); + + while ((inputLine = in.readLine()) != null) { + response.append(inputLine); + } + in.close(); + + String keyValuePairs = response.toString(); + Gson gson = new Gson(); + JsonObject jsonObject = gson.fromJson(keyValuePairs, JsonObject.class); + + Type mapType = new TypeToken>(){}.getType(); + Map map = gson.fromJson(jsonObject, mapType); + return map; + } else { + System.out.println(method + " request not worked"); + } + } catch (Exception e) { + e.printStackTrace(); + } + return new HashMap<>(); + } + +} diff --git a/src/main/java/vvpkassistant/Tools/VVTools.java b/src/main/java/vvpkassistant/Tools/VVTools.java new file mode 100644 index 0000000..db45ec7 --- /dev/null +++ b/src/main/java/vvpkassistant/Tools/VVTools.java @@ -0,0 +1,128 @@ +package vvpkassistant.Tools; + +import lombok.Data; + +import java.time.Instant; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.util.Arrays; +import java.util.Calendar; +import java.util.HashMap; +import java.util.Map; + +/************************ + * 工具类 * + ************************/ +public class VVTools { + + // 获取当前时间戳 + public static long currentTimeStamp() { + long timeStamp = Calendar.getInstance().getTimeInMillis() / 1000; + return timeStamp; + } + + // 查询当天所有的 + public static Map startAndEndTimeStampForToday() { + // 获取当前日期(不含时间) + LocalDate today = LocalDate.now(); + + // 当天的 00:00:00 + LocalDateTime startOfDay = today.atStartOfDay(); + long startTimestamp = startOfDay.atZone(ZoneId.systemDefault()).toEpochSecond(); + + // 当天的 23:59:59 + LocalDateTime endOfDay = today.atTime(23, 59, 59); + long endTimestamp = endOfDay.atZone(ZoneId.systemDefault()).toEpochSecond(); + + Map result = new HashMap<>(); + result.put("start",startTimestamp); + result.put("end", endTimestamp); + return result; + } + + /** + * 获取当前时间字符串 + * @param pattern 时间格式 + * @return 返回当前时间 + */ + public static String getCurrentTime(String pattern) { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern); + return LocalDateTime.now().format(formatter); + } + + /** + * 替换替换字符串 + * @param wordA 原文本 + * @param wordB 需要替换的文本 + */ + public static String replaceChar(String wordA, char wordB) { + + if (wordA == null || wordA.length() <= 2) { + return wordA; // 如果字符串太短(<=2个字符),直接返回 + } + + char[] chars = wordA.toCharArray(); + Arrays.fill(chars, 1, chars.length - 1, wordB); + return new String(chars); + } + + + /** + * 判断时间戳是否在当天内(基于系统默认时区) + * @param timestamp 毫秒级时间戳 + * @return true-在当天内,false-不在当天内 + */ + public static boolean isTimestampInToday(long timestamp) { + // 1. 获取当前时间戳对应的日期(系统默认时区) + LocalDate today = LocalDate.now(); + + // 2. 将目标时间戳转为日期(同一时区) + LocalDate targetDate = Instant.ofEpochMilli(timestamp) + .atZone(ZoneId.systemDefault()) + .toLocalDate(); + + // 3. 比较日期是否相同 + return targetDate.isEqual(today); + } + + // 根据传入的时间戳。计算出当天的开始时间和结束时间的时间戳 + public static Map getDayStartAndEndTimestamp(long timestamp) { + // 将10位时间戳转换为LocalDateTime + Instant instant = Instant.ofEpochSecond(timestamp); + LocalDateTime dateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault()); + + // 获取当天的LocalDate + LocalDate date = dateTime.toLocalDate(); + + // 计算当天的开始时间(00:00:00) + LocalDateTime startOfDay = date.atStartOfDay(); + long startTimestamp = startOfDay.atZone(ZoneId.systemDefault()).toEpochSecond(); + + // 计算当天的结束时间(23:59:59) + LocalDateTime endOfDay = date.atTime(23, 59, 59); + long endTimestamp = endOfDay.atZone(ZoneId.systemDefault()).toEpochSecond(); + + // 创建并返回Map + Map result = new HashMap<>(); + result.put("start", startTimestamp); + result.put("end", endTimestamp); + + return result; + } + + + // 计算两个时间戳之间的小时数量 + public static long calculateHoursRound(long expireTime, long currentTime) { + if (expireTime <= currentTime) return 0; + long diffSeconds = expireTime - currentTime; + return diffSeconds / 3600; + } + + // 返还积分用(不足1小时忽略) + public static long calculateHoursFloor(long expireTime, long currentTime) { + if (expireTime <= currentTime) return 0; + return (expireTime - currentTime) / 3600; + } +} diff --git a/src/main/java/vvpkassistant/Tools/WebMvcConfig.java b/src/main/java/vvpkassistant/Tools/WebMvcConfig.java new file mode 100644 index 0000000..9ec2cc5 --- /dev/null +++ b/src/main/java/vvpkassistant/Tools/WebMvcConfig.java @@ -0,0 +1,17 @@ +package vvpkassistant.Tools; + +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.CorsRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +@Configuration +public class WebMvcConfig implements WebMvcConfigurer { + @Override + public void addCorsMappings(CorsRegistry registry) { + registry.addMapping("/**") // 所有接口 + .allowedOrigins("*") // 允许所有来源 + .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") // 允许的HTTP方法 + .allowedHeaders("*") // 允许所有头 + .maxAge(3600); // 预检请求缓存时间 + } +} \ No newline at end of file diff --git a/src/main/java/vvpkassistant/User/UserController.java b/src/main/java/vvpkassistant/User/UserController.java new file mode 100644 index 0000000..52f1336 --- /dev/null +++ b/src/main/java/vvpkassistant/User/UserController.java @@ -0,0 +1,363 @@ +package vvpkassistant.User; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; +import vvpkassistant.CoinRecords.CoinRecords; +import vvpkassistant.CoinRecords.CoinRecordsDao; +import vvpkassistant.Data.ResponseData; +import vvpkassistant.Data.ResponseInfo; +import vvpkassistant.Data.WxChatParam; +import vvpkassistant.FunctionConfig.FunctionConfigHolder; +import vvpkassistant.Tools.VVRequester; +import vvpkassistant.Tools.VVTools; +import vvpkassistant.pk.PkInfoDao; +import vvpkassistant.pk.PkInfoModel; +import vvpkassistant.pk.PkRecordDetail; +import vvpkassistant.pk.PkRecordDetailDao; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@RestController +@RequestMapping("user") +public class UserController { + + @Autowired + private UserDao userDao; + + @Autowired + private PkInfoDao pkInfoDao; + + @Autowired + private PkRecordDetailDao detailDao; + + @Autowired + private CoinRecordsDao coinRecordsDao; + + @Autowired + private WxChatParam wxChatParam; + + @Autowired + private VVRequester vvRequester; + + // 配置用户信息 + @PostMapping("inputUserInfo") + public ResponseData inputUserInfo(@RequestBody Map param) { + + if (!param.containsKey("code")) { + return ResponseData.error(ResponseInfo.ERROR, "code不能为空"); + } + + if (!param.containsKey("id")) { + return ResponseData.error(ResponseInfo.ERROR, "id不能为空"); + } + + //获取前端传递过来的code + String code = param.get("code").toString(); + + // 调用微信获取openid接口 + Map wx_result = vvRequester.loginApp(code); + + // 错误处理 + if (wx_result.containsKey("errcode")) { + Integer errcode = Integer.valueOf(wx_result.get("errcode").toString()); + + if (errcode == 45011) { + return ResponseData.error(ResponseInfo.ERROR, "API 调用太频繁,请稍候再试。"); + } + + if (errcode == 40029) { + return ResponseData.error(ResponseInfo.ERROR, "js_code 无效"); + } + + if (errcode == 40226) { + return ResponseData.error(ResponseInfo.ERROR, "该账号为风险用户。禁止登录小程序"); + } + + if (errcode == -1) { + return ResponseData.error(ResponseInfo.ERROR, "系统繁忙"); + } + + if (!wx_result.containsKey("openid")) { + return ResponseData.error(ResponseInfo.ERROR, "获取用户信息失败,请稍后再试。"); + } + } + + //查询用户 + String openId = wx_result.get("openid").toString(); + String sessionKey = wx_result.get("session_key").toString(); + + // 创建一个临时model + UserModel tempModel = new UserModel(); + tempModel.setId(Integer.valueOf(param.get("id").toString())); + tempModel.setOpenid(openId); + tempModel.setHeaderIcon(param.get("headerIcon").toString()); + tempModel.setNickName(param.get("nickName").toString()); + tempModel.setSessionKey(sessionKey); + tempModel.setUserChatId(openId); + int i = userDao.updateById(tempModel); + if (i == 1) { +// String usersig = param.get("usersig").toString(); +// // 注册聊天账号 +// Integer createAccountResult = vvRequester.createChatAccount(tempModel, usersig); +// if (createAccountResult != 0) { +// return ResponseData.error(ResponseInfo.ERROR,"创建聊天账号失败,请稍后再试"); +// } + Map result = new HashMap<>(); + result.put("info", tempModel); + result.put("newAccount",false); + //否则直接返回用户 + return ResponseData.success(result); + } + + return ResponseData.error(ResponseInfo.ERROR,"未知错误"); + } + + // 手机号登录 / 注册 + @PostMapping("loginWithPhoneNumber") + public ResponseData loginWithPhoneNumber(@RequestBody Map param) { + + if (!param.containsKey("code")) { + return ResponseData.error(ResponseInfo.ERROR,"code不能为空"); + } + + String code = param.get("code").toString(); + String phoneNumber = vvRequester.queryPhoneNumber(code); + + if (phoneNumber.isEmpty()) { + return ResponseData.error(ResponseInfo.ERROR,"手机号码无法查询"); + } + + // 查询是否存在用户。如果用户存在直接返回 如果用户不存在则新建用户 + UserModel model = userDao.queryWithPhoneNumber(phoneNumber); + Map result = new HashMap<>(); + if (model != null) { // 老用户 + result.put("info",model); + result.put("newAccount", false); + result.put("chatInfo",wxChatParam); + return ResponseData.success(result); + }else{ // 新用户 + UserModel tempModel = new UserModel(); + tempModel.setPhoneNumber(phoneNumber); + tempModel.setCreateTime(VVTools.currentTimeStamp()); + //设置状态为正常 + tempModel.setStatus(0); + //设置积分为0 + tempModel.setPoints(0); + userDao.insert(tempModel); + + // 判断用户是否为邀请用户 + if (param.containsKey("inviterId")) { + int inviterId = (int) param.get("inviterId"); + // 查询用户增加积分 + UserModel oldUser = userDao.selectById(inviterId); + oldUser.setPoints(oldUser.getPoints() + 10); + userDao.updateById(oldUser); + } + + result.put("info",tempModel); + result.put("newAccount",true); + result.put("chatInfo",wxChatParam); + return ResponseData.success(result); + + } + + } + + // 修改用户信息 + @PostMapping("updateUserInfo") + public ResponseData updateUserInfo(@RequestBody Map map) { + UserModel userModel = new UserModel(); + //设置用户id + userModel.setId(Integer.valueOf(map.get("id").toString())); + //设置用户头像 + userModel.setHeaderIcon(map.get("headerIcon").toString()); + //设置用户昵称 + userModel.setNickName(map.get("nickName").toString()); + + int i = userDao.updateById(userModel); + // 返回结果 + Map result = new HashMap<>(); + result.put("info", userDao.selectById(map.get("id").toString())); + result.put("newAccount", false); + return i == 1 ? ResponseData.success(result) : ResponseData.error(ResponseInfo.ERROR, ""); + } + + // 获取用户信息 + @PostMapping("getUserInfo") + public ResponseData getUserInfo(@RequestBody Map map) { + UserModel userModel = userDao.selectById(map.get("id")); + return ResponseData.success(userModel); + } + + // 查询用户所有pk数据 + @PostMapping("queryMyAllPkData") + public ResponseData queryMyAllPkData(@RequestBody Map map) { + Integer userId = map.get("userId"); + Integer page = map.get("page"); + Integer size = map.get("size"); + List pkInfoModels = pkInfoDao.queryAllPkData(userId, page * size, size); + long currentTimeStamp = VVTools.currentTimeStamp(); + // 查找置顶的数据 + for (PkInfoModel pkInfoModel : pkInfoModels) { + pkInfoModel.setIsPin(pkInfoModel.getPinExpireTime() > currentTimeStamp); + } + return ResponseData.success(pkInfoModels); + } + + // 查询我的pk记录 列表 + @PostMapping("handlePkInfo") + public ResponseData handlePkInfo(@RequestBody Map map) { + Integer type = map.get("type"); + Integer id = map.get("userId"); + Integer page = map.get("page"); + Integer size = map.get("size"); + + // 我发起的pk数据 + if (type == 1) { + return ResponseData.success(userDao.findCreatedPk(id, page * size, size)); + }else if (type == 2){ + // 别人邀请我的pk数据 + return ResponseData.success(userDao.getMyGuestPkList(id, page * size, size)); + } + return ResponseData.error(ResponseInfo.ERROR,"未知错误"); + } + + + // 查詢单条pk记录详情 + @PostMapping("pkRecordDetail") + public ResponseData pkRecordDetail(@RequestBody Map map) { + Integer id = map.get("id"); + List pkRecordDetails = detailDao.queryDetail(id); + return ResponseData.success(pkRecordDetails); + } + + // 签到 + @PostMapping("signIn") + public ResponseData signIn(@RequestBody Map map) { + Integer userId = map.get("userId"); + int i = userDao.checkSignStatus(userId); + if (i != 0) { + return ResponseData.error(ResponseInfo.ERROR,"当天已签到"); + } + + int result = userDao.signIn(userId); + UserModel userModel = userDao.selectById(userId); + int count = Integer.parseInt(FunctionConfigHolder.getValue("签到增加积分")); + + // 增加积分 + userModel.setPoints(userModel.getPoints() + count); + + // 入库 + userDao.updateById(userModel); + + if (result == 1) { + // 增加记录 + CoinRecords coinRecords = new CoinRecords("签到增加积分",userId,count, (int) VVTools.currentTimeStamp(),1); + coinRecordsDao.insert(coinRecords); + return ResponseData.success(null); + }else { + return ResponseData.error(ResponseInfo.ERROR,null); + } + } + + // 查询用户当天签到状态 + @GetMapping("checkSignStatus") + public ResponseData checkSignStatus(Integer userId) { + int i = userDao.checkSignStatus(userId); + return i == 0 ? ResponseData.success(true) : ResponseData.success(false); + } + + // 置顶文章 + @PostMapping("pinToTop") + public ResponseData pinToTop(@RequestBody Map map) { + // 文章id + Integer articleId = map.get("articleId"); + PkInfoModel pkInfoModel = pkInfoDao.selectById(articleId); + Integer userId = pkInfoModel.getSenderId(); + // 到期时间戳 + Integer pinExpireTime = map.get("pinExpireTime"); + + long currentTimeStamp = VVTools.currentTimeStamp(); + long hour = VVTools.calculateHoursRound(pinExpireTime, currentTimeStamp); + String coin = FunctionConfigHolder.getValue("置顶扣除积分"); + int totalCoin = (int) (Integer.parseInt(coin) * hour); + + UserModel userModel = userDao.selectById(userId); + if (userModel != null) { + // 扣除积分 更新数据 + Integer points = userModel.getPoints(); + if (points - totalCoin > 0) { + userModel.setPoints(userModel.getPoints() - totalCoin); + userDao.updateById(userModel); + // 设置置顶到期时间 + pkInfoModel.setPinExpireTime(pinExpireTime); + // 设置创建置顶的时间 + pkInfoModel.setPinCreateTime((int) VVTools.currentTimeStamp()); + // 更新pk文章数据 + int i = pkInfoDao.updateById(pkInfoModel); + if (i == 1) { + String info = String.format("置顶成功,扣除%d积分",totalCoin); + // 增加积分变动记录 + CoinRecords coinRecords = new CoinRecords("置顶扣除积分",userId,totalCoin, (int) VVTools.currentTimeStamp(),0); + coinRecordsDao.insert(coinRecords); + // 返回给前端数据 + return ResponseData.success(info); + }else { + return ResponseData.error(ResponseInfo.ERROR,null); + } + }else { + return ResponseData.error(ResponseInfo.ERROR,String.format("积分不足,需要%d积分",totalCoin)); + } + }else { + return ResponseData.error(ResponseInfo.ERROR,"用户不存在"); + } + } + + // 取消置顶 + @PostMapping("cancelPin") + public ResponseData cancelPin(@RequestBody Map map) { + Integer articleId = map.get("articleId"); + PkInfoModel pkInfoModel = pkInfoDao.selectById(articleId); + Integer pinExpireTime = pkInfoModel.getPinExpireTime(); + long hour = VVTools.calculateHoursFloor(pinExpireTime, VVTools.currentTimeStamp()); + + String coin = FunctionConfigHolder.getValue("置顶扣除积分"); + // 计算总积分。用于返还给用户 + int totalCoin = (int) (Integer.parseInt(coin) * hour); + + // 获取用户对象 + UserModel userModel = userDao.selectById(pkInfoModel.getSenderId()); + Integer points = userModel.getPoints(); + // 返还用户积分 + userModel.setPoints(points + totalCoin); + // 更新数据库 + userDao.updateById(userModel); + + // 重置置顶时间 + pkInfoModel.setPinExpireTime(0); + pkInfoModel.setPinCreateTime(0); + int i = pkInfoDao.updateById(pkInfoModel); + if (i == 1) { + // 添加积分更变相关记录 + CoinRecords coinRecords = new CoinRecords("取消置顶返还积分",pkInfoModel.getSenderId(),totalCoin, (int) VVTools.currentTimeStamp(),1); + coinRecordsDao.insert(coinRecords); + return ResponseData.success(String.format("操作成功,返还%d积分",totalCoin)); + }else { + return ResponseData.error(ResponseInfo.ERROR,null); + } + + } + + + // 获取积分明细 + @PostMapping("pointsDetail") + public ResponseData pointsDetail(@RequestBody Map map) { + Integer userId = map.get("userId"); + Integer page = map.get("page"); + Integer size = map.get("size"); + List coinRecords = coinRecordsDao.fetchMyPointsData(userId, page * size, size); + return ResponseData.success(coinRecords); + } + + +} diff --git a/src/main/java/vvpkassistant/User/UserDao.java b/src/main/java/vvpkassistant/User/UserDao.java new file mode 100644 index 0000000..a349b18 --- /dev/null +++ b/src/main/java/vvpkassistant/User/UserDao.java @@ -0,0 +1,34 @@ +package vvpkassistant.User; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Insert; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; +import vvpkassistant.pk.PkRecord; +import java.util.List; + +@Mapper +public interface UserDao extends BaseMapper { + + // 根据用户的手机号查询用户 + @Select("SELECT * FROM `user` WHERE phone_number = #{phoneNumber}") + UserModel queryWithPhoneNumber(@Param("phoneNumber") String phoneNumber); + + // 我邀请的pk数据 + @Select("SELECT * FROM pk_record WHERE user_id_b = #{userId} ORDER BY id DESC LIMIT #{page}, #{size};") + List getMyGuestPkList(@Param("userId") Integer userId , @Param("page") Integer page, @Param("size") Integer size); + + // 我发起的pk数据 + @Select("SELECT * FROM pk_record WHERE user_id_a = #{userId} ORDER BY id DESC LIMIT #{page}, #{size};") + List findCreatedPk(@Param("userId") Integer userId , @Param("page") Integer page, @Param("size") Integer size); + + // 签到 + @Insert("insert into `sign_in_records` set user_id = #{userId} , time = replace(current_date, '-', '')") + int signIn(@Param("userId") int userId); + + // 查询当天签到状态 + @Select("SELECT COUNT(*) FROM `sign_in_records` WHERE user_id = #{userId} AND time = REPLACE(CURDATE(), '-', '')") + int checkSignStatus(@Param("userId") int userId); + +} diff --git a/src/main/java/vvpkassistant/User/UserModel.java b/src/main/java/vvpkassistant/User/UserModel.java new file mode 100644 index 0000000..71fa030 --- /dev/null +++ b/src/main/java/vvpkassistant/User/UserModel.java @@ -0,0 +1,23 @@ +package vvpkassistant.User; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +@Data +@TableName("user") +public class UserModel { + @TableId(type = IdType.AUTO) + private Integer id; // 主键 + private String nickName; // 昵称 + private String phoneNumber; // 手机号码 + private String headerIcon; // 头像 + private String openid; // openid + private String sessionKey; // session key + private Integer status; // 用户状态 0 正常 其他业务逻辑待定 + private Long createTime; // 创建时间 + private String userChatId; // 聊天使用的id,使用微信的openid作为标识 + private Integer points; // 用户积分 + private Integer inviterId; // 邀请人id +} diff --git a/src/main/java/vvpkassistant/chat/ChatController.java b/src/main/java/vvpkassistant/chat/ChatController.java new file mode 100644 index 0000000..47fb51d --- /dev/null +++ b/src/main/java/vvpkassistant/chat/ChatController.java @@ -0,0 +1,43 @@ +package vvpkassistant.chat; + + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; +import vvpkassistant.Data.ResponseData; +import vvpkassistant.Data.ResponseInfo; + +import java.util.HashMap; +import java.util.Map; + +@RestController +@RequestMapping("chat") +public class ChatController { + + @Autowired + private ChatDao chatDao; + + //插入数据 + @PostMapping("add") + public ResponseData add(@RequestBody ChatModel model) { + int insert = chatDao.insert(model); + return insert == 1 ? ResponseData.success("") : ResponseData.error(ResponseInfo.ERROR,null); + } + + //根据ip查询数据 + @PostMapping("fetchWithKeyId") + public ResponseData query(@RequestBody ChatModel model) { + ChatModel chatModel = chatDao.selectModelWithKeyId(model.getKeyId()); + return ResponseData.success(chatModel); + } + + //接收im消息 + @PostMapping("receiveImMessage") + public Map receiveImMessage(@RequestBody Map data) { + System.out.println(data); + Map result = new HashMap<>(); + result.put("code",200); + result.put("content","success"); + return result; + } + +} diff --git a/src/main/java/vvpkassistant/chat/ChatDao.java b/src/main/java/vvpkassistant/chat/ChatDao.java new file mode 100644 index 0000000..638a983 --- /dev/null +++ b/src/main/java/vvpkassistant/chat/ChatDao.java @@ -0,0 +1,16 @@ +package vvpkassistant.chat; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; + +@Mapper +public interface ChatDao extends BaseMapper { + + // 根据key_id 查询数据 + @Select("select * from pk_chat where key_id = #{keyId}") + ChatModel selectModelWithKeyId(@Param("keyId") String keyId); + + +} diff --git a/src/main/java/vvpkassistant/chat/ChatModel.java b/src/main/java/vvpkassistant/chat/ChatModel.java new file mode 100644 index 0000000..935ab5a --- /dev/null +++ b/src/main/java/vvpkassistant/chat/ChatModel.java @@ -0,0 +1,17 @@ +package vvpkassistant.chat; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +@Data +@TableName("pk_chat") +public class ChatModel { + + @TableId(type = IdType.AUTO) + private Integer id; // 主键 + private String messageInfo; // 消息内容 + private String keyId; // 消息唯一id + +} diff --git a/src/main/java/vvpkassistant/pk/PkController.java b/src/main/java/vvpkassistant/pk/PkController.java new file mode 100644 index 0000000..c1a2c49 --- /dev/null +++ b/src/main/java/vvpkassistant/pk/PkController.java @@ -0,0 +1,326 @@ +package vvpkassistant.pk; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; +import vvpkassistant.CoinRecords.CoinRecords; +import vvpkassistant.CoinRecords.CoinRecordsDao; +import vvpkassistant.Data.ResponseData; +import vvpkassistant.Data.ResponseInfo; +import vvpkassistant.FunctionConfig.FunctionConfigHolder; +import vvpkassistant.Tools.VVTools; +import vvpkassistant.User.UserDao; +import vvpkassistant.User.UserModel; + +import java.util.List; +import java.util.Map; + + +@RestController +@RequestMapping("pk") +public class PkController { + + @Autowired + private PkInfoDao pkDao; + + @Autowired + private PkRecordDao recordDao; + + @Autowired + private PkRecordDetailDao detailDao; + + @Autowired + private UserDao userDao; + + @Autowired + private CoinRecordsDao coinRecordsDao; + + // 创建pk数据 + @PostMapping("addPkData") + public ResponseData addPkData(@RequestBody PkInfoModel pkModel) { + + // 初始可邀请状态为0 + pkModel.setInviteStatus(0); + pkModel.setPinExpireTime(0); + + // 获取主播id + String anchorId = pkModel.getAnchorId(); + // 查询当天是否存在该主播发布的pk信息。 + Integer pkTime = pkModel.getPkTime(); + + // 根据设置的pk时间。查询出当天的开始时间和结束时间 + Map dayStartAndEndTimestamp = VVTools.getDayStartAndEndTimestamp(pkTime); + + Long start = dayStartAndEndTimestamp.get("start"); + Long end = dayStartAndEndTimestamp.get("end"); + + // 查询主播在当天是否有发布过pk信息 + List pkInfoModels = pkDao.selectDataWithAnchorIdAndTime(anchorId, start, end); + + // 判断该主播在当日是否已发布过pk信息 + if (pkInfoModels.size() > 0) { + return ResponseData.error(ResponseInfo.ERROR,"该主播当日已有pk信息"); + } + + int insert = pkDao.insert(pkModel); + return insert == 1 ? ResponseData.success(pkModel) : ResponseData.error(ResponseInfo.ERROR,null); + } + + // 更新pk信息 + @PostMapping("updatePkStatus") + public ResponseData updatePkStatus(@RequestBody PkRecord recordModel) { + + //如果是同意了pk邀请、则更新已发布的主播pk可邀请状态 + if (recordModel.getPkStatus() == 1) { + + // 查询出记录信息 + PkRecord pkRecordById = recordDao.singleRecord(recordModel.getId()); + + // 更新可邀请状态 + PkInfoModel pkInfoModelA = pkDao.selectById(pkRecordById.getPkIdA()); + pkInfoModelA.setInviteStatus(1); + + PkInfoModel pkInfoModelB = pkDao.selectById(pkRecordById.getPkIdB()); + pkInfoModelB.setInviteStatus(1); + + pkDao.updateById(pkInfoModelA); + pkDao.updateById(pkInfoModelB); + + // 如果有置顶的状态。需要取消置顶 + if (pkInfoModelA.getPinExpireTime() > VVTools.currentTimeStamp()) { + long hour = VVTools.calculateHoursFloor(pkInfoModelA.getPinExpireTime(),VVTools.currentTimeStamp()); + int coin = Integer.parseInt(FunctionConfigHolder.getValue("置顶扣除积分")); + int totalCoin = (int) (coin * hour); + + // 插入记录 + CoinRecords coinRecords = new CoinRecords("成功预约pk,自动取消置顶", pkInfoModelA.getSenderId(),totalCoin, (int) VVTools.currentTimeStamp(),1); + coinRecordsDao.insert(coinRecords); + + // 更新积分 + UserModel userModel = userDao.selectById(pkRecordById.getUserIdA()); + Integer points = userModel.getPoints(); + userModel.setPoints(points + totalCoin); + } + + if (pkInfoModelB.getPinExpireTime() > VVTools.currentTimeStamp()) { + long hour = VVTools.calculateHoursFloor(pkInfoModelB.getPinExpireTime(),VVTools.currentTimeStamp()); + int coin = Integer.parseInt(FunctionConfigHolder.getValue("置顶扣除积分")); + int totalCoin = (int) (coin * hour); + + // 插入记录 + CoinRecords coinRecords = new CoinRecords("成功预约pk,自动取消置顶", pkInfoModelB.getSenderId(),totalCoin, (int) VVTools.currentTimeStamp(),1); + coinRecordsDao.insert(coinRecords); + + // 更新积分 + UserModel userModel = userDao.selectById(pkRecordById.getUserIdB()); + Integer points = userModel.getPoints(); + userModel.setPoints(points + totalCoin); + } + } + + // 更新pk邀请记录 + int update = recordDao.updateById(recordModel); + return update == 1 ? ResponseData.success("") : ResponseData.error(ResponseInfo.ERROR,null); + } + + // 创建PK记录 + @PostMapping("createPkRecord") + public ResponseData createPkRecord(@RequestBody PkRecord record) { + + // 如果这两个邀约直播之间存在未处理的邀请记录。那就不允许继续发送pk邀请 + String anchorIdA = record.getAnchorIdA(); + String anchorIdB = record.getAnchorIdB(); + Integer dataCount = recordDao.getPendingInvitations(anchorIdA, anchorIdB); + + if (dataCount > 0) { + return ResponseData.error(ResponseInfo.ERROR,"已存在一条未处理的pk申请,不能重复发送,"); + } + + record.setPkStatus(0); + int insert = recordDao.insert(record); + return insert == 1 ? ResponseData.success(record) : ResponseData.error(ResponseInfo.ERROR,null); + } + + // pk列表 + @PostMapping("pkList") + public ResponseData pkList(@RequestBody Map map) { + + Integer page = (Integer) map.get("page"); + Integer size = (Integer) map.get("size"); + Map condition = (Map) map.get("condition"); + + Map todayTimeStampMap = VVTools.startAndEndTimeStampForToday(); + Long start = VVTools.currentTimeStamp(); + Long end = todayTimeStampMap.get("end"); + + List pkModels = pkDao.selectPkInfoByCondition(page * size, size, condition, start, end); + + long currentTimeStamp = VVTools.currentTimeStamp(); + + //如果传了用户id + if (map.containsKey("userId")) { + Long begin = VVTools.currentTimeStamp(); + Integer userId = Integer.valueOf(map.get("userId").toString()); + // 查询出当前用户大于等于今天的已接受邀请的pk数据 + List pkRecords = recordDao.fetchDataFromTodayWithUserId(userId, begin); + // 遍历查询出的数据。如果文章的id相同。就显示完整的主播名称, + for (PkInfoModel pkModel : pkModels) { + pkModel.setDisPlayId(pkModel.getAnchorId()); + // 设置是否为置顶 + pkModel.setIsPin(pkModel.getPinExpireTime() > currentTimeStamp); + // 如果文章的发布者不是当前登录主播。 + if (pkModel.getSenderId().intValue() != userId) { + boolean showId = false; + // 查找是否和当前登录的账号有pk关系。 + for (PkRecord pkRecord : pkRecords) { + // 如果当前用户是邀请pk的,并且对方已接受pk,也可以看到主播id + if (pkRecord.getUserIdB().intValue() == userId && + pkRecord.getPkIdA().intValue() == pkModel.getId().intValue() && + pkRecord.getPkStatus() == 1) { + showId = true; + break; + } + } + // 条件不满足则隐藏主播id' + if (!showId) { + pkModel.setDisPlayId(VVTools.replaceChar(pkModel.getAnchorId(), '*')); + } + } + } + }else{ + for (PkInfoModel pkModel : pkModels) { + // 设置是否为置顶 + pkModel.setIsPin(pkModel.getPinExpireTime() > currentTimeStamp); + pkModel.setDisPlayId(VVTools.replaceChar(pkModel.getAnchorId(), '*')); + } + } + + return ResponseData.success(pkModels); + } + + // 查询用户发布的大于当前时间的pk数据 + @PostMapping("queryMyCanUsePkData") + public ResponseData queryMyCanUsePkData(@RequestBody Map map) { + Long time = VVTools.currentTimeStamp(); + Integer userId = (Integer) map.get("userId"); + List pkModels = pkDao.queryCanUseData(userId, time); + return ResponseData.success(pkModels); + } + + //pk文章详情 + @PostMapping("pkInfoDetail") + public ResponseData pkInfoDetail(@RequestBody Map map) { + Integer id = map.get("id"); + Integer userId = map.get("userId"); + Integer from = map.get("from"); // 1 首页 2 聊天 + + PkInfoModel pkInfoModel = pkDao.selectById(id); + if (pkInfoModel == null) { + return ResponseData.error(ResponseInfo.ERROR,"该信息不存在"); + } + + if (from == 1) { + if (pkInfoModel.getPkTime() > VVTools.currentTimeStamp()) { + // 判断是否是自己发布的数据 如果不是,就隐藏主播id + if (pkInfoModel.getSenderId().equals(userId)) { + pkInfoModel.setDisPlayId(pkInfoModel.getAnchorId()); + } else { + // 查询是否存在未完成的pk记录 + Integer isHave = pkDao.checkIfUnfinishedPKExistsWithAnchor(userId, pkInfoModel.getAnchorId()); + if (isHave > 0) { + pkInfoModel.setDisPlayId(pkInfoModel.getAnchorId()); + }else { + pkInfoModel.setDisPlayId(VVTools.replaceChar(pkInfoModel.getAnchorId(), '*')); + } + } + return ResponseData.success(pkInfoModel); + }else { + return ResponseData.error(ResponseInfo.ERROR,"当前信息已无效"); + } + }else{ + Integer isHave = pkDao.checkIfUnfinishedPKExistsWithAnchor(userId, pkInfoModel.getAnchorId()); + if (isHave > 0) { + pkInfoModel.setDisPlayId(pkInfoModel.getAnchorId()); + }else { + pkInfoModel.setDisPlayId(VVTools.replaceChar(pkInfoModel.getAnchorId(), '*')); + } + return ResponseData.success(pkInfoModel); + } + } + + //删除自己的pk数据 (单个) + @PostMapping("deletePkDataWithId") + public ResponseData deletePkDataWithId(@RequestBody Map map) { + Integer id = map.get("id"); + PkInfoModel pkInfoModel = pkDao.selectById(id); + + if (pkInfoModel.getPinExpireTime() > VVTools.currentTimeStamp()) { + return ResponseData.error(ResponseInfo.ERROR,"该信息在置顶中。如要删除清先取消置顶"); + } + + Integer result = pkDao.deletePkDataWithId(id); + return result == 1 ? ResponseData.success("") : ResponseData.error(ResponseInfo.ERROR,"删除数据失败"); + } + + //修改pk信息内容 + @PostMapping("updatePkInfoById") + public ResponseData updatePkInfoById(@RequestBody PkInfoModel infoModel) { + int result = pkDao.updateById(infoModel); + return result == 1 ? ResponseData.success("") : ResponseData.error(ResponseInfo.ERROR,null); + } + + // 根据id查询pk记录 + @PostMapping("singleRecord") + public ResponseData singleRecord(@RequestBody PkRecord record) { + PkRecord data = recordDao.singleRecord(record.getId()); + return ResponseData.success(data); + } + + // 查询pk中每个场次的详细数据 + @PostMapping("fetchDetailPkDataWithId") + public ResponseData fetchDetailPkDataWithId(@RequestBody Map map) { + Integer id = map.get("id"); + List pkRecordDetails = recordDao.fetchDetailPkDataWithId(id); + return ResponseData.success(pkRecordDetails); + } + + // 根据用户id查询该用户已发布的未被邀请的主播列表 + @PostMapping("listUninvitedPublishedAnchorsByUserId") + public ResponseData listUninvitedPublishedAnchorsByUserId(@RequestBody Map map) { + Integer userId = map.get("userId"); + List pkInfoModels = pkDao.listUninvitedPublishedAnchorsByUserId(userId); + for (PkInfoModel pkInfoModel : pkInfoModels) { + pkInfoModel.setDisPlayId(VVTools.replaceChar(pkInfoModel.getAnchorId(),'*')); + } + return ResponseData.success(pkInfoModels); + } + + + /************************************************************************************************************************************/ + /** Python 相关接口 */ + /************************************************************************************************************************************/ + // Python那边需要的pk数据 + @PostMapping("pkListForPython") + public ResponseData pkDataListForPython() { + // 获取当日的开始时间和结束时间 + Map timeMap = VVTools.startAndEndTimeStampForToday(); + long start = timeMap.get("start"); + long end = timeMap.get("end"); + List result = recordDao.pkListForToday(start, end); + return ResponseData.success(result); + } + + // 更新pk结果信息 + @PostMapping("updatePkRecordInfo") + public ResponseData updatePkRecordInfo(@RequestBody PkRecord record) { + int i = recordDao.updateById(record); + return i == 1 ? ResponseData.success("") : ResponseData.error(ResponseInfo.ERROR,null); + } + + // 插入pk明细表数据 + @PostMapping("insertPkDetail") + public ResponseData insert(@RequestBody PkRecordDetail detail) { + detail.setCreateTime(VVTools.currentTimeStamp()); + int insert = detailDao.insert(detail); + return insert == 1 ? ResponseData.success("") : ResponseData.error(ResponseInfo.ERROR,null); + } + +} diff --git a/src/main/java/vvpkassistant/pk/PkInfoDao.java b/src/main/java/vvpkassistant/pk/PkInfoDao.java new file mode 100644 index 0000000..768f1ba --- /dev/null +++ b/src/main/java/vvpkassistant/pk/PkInfoDao.java @@ -0,0 +1,77 @@ +package vvpkassistant.pk; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.*; +import org.jetbrains.annotations.Nullable; + +import java.util.List; +import java.util.Map; + +@Mapper +public interface PkInfoDao extends BaseMapper { + + //根据条件筛选pk列表数据 + @Select("") + List selectPkInfoByCondition( + @Param("page") int page, + @Param("size") int size, + @Param("condition") Map condition, + @Param("todayStart") long todayStart, // 当天开始时间戳(00:00:00) + @Param("todayEnd") long todayEnd // 当天结束时间戳(23:59:59) + ); + + // 查询用户发布的大于当前时间的pk数据 + @Select("select * from pk_info where #{userId} = sender_id and #{time} <= pk_time and invite_status = 0;") + List queryCanUseData(@Param("userId") Integer userId , @Param("time") Long time); + + // 查询用户发布的所有pk数据 + @Select("select * from pk_info where sender_id = #{userId} order by id desc limit #{page}, #{size};") + List queryAllPkData(@Param("userId") Integer userId, @Param("page") Integer page, @Param("size") Integer size); + + // 根据id删除pk信息 + @Delete("delete from pk_info where id = #{id}") + Integer deletePkDataWithId(@Param("id") Integer id); + + //查询制定时间范围,制定主播的pk信息 + @Select("select * from pk_info where anchor_id = #{anchorId} and pk_time between #{startTime} and #{endTime}") + List selectDataWithAnchorIdAndTime(@Param("anchorId") String anchorId, @Param("startTime") long startTime , @Param("endTime") long endTime); + + // 置顶和取消置顶 + @Update("update pk_info set pin_expire_time = #{time} where id = #{id}") + int setPinTime(@Param("id") Integer id, @Param("time") @Nullable Integer time); + + // 根据用户id查询该用户已发布的未被邀请的主播列表 + @Select("select * from pk_info where sender_id = #{userId} and invite_status = 0 and pk_time > UNIX_TIMESTAMP();") + List listUninvitedPublishedAnchorsByUserId(@Param("userId") Integer userId); + + // 查询当前用户与该主播是否存在未完成的pk记录 + @Select("SELECT COUNT(*) FROM `pk_record`\n" + + "WHERE (user_id_a = #{userId} OR user_id_b = #{userId})\n" + + "AND (anchor_id_a = #{anchorId} OR anchor_id_b = #{anchorId})\n" + + "AND pk_status = 1\n" + + "AND pk_time > UNIX_TIMESTAMP()") + Integer checkIfUnfinishedPKExistsWithAnchor(@Param("userId") Integer userId, @Param("anchorId") String anchorId); + + +} diff --git a/src/main/java/vvpkassistant/pk/PkInfoModel.java b/src/main/java/vvpkassistant/pk/PkInfoModel.java new file mode 100644 index 0000000..962f715 --- /dev/null +++ b/src/main/java/vvpkassistant/pk/PkInfoModel.java @@ -0,0 +1,31 @@ +package vvpkassistant.pk; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +@Data +@TableName("pk_info") +public class PkInfoModel { + @TableId(type = IdType.AUTO) + private Integer id; // 主键,自动递增 + private String anchorId; // 主播ID + private Integer pkTime; // PK时间 + private String sex; // 性别 1 男 2 女 + private String country; // 国家 + private Integer coin; // 金币 + private String remark; // 描述 + private Integer senderId; // 发布人id + private Integer pkNumber; // pk场次 + private String anchorIcon; // 主播头像 + private Integer inviteStatus; // 可邀请状态 0 未邀请 1 已邀请 + private Integer pinExpireTime; // 文章置顶到期时间 + private Integer pinCreateTime; // 置顶创建时间 + @TableField(exist = false) + private String disPlayId; // 页面上显示的id + @TableField(exist = false) + private Boolean isPin; // 是否在置顶 + +} diff --git a/src/main/java/vvpkassistant/pk/PkRecord.java b/src/main/java/vvpkassistant/pk/PkRecord.java new file mode 100644 index 0000000..2ffa951 --- /dev/null +++ b/src/main/java/vvpkassistant/pk/PkRecord.java @@ -0,0 +1,27 @@ +package vvpkassistant.pk; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import lombok.Data; + +@Data +public class PkRecord { + + @TableId(type = IdType.AUTO) + private Integer id; // 数据库主键 + private Integer pkIdA; // 发起方的pk表id + private Integer pkIdB; // 被邀请方的pk表id + private Integer userIdA; // 发起人的小程序id + private Integer userIdB; // 邀请人的小程序id + private String anchorIdA; // 主播A的id + private String anchorIdB; // 主播B的id + private String anchorIconA; // 主播A的头像 + private String anchorIconB; // 主播B的头像 + private Integer userACoins; // 用户A的金币数量 + private String pkTime; // pk时间 + private Integer userBCoins; // 用户B的金币数量 + private Integer pkNumber; // pk场次 + private Integer winnerId; // 获胜的userid + private String winnerAnchorId; // 获胜主播的Tik Tok id + private Integer pkStatus; // 状态 0 未处理 1 同意 2 拒绝 + +} diff --git a/src/main/java/vvpkassistant/pk/PkRecordDao.java b/src/main/java/vvpkassistant/pk/PkRecordDao.java new file mode 100644 index 0000000..cc2a858 --- /dev/null +++ b/src/main/java/vvpkassistant/pk/PkRecordDao.java @@ -0,0 +1,38 @@ +package vvpkassistant.pk; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; +import java.util.List; + + +@Mapper +public interface PkRecordDao extends BaseMapper { + + // 查询当天所有的pk数据 Python使用 + @Select("SELECT * FROM pk_record WHERE pk_time BETWEEN #{startTime} AND #{endTime} and pk_status = 1;") + List pkListForToday(@Param("startTime") long start, @Param("endTime") long end); + + // 查询大于等于今天的PK记录数据 + @Select("select * from pk_record where (user_id_a = #{userId} or user_id_b = #{userId}) and pk_time >= #{fromTime}") + List fetchDataFromTodayWithUserId(@Param("userId") Integer userId, @Param("fromTime") Long fromTime); + + // 查询是否存在未处理的邀请数据 + @Select("select count(*) from pk_record where anchor_id_a = #{anchorA} and anchor_id_b = #{anchorB} and pk_status = 0") + Integer getPendingInvitations(@Param("anchorA") String anchorA , @Param("anchorB") String anchorB); + + // 根据id查询记录详情 + @Select("select * from pk_record where id = #{id}") + PkRecord singleRecord(@Param("id") Integer id); + + + // 查询每场pk的详细数据 + @Select("select * from pk_record_detail where pk_record_id = #{id}") + List fetchDetailPkDataWithId(@Param("id") Integer id); + + // 查询主播是否存在pk记录 + @Select("select count(*) from pk_record where anchor_id_a = #{id} or anchor_id_b = #{id}") + int existsPkRecordByAnchor(@Param("id") String id); + +} diff --git a/src/main/java/vvpkassistant/pk/PkRecordDetail.java b/src/main/java/vvpkassistant/pk/PkRecordDetail.java new file mode 100644 index 0000000..b7f1f05 --- /dev/null +++ b/src/main/java/vvpkassistant/pk/PkRecordDetail.java @@ -0,0 +1,21 @@ +package vvpkassistant.pk; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import lombok.Data; + +@Data +public class PkRecordDetail { + + @TableId(type = IdType.AUTO) + private Integer id; + private Integer pkRecordId; // 记录表主id + private String winnerAnchorId; // 获胜主播ID + private Integer winnerId; // 胜利方用户id + private String anchorIdA; // 主播A + private Integer anchorCoinA; // 主播A的金币 + private Integer anchorCoinB; + private String anchorIdB; // 主播B + // 主播B的金币 + private Long createTime; // 数据创建时间 + +} diff --git a/src/main/java/vvpkassistant/pk/PkRecordDetailDao.java b/src/main/java/vvpkassistant/pk/PkRecordDetailDao.java new file mode 100644 index 0000000..9aea234 --- /dev/null +++ b/src/main/java/vvpkassistant/pk/PkRecordDetailDao.java @@ -0,0 +1,17 @@ +package vvpkassistant.pk; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; + +import java.util.List; + +@Mapper +public interface PkRecordDetailDao extends BaseMapper { + + // 根据id查询对应的明细数据 + @Select("select * from pk_record_detail where pk_record_id = #{id}") + List queryDetail(@Param("id") Integer id); + +} diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml new file mode 100644 index 0000000..8822912 --- /dev/null +++ b/src/main/resources/application-dev.yml @@ -0,0 +1,14 @@ + + +spring: + datasource: + driver-class-name: com.mysql.cj.jdbc.Driver + username: root + password: wfn53400 + url: jdbc:mysql://mysql.text.zhukeping.com:3326/vv_assistant?allowMultiQueries=true + + + +chat: + appId: 1600092688 + appKey: 9bb6df04907a8cff9292eee8d6b32158d008350198acba11607068d91cb65f66 \ No newline at end of file diff --git a/src/main/resources/application-local.yml b/src/main/resources/application-local.yml new file mode 100644 index 0000000..4b3c730 --- /dev/null +++ b/src/main/resources/application-local.yml @@ -0,0 +1,13 @@ + + +spring: + datasource: + driver-class-name: com.mysql.cj.jdbc.Driver + username: root + password: wfn53400 + url: jdbc:mysql://mysql.text.zhukeping.com:3326/vv_assistant?allowMultiQueries=true + + +chat: + appId: 1600092688 + appKey: 9bb6df04907a8cff9292eee8d6b32158d008350198acba11607068d91cb65f66 \ No newline at end of file diff --git a/src/main/resources/application-prd.yml b/src/main/resources/application-prd.yml new file mode 100644 index 0000000..89e0694 --- /dev/null +++ b/src/main/resources/application-prd.yml @@ -0,0 +1,13 @@ + + +spring: + datasource: + driver-class-name: com.mysql.cj.jdbc.Driver + username: root + password: niu995228 + url: jdbc:mysql://49.235.115.212:3336/vv_assistant + + +chat: + appId: 1600086767 + appKey: 4f240bf11de12b5d8fc596556953f4f732416456ba5bcdc30c689913def0fc35 \ No newline at end of file diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml new file mode 100644 index 0000000..5a53e53 --- /dev/null +++ b/src/main/resources/application.yml @@ -0,0 +1,9 @@ +server: + port: 8086 + +spring: + profiles: + active: dev + + + diff --git a/src/main/resources/log4j2.xml b/src/main/resources/log4j2.xml new file mode 100644 index 0000000..c537b9f --- /dev/null +++ b/src/main/resources/log4j2.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/src/test/java/vvpkassistant/ApplicationTests.java b/src/test/java/vvpkassistant/ApplicationTests.java new file mode 100644 index 0000000..a464631 --- /dev/null +++ b/src/test/java/vvpkassistant/ApplicationTests.java @@ -0,0 +1,22 @@ +package vvpkassistant; +import lombok.SneakyThrows; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import vvpkassistant.Data.WxChatParam; +import vvpkassistant.Tools.VVRequester; + + +@SpringBootTest +class ApplicationTests { + + @Autowired + private WxChatParam wxChatParam; + + @Test + @SneakyThrows + void contextLoads() { + System.out.println(wxChatParam); + } + +} diff --git a/target/classes/META-INF/spring-configuration-metadata.json b/target/classes/META-INF/spring-configuration-metadata.json new file mode 100644 index 0000000..a6de442 --- /dev/null +++ b/target/classes/META-INF/spring-configuration-metadata.json @@ -0,0 +1,22 @@ +{ + "groups": [ + { + "name": "chat", + "type": "vvpkassistant.Data.WxChatParam", + "sourceType": "vvpkassistant.Data.WxChatParam" + } + ], + "properties": [ + { + "name": "chat.app-id", + "type": "java.lang.String", + "sourceType": "vvpkassistant.Data.WxChatParam" + }, + { + "name": "chat.app-key", + "type": "java.lang.String", + "sourceType": "vvpkassistant.Data.WxChatParam" + } + ], + "hints": [] +} \ No newline at end of file diff --git a/target/classes/application-dev.yml b/target/classes/application-dev.yml new file mode 100644 index 0000000..8822912 --- /dev/null +++ b/target/classes/application-dev.yml @@ -0,0 +1,14 @@ + + +spring: + datasource: + driver-class-name: com.mysql.cj.jdbc.Driver + username: root + password: wfn53400 + url: jdbc:mysql://mysql.text.zhukeping.com:3326/vv_assistant?allowMultiQueries=true + + + +chat: + appId: 1600092688 + appKey: 9bb6df04907a8cff9292eee8d6b32158d008350198acba11607068d91cb65f66 \ No newline at end of file diff --git a/target/classes/application-local.yml b/target/classes/application-local.yml new file mode 100644 index 0000000..4b3c730 --- /dev/null +++ b/target/classes/application-local.yml @@ -0,0 +1,13 @@ + + +spring: + datasource: + driver-class-name: com.mysql.cj.jdbc.Driver + username: root + password: wfn53400 + url: jdbc:mysql://mysql.text.zhukeping.com:3326/vv_assistant?allowMultiQueries=true + + +chat: + appId: 1600092688 + appKey: 9bb6df04907a8cff9292eee8d6b32158d008350198acba11607068d91cb65f66 \ No newline at end of file diff --git a/target/classes/application-prd.yml b/target/classes/application-prd.yml new file mode 100644 index 0000000..89e0694 --- /dev/null +++ b/target/classes/application-prd.yml @@ -0,0 +1,13 @@ + + +spring: + datasource: + driver-class-name: com.mysql.cj.jdbc.Driver + username: root + password: niu995228 + url: jdbc:mysql://49.235.115.212:3336/vv_assistant + + +chat: + appId: 1600086767 + appKey: 4f240bf11de12b5d8fc596556953f4f732416456ba5bcdc30c689913def0fc35 \ No newline at end of file diff --git a/target/classes/application.yml b/target/classes/application.yml new file mode 100644 index 0000000..5a53e53 --- /dev/null +++ b/target/classes/application.yml @@ -0,0 +1,9 @@ +server: + port: 8086 + +spring: + profiles: + active: dev + + + diff --git a/target/classes/log4j2.xml b/target/classes/log4j2.xml new file mode 100644 index 0000000..c537b9f --- /dev/null +++ b/target/classes/log4j2.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/target/maven-archiver/pom.properties b/target/maven-archiver/pom.properties new file mode 100644 index 0000000..fa8265c --- /dev/null +++ b/target/maven-archiver/pom.properties @@ -0,0 +1,5 @@ +#Generated by Maven +#Wed Jul 30 13:17:57 CST 2025 +version=0.0.1 +groupId=com.vv.pk.assistant +artifactId=vvPkAssistant diff --git a/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst b/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst new file mode 100644 index 0000000..fbfbf6f --- /dev/null +++ b/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst @@ -0,0 +1,38 @@ +vvpkassistant\FunctionConfig\FunctionConfigHolder.class +vvpkassistant\FunctionConfig\FunctionConfigMapper.class +vvpkassistant\User\UserModel.class +vvpkassistant\pk\PkInfoDao.class +vvpkassistant\pk\PkRecordDetail.class +META-INF\spring-configuration-metadata.json +vvpkassistant\Anchors\AnchorModel.class +vvpkassistant\CoinRecords\CoinRecordsDao.class +vvpkassistant\Data\ResponseData.class +vvpkassistant\SystemMessage\SystemMessageDao.class +vvpkassistant\SystemMessage\SystemMessage.class +vvpkassistant\Tools\VVRequester.class +vvpkassistant\Anchors\AnchorDao.class +vvpkassistant\FunctionConfig\FunctionConfigController.class +vvpkassistant\pk\PkRecord.class +vvpkassistant\Tools\OkHttpUtils.class +vvpkassistant\Tools\COSSigner.class +vvpkassistant\chat\ChatModel.class +vvpkassistant\pk\PkRecordDetailDao.class +vvpkassistant\Tools\VVRequester$1.class +vvpkassistant\Data\WxChatParam.class +vvpkassistant\chat\ChatDao.class +vvpkassistant\pk\PkInfoModel.class +vvpkassistant\SystemMessage\SystemMessageController.class +vvpkassistant\Data\ResponseInfo.class +vvpkassistant\chat\ChatController.class +vvpkassistant\FunctionConfig\FunctionConfigModel.class +vvpkassistant\User\UserDao.class +vvpkassistant\pk\PkController.class +vvpkassistant\Anchors\AnchorsController.class +vvpkassistant\Application.class +vvpkassistant\pk\PkRecordDao.class +vvpkassistant\CoinRecords\CoinRecords.class +vvpkassistant\Tools\VVTools.class +vvpkassistant\Tools\LogUtil.class +vvpkassistant\User\UserController.class +vvpkassistant\Tools\WebMvcConfig.class +vvpkassistant\Data\WxParam.class diff --git a/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst b/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst new file mode 100644 index 0000000..c866d4f --- /dev/null +++ b/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst @@ -0,0 +1,36 @@ +E:\Code\java\vvPkAssistant\src\main\java\vvpkassistant\chat\ChatModel.java +E:\Code\java\vvPkAssistant\src\main\java\vvpkassistant\Application.java +E:\Code\java\vvPkAssistant\src\main\java\vvpkassistant\chat\ChatDao.java +E:\Code\java\vvPkAssistant\src\main\java\vvpkassistant\Data\ResponseInfo.java +E:\Code\java\vvPkAssistant\src\main\java\vvpkassistant\FunctionConfig\FunctionConfigController.java +E:\Code\java\vvPkAssistant\src\main\java\vvpkassistant\FunctionConfig\FunctionConfigModel.java +E:\Code\java\vvPkAssistant\src\main\java\vvpkassistant\CoinRecords\CoinRecordsDao.java +E:\Code\java\vvPkAssistant\src\main\java\vvpkassistant\Tools\OkHttpUtils.java +E:\Code\java\vvPkAssistant\src\main\java\vvpkassistant\Tools\LogUtil.java +E:\Code\java\vvPkAssistant\src\main\java\vvpkassistant\Anchors\AnchorDao.java +E:\Code\java\vvPkAssistant\src\main\java\vvpkassistant\CoinRecords\CoinRecords.java +E:\Code\java\vvPkAssistant\src\main\java\vvpkassistant\pk\PkController.java +E:\Code\java\vvPkAssistant\src\main\java\vvpkassistant\Data\WxChatParam.java +E:\Code\java\vvPkAssistant\src\main\java\vvpkassistant\Anchors\AnchorModel.java +E:\Code\java\vvPkAssistant\src\main\java\vvpkassistant\FunctionConfig\FunctionConfigHolder.java +E:\Code\java\vvPkAssistant\src\main\java\vvpkassistant\SystemMessage\SystemMessage.java +E:\Code\java\vvPkAssistant\src\main\java\vvpkassistant\SystemMessage\SystemMessageDao.java +E:\Code\java\vvPkAssistant\src\main\java\vvpkassistant\pk\PkInfoModel.java +E:\Code\java\vvPkAssistant\src\main\java\vvpkassistant\pk\PkRecordDao.java +E:\Code\java\vvPkAssistant\src\main\java\vvpkassistant\SystemMessage\SystemMessageController.java +E:\Code\java\vvPkAssistant\src\main\java\vvpkassistant\Data\WxParam.java +E:\Code\java\vvPkAssistant\src\main\java\vvpkassistant\pk\PkRecord.java +E:\Code\java\vvPkAssistant\src\main\java\vvpkassistant\Data\ResponseData.java +E:\Code\java\vvPkAssistant\src\main\java\vvpkassistant\Anchors\AnchorsController.java +E:\Code\java\vvPkAssistant\src\main\java\vvpkassistant\pk\PkInfoDao.java +E:\Code\java\vvPkAssistant\src\main\java\vvpkassistant\pk\PkRecordDetail.java +E:\Code\java\vvPkAssistant\src\main\java\vvpkassistant\Tools\COSSigner.java +E:\Code\java\vvPkAssistant\src\main\java\vvpkassistant\FunctionConfig\FunctionConfigMapper.java +E:\Code\java\vvPkAssistant\src\main\java\vvpkassistant\Tools\WebMvcConfig.java +E:\Code\java\vvPkAssistant\src\main\java\vvpkassistant\pk\PkRecordDetailDao.java +E:\Code\java\vvPkAssistant\src\main\java\vvpkassistant\chat\ChatController.java +E:\Code\java\vvPkAssistant\src\main\java\vvpkassistant\Tools\VVTools.java +E:\Code\java\vvPkAssistant\src\main\java\vvpkassistant\User\UserDao.java +E:\Code\java\vvPkAssistant\src\main\java\vvpkassistant\Tools\VVRequester.java +E:\Code\java\vvPkAssistant\src\main\java\vvpkassistant\User\UserController.java +E:\Code\java\vvPkAssistant\src\main\java\vvpkassistant\User\UserModel.java diff --git a/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/createdFiles.lst b/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/createdFiles.lst new file mode 100644 index 0000000..1e60b66 --- /dev/null +++ b/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/createdFiles.lst @@ -0,0 +1 @@ +vvpkassistant\ApplicationTests.class diff --git a/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/inputFiles.lst b/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/inputFiles.lst new file mode 100644 index 0000000..9df5bb8 --- /dev/null +++ b/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/inputFiles.lst @@ -0,0 +1 @@ +E:\Code\java\vvPkAssistant\src\test\java\vvpkassistant\ApplicationTests.java diff --git a/target/vvPkAssistant-0.0.1.jar.original b/target/vvPkAssistant-0.0.1.jar.original new file mode 100644 index 0000000..cc5ba39 Binary files /dev/null and b/target/vvPkAssistant-0.0.1.jar.original differ diff --git a/vvPkAssistant.iml b/vvPkAssistant.iml new file mode 100644 index 0000000..6cf5908 --- /dev/null +++ b/vvPkAssistant.iml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file