Compare commits
9 Commits
323e038e86
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 723992f360 | |||
| 05e15998f5 | |||
| 44d55c0ed6 | |||
| 06bb86ccd5 | |||
| 6f1cf2083d | |||
| fd71f330d2 | |||
| cdff62b3b5 | |||
| 2ba868b3b6 | |||
| c270ae177d |
1
.gitignore
vendored
1
.gitignore
vendored
@ -2,6 +2,7 @@
|
|||||||
/data
|
/data
|
||||||
/logs
|
/logs
|
||||||
/target
|
/target
|
||||||
|
/temp
|
||||||
|
|
||||||
multilingualField/
|
multilingualField/
|
||||||
!.mvn/wrapper/maven-wrapper.jar
|
!.mvn/wrapper/maven-wrapper.jar
|
||||||
|
|||||||
1
.idea/.gitignore
generated
vendored
1
.idea/.gitignore
generated
vendored
@ -2,3 +2,4 @@
|
|||||||
/shelf/
|
/shelf/
|
||||||
/workspace.xml
|
/workspace.xml
|
||||||
CopilotChatHistory.xml
|
CopilotChatHistory.xml
|
||||||
|
developer-tools.xml
|
||||||
82
pom.xml
82
pom.xml
@ -30,6 +30,57 @@
|
|||||||
</repository>
|
</repository>
|
||||||
</repositories>
|
</repositories>
|
||||||
|
|
||||||
|
<profiles>
|
||||||
|
<profile>
|
||||||
|
<id>dev-windows</id>
|
||||||
|
<activation>
|
||||||
|
<activeByDefault>true</activeByDefault>
|
||||||
|
</activation>
|
||||||
|
<properties>
|
||||||
|
<native.classifier>windows-x86_64</native.classifier>
|
||||||
|
</properties>
|
||||||
|
</profile>
|
||||||
|
<profile>
|
||||||
|
<id>prod-linux</id>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.bytedeco</groupId>
|
||||||
|
<artifactId>ffmpeg</artifactId>
|
||||||
|
<version>7.1.1-1.5.12</version>
|
||||||
|
<classifier>linux-x86_64</classifier>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.bytedeco</groupId>
|
||||||
|
<artifactId>opencv</artifactId>
|
||||||
|
<version>4.11.0-1.5.12</version>
|
||||||
|
<classifier>linux-x86_64</classifier>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<excludes>
|
||||||
|
<exclude>
|
||||||
|
<groupId>org.bytedeco</groupId>
|
||||||
|
<artifactId>ffmpeg</artifactId>
|
||||||
|
<classifier>windows-x86_64</classifier>
|
||||||
|
</exclude>
|
||||||
|
<exclude>
|
||||||
|
<groupId>org.bytedeco</groupId>
|
||||||
|
<artifactId>opencv</artifactId>
|
||||||
|
<classifier>windows-x86_64</classifier>
|
||||||
|
</exclude>
|
||||||
|
</excludes>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</profile>
|
||||||
|
</profiles>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
<defaultGoal>compile</defaultGoal>
|
<defaultGoal>compile</defaultGoal>
|
||||||
<plugins>
|
<plugins>
|
||||||
@ -57,17 +108,17 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.imyeyu.spring</groupId>
|
<groupId>com.imyeyu.spring</groupId>
|
||||||
<artifactId>timi-spring</artifactId>
|
<artifactId>timi-spring</artifactId>
|
||||||
<version>0.0.1</version>
|
<version>0.0.2</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.imyeyu.network</groupId>
|
<groupId>com.imyeyu.network</groupId>
|
||||||
<artifactId>timi-network</artifactId>
|
<artifactId>timi-network</artifactId>
|
||||||
<version>0.0.1</version>
|
<version>0.0.2</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.imyeyu.lang</groupId>
|
<groupId>com.imyeyu.lang</groupId>
|
||||||
<artifactId>timi-lang</artifactId>
|
<artifactId>timi-lang</artifactId>
|
||||||
<version>0.0.1</version>
|
<version>0.0.2</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
@ -167,6 +218,25 @@
|
|||||||
<artifactId>jcodec-javase</artifactId>
|
<artifactId>jcodec-javase</artifactId>
|
||||||
<version>0.2.5</version>
|
<version>0.2.5</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.bytedeco</groupId>
|
||||||
|
<artifactId>javacv</artifactId>
|
||||||
|
<version>1.5.12</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.bytedeco</groupId>
|
||||||
|
<artifactId>ffmpeg</artifactId>
|
||||||
|
<version>7.1.1-1.5.12</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
<classifier>windows-x86_64</classifier>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.bytedeco</groupId>
|
||||||
|
<artifactId>opencv</artifactId>
|
||||||
|
<version>4.11.0-1.5.12</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
<classifier>windows-x86_64</classifier>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jsoup</groupId>
|
<groupId>org.jsoup</groupId>
|
||||||
<artifactId>jsoup</artifactId>
|
<artifactId>jsoup</artifactId>
|
||||||
@ -177,5 +247,11 @@
|
|||||||
<artifactId>commons-codec</artifactId>
|
<artifactId>commons-codec</artifactId>
|
||||||
<version>1.17.0</version>
|
<version>1.17.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.jayway.jsonpath</groupId>
|
||||||
|
<artifactId>json-path</artifactId>
|
||||||
|
<version>2.9.0</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</project>
|
</project>
|
||||||
|
|||||||
@ -0,0 +1,15 @@
|
|||||||
|
package com.imyeyu.api.bean.wechat;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author 夜雨
|
||||||
|
* @since 2025-09-27 11:33
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class InitCodeResponse {
|
||||||
|
|
||||||
|
private String session_key;
|
||||||
|
|
||||||
|
private String openid;
|
||||||
|
}
|
||||||
@ -7,6 +7,7 @@ import com.imyeyu.api.annotation.RequiredTokenInterceptor;
|
|||||||
import com.imyeyu.api.modules.common.entity.Attachment;
|
import com.imyeyu.api.modules.common.entity.Attachment;
|
||||||
import com.imyeyu.api.modules.common.vo.user.UserProfileView;
|
import com.imyeyu.api.modules.common.vo.user.UserProfileView;
|
||||||
import com.imyeyu.api.modules.common.vo.user.UserView;
|
import com.imyeyu.api.modules.common.vo.user.UserView;
|
||||||
|
import com.imyeyu.api.modules.journal.util.JournalAPIInterceptor;
|
||||||
import com.imyeyu.api.modules.minecraft.annotation.RequiredFMCServerTokenInterceptor;
|
import com.imyeyu.api.modules.minecraft.annotation.RequiredFMCServerTokenInterceptor;
|
||||||
import com.imyeyu.api.modules.minecraft.entity.MinecraftPlayer;
|
import com.imyeyu.api.modules.minecraft.entity.MinecraftPlayer;
|
||||||
import com.imyeyu.api.modules.mirror.vo.MirrorView;
|
import com.imyeyu.api.modules.mirror.vo.MirrorView;
|
||||||
@ -41,6 +42,7 @@ public class WebConfig implements WebMvcConfigurer {
|
|||||||
|
|
||||||
private final SystemAPIInterceptor systemAPIInterceptor;
|
private final SystemAPIInterceptor systemAPIInterceptor;
|
||||||
private final GsonSerializerAdapter gsonSerializerAdapter;
|
private final GsonSerializerAdapter gsonSerializerAdapter;
|
||||||
|
private final JournalAPIInterceptor journalAPIInterceptor;
|
||||||
private final RequiredTokenInterceptor requiredTokenInterceptor;
|
private final RequiredTokenInterceptor requiredTokenInterceptor;
|
||||||
private final EnableSettingInterceptor enableSettingInterceptor;
|
private final EnableSettingInterceptor enableSettingInterceptor;
|
||||||
private final RequestSingleParamResolver requestSingleParamResolver;
|
private final RequestSingleParamResolver requestSingleParamResolver;
|
||||||
@ -55,6 +57,7 @@ public class WebConfig implements WebMvcConfigurer {
|
|||||||
@Override
|
@Override
|
||||||
public void addInterceptors(InterceptorRegistry registry) {
|
public void addInterceptors(InterceptorRegistry registry) {
|
||||||
registry.addInterceptor(systemAPIInterceptor).addPathPatterns(SystemAPIInterceptor.PATH);
|
registry.addInterceptor(systemAPIInterceptor).addPathPatterns(SystemAPIInterceptor.PATH);
|
||||||
|
registry.addInterceptor(journalAPIInterceptor).addPathPatterns(JournalAPIInterceptor.PATH);
|
||||||
registry.addInterceptor(requiredFMCServerTokenInterceptor).addPathPatterns("/fmc/server/**");
|
registry.addInterceptor(requiredFMCServerTokenInterceptor).addPathPatterns("/fmc/server/**");
|
||||||
registry.addInterceptor(requiredTokenInterceptor).addPathPatterns("/**");
|
registry.addInterceptor(requiredTokenInterceptor).addPathPatterns("/**");
|
||||||
registry.addInterceptor(enableSettingInterceptor).addPathPatterns("/**");
|
registry.addInterceptor(enableSettingInterceptor).addPathPatterns("/**");
|
||||||
|
|||||||
@ -38,6 +38,7 @@ import java.util.List;
|
|||||||
"com.imyeyu.api.modules.mirror.mapper",
|
"com.imyeyu.api.modules.mirror.mapper",
|
||||||
"com.imyeyu.api.modules.system.mapper",
|
"com.imyeyu.api.modules.system.mapper",
|
||||||
"com.imyeyu.api.modules.common.mapper",
|
"com.imyeyu.api.modules.common.mapper",
|
||||||
|
"com.imyeyu.api.modules.journal.mapper",
|
||||||
"com.imyeyu.api.modules.minecraft.mapper"
|
"com.imyeyu.api.modules.minecraft.mapper"
|
||||||
}, sqlSessionFactoryRef = "timiServerSqlSessionFactory")
|
}, sqlSessionFactoryRef = "timiServerSqlSessionFactory")
|
||||||
public class TimiServerDBConfig {
|
public class TimiServerDBConfig {
|
||||||
@ -93,6 +94,7 @@ public class TimiServerDBConfig {
|
|||||||
"com.imyeyu.api.modules.mirror.entity",
|
"com.imyeyu.api.modules.mirror.entity",
|
||||||
"com.imyeyu.api.modules.system.entity",
|
"com.imyeyu.api.modules.system.entity",
|
||||||
"com.imyeyu.api.modules.common.entity",
|
"com.imyeyu.api.modules.common.entity",
|
||||||
|
"com.imyeyu.api.modules.journal.entity",
|
||||||
"com.imyeyu.api.modules.minecraft.entity"
|
"com.imyeyu.api.modules.minecraft.entity"
|
||||||
};
|
};
|
||||||
String[] typeHandlers = {
|
String[] typeHandlers = {
|
||||||
|
|||||||
@ -14,6 +14,12 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
public interface ArticleMapper extends BaseMapper<Article, Long> {
|
public interface ArticleMapper extends BaseMapper<Article, Long> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
long count();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
List<Article> list(long offset, int limit);
|
||||||
|
|
||||||
long countByKeyword(String keyword);
|
long countByKeyword(String keyword);
|
||||||
|
|
||||||
List<Article> selectByKeyword(String keyword, Long offset, int limit);
|
List<Article> selectByKeyword(String keyword, Long offset, int limit);
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
package com.imyeyu.api.modules.blog.service.implement;
|
package com.imyeyu.api.modules.blog.service.implement;
|
||||||
|
|
||||||
import com.imyeyu.java.bean.timi.TimiException;
|
|
||||||
import com.imyeyu.api.config.dbsource.TimiServerDBConfig;
|
import com.imyeyu.api.config.dbsource.TimiServerDBConfig;
|
||||||
import com.imyeyu.api.modules.blog.entity.Article;
|
import com.imyeyu.api.modules.blog.entity.Article;
|
||||||
import com.imyeyu.api.modules.blog.entity.ArticleRanking;
|
import com.imyeyu.api.modules.blog.entity.ArticleRanking;
|
||||||
@ -14,7 +13,9 @@ import com.imyeyu.api.modules.common.entity.Tag;
|
|||||||
import com.imyeyu.api.modules.common.mapper.CommentMapper;
|
import com.imyeyu.api.modules.common.mapper.CommentMapper;
|
||||||
import com.imyeyu.api.modules.common.service.AttachmentService;
|
import com.imyeyu.api.modules.common.service.AttachmentService;
|
||||||
import com.imyeyu.api.modules.common.service.TagService;
|
import com.imyeyu.api.modules.common.service.TagService;
|
||||||
|
import com.imyeyu.java.bean.timi.TimiException;
|
||||||
import com.imyeyu.spring.TimiSpring;
|
import com.imyeyu.spring.TimiSpring;
|
||||||
|
import com.imyeyu.spring.bean.Page;
|
||||||
import com.imyeyu.spring.bean.PageResult;
|
import com.imyeyu.spring.bean.PageResult;
|
||||||
import com.imyeyu.spring.mapper.BaseMapper;
|
import com.imyeyu.spring.mapper.BaseMapper;
|
||||||
import com.imyeyu.spring.service.AbstractEntityService;
|
import com.imyeyu.spring.service.AbstractEntityService;
|
||||||
@ -54,6 +55,14 @@ public class ArticleServiceImplement extends AbstractEntityService<Article, Long
|
|||||||
return mapper;
|
return mapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PageResult<Article> page(Page page) {
|
||||||
|
PageResult<Article> result = new PageResult<>();
|
||||||
|
result.setList(mapper.list(page.getOffset(), page.getLimit()));
|
||||||
|
result.setTotal(mapper.count());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
@Transactional(TimiServerDBConfig.ROLLBACKER)
|
@Transactional(TimiServerDBConfig.ROLLBACKER)
|
||||||
@Override
|
@Override
|
||||||
public ArticleView view(long id) {
|
public ArticleView view(long id) {
|
||||||
|
|||||||
@ -0,0 +1,39 @@
|
|||||||
|
package com.imyeyu.api.modules.common.bean;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author 夜雨
|
||||||
|
* @since 2025-10-20 15:04
|
||||||
|
*/
|
||||||
|
public class MediaAttach {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author 夜雨
|
||||||
|
* @since 2025-09-28 02:01
|
||||||
|
*/
|
||||||
|
public enum Type {
|
||||||
|
|
||||||
|
SOURCE,
|
||||||
|
|
||||||
|
THUMB
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @author 夜雨
|
||||||
|
* @since 2025-10-20 15:04
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public static class ExtData {
|
||||||
|
|
||||||
|
private Long sourceId;
|
||||||
|
|
||||||
|
private String sourceMongoId;
|
||||||
|
|
||||||
|
private boolean isImage;
|
||||||
|
|
||||||
|
private boolean isVideo;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -32,6 +32,8 @@ public enum SettingKey {
|
|||||||
/** 启用灰色滤镜 */
|
/** 启用灰色滤镜 */
|
||||||
ENABLE_GRAY_FILTER,
|
ENABLE_GRAY_FILTER,
|
||||||
|
|
||||||
|
TEMP_FILE_PATH,
|
||||||
|
|
||||||
// ---------- ICP 备案号 ----------
|
// ---------- ICP 备案号 ----------
|
||||||
|
|
||||||
ICP_IMYEYU_COM,
|
ICP_IMYEYU_COM,
|
||||||
@ -129,6 +131,16 @@ public enum SettingKey {
|
|||||||
|
|
||||||
MUSIC_CONTROLLER_URI,
|
MUSIC_CONTROLLER_URI,
|
||||||
|
|
||||||
|
// ---------- ----------
|
||||||
|
|
||||||
|
JOURNAL_KEY,
|
||||||
|
|
||||||
|
JOURNAL_APP_ID,
|
||||||
|
|
||||||
|
JOURNAL_APP_SECRET,
|
||||||
|
|
||||||
|
JOURNAL_TRAVEL,
|
||||||
|
|
||||||
// ---------- 系统 ----------
|
// ---------- 系统 ----------
|
||||||
|
|
||||||
SYSTEM_FILE_BASE,
|
SYSTEM_FILE_BASE,
|
||||||
|
|||||||
@ -0,0 +1,23 @@
|
|||||||
|
package com.imyeyu.api.modules.common.bean;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.nio.file.Path;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author 夜雨
|
||||||
|
* @since 2025-09-27 01:47
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class TempFileMetaData {
|
||||||
|
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
private String originalName;
|
||||||
|
|
||||||
|
private Path path;
|
||||||
|
|
||||||
|
private Long lastAccessAt;
|
||||||
|
}
|
||||||
@ -2,12 +2,6 @@ package com.imyeyu.api.modules.common.controller;
|
|||||||
|
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import com.google.gson.reflect.TypeToken;
|
import com.google.gson.reflect.TypeToken;
|
||||||
import com.imyeyu.io.IO;
|
|
||||||
import com.imyeyu.java.TimiJava;
|
|
||||||
import com.imyeyu.java.bean.timi.TimiCode;
|
|
||||||
import com.imyeyu.java.bean.timi.TimiException;
|
|
||||||
import com.imyeyu.java.ref.Ref;
|
|
||||||
import com.imyeyu.network.Network;
|
|
||||||
import com.imyeyu.api.bean.CaptchaFrom;
|
import com.imyeyu.api.bean.CaptchaFrom;
|
||||||
import com.imyeyu.api.modules.common.bean.ImageType;
|
import com.imyeyu.api.modules.common.bean.ImageType;
|
||||||
import com.imyeyu.api.modules.common.bean.SettingKey;
|
import com.imyeyu.api.modules.common.bean.SettingKey;
|
||||||
@ -20,17 +14,26 @@ import com.imyeyu.api.modules.common.service.AttachmentService;
|
|||||||
import com.imyeyu.api.modules.common.service.FeedbackService;
|
import com.imyeyu.api.modules.common.service.FeedbackService;
|
||||||
import com.imyeyu.api.modules.common.service.SettingService;
|
import com.imyeyu.api.modules.common.service.SettingService;
|
||||||
import com.imyeyu.api.modules.common.service.TaskService;
|
import com.imyeyu.api.modules.common.service.TaskService;
|
||||||
|
import com.imyeyu.api.modules.common.service.TempFileService;
|
||||||
import com.imyeyu.api.modules.common.service.TemplateService;
|
import com.imyeyu.api.modules.common.service.TemplateService;
|
||||||
import com.imyeyu.api.modules.common.service.VersionService;
|
import com.imyeyu.api.modules.common.service.VersionService;
|
||||||
import com.imyeyu.api.modules.common.vo.FeedbackRequest;
|
import com.imyeyu.api.modules.common.vo.FeedbackRequest;
|
||||||
|
import com.imyeyu.api.modules.common.vo.TempFileResponse;
|
||||||
import com.imyeyu.api.modules.common.vo.attachment.AttachmentView;
|
import com.imyeyu.api.modules.common.vo.attachment.AttachmentView;
|
||||||
import com.imyeyu.api.modules.system.util.ResourceHandler;
|
import com.imyeyu.api.modules.system.util.ResourceHandler;
|
||||||
import com.imyeyu.api.util.CaptchaManager;
|
import com.imyeyu.api.util.CaptchaManager;
|
||||||
|
import com.imyeyu.io.IO;
|
||||||
|
import com.imyeyu.java.TimiJava;
|
||||||
|
import com.imyeyu.java.bean.timi.TimiCode;
|
||||||
|
import com.imyeyu.java.bean.timi.TimiException;
|
||||||
|
import com.imyeyu.java.ref.Ref;
|
||||||
|
import com.imyeyu.network.Network;
|
||||||
import com.imyeyu.spring.TimiSpring;
|
import com.imyeyu.spring.TimiSpring;
|
||||||
import com.imyeyu.spring.annotation.AOPLog;
|
import com.imyeyu.spring.annotation.AOPLog;
|
||||||
import com.imyeyu.spring.annotation.IgnoreGlobalReturn;
|
import com.imyeyu.spring.annotation.IgnoreGlobalReturn;
|
||||||
import com.imyeyu.spring.annotation.RequestRateLimit;
|
import com.imyeyu.spring.annotation.RequestRateLimit;
|
||||||
import com.imyeyu.spring.bean.CaptchaData;
|
import com.imyeyu.spring.bean.CaptchaData;
|
||||||
|
import com.imyeyu.spring.bean.RequestRange;
|
||||||
import com.mongodb.client.gridfs.GridFSBucket;
|
import com.mongodb.client.gridfs.GridFSBucket;
|
||||||
import com.mongodb.client.gridfs.GridFSDownloadStream;
|
import com.mongodb.client.gridfs.GridFSDownloadStream;
|
||||||
import com.mongodb.client.gridfs.model.GridFSFile;
|
import com.mongodb.client.gridfs.model.GridFSFile;
|
||||||
@ -39,6 +42,7 @@ import jakarta.servlet.http.HttpServletResponse;
|
|||||||
import jakarta.validation.Valid;
|
import jakarta.validation.Valid;
|
||||||
import jakarta.validation.constraints.NotBlank;
|
import jakarta.validation.constraints.NotBlank;
|
||||||
import jakarta.validation.constraints.NotNull;
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
import lombok.Cleanup;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.tika.Tika;
|
import org.apache.tika.Tika;
|
||||||
@ -51,6 +55,7 @@ import org.springframework.web.bind.annotation.RequestBody;
|
|||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
import org.yaml.snakeyaml.Yaml;
|
import org.yaml.snakeyaml.Yaml;
|
||||||
|
|
||||||
import javax.imageio.ImageIO;
|
import javax.imageio.ImageIO;
|
||||||
@ -58,8 +63,12 @@ import java.awt.Graphics2D;
|
|||||||
import java.awt.RenderingHints;
|
import java.awt.RenderingHints;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.RandomAccessFile;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -83,6 +92,7 @@ public class CommonController {
|
|||||||
private final SettingService settingService;
|
private final SettingService settingService;
|
||||||
private final FeedbackService feedbackService;
|
private final FeedbackService feedbackService;
|
||||||
private final TemplateService templateService;
|
private final TemplateService templateService;
|
||||||
|
private final TempFileService tempFileService;
|
||||||
private final AttachmentService attachmentService;
|
private final AttachmentService attachmentService;
|
||||||
|
|
||||||
private final Gson gson;
|
private final Gson gson;
|
||||||
@ -171,7 +181,7 @@ public class CommonController {
|
|||||||
@RequestRateLimit
|
@RequestRateLimit
|
||||||
@PostMapping("/feedback")
|
@PostMapping("/feedback")
|
||||||
public void createFeedback(@Valid @NotNull @RequestBody CaptchaData<FeedbackRequest> request) {
|
public void createFeedback(@Valid @NotNull @RequestBody CaptchaData<FeedbackRequest> request) {
|
||||||
captchaManager.test(request.getCaptcha(), request.getFrom());
|
captchaManager.test(request.getCaptcha(), request.getCaptchaId());
|
||||||
feedbackService.create(request.getData());
|
feedbackService.create(request.getData());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -250,12 +260,6 @@ public class CommonController {
|
|||||||
return result.stream().collect(Collectors.toMap(Setting::getKey, Setting::getValue));
|
return result.stream().collect(Collectors.toMap(Setting::getKey, Setting::getValue));
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequestRateLimit
|
|
||||||
@GetMapping("/setting/flushCache")
|
|
||||||
public void settingFlushCache() {
|
|
||||||
settingService.flushCache();
|
|
||||||
}
|
|
||||||
|
|
||||||
@AOPLog
|
@AOPLog
|
||||||
@RequestRateLimit
|
@RequestRateLimit
|
||||||
@GetMapping("/attachment/{mongoId}")
|
@GetMapping("/attachment/{mongoId}")
|
||||||
@ -264,7 +268,6 @@ public class CommonController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@AOPLog
|
@AOPLog
|
||||||
@RequestRateLimit
|
|
||||||
@IgnoreGlobalReturn
|
@IgnoreGlobalReturn
|
||||||
@GetMapping("/attachment/read/{mongoId}")
|
@GetMapping("/attachment/read/{mongoId}")
|
||||||
public void readAttachment(
|
public void readAttachment(
|
||||||
@ -372,4 +375,72 @@ public class CommonController {
|
|||||||
resp.setCharacterEncoding(StandardCharsets.UTF_8.toString());
|
resp.setCharacterEncoding(StandardCharsets.UTF_8.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@AOPLog
|
||||||
|
@PostMapping("/temp/file/upload")
|
||||||
|
public List<TempFileResponse> uploadFile(@RequestParam("file") List<MultipartFile> files) {
|
||||||
|
return tempFileService.store(files);
|
||||||
|
}
|
||||||
|
|
||||||
|
@AOPLog
|
||||||
|
@RequestRateLimit
|
||||||
|
@IgnoreGlobalReturn
|
||||||
|
@GetMapping("/temp/file/read/{fileId}")
|
||||||
|
public void tempFileRead(@PathVariable String fileId, HttpServletRequest req, HttpServletResponse resp) {
|
||||||
|
try {
|
||||||
|
File file = tempFileService.get(fileId);
|
||||||
|
if (TimiJava.isEmpty(file) && file.exists()) {
|
||||||
|
resp.setStatus(HttpServletResponse.SC_NOT_FOUND);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Path filePath = file.toPath();
|
||||||
|
resp.setContentLengthLong(Files.size(filePath));
|
||||||
|
String mimeType = new Tika().detect(filePath);
|
||||||
|
if (TimiJava.isNotEmpty(mimeType)) {
|
||||||
|
resp.setContentType(mimeType);
|
||||||
|
}
|
||||||
|
req.setAttribute(ResourceHandler.ATTR_TYPE, ResourceHandler.Type.FILE);
|
||||||
|
req.setAttribute(ResourceHandler.ATTR_VALUE, filePath);
|
||||||
|
resourceHandler.handleRequest(req, resp);
|
||||||
|
} catch (Exception e) {
|
||||||
|
resp.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@AOPLog
|
||||||
|
@RequestRateLimit
|
||||||
|
@IgnoreGlobalReturn
|
||||||
|
@RequestMapping("/temp/file/download/{fileId}")
|
||||||
|
public void tempFileDownload(@PathVariable String fileId, HttpServletResponse resp) {
|
||||||
|
try {
|
||||||
|
File file = tempFileService.get(fileId);
|
||||||
|
if (TimiJava.isEmpty(file) && file.exists()) {
|
||||||
|
resp.setStatus(HttpServletResponse.SC_NOT_FOUND);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String mimeType = new Tika().detect(file);
|
||||||
|
resp.setContentType(mimeType);
|
||||||
|
resp.setHeader("Content-Disposition", Network.getFileDownloadHeader(file.getName()));
|
||||||
|
resp.setHeader("Accept-Ranges", "bytes");
|
||||||
|
|
||||||
|
RequestRange range = TimiSpring.requestRange(file.length());
|
||||||
|
if (range == null) {
|
||||||
|
// 完整文件
|
||||||
|
resp.setContentLengthLong(file.length());
|
||||||
|
resp.setStatus(HttpServletResponse.SC_OK);
|
||||||
|
IO.toOutputStream(resp.getOutputStream(), file);
|
||||||
|
} else {
|
||||||
|
// 分片文件
|
||||||
|
resp.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
|
||||||
|
resp.setHeader("Content-Range", "bytes %s-%s/%s".formatted(range.getStart(), range.getEnd(), file.length()));
|
||||||
|
resp.setContentLengthLong(range.getLength());
|
||||||
|
|
||||||
|
@Cleanup RandomAccessFile raf = new RandomAccessFile(file, "r");
|
||||||
|
raf.seek(range.getStart());
|
||||||
|
IO.toOutputStream(resp.getOutputStream(), raf, range.getStart(), range.getLength());
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("download error", e);
|
||||||
|
resp.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
package com.imyeyu.api.modules.common.entity;
|
package com.imyeyu.api.modules.common.entity;
|
||||||
|
|
||||||
import com.imyeyu.java.ref.Ref;
|
|
||||||
import com.imyeyu.api.bean.MultilingualHandler;
|
import com.imyeyu.api.bean.MultilingualHandler;
|
||||||
|
import com.imyeyu.java.ref.Ref;
|
||||||
import com.imyeyu.spring.entity.Entity;
|
import com.imyeyu.spring.entity.Entity;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
@ -44,24 +44,36 @@ public class Attachment extends Entity implements MultilingualHandler {
|
|||||||
/** 镜像 */
|
/** 镜像 */
|
||||||
MIRROR,
|
MIRROR,
|
||||||
|
|
||||||
|
JOURNAL,
|
||||||
|
|
||||||
|
JOURNAL_TRAVEL,
|
||||||
|
|
||||||
|
JOURNAL_MOMENT,
|
||||||
|
|
||||||
/** 系统 */
|
/** 系统 */
|
||||||
SYSTEM
|
SYSTEM
|
||||||
}
|
}
|
||||||
|
|
||||||
private BizType bizType;
|
protected BizType bizType;
|
||||||
|
|
||||||
private Long bizId;
|
protected Long bizId;
|
||||||
|
|
||||||
private String attachType;
|
protected String attachType;
|
||||||
|
|
||||||
private String mongoId;
|
protected String mongoId;
|
||||||
|
|
||||||
@MultilingualField
|
@MultilingualField
|
||||||
private String title;
|
protected String title;
|
||||||
|
|
||||||
private String name;
|
protected String name;
|
||||||
|
|
||||||
private Long size;
|
protected Long size;
|
||||||
|
|
||||||
|
protected String md5;
|
||||||
|
|
||||||
|
protected String ext;
|
||||||
|
|
||||||
|
protected Long destroyAt;
|
||||||
|
|
||||||
public void setAttachTypeValue(Enum<?> attachType) {
|
public void setAttachTypeValue(Enum<?> attachType) {
|
||||||
this.attachType = attachType.toString();
|
this.attachType = attachType.toString();
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
package com.imyeyu.api.modules.common.mapper;
|
package com.imyeyu.api.modules.common.mapper;
|
||||||
|
|
||||||
import com.imyeyu.api.modules.common.entity.Attachment;
|
import com.imyeyu.api.modules.common.entity.Attachment;
|
||||||
|
import com.imyeyu.spring.bean.Page;
|
||||||
import com.imyeyu.spring.mapper.BaseMapper;
|
import com.imyeyu.spring.mapper.BaseMapper;
|
||||||
import org.apache.ibatis.annotations.Select;
|
import org.apache.ibatis.annotations.Select;
|
||||||
|
|
||||||
@ -24,8 +25,9 @@ public interface AttachmentMapper extends BaseMapper<Attachment, Long> {
|
|||||||
@Select("SELECT * FROM attachment WHERE biz_type = #{bizType} AND biz_id = #{bizId} AND attach_type = #{attachType} " + VALID + LIMIT_1)
|
@Select("SELECT * FROM attachment WHERE biz_type = #{bizType} AND biz_id = #{bizId} AND attach_type = #{attachType} " + VALID + LIMIT_1)
|
||||||
Attachment selectByAttachType(Attachment.BizType bizType, long bizId, Enum<?> attachType);
|
Attachment selectByAttachType(Attachment.BizType bizType, long bizId, Enum<?> attachType);
|
||||||
|
|
||||||
@Select("SELECT * FROM attachment WHERE biz_type = #{bizType} AND biz_id = #{bizId} AND " + VALID + PAGE)
|
List<Attachment> listByBizId(Attachment.BizType bizType, Long bizId, List<Enum<?>> attachTypes, Page page);
|
||||||
List<Attachment> listByBizId(Attachment.BizType bizType, long bizId, long offset, int limit);
|
|
||||||
|
|
||||||
List<Attachment> listByAttachType(Attachment.BizType bizType, long bizId, Enum<?> ...attachTypes);
|
long countByBizId(Attachment.BizType bizType, Long bizId, List<Enum<?>> attachTypes);
|
||||||
|
|
||||||
|
List<Attachment> listByMd5s(Attachment.BizType bizType, Long bizId, List<Enum<?>> attachTypes, List<String> md5s);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,6 +17,12 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
public interface CommentMapper extends BaseMapper<Comment, Long> {
|
public interface CommentMapper extends BaseMapper<Comment, Long> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
long count();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
List<Comment> list(long offset, int limit);
|
||||||
|
|
||||||
@Select("SELECT * FROM comment WHERE id = #{id}" + NOT_DELETE)
|
@Select("SELECT * FROM comment WHERE id = #{id}" + NOT_DELETE)
|
||||||
Comment select(Long id);
|
Comment select(Long id);
|
||||||
|
|
||||||
|
|||||||
@ -1,12 +1,16 @@
|
|||||||
package com.imyeyu.api.modules.common.service;
|
package com.imyeyu.api.modules.common.service;
|
||||||
|
|
||||||
import com.imyeyu.java.bean.timi.TimiException;
|
|
||||||
import com.imyeyu.api.modules.common.entity.Attachment;
|
import com.imyeyu.api.modules.common.entity.Attachment;
|
||||||
import com.imyeyu.api.modules.common.vo.attachment.AttachmentRequest;
|
import com.imyeyu.api.modules.common.vo.attachment.AttachmentRequest;
|
||||||
import com.imyeyu.api.modules.common.vo.attachment.AttachmentView;
|
import com.imyeyu.api.modules.common.vo.attachment.AttachmentView;
|
||||||
|
import com.imyeyu.java.bean.timi.TimiException;
|
||||||
|
import com.imyeyu.spring.bean.Page;
|
||||||
|
import com.imyeyu.spring.bean.PageResult;
|
||||||
import com.imyeyu.spring.service.DeletableService;
|
import com.imyeyu.spring.service.DeletableService;
|
||||||
import com.imyeyu.spring.service.DestroyableService;
|
import com.imyeyu.spring.service.DestroyableService;
|
||||||
import com.imyeyu.spring.service.GettableService;
|
import com.imyeyu.spring.service.GettableService;
|
||||||
|
import com.imyeyu.spring.service.PageableService;
|
||||||
|
import com.imyeyu.spring.service.UpdatableService;
|
||||||
import com.mongodb.client.gridfs.model.GridFSFile;
|
import com.mongodb.client.gridfs.model.GridFSFile;
|
||||||
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
@ -20,7 +24,7 @@ import java.util.List;
|
|||||||
* @author 夜雨
|
* @author 夜雨
|
||||||
* @since 2023-08-15 10:21
|
* @since 2023-08-15 10:21
|
||||||
*/
|
*/
|
||||||
public interface AttachmentService extends GettableService<Attachment, Long>, DeletableService<Long>, DestroyableService<Long> {
|
public interface AttachmentService extends GettableService<Attachment, Long>, PageableService<Attachment>, UpdatableService<Attachment>, DeletableService<Long>, DestroyableService<Long> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@ -29,6 +33,16 @@ public interface AttachmentService extends GettableService<Attachment, Long>, De
|
|||||||
*/
|
*/
|
||||||
void create(AttachmentRequest request);
|
void create(AttachmentRequest request);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建媒体附件,同步创建缩略图
|
||||||
|
*
|
||||||
|
* @param request 附件请求
|
||||||
|
* @return 缩略图附件
|
||||||
|
*/
|
||||||
|
Attachment createMedia(AttachmentRequest request) throws TimiException;
|
||||||
|
|
||||||
|
void deleteMedia(Long thumbId) throws TimiException;
|
||||||
|
|
||||||
Attachment getByBizId(Attachment.BizType bizType, long bizId);
|
Attachment getByBizId(Attachment.BizType bizType, long bizId);
|
||||||
|
|
||||||
Attachment getByAttachType(Attachment.BizType bizType, long bizId, Enum<?> attachType);
|
Attachment getByAttachType(Attachment.BizType bizType, long bizId, Enum<?> attachType);
|
||||||
@ -47,10 +61,25 @@ public interface AttachmentService extends GettableService<Attachment, Long>, De
|
|||||||
* 根据业务获取所有附件
|
* 根据业务获取所有附件
|
||||||
*
|
*
|
||||||
* @param bizType 业务类型
|
* @param bizType 业务类型
|
||||||
* @param bizId 业务 ID
|
* @param bizId 业务 ID,可为 null
|
||||||
* @param attachTypes
|
* @param attachTypes 附件类型,可为 null
|
||||||
* @return 所有附件
|
* @return 所有附件
|
||||||
* @throws TimiException 服务异常
|
* @throws TimiException 服务异常
|
||||||
*/
|
*/
|
||||||
List<Attachment> listByBizId(Attachment.BizType bizType, long bizId, Enum<?> ...attachTypes);
|
List<Attachment> listByBizId(Attachment.BizType bizType, Long bizId, Enum<?> ...attachTypes);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据业务获取所有附件
|
||||||
|
*
|
||||||
|
* @param bizType 业务类型
|
||||||
|
* @param bizId 业务 ID,可为 null
|
||||||
|
* @param attachTypes 附件类型,可为 null
|
||||||
|
* @return 附件数量
|
||||||
|
* @throws TimiException 服务异常
|
||||||
|
*/
|
||||||
|
long countByBizId(Attachment.BizType bizType, Long bizId, Enum<?> ...attachTypes);
|
||||||
|
|
||||||
|
List<Attachment> listByMd5s(Attachment.BizType bizType, Long bizId, List<Enum<?>> attachTypeList, List<String> md5s) throws TimiException;
|
||||||
|
|
||||||
|
PageResult<Attachment> pageByBizId(Attachment.BizType bizType, Long bizId, List<Enum<?>> attachTypeList, Page page) throws TimiException;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -74,5 +74,7 @@ public interface SettingService extends UpdatableService<Setting> {
|
|||||||
|
|
||||||
List<Setting> listAll();
|
List<Setting> listAll();
|
||||||
|
|
||||||
|
void clearCache(SettingKey key);
|
||||||
|
|
||||||
void flushCache();
|
void flushCache();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,22 @@
|
|||||||
|
package com.imyeyu.api.modules.common.service;
|
||||||
|
|
||||||
|
import com.imyeyu.api.modules.common.bean.TempFileMetaData;
|
||||||
|
import com.imyeyu.api.modules.common.vo.TempFileResponse;
|
||||||
|
import com.imyeyu.java.bean.timi.TimiException;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author 夜雨
|
||||||
|
* @since 2025-09-27 01:35
|
||||||
|
*/
|
||||||
|
public interface TempFileService {
|
||||||
|
|
||||||
|
List<TempFileResponse> store(List<MultipartFile> files) throws TimiException;
|
||||||
|
|
||||||
|
File get(String id) throws TimiException;
|
||||||
|
|
||||||
|
TempFileMetaData metadata(String id) throws TimiException;
|
||||||
|
}
|
||||||
@ -1,15 +1,22 @@
|
|||||||
package com.imyeyu.api.modules.common.service.implement;
|
package com.imyeyu.api.modules.common.service.implement;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.imyeyu.api.config.dbsource.TimiServerDBConfig;
|
||||||
|
import com.imyeyu.api.modules.common.bean.MediaAttach;
|
||||||
|
import com.imyeyu.api.modules.common.entity.Attachment;
|
||||||
|
import com.imyeyu.api.modules.common.mapper.AttachmentMapper;
|
||||||
|
import com.imyeyu.api.modules.common.service.AttachmentService;
|
||||||
|
import com.imyeyu.api.modules.common.service.SettingService;
|
||||||
|
import com.imyeyu.api.modules.common.vo.attachment.AttachmentRequest;
|
||||||
|
import com.imyeyu.api.modules.common.vo.attachment.AttachmentView;
|
||||||
|
import com.imyeyu.api.util.JavaCV;
|
||||||
import com.imyeyu.io.IO;
|
import com.imyeyu.io.IO;
|
||||||
import com.imyeyu.java.TimiJava;
|
import com.imyeyu.java.TimiJava;
|
||||||
import com.imyeyu.java.bean.timi.TimiCode;
|
import com.imyeyu.java.bean.timi.TimiCode;
|
||||||
import com.imyeyu.java.bean.timi.TimiException;
|
import com.imyeyu.java.bean.timi.TimiException;
|
||||||
import com.imyeyu.api.config.dbsource.TimiServerDBConfig;
|
import com.imyeyu.network.Network;
|
||||||
import com.imyeyu.api.modules.common.entity.Attachment;
|
import com.imyeyu.spring.bean.Page;
|
||||||
import com.imyeyu.api.modules.common.mapper.AttachmentMapper;
|
import com.imyeyu.spring.bean.PageResult;
|
||||||
import com.imyeyu.api.modules.common.service.AttachmentService;
|
|
||||||
import com.imyeyu.api.modules.common.vo.attachment.AttachmentRequest;
|
|
||||||
import com.imyeyu.api.modules.common.vo.attachment.AttachmentView;
|
|
||||||
import com.imyeyu.spring.mapper.BaseMapper;
|
import com.imyeyu.spring.mapper.BaseMapper;
|
||||||
import com.imyeyu.spring.service.AbstractEntityService;
|
import com.imyeyu.spring.service.AbstractEntityService;
|
||||||
import com.imyeyu.utils.Time;
|
import com.imyeyu.utils.Time;
|
||||||
@ -17,6 +24,8 @@ import com.mongodb.client.gridfs.GridFSBucket;
|
|||||||
import com.mongodb.client.gridfs.model.GridFSFile;
|
import com.mongodb.client.gridfs.model.GridFSFile;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import net.coobird.thumbnailator.Thumbnails;
|
||||||
|
import org.apache.tika.Tika;
|
||||||
import org.springframework.beans.BeanUtils;
|
import org.springframework.beans.BeanUtils;
|
||||||
import org.springframework.data.mongodb.core.query.Criteria;
|
import org.springframework.data.mongodb.core.query.Criteria;
|
||||||
import org.springframework.data.mongodb.core.query.Query;
|
import org.springframework.data.mongodb.core.query.Query;
|
||||||
@ -24,9 +33,14 @@ import org.springframework.data.mongodb.gridfs.GridFsTemplate;
|
|||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author 夜雨
|
* @author 夜雨
|
||||||
@ -37,8 +51,11 @@ import java.util.List;
|
|||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class AttachmentServiceImplement extends AbstractEntityService<Attachment, Long> implements AttachmentService {
|
public class AttachmentServiceImplement extends AbstractEntityService<Attachment, Long> implements AttachmentService {
|
||||||
|
|
||||||
|
private final SettingService settingService;
|
||||||
|
|
||||||
private final AttachmentMapper mapper;
|
private final AttachmentMapper mapper;
|
||||||
|
|
||||||
|
private final Gson gson;
|
||||||
private final GridFSBucket gridFSBucket;
|
private final GridFSBucket gridFSBucket;
|
||||||
private final GridFsTemplate gridFsTemplate;
|
private final GridFsTemplate gridFsTemplate;
|
||||||
|
|
||||||
@ -52,11 +69,11 @@ public class AttachmentServiceImplement extends AbstractEntityService<Attachment
|
|||||||
public void destroy(Long id) {
|
public void destroy(Long id) {
|
||||||
try {
|
try {
|
||||||
Attachment attachment = get(id);
|
Attachment attachment = get(id);
|
||||||
if (!attachment.isDeleted()) {
|
|
||||||
delete(id);
|
|
||||||
}
|
|
||||||
mapper.destroy(attachment.getId());
|
|
||||||
gridFsTemplate.delete(Query.query(Criteria.where("_id").is(attachment.getMongoId())));
|
gridFsTemplate.delete(Query.query(Criteria.where("_id").is(attachment.getMongoId())));
|
||||||
|
|
||||||
|
attachment.setDeletedAt(Time.now());
|
||||||
|
attachment.setDestroyAt(Time.now());
|
||||||
|
mapper.update(attachment);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("delete mongo file error", e);
|
log.error("delete mongo file error", e);
|
||||||
throw new TimiException(TimiCode.ERROR).msgKey("TODO delete mongo file error");
|
throw new TimiException(TimiCode.ERROR).msgKey("TODO delete mongo file error");
|
||||||
@ -81,12 +98,12 @@ public class AttachmentServiceImplement extends AbstractEntityService<Attachment
|
|||||||
}
|
}
|
||||||
mongoName.append(request.getName());
|
mongoName.append(request.getName());
|
||||||
|
|
||||||
mongoId = gridFsTemplate.store(is, mongoName.toString()).toString();
|
mongoId = gridFsTemplate.store(request.getInputStream(), mongoName.toString()).toString();
|
||||||
Attachment attachment = new Attachment();
|
GridFSFile gridFSFile = gridFsTemplate.findOne(new Query(Criteria.where("_id").is(mongoId)));
|
||||||
BeanUtils.copyProperties(request, attachment);
|
request.setMongoId(mongoId);
|
||||||
attachment.setMongoId(mongoId);
|
request.setSize(gridFSFile.getLength());
|
||||||
attachment.setCreatedAt(Time.now());
|
request.setMd5(IO.md5(gridFSBucket.openDownloadStream(gridFSFile.getObjectId())));
|
||||||
mapper.insert(attachment);
|
mapper.insert(request);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
if (mongoId != null) {
|
if (mongoId != null) {
|
||||||
gridFsTemplate.delete(Query.query(Criteria.where("_id").is(mongoId)));
|
gridFsTemplate.delete(Query.query(Criteria.where("_id").is(mongoId)));
|
||||||
@ -96,6 +113,74 @@ public class AttachmentServiceImplement extends AbstractEntityService<Attachment
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Transactional(TimiServerDBConfig.ROLLBACKER)
|
||||||
|
@Override
|
||||||
|
public Attachment createMedia(AttachmentRequest request) throws TimiException {
|
||||||
|
TimiException.required(request.getName(), "not found name");
|
||||||
|
TimiException.required(request.getBizType(), "not found bizType");
|
||||||
|
TimiException.required(request.getInputStream(), "not found inputStream");
|
||||||
|
try {
|
||||||
|
// 储存源文件
|
||||||
|
request.setAttachTypeValue(MediaAttach.Type.SOURCE);
|
||||||
|
create(request);
|
||||||
|
|
||||||
|
// 生成缩略图
|
||||||
|
InputStream mimeStream = getInputStreamByMongoId(request.getMongoId());
|
||||||
|
String mimeType = new Tika().detect(mimeStream);
|
||||||
|
boolean isImage = false;
|
||||||
|
|
||||||
|
InputStream sourceStream = getInputStreamByMongoId(request.getMongoId());
|
||||||
|
ByteArrayOutputStream thumbStream = new ByteArrayOutputStream();
|
||||||
|
switch (mimeType) {
|
||||||
|
case "image/png", "image/bmp", "image/jpeg" -> {
|
||||||
|
isImage = true;
|
||||||
|
Thumbnails.of(sourceStream).width(256).keepAspectRatio(true).toOutputStream(thumbStream);
|
||||||
|
}
|
||||||
|
case "video/mp4", "video/quicktime" -> {
|
||||||
|
log.info("capturing thumbnail: {}", request.getName());
|
||||||
|
long start = Time.now();
|
||||||
|
File tempFile = IO.file("temp/%s_%s".formatted(UUID.randomUUID().toString(), request.getName()));
|
||||||
|
try {
|
||||||
|
IO.toFile(tempFile, sourceStream);
|
||||||
|
ByteArrayOutputStream baos = JavaCV.captureThumbnail(IO.getInputStream(tempFile), 2);
|
||||||
|
Thumbnails.of(IO.toInputStream(baos)).width(256).keepAspectRatio(true).toOutputStream(thumbStream);
|
||||||
|
log.info("captured thumbnail: {} at {} ms", request.getName(), Time.now() - start);
|
||||||
|
} finally {
|
||||||
|
IO.destroy(tempFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MediaAttach.ExtData extData = new MediaAttach.ExtData();
|
||||||
|
extData.setImage(isImage);
|
||||||
|
extData.setVideo(!isImage);
|
||||||
|
extData.setSourceId(request.getId());
|
||||||
|
extData.setSourceMongoId(request.getMongoId());
|
||||||
|
|
||||||
|
AttachmentRequest thumbAttach = new AttachmentRequest();
|
||||||
|
thumbAttach.setName(Network.simpleURIFileName(request.getName()) + ".png");
|
||||||
|
thumbAttach.setBizType(request.getBizType());
|
||||||
|
thumbAttach.setBizId(request.getBizId());
|
||||||
|
thumbAttach.setAttachTypeValue(MediaAttach.Type.THUMB);
|
||||||
|
thumbAttach.setExt(gson.toJson(extData));
|
||||||
|
thumbAttach.setInputStream(new ByteArrayInputStream(thumbStream.toByteArray()));
|
||||||
|
create(thumbAttach);
|
||||||
|
|
||||||
|
return get(thumbAttach.getId());
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("create media attachment error", e);
|
||||||
|
throw new TimiException(TimiCode.ERROR).msgKey("TODO create media attachment error");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional(TimiServerDBConfig.ROLLBACKER)
|
||||||
|
@Override
|
||||||
|
public void deleteMedia(Long thumbId) throws TimiException {
|
||||||
|
Attachment attachment = get(thumbId);
|
||||||
|
delete(attachment.getId());
|
||||||
|
MediaAttach.ExtData data = gson.fromJson(attachment.getExt(), MediaAttach.ExtData.class);
|
||||||
|
delete(data.getSourceId());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Attachment getByBizId(Attachment.BizType bizType, long bizId) {
|
public Attachment getByBizId(Attachment.BizType bizType, long bizId) {
|
||||||
return mapper.selectByBizId(bizType, bizId);
|
return mapper.selectByBizId(bizType, bizId);
|
||||||
@ -144,7 +229,25 @@ public class AttachmentServiceImplement extends AbstractEntityService<Attachment
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Attachment> listByBizId(Attachment.BizType bizType, long bizId, Enum<?>... attachTypes) {
|
public List<Attachment> listByBizId(Attachment.BizType bizType, Long bizId, Enum<?>... attachTypes) {
|
||||||
return mapper.listByAttachType(bizType, bizId, attachTypes);
|
return mapper.listByBizId(bizType, bizId, Arrays.asList(attachTypes), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long countByBizId(Attachment.BizType bizType, Long bizId, Enum<?>... attachTypes) {
|
||||||
|
return mapper.countByBizId(bizType, bizId, Arrays.asList(attachTypes));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Attachment> listByMd5s(Attachment.BizType bizType, Long bizId, List<Enum<?>> attachTypeList, List<String> md5s) throws TimiException {
|
||||||
|
return mapper.listByMd5s(bizType, bizId, attachTypeList, md5s);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PageResult<Attachment> pageByBizId(Attachment.BizType bizType, Long bizId, List<Enum<?>> attachTypeList, Page page) throws TimiException {
|
||||||
|
PageResult<Attachment> result = new PageResult<>();
|
||||||
|
result.setList(mapper.listByBizId(bizType, bizId, attachTypeList, page));
|
||||||
|
result.setTotal(mapper.countByBizId(bizType, bizId, attachTypeList));
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,13 +6,13 @@ import com.google.gson.JsonElement;
|
|||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
import com.google.gson.JsonParser;
|
import com.google.gson.JsonParser;
|
||||||
import com.google.gson.reflect.TypeToken;
|
import com.google.gson.reflect.TypeToken;
|
||||||
import com.imyeyu.java.TimiJava;
|
|
||||||
import com.imyeyu.java.bean.timi.TimiCode;
|
|
||||||
import com.imyeyu.java.bean.timi.TimiException;
|
|
||||||
import com.imyeyu.api.modules.common.bean.SettingKey;
|
import com.imyeyu.api.modules.common.bean.SettingKey;
|
||||||
import com.imyeyu.api.modules.common.entity.Setting;
|
import com.imyeyu.api.modules.common.entity.Setting;
|
||||||
import com.imyeyu.api.modules.common.mapper.SettingMapper;
|
import com.imyeyu.api.modules.common.mapper.SettingMapper;
|
||||||
import com.imyeyu.api.modules.common.service.SettingService;
|
import com.imyeyu.api.modules.common.service.SettingService;
|
||||||
|
import com.imyeyu.java.TimiJava;
|
||||||
|
import com.imyeyu.java.bean.timi.TimiCode;
|
||||||
|
import com.imyeyu.java.bean.timi.TimiException;
|
||||||
import com.imyeyu.spring.mapper.BaseMapper;
|
import com.imyeyu.spring.mapper.BaseMapper;
|
||||||
import com.imyeyu.spring.service.AbstractEntityService;
|
import com.imyeyu.spring.service.AbstractEntityService;
|
||||||
import com.imyeyu.spring.util.Redis;
|
import com.imyeyu.spring.util.Redis;
|
||||||
@ -144,6 +144,11 @@ public class SettingServiceImplement extends AbstractEntityService<Setting, Stri
|
|||||||
return mapper.listAll();
|
return mapper.listAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clearCache(SettingKey key) {
|
||||||
|
redisSetting.destroy(key.toString());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void flushCache() {
|
public void flushCache() {
|
||||||
redisSetting.flushAll();
|
redisSetting.flushAll();
|
||||||
|
|||||||
@ -0,0 +1,132 @@
|
|||||||
|
package com.imyeyu.api.modules.common.service.implement;
|
||||||
|
|
||||||
|
import com.imyeyu.api.modules.common.bean.SettingKey;
|
||||||
|
import com.imyeyu.api.modules.common.bean.TempFileMetaData;
|
||||||
|
import com.imyeyu.api.modules.common.service.AttachmentService;
|
||||||
|
import com.imyeyu.api.modules.common.service.SettingService;
|
||||||
|
import com.imyeyu.api.modules.common.service.TempFileService;
|
||||||
|
import com.imyeyu.api.modules.common.vo.TempFileResponse;
|
||||||
|
import com.imyeyu.io.IO;
|
||||||
|
import com.imyeyu.io.IOSize;
|
||||||
|
import com.imyeyu.java.TimiJava;
|
||||||
|
import com.imyeyu.java.bean.timi.TimiCode;
|
||||||
|
import com.imyeyu.java.bean.timi.TimiException;
|
||||||
|
import com.imyeyu.network.Network;
|
||||||
|
import com.imyeyu.spring.TimiSpring;
|
||||||
|
import com.imyeyu.utils.Time;
|
||||||
|
import jakarta.annotation.PostConstruct;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author 夜雨
|
||||||
|
* @since 2025-09-27 01:47
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class TempFileServiceImplement implements TempFileService {
|
||||||
|
|
||||||
|
private static final Long TTL = Time.H * 6;
|
||||||
|
private static final Long LIMIT = IOSize.GB * 10;
|
||||||
|
|
||||||
|
private final SettingService settingService;
|
||||||
|
private final AttachmentService attachmentService;
|
||||||
|
|
||||||
|
private Path storagePath;
|
||||||
|
|
||||||
|
private final Map<String, TempFileMetaData> metadataMap = new ConcurrentHashMap<>();
|
||||||
|
private final Map<String, Long> usageMap = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
public void init() throws IOException {
|
||||||
|
storagePath = Paths.get(settingService.getAsString(SettingKey.TEMP_FILE_PATH));
|
||||||
|
IO.destroy(storagePath.toFile());
|
||||||
|
Files.createDirectories(storagePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<TempFileResponse> store(List<MultipartFile> files) throws TimiException {
|
||||||
|
long newFileSize = files.stream().mapToLong(MultipartFile::getSize).sum();
|
||||||
|
long currentUsage = usageMap.getOrDefault(TimiSpring.getRequestIP(), 0L);
|
||||||
|
TimiException.requiredTrue(currentUsage + newFileSize < LIMIT, "out of storage limit(10 GB)");
|
||||||
|
|
||||||
|
try {
|
||||||
|
List<TempFileResponse> result = new ArrayList<>();
|
||||||
|
for (int i = 0; i < files.size(); i++) {
|
||||||
|
MultipartFile file = files.get(i);
|
||||||
|
|
||||||
|
String fileId = UUID.randomUUID().toString();
|
||||||
|
String fileName = fileId;
|
||||||
|
if (TimiJava.isNotEmpty(file.getOriginalFilename())) {
|
||||||
|
fileName = fileId + "." + Network.uriFileExtension(file.getOriginalFilename());
|
||||||
|
}
|
||||||
|
Path filePath = storagePath.resolve(fileName);
|
||||||
|
Files.copy(file.getInputStream(), filePath);
|
||||||
|
|
||||||
|
// 创建元数据
|
||||||
|
TempFileMetaData metadata = new TempFileMetaData();
|
||||||
|
metadata.setId(fileId);
|
||||||
|
metadata.setPath(filePath);
|
||||||
|
metadata.setName(fileName);
|
||||||
|
metadata.setOriginalName(file.getOriginalFilename());
|
||||||
|
metadata.setLastAccessAt(Time.now());
|
||||||
|
metadataMap.put(metadata.getId(), metadata);
|
||||||
|
|
||||||
|
TempFileResponse resp = new TempFileResponse();
|
||||||
|
resp.setId(metadata.getId());
|
||||||
|
resp.setExpireAt(metadata.getLastAccessAt() + TTL);
|
||||||
|
|
||||||
|
usageMap.put(TimiSpring.getRequestIP(), currentUsage + newFileSize);
|
||||||
|
result.add(resp);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("store temp file error", e);
|
||||||
|
throw new TimiException(TimiCode.ERROR, "store temp file error", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public File get(String id) throws TimiException {
|
||||||
|
TempFileMetaData metaData = metadataMap.get(id);
|
||||||
|
TimiException.required(metaData, "not found temp file");
|
||||||
|
metaData.setLastAccessAt(Time.now());
|
||||||
|
return metaData.getPath().toFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TempFileMetaData metadata(String id) throws TimiException {
|
||||||
|
return metadataMap.get(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Scheduled(fixedRate = 3600000)
|
||||||
|
public void cleanup() {
|
||||||
|
List<String> expiredIds = metadataMap.values()
|
||||||
|
.stream()
|
||||||
|
.filter(metadata -> metadata.getLastAccessAt() + TTL < Time.now())
|
||||||
|
.map(TempFileMetaData::getId)
|
||||||
|
.toList();
|
||||||
|
for (int i = 0; i < expiredIds.size(); i++) {
|
||||||
|
TempFileMetaData removed = metadataMap.remove(expiredIds.get(i));
|
||||||
|
if (TimiJava.isNotEmpty(removed)) {
|
||||||
|
File file = removed.getPath().toFile();
|
||||||
|
IO.destroy(file);
|
||||||
|
usageMap.computeIfPresent(TimiSpring.getRequestIP(), (ip, usage) -> usage - file.length());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -3,17 +3,17 @@ package com.imyeyu.api.modules.common.task;
|
|||||||
import com.google.gson.JsonArray;
|
import com.google.gson.JsonArray;
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
import com.google.gson.JsonParser;
|
import com.google.gson.JsonParser;
|
||||||
import com.imyeyu.java.TimiJava;
|
|
||||||
import com.imyeyu.java.bean.Language;
|
|
||||||
import com.imyeyu.java.bean.timi.TimiCode;
|
|
||||||
import com.imyeyu.java.bean.timi.TimiException;
|
|
||||||
import com.imyeyu.java.ref.Ref;
|
|
||||||
import com.imyeyu.network.FormMap;
|
|
||||||
import com.imyeyu.api.config.dbsource.TimiServerDBConfig;
|
import com.imyeyu.api.config.dbsource.TimiServerDBConfig;
|
||||||
import com.imyeyu.api.modules.common.bean.SettingKey;
|
import com.imyeyu.api.modules.common.bean.SettingKey;
|
||||||
import com.imyeyu.api.modules.common.entity.Multilingual;
|
import com.imyeyu.api.modules.common.entity.Multilingual;
|
||||||
import com.imyeyu.api.modules.common.service.MultilingualService;
|
import com.imyeyu.api.modules.common.service.MultilingualService;
|
||||||
import com.imyeyu.api.modules.common.service.SettingService;
|
import com.imyeyu.api.modules.common.service.SettingService;
|
||||||
|
import com.imyeyu.java.TimiJava;
|
||||||
|
import com.imyeyu.java.bean.Language;
|
||||||
|
import com.imyeyu.java.bean.timi.TimiCode;
|
||||||
|
import com.imyeyu.java.bean.timi.TimiException;
|
||||||
|
import com.imyeyu.java.ref.Ref;
|
||||||
|
import com.imyeyu.network.ArgMap;
|
||||||
import com.imyeyu.utils.Digest;
|
import com.imyeyu.utils.Digest;
|
||||||
import com.imyeyu.utils.Time;
|
import com.imyeyu.utils.Time;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
@ -134,7 +134,7 @@ public class MultilingualTranslateTask {
|
|||||||
String appId = settingService.getAsString(SettingKey.MULTILINGUAL_TRANSLATE_APP_ID);
|
String appId = settingService.getAsString(SettingKey.MULTILINGUAL_TRANSLATE_APP_ID);
|
||||||
String key = settingService.getAsString(SettingKey.MULTILINGUAL_TRANSLATE_KEY);
|
String key = settingService.getAsString(SettingKey.MULTILINGUAL_TRANSLATE_KEY);
|
||||||
|
|
||||||
FormMap<String, Object> args = new FormMap<>();
|
ArgMap<String, Object> args = new ArgMap<>();
|
||||||
args.put("q", text);
|
args.put("q", text);
|
||||||
args.put("from", BaiduLanguage.ZH.toString().toLowerCase());
|
args.put("from", BaiduLanguage.ZH.toString().toLowerCase());
|
||||||
args.put("to", to.toString().toLowerCase());
|
args.put("to", to.toString().toLowerCase());
|
||||||
@ -143,7 +143,7 @@ public class MultilingualTranslateTask {
|
|||||||
args.put("sign", Digest.md5(appId + text + random + key));
|
args.put("sign", Digest.md5(appId + text + random + key));
|
||||||
|
|
||||||
String response = Request.post(settingService.getAsString(SettingKey.MULTILINGUAL_TRANSLATE_API))
|
String response = Request.post(settingService.getAsString(SettingKey.MULTILINGUAL_TRANSLATE_API))
|
||||||
.bodyForm(args.build())
|
.bodyForm(args.toNameValuePair())
|
||||||
.execute()
|
.execute()
|
||||||
.returnContent()
|
.returnContent()
|
||||||
.asString();
|
.asString();
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
package com.imyeyu.api.modules.common.validation.validtor;
|
package com.imyeyu.api.modules.common.validation.validtor;
|
||||||
|
|
||||||
import com.imyeyu.java.TimiJava;
|
|
||||||
import com.imyeyu.api.modules.common.validation.UserName;
|
import com.imyeyu.api.modules.common.validation.UserName;
|
||||||
|
import com.imyeyu.java.TimiJava;
|
||||||
import com.imyeyu.spring.util.AbstractValidator;
|
import com.imyeyu.spring.util.AbstractValidator;
|
||||||
import com.imyeyu.utils.Text;
|
import com.imyeyu.utils.Regex;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 用户名基本验证
|
* 用户名基本验证
|
||||||
@ -24,10 +24,10 @@ public class UserNameValidator extends AbstractValidator<UserName, String> {
|
|||||||
if (userName.contains("@")) {
|
if (userName.contains("@")) {
|
||||||
return "user.name.contains_at";
|
return "user.name.contains_at";
|
||||||
}
|
}
|
||||||
if (Text.testReg("^[0-9]+.?[0-9]*$", userName)) {
|
if (Regex.isMatch("^[0-9]+.?[0-9]*$", userName)) {
|
||||||
return "user.name.only_number";
|
return "user.name.only_number";
|
||||||
}
|
}
|
||||||
if (!Text.testReg("^[A-Za-z0-9_一-龥]+$", userName)) {
|
if (Regex.isNotMatch("^[A-Za-z0-9_一-龥]+$", userName)) {
|
||||||
return "user.name.not_match_regex";
|
return "user.name.not_match_regex";
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
package com.imyeyu.api.modules.common.validation.validtor;
|
package com.imyeyu.api.modules.common.validation.validtor;
|
||||||
|
|
||||||
import com.imyeyu.java.TimiJava;
|
|
||||||
import com.imyeyu.api.modules.common.validation.UserPassword;
|
import com.imyeyu.api.modules.common.validation.UserPassword;
|
||||||
|
import com.imyeyu.java.TimiJava;
|
||||||
import com.imyeyu.spring.util.AbstractValidator;
|
import com.imyeyu.spring.util.AbstractValidator;
|
||||||
import com.imyeyu.utils.Text;
|
import com.imyeyu.utils.Regex;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 用户密码基本验证
|
* 用户密码基本验证
|
||||||
@ -24,7 +24,7 @@ public class UserPasswordValidator extends AbstractValidator<UserPassword, Strin
|
|||||||
if (20 < password.length()) {
|
if (20 < password.length()) {
|
||||||
return "user.password.too_long";
|
return "user.password.too_long";
|
||||||
}
|
}
|
||||||
if (!Text.testReg("(?=.*([a-zA-Z].*))(?=.*[0-9].*)[a-zA-Z0-9-*/+.~!@#$%^&*()]{6,20}$", password)) {
|
if (Regex.isNotMatch("(?=.*([a-zA-Z].*))(?=.*[0-9].*)[a-zA-Z0-9-*/+.~!@#$%^&*()]{6,20}$", password)) {
|
||||||
return "user.password.not_match_regex";
|
return "user.password.not_match_regex";
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@ -0,0 +1,15 @@
|
|||||||
|
package com.imyeyu.api.modules.common.vo;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author 夜雨
|
||||||
|
* @since 2025-09-27 01:37
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class TempFileResponse {
|
||||||
|
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
private Long expireAt;
|
||||||
|
}
|
||||||
@ -1,7 +1,9 @@
|
|||||||
package com.imyeyu.api.modules.forevermc.bean;
|
package com.imyeyu.api.modules.forevermc.bean;
|
||||||
|
|
||||||
import com.imyeyu.api.modules.forevermc.entity.Server;
|
import com.imyeyu.api.modules.forevermc.entity.Server;
|
||||||
|
import jakarta.validation.Valid;
|
||||||
import jakarta.validation.constraints.Min;
|
import jakarta.validation.constraints.Min;
|
||||||
|
import jakarta.validation.constraints.NotBlank;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
@ -17,6 +19,8 @@ import java.util.List;
|
|||||||
@Data
|
@Data
|
||||||
public class ServerStatus implements Cloneable {
|
public class ServerStatus implements Cloneable {
|
||||||
|
|
||||||
|
@Valid
|
||||||
|
@NotBlank
|
||||||
private String id;
|
private String id;
|
||||||
|
|
||||||
/** true 为维护中 */
|
/** true 为维护中 */
|
||||||
@ -60,7 +64,7 @@ public class ServerStatus implements Cloneable {
|
|||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
@EqualsAndHashCode(callSuper = true)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
public static class BaseInfo extends Server implements Cloneable {
|
public static class BaseInfo extends Server {
|
||||||
|
|
||||||
/** 核心 */
|
/** 核心 */
|
||||||
private String core;
|
private String core;
|
||||||
@ -76,14 +80,6 @@ public class ServerStatus implements Cloneable {
|
|||||||
|
|
||||||
/** 游戏版本 */
|
/** 游戏版本 */
|
||||||
private String version;
|
private String version;
|
||||||
|
|
||||||
// @Override
|
|
||||||
// protected BaseInfo clone() throws CloneNotSupportedException {
|
|
||||||
// BaseInfo clone = (BaseInfo) super.clone();
|
|
||||||
// clone.core = core;
|
|
||||||
// clone.bootAt = bootAt;
|
|
||||||
// }
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -0,0 +1,42 @@
|
|||||||
|
package com.imyeyu.api.modules.forevermc.controller;
|
||||||
|
|
||||||
|
import com.imyeyu.api.modules.forevermc.entity.ClientPack;
|
||||||
|
import com.imyeyu.api.modules.forevermc.entity.ClientPackSrc;
|
||||||
|
import com.imyeyu.api.modules.forevermc.service.ClientPackService;
|
||||||
|
import com.imyeyu.spring.annotation.AOPLog;
|
||||||
|
import com.imyeyu.spring.annotation.RequestRateLimit;
|
||||||
|
import com.imyeyu.spring.bean.Page;
|
||||||
|
import com.imyeyu.spring.bean.PageResult;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author 夜雨
|
||||||
|
* @since 2025-07-24 21:43
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@RequestMapping("/fmc/client")
|
||||||
|
public class ClientPackController {
|
||||||
|
|
||||||
|
private final ClientPackService service;
|
||||||
|
|
||||||
|
@AOPLog
|
||||||
|
@RequestRateLimit
|
||||||
|
@RequestMapping("/list")
|
||||||
|
public PageResult<ClientPack> listClientPack(@RequestBody Page page) {
|
||||||
|
return service.page(page);
|
||||||
|
}
|
||||||
|
|
||||||
|
@AOPLog
|
||||||
|
@RequestRateLimit
|
||||||
|
@RequestMapping("/src/{clientId}")
|
||||||
|
public List<ClientPackSrc> listClientPackSrc(@PathVariable("clientId") long clientId) {
|
||||||
|
return service.listClientPackSrc(clientId);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,15 +1,19 @@
|
|||||||
package com.imyeyu.api.modules.forevermc.controller;
|
package com.imyeyu.api.modules.forevermc.controller;
|
||||||
|
|
||||||
import com.imyeyu.java.TimiJava;
|
|
||||||
import com.imyeyu.java.bean.timi.TimiCode;
|
|
||||||
import com.imyeyu.java.bean.timi.TimiException;
|
|
||||||
import com.imyeyu.api.modules.forevermc.bean.ServerStatus;
|
import com.imyeyu.api.modules.forevermc.bean.ServerStatus;
|
||||||
|
import com.imyeyu.api.modules.forevermc.entity.ClientPack;
|
||||||
|
import com.imyeyu.api.modules.forevermc.service.ClientPackService;
|
||||||
import com.imyeyu.api.modules.forevermc.service.ServerService;
|
import com.imyeyu.api.modules.forevermc.service.ServerService;
|
||||||
import com.imyeyu.api.modules.minecraft.annotation.RequiredFMCServerToken;
|
import com.imyeyu.api.modules.minecraft.annotation.RequiredFMCServerToken;
|
||||||
import com.imyeyu.api.modules.minecraft.vo.server.ReportRequest;
|
import com.imyeyu.api.modules.minecraft.vo.server.ReportRequest;
|
||||||
|
import com.imyeyu.java.TimiJava;
|
||||||
|
import com.imyeyu.java.bean.timi.TimiCode;
|
||||||
|
import com.imyeyu.java.bean.timi.TimiException;
|
||||||
import com.imyeyu.spring.annotation.AOPLog;
|
import com.imyeyu.spring.annotation.AOPLog;
|
||||||
import com.imyeyu.spring.annotation.IgnoreGlobalReturn;
|
import com.imyeyu.spring.annotation.IgnoreGlobalReturn;
|
||||||
import com.imyeyu.spring.annotation.RequestRateLimit;
|
import com.imyeyu.spring.annotation.RequestRateLimit;
|
||||||
|
import com.imyeyu.spring.bean.Page;
|
||||||
|
import com.imyeyu.spring.bean.PageResult;
|
||||||
import com.imyeyu.utils.Decoder;
|
import com.imyeyu.utils.Decoder;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
import jakarta.validation.constraints.NotNull;
|
import jakarta.validation.constraints.NotNull;
|
||||||
@ -44,6 +48,7 @@ import java.util.List;
|
|||||||
public class ServerController {
|
public class ServerController {
|
||||||
|
|
||||||
private final ServerService service;
|
private final ServerService service;
|
||||||
|
private final ClientPackService clientService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 服务器状态报告,由 FMCServer 服务端插件发送
|
* 服务器状态报告,由 FMCServer 服务端插件发送
|
||||||
@ -88,6 +93,13 @@ public class ServerController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@AOPLog
|
||||||
|
@RequestRateLimit
|
||||||
|
@GetMapping("/client/{serverId}")
|
||||||
|
public List<ClientPack> listClientPack(@PathVariable("serverId") String serverId) {
|
||||||
|
return service.listClientPack(serverId);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取服务器状态列表
|
* 获取服务器状态列表
|
||||||
*
|
*
|
||||||
@ -112,4 +124,10 @@ public class ServerController {
|
|||||||
result.sort(Comparator.comparingInt(o -> o.getBaseInfo().getOrder()));
|
result.sort(Comparator.comparingInt(o -> o.getBaseInfo().getOrder()));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@RequestRateLimit
|
||||||
|
@PostMapping("/client/list")
|
||||||
|
public PageResult<ClientPack> listClient(@RequestBody Page page) {
|
||||||
|
return clientService.page(page);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,45 @@
|
|||||||
|
package com.imyeyu.api.modules.forevermc.entity;
|
||||||
|
|
||||||
|
import com.imyeyu.spring.annotation.table.Column;
|
||||||
|
import com.imyeyu.spring.entity.Entity;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 服务器客户端
|
||||||
|
*
|
||||||
|
* @author 夜雨
|
||||||
|
* @since 2025-01-27 20:40
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public class ClientPack extends Entity {
|
||||||
|
|
||||||
|
/** 名称 */
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
/** 说明 */
|
||||||
|
private String description;
|
||||||
|
|
||||||
|
/** 游戏 ID */
|
||||||
|
private String gameId;
|
||||||
|
|
||||||
|
/** 游戏版本 */
|
||||||
|
private String gameVersion;
|
||||||
|
|
||||||
|
/** 客户端版本 */
|
||||||
|
private String version;
|
||||||
|
|
||||||
|
/** 需要运行时版本 */
|
||||||
|
private String runtimeVersion;
|
||||||
|
|
||||||
|
/** 文件大小 */
|
||||||
|
private Long size;
|
||||||
|
|
||||||
|
/** true 为支持 FMC 授权验证 */
|
||||||
|
@Column("can_fmc_auth")
|
||||||
|
private Boolean canFMCAuth;
|
||||||
|
|
||||||
|
/** true 为已过时 */
|
||||||
|
private boolean isDeprecated;
|
||||||
|
}
|
||||||
@ -1,8 +1,8 @@
|
|||||||
package com.imyeyu.api.modules.forevermc.entity;
|
package com.imyeyu.api.modules.forevermc.entity;
|
||||||
|
|
||||||
|
import com.imyeyu.spring.entity.Entity;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import com.imyeyu.spring.entity.Entity;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 服务器客户端下载源
|
* 服务器客户端下载源
|
||||||
@ -12,7 +12,7 @@ import com.imyeyu.spring.entity.Entity;
|
|||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
@EqualsAndHashCode(callSuper = true)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
public class ServerClientSrc extends Entity {
|
public class ClientPackSrc extends Entity {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 下载源类型
|
* 下载源类型
|
||||||
@ -32,12 +32,9 @@ public class ServerClientSrc extends Entity {
|
|||||||
URL
|
URL
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 客户端 ID,关联 {@link ServerClient#getId()} */
|
/** 客户端 ID,关联 {@link ClientPack#getId()} */
|
||||||
private Long clientId;
|
private Long clientId;
|
||||||
|
|
||||||
/** 服务器 ID,关联 {@link Server#getId()} */
|
|
||||||
private String serverId;
|
|
||||||
|
|
||||||
/** 下载源类型 */
|
/** 下载源类型 */
|
||||||
private BizType bizType;
|
private BizType bizType;
|
||||||
|
|
||||||
@ -1,13 +1,10 @@
|
|||||||
package com.imyeyu.api.modules.forevermc.entity;
|
package com.imyeyu.api.modules.forevermc.entity;
|
||||||
|
|
||||||
import com.imyeyu.spring.annotation.table.Transient;
|
|
||||||
import com.imyeyu.spring.entity.Destroyable;
|
import com.imyeyu.spring.entity.Destroyable;
|
||||||
import com.imyeyu.spring.entity.UUIDEntity;
|
import com.imyeyu.spring.entity.UUIDEntity;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 服务器
|
* 服务器
|
||||||
*
|
*
|
||||||
@ -36,6 +33,9 @@ public class Server extends UUIDEntity implements Destroyable {
|
|||||||
/** 上级服务器 ID */
|
/** 上级服务器 ID */
|
||||||
protected String pid;
|
protected String pid;
|
||||||
|
|
||||||
|
/** 类型 */
|
||||||
|
protected Type type;
|
||||||
|
|
||||||
/** 标题 */
|
/** 标题 */
|
||||||
protected String title;
|
protected String title;
|
||||||
|
|
||||||
@ -45,13 +45,6 @@ public class Server extends UUIDEntity implements Destroyable {
|
|||||||
/** 地址 */
|
/** 地址 */
|
||||||
protected String host;
|
protected String host;
|
||||||
|
|
||||||
/** 类型 */
|
|
||||||
protected Type type;
|
|
||||||
|
|
||||||
/** 排序 */
|
/** 排序 */
|
||||||
protected int order;
|
protected int order;
|
||||||
|
|
||||||
/** 客户端列表 */
|
|
||||||
@Transient
|
|
||||||
protected List<ServerClient> clientList;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,40 +1,15 @@
|
|||||||
package com.imyeyu.api.modules.forevermc.entity;
|
package com.imyeyu.api.modules.forevermc.entity;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
|
||||||
import com.imyeyu.spring.annotation.table.Transient;
|
|
||||||
import com.imyeyu.spring.entity.Entity;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 服务器客户端
|
|
||||||
*
|
|
||||||
* @author 夜雨
|
* @author 夜雨
|
||||||
* @since 2025-01-27 20:40
|
* @since 2025-07-23 21:54
|
||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
@EqualsAndHashCode(callSuper = true)
|
public class ServerClient {
|
||||||
public class ServerClient extends Entity {
|
|
||||||
|
|
||||||
/** 服务器 ID,关联 {@link Server#getId()} */
|
|
||||||
private String serverId;
|
private String serverId;
|
||||||
|
|
||||||
/** 文件名 */
|
private Long clientId;
|
||||||
private String fileName;
|
|
||||||
|
|
||||||
/** 客户端版本 */
|
|
||||||
private String version;
|
|
||||||
|
|
||||||
/** 默认配置 */
|
|
||||||
private String defOption;
|
|
||||||
|
|
||||||
/** 文件大小 */
|
|
||||||
private Long size;
|
|
||||||
|
|
||||||
/** true 为已过时 */
|
|
||||||
private boolean isDeprecated;
|
|
||||||
|
|
||||||
@Transient
|
|
||||||
private List<ServerClientSrc> srcList;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,12 @@
|
|||||||
|
package com.imyeyu.api.modules.forevermc.mapper;
|
||||||
|
|
||||||
|
import com.imyeyu.api.modules.forevermc.entity.ClientPack;
|
||||||
|
import com.imyeyu.spring.mapper.BaseMapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author 夜雨
|
||||||
|
* @since 2025-02-07 17:03
|
||||||
|
*/
|
||||||
|
public interface ClientPackMapper extends BaseMapper<ClientPack, Long> {
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,17 @@
|
|||||||
|
package com.imyeyu.api.modules.forevermc.mapper;
|
||||||
|
|
||||||
|
import com.imyeyu.api.modules.forevermc.entity.ClientPackSrc;
|
||||||
|
import com.imyeyu.spring.mapper.BaseMapper;
|
||||||
|
import org.apache.ibatis.annotations.Select;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author 夜雨
|
||||||
|
* @since 2025-02-07 17:20
|
||||||
|
*/
|
||||||
|
public interface ClientPackSrcMapper extends BaseMapper<ClientPackSrc, Long> {
|
||||||
|
|
||||||
|
@Select("SELECT * FROM client_pack_src WHERE client_id = #{clientId}" + NOT_DELETE + " ORDER BY `order` ASC")
|
||||||
|
List<ClientPackSrc> selectByClientId(long clientId);
|
||||||
|
}
|
||||||
@ -1,17 +1,14 @@
|
|||||||
package com.imyeyu.api.modules.forevermc.mapper;
|
package com.imyeyu.api.modules.forevermc.mapper;
|
||||||
|
|
||||||
import com.imyeyu.api.modules.forevermc.entity.ServerClient;
|
import com.imyeyu.api.modules.forevermc.entity.ClientPack;
|
||||||
import com.imyeyu.spring.mapper.BaseMapper;
|
|
||||||
import org.apache.ibatis.annotations.Select;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author 夜雨
|
* @author 夜雨
|
||||||
* @since 2025-02-07 17:03
|
* @since 2025-07-23 22:03
|
||||||
*/
|
*/
|
||||||
public interface ServerClientMapper extends BaseMapper<ServerClient, Long> {
|
public interface ServerClientMapper {
|
||||||
|
|
||||||
@Select("SELECT * FROM server_client WHERE server_id = #{serverId}" + NOT_DELETE)
|
List<ClientPack> selectByServerId(String serverId);
|
||||||
List<ServerClient> selectByServerId(String serverId);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,17 +0,0 @@
|
|||||||
package com.imyeyu.api.modules.forevermc.mapper;
|
|
||||||
|
|
||||||
import com.imyeyu.api.modules.forevermc.entity.ServerClientSrc;
|
|
||||||
import com.imyeyu.spring.mapper.BaseMapper;
|
|
||||||
import org.apache.ibatis.annotations.Select;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author 夜雨
|
|
||||||
* @since 2025-02-07 17:20
|
|
||||||
*/
|
|
||||||
public interface ServerClientSrcMapper extends BaseMapper<ServerClientSrc, Long> {
|
|
||||||
|
|
||||||
@Select("SELECT * FROM server_client_src WHERE client_id = #{clientId}" + NOT_DELETE + " ORDER BY order ASC")
|
|
||||||
List<ServerClientSrc> selectByClientId(Long clientId);
|
|
||||||
}
|
|
||||||
@ -0,0 +1,19 @@
|
|||||||
|
package com.imyeyu.api.modules.forevermc.service;
|
||||||
|
|
||||||
|
import com.imyeyu.api.modules.forevermc.entity.ClientPack;
|
||||||
|
import com.imyeyu.api.modules.forevermc.entity.ClientPackSrc;
|
||||||
|
import com.imyeyu.spring.service.DeletableService;
|
||||||
|
import com.imyeyu.spring.service.GettableService;
|
||||||
|
import com.imyeyu.spring.service.PageableService;
|
||||||
|
import com.imyeyu.spring.service.UpdatableService;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author 夜雨
|
||||||
|
* @since 2025-07-23 16:59
|
||||||
|
*/
|
||||||
|
public interface ClientPackService extends PageableService<ClientPack>, GettableService<ClientPack, Long>, UpdatableService<ClientPack>, DeletableService<Long> {
|
||||||
|
|
||||||
|
List<ClientPackSrc> listClientPackSrc(long clientId);
|
||||||
|
}
|
||||||
@ -1,9 +1,10 @@
|
|||||||
package com.imyeyu.api.modules.forevermc.service;
|
package com.imyeyu.api.modules.forevermc.service;
|
||||||
|
|
||||||
|
import com.imyeyu.api.modules.forevermc.bean.ServerStatus;
|
||||||
|
import com.imyeyu.api.modules.forevermc.entity.ClientPack;
|
||||||
|
import com.imyeyu.api.modules.minecraft.vo.server.ReportRequest;
|
||||||
import com.imyeyu.java.TimiJava;
|
import com.imyeyu.java.TimiJava;
|
||||||
import com.imyeyu.java.bean.timi.TimiException;
|
import com.imyeyu.java.bean.timi.TimiException;
|
||||||
import com.imyeyu.api.modules.forevermc.bean.ServerStatus;
|
|
||||||
import com.imyeyu.api.modules.minecraft.vo.server.ReportRequest;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@ -23,6 +24,8 @@ public interface ServerService extends TimiJava {
|
|||||||
*/
|
*/
|
||||||
void report(ReportRequest request);
|
void report(ReportRequest request);
|
||||||
|
|
||||||
|
List<ClientPack> listClientPack(String serverId);
|
||||||
|
|
||||||
String getIcon(String serverId);
|
String getIcon(String serverId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -0,0 +1,35 @@
|
|||||||
|
package com.imyeyu.api.modules.forevermc.service.implement;
|
||||||
|
|
||||||
|
import com.imyeyu.api.modules.forevermc.entity.ClientPack;
|
||||||
|
import com.imyeyu.api.modules.forevermc.entity.ClientPackSrc;
|
||||||
|
import com.imyeyu.api.modules.forevermc.mapper.ClientPackMapper;
|
||||||
|
import com.imyeyu.api.modules.forevermc.mapper.ClientPackSrcMapper;
|
||||||
|
import com.imyeyu.api.modules.forevermc.service.ClientPackService;
|
||||||
|
import com.imyeyu.spring.mapper.BaseMapper;
|
||||||
|
import com.imyeyu.spring.service.AbstractEntityService;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author 夜雨
|
||||||
|
* @since 2025-07-23 16:59
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class ClientPackServiceImplement extends AbstractEntityService<ClientPack, Long> implements ClientPackService {
|
||||||
|
|
||||||
|
private final ClientPackMapper mapper;
|
||||||
|
private final ClientPackSrcMapper srcMapper;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected BaseMapper<ClientPack, Long> mapper() {
|
||||||
|
return mapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ClientPackSrc> listClientPackSrc(long clientId) {
|
||||||
|
return srcMapper.selectByClientId(clientId);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,16 +1,15 @@
|
|||||||
package com.imyeyu.api.modules.forevermc.service.implement;
|
package com.imyeyu.api.modules.forevermc.service.implement;
|
||||||
|
|
||||||
import com.imyeyu.java.TimiJava;
|
|
||||||
import com.imyeyu.java.bean.timi.TimiCode;
|
|
||||||
import com.imyeyu.java.bean.timi.TimiException;
|
|
||||||
import com.imyeyu.api.modules.forevermc.bean.ServerStatus;
|
import com.imyeyu.api.modules.forevermc.bean.ServerStatus;
|
||||||
|
import com.imyeyu.api.modules.forevermc.entity.ClientPack;
|
||||||
import com.imyeyu.api.modules.forevermc.entity.Server;
|
import com.imyeyu.api.modules.forevermc.entity.Server;
|
||||||
import com.imyeyu.api.modules.forevermc.entity.ServerClient;
|
|
||||||
import com.imyeyu.api.modules.forevermc.mapper.ServerClientMapper;
|
import com.imyeyu.api.modules.forevermc.mapper.ServerClientMapper;
|
||||||
import com.imyeyu.api.modules.forevermc.mapper.ServerClientSrcMapper;
|
|
||||||
import com.imyeyu.api.modules.forevermc.mapper.ServerMapper;
|
import com.imyeyu.api.modules.forevermc.mapper.ServerMapper;
|
||||||
import com.imyeyu.api.modules.forevermc.service.ServerService;
|
import com.imyeyu.api.modules.forevermc.service.ServerService;
|
||||||
import com.imyeyu.api.modules.minecraft.vo.server.ReportRequest;
|
import com.imyeyu.api.modules.minecraft.vo.server.ReportRequest;
|
||||||
|
import com.imyeyu.java.TimiJava;
|
||||||
|
import com.imyeyu.java.bean.timi.TimiCode;
|
||||||
|
import com.imyeyu.java.bean.timi.TimiException;
|
||||||
import com.imyeyu.utils.Time;
|
import com.imyeyu.utils.Time;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.beans.BeanUtils;
|
import org.springframework.beans.BeanUtils;
|
||||||
@ -36,7 +35,6 @@ public class ServerServiceImplement implements ServerService {
|
|||||||
|
|
||||||
private final ServerMapper serverMapper;
|
private final ServerMapper serverMapper;
|
||||||
private final ServerClientMapper serverClientMapper;
|
private final ServerClientMapper serverClientMapper;
|
||||||
private final ServerClientSrcMapper serverClientSrcMapper;
|
|
||||||
|
|
||||||
private final Map<String, ServerStatus> serverMap = new HashMap<>();
|
private final Map<String, ServerStatus> serverMap = new HashMap<>();
|
||||||
|
|
||||||
@ -50,13 +48,6 @@ public class ServerServiceImplement implements ServerService {
|
|||||||
}
|
}
|
||||||
Server server = serverMapper.select(item.getKey());
|
Server server = serverMapper.select(item.getKey());
|
||||||
TimiException.required(server, "not found server");
|
TimiException.required(server, "not found server");
|
||||||
|
|
||||||
List<ServerClient> clientList = serverClientMapper.selectByServerId(server.getId());
|
|
||||||
for (int i = 0; i < clientList.size(); i++) {
|
|
||||||
ServerClient client = clientList.get(i);
|
|
||||||
client.setSrcList(serverClientSrcMapper.selectByClientId(client.getId()));
|
|
||||||
}
|
|
||||||
server.setClientList(clientList);
|
|
||||||
BeanUtils.copyProperties(server, item.getValue().getBaseInfo());
|
BeanUtils.copyProperties(server, item.getValue().getBaseInfo());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -74,6 +65,11 @@ public class ServerServiceImplement implements ServerService {
|
|||||||
serverMap.put(request.getId(), request);
|
serverMap.put(request.getId(), request);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ClientPack> listClientPack(String serverId) {
|
||||||
|
return serverClientMapper.selectByServerId(serverId);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getIcon(String serverId) {
|
public String getIcon(String serverId) {
|
||||||
ServerStatus status = serverMap.get(serverId);
|
ServerStatus status = serverMap.get(serverId);
|
||||||
|
|||||||
@ -0,0 +1,59 @@
|
|||||||
|
package com.imyeyu.api.modules.journal.bean;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author 夜雨
|
||||||
|
* @since 2025-09-30 11:51
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class Travel {
|
||||||
|
|
||||||
|
private Luggage luggage;
|
||||||
|
|
||||||
|
private List<Guide> guides;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @author 夜雨
|
||||||
|
* @since 2025-09-30 11:52
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public static class Luggage {
|
||||||
|
|
||||||
|
private List<Item> gao;
|
||||||
|
|
||||||
|
private List<Item> yu;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @author 夜雨
|
||||||
|
* @since 2025-09-30 11:52
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public static class Item {
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
private boolean isTaken;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @author 夜雨
|
||||||
|
* @since 2025-09-30 11:54
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public static class Guide {
|
||||||
|
|
||||||
|
private String title;
|
||||||
|
|
||||||
|
private List<String> images;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,167 @@
|
|||||||
|
package com.imyeyu.api.modules.journal.controller;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.imyeyu.api.bean.wechat.InitCodeResponse;
|
||||||
|
import com.imyeyu.api.modules.common.bean.MediaAttach;
|
||||||
|
import com.imyeyu.api.modules.common.bean.SettingKey;
|
||||||
|
import com.imyeyu.api.modules.common.entity.Attachment;
|
||||||
|
import com.imyeyu.api.modules.common.service.AttachmentService;
|
||||||
|
import com.imyeyu.api.modules.common.service.SettingService;
|
||||||
|
import com.imyeyu.api.modules.journal.bean.Travel;
|
||||||
|
import com.imyeyu.api.modules.journal.entity.Journal;
|
||||||
|
import com.imyeyu.api.modules.journal.service.JournalService;
|
||||||
|
import com.imyeyu.api.modules.journal.vo.AppendRequest;
|
||||||
|
import com.imyeyu.api.modules.journal.vo.ArchiveRequest;
|
||||||
|
import com.imyeyu.api.modules.journal.vo.JournalPage;
|
||||||
|
import com.imyeyu.api.modules.journal.vo.JournalRequest;
|
||||||
|
import com.imyeyu.api.modules.journal.vo.JournalResponse;
|
||||||
|
import com.imyeyu.java.bean.timi.TimiCode;
|
||||||
|
import com.imyeyu.java.bean.timi.TimiException;
|
||||||
|
import com.imyeyu.network.ArgMap;
|
||||||
|
import com.imyeyu.network.GsonRequest;
|
||||||
|
import com.imyeyu.spring.annotation.AOPLog;
|
||||||
|
import com.imyeyu.spring.annotation.RequestRateLimit;
|
||||||
|
import com.imyeyu.spring.annotation.RequestSingleParam;
|
||||||
|
import com.imyeyu.spring.bean.PageResult;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.BeanUtils;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
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 java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author 夜雨
|
||||||
|
* @since 2025-09-26 15:55
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@RestController
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@RequestMapping("/journal")
|
||||||
|
public class JournalController {
|
||||||
|
|
||||||
|
private final Gson gson;
|
||||||
|
private final JournalService service;
|
||||||
|
private final SettingService settingService;
|
||||||
|
private final AttachmentService attachmentService;
|
||||||
|
|
||||||
|
@AOPLog
|
||||||
|
@RequestRateLimit
|
||||||
|
@PostMapping("/openid")
|
||||||
|
public String initOpenId(@RequestSingleParam String code) {
|
||||||
|
try {
|
||||||
|
ArgMap<String, String> args = new ArgMap<>();
|
||||||
|
args.put("appid", settingService.getAsString(SettingKey.JOURNAL_APP_ID));
|
||||||
|
args.put("secret", settingService.getAsString(SettingKey.JOURNAL_APP_SECRET));
|
||||||
|
args.put("js_code", code);
|
||||||
|
args.put("grant_type", "authorization_code");
|
||||||
|
InitCodeResponse resp = GsonRequest.get(args.toURL("https://api.weixin.qq.com/sns/jscode2session")).resultAs(InitCodeResponse.class);
|
||||||
|
return resp.getOpenid();
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("init WeChat openId error", e);
|
||||||
|
throw new TimiException(TimiCode.ERROR, "init openId error", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@AOPLog
|
||||||
|
@RequestRateLimit
|
||||||
|
@PostMapping("/create")
|
||||||
|
public void create(@RequestBody JournalRequest request) {
|
||||||
|
service.create(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/append")
|
||||||
|
public void append(@RequestBody AppendRequest request) {
|
||||||
|
service.appendItems(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
@AOPLog
|
||||||
|
@PostMapping("/delete")
|
||||||
|
public void delete(@RequestBody Long thumbId) {
|
||||||
|
attachmentService.deleteMedia(thumbId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@AOPLog
|
||||||
|
@RequestRateLimit
|
||||||
|
@RequestMapping("/list")
|
||||||
|
public PageResult<JournalResponse> list(@RequestBody JournalPage page) {
|
||||||
|
PageResult<Journal> pageResult = service.page(page);
|
||||||
|
|
||||||
|
PageResult<JournalResponse> result = new PageResult<>();
|
||||||
|
result.setTotal(pageResult.getTotal());
|
||||||
|
result.setList(pageResult.getList().stream().map(item -> {
|
||||||
|
JournalResponse resp = new JournalResponse();
|
||||||
|
resp.setItems(attachmentService.listByBizId(Attachment.BizType.JOURNAL, item.getId()));
|
||||||
|
BeanUtils.copyProperties(item, resp);
|
||||||
|
return resp;
|
||||||
|
}).toList());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@AOPLog
|
||||||
|
@RequestRateLimit
|
||||||
|
@GetMapping("/list/date")
|
||||||
|
public Long[] listDate() {
|
||||||
|
return service.listDate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequestRateLimit
|
||||||
|
@GetMapping("/total")
|
||||||
|
public long total() {
|
||||||
|
long journal = attachmentService.countByBizId(Attachment.BizType.JOURNAL, null, MediaAttach.Type.SOURCE);
|
||||||
|
long journalTravel = attachmentService.countByBizId(Attachment.BizType.JOURNAL_TRAVEL, null, MediaAttach.Type.SOURCE);
|
||||||
|
return journal + journalTravel;
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequestRateLimit
|
||||||
|
@GetMapping("/travel")
|
||||||
|
public Travel getTravel() {
|
||||||
|
return service.getTravel();
|
||||||
|
}
|
||||||
|
|
||||||
|
@AOPLog
|
||||||
|
@RequestRateLimit
|
||||||
|
@PostMapping("/travel/luggage/update")
|
||||||
|
public void updateTravel(@RequestBody Travel.Luggage luggage) {
|
||||||
|
service.updateTravelLuggage(luggage);
|
||||||
|
}
|
||||||
|
|
||||||
|
@AOPLog
|
||||||
|
@RequestRateLimit
|
||||||
|
@PostMapping("/moment/create")
|
||||||
|
public List<Attachment> createMoment(@RequestBody String[] tempFileIds) {
|
||||||
|
return service.createMoment(tempFileIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
@AOPLog
|
||||||
|
@RequestRateLimit
|
||||||
|
@PostMapping("/moment/list")
|
||||||
|
public List<Attachment> listMoment() {
|
||||||
|
return service.listMoment();
|
||||||
|
}
|
||||||
|
|
||||||
|
@AOPLog
|
||||||
|
@RequestRateLimit
|
||||||
|
@PostMapping("/moment/filter")
|
||||||
|
public String[] filterExistMoment(@RequestBody String[] md5s) {
|
||||||
|
return service.filterExistMoment(md5s);
|
||||||
|
}
|
||||||
|
|
||||||
|
@AOPLog
|
||||||
|
@RequestRateLimit
|
||||||
|
@PostMapping("/moment/delete")
|
||||||
|
public void deleteMoment(@RequestBody Long[] thumbIds) {
|
||||||
|
service.deleteMoment(thumbIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
@AOPLog
|
||||||
|
@RequestRateLimit
|
||||||
|
@PostMapping("/moment/archive")
|
||||||
|
public void archiveMoment(@RequestBody ArchiveRequest request) {
|
||||||
|
service.archiveMoment(request);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,41 @@
|
|||||||
|
package com.imyeyu.api.modules.journal.entity;
|
||||||
|
|
||||||
|
import com.imyeyu.spring.entity.Entity;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author 夜雨
|
||||||
|
* @since 2025-09-26 15:48
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public class Journal extends Entity {
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @author 夜雨
|
||||||
|
* @since 2025-10-09 18:44
|
||||||
|
*/
|
||||||
|
public enum Type {
|
||||||
|
|
||||||
|
NORMAL,
|
||||||
|
|
||||||
|
PORTFOLIO
|
||||||
|
}
|
||||||
|
|
||||||
|
private Type type;
|
||||||
|
|
||||||
|
private String idea;
|
||||||
|
|
||||||
|
private Double lat;
|
||||||
|
|
||||||
|
private Double lng;
|
||||||
|
|
||||||
|
private String location;
|
||||||
|
|
||||||
|
private String weather;
|
||||||
|
|
||||||
|
private String pusher;
|
||||||
|
}
|
||||||
@ -0,0 +1,23 @@
|
|||||||
|
package com.imyeyu.api.modules.journal.mapper;
|
||||||
|
|
||||||
|
import com.imyeyu.api.modules.journal.entity.Journal;
|
||||||
|
import com.imyeyu.spring.mapper.BaseMapper;
|
||||||
|
import org.apache.ibatis.annotations.Select;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author 夜雨
|
||||||
|
* @since 2025-09-26 15:54
|
||||||
|
*/
|
||||||
|
public interface JournalMapper extends BaseMapper<Journal, Long> {
|
||||||
|
|
||||||
|
@Select("SELECT COUNT(1) FROM `journal` WHERE `type` = #{type}")
|
||||||
|
long countByType(Journal.Type type);
|
||||||
|
|
||||||
|
@Select("SELECT * FROM `journal` WHERE `type` = #{type} AND `deleted_at` IS NULL ORDER BY `created_at` DESC LIMIT #{offset}, #{limit}")
|
||||||
|
List<Journal> listByType(Journal.Type type, long offset, int limit);
|
||||||
|
|
||||||
|
@Select("SELECT created_at FROM `journal` WHERE `deleted_at` IS NULL")
|
||||||
|
Long[] listDate();
|
||||||
|
}
|
||||||
@ -0,0 +1,43 @@
|
|||||||
|
package com.imyeyu.api.modules.journal.service;
|
||||||
|
|
||||||
|
import com.imyeyu.api.modules.common.entity.Attachment;
|
||||||
|
import com.imyeyu.api.modules.journal.bean.Travel;
|
||||||
|
import com.imyeyu.api.modules.journal.entity.Journal;
|
||||||
|
import com.imyeyu.api.modules.journal.vo.AppendRequest;
|
||||||
|
import com.imyeyu.api.modules.journal.vo.ArchiveRequest;
|
||||||
|
import com.imyeyu.api.modules.journal.vo.JournalPage;
|
||||||
|
import com.imyeyu.api.modules.journal.vo.JournalRequest;
|
||||||
|
import com.imyeyu.java.bean.timi.TimiException;
|
||||||
|
import com.imyeyu.spring.bean.PageResult;
|
||||||
|
import com.imyeyu.spring.service.DeletableService;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author 夜雨
|
||||||
|
* @since 2025-09-26 15:53
|
||||||
|
*/
|
||||||
|
public interface JournalService extends DeletableService<Long> {
|
||||||
|
|
||||||
|
PageResult<Journal> page(JournalPage page) throws TimiException;
|
||||||
|
|
||||||
|
Long[] listDate() throws TimiException;
|
||||||
|
|
||||||
|
void create(JournalRequest request) throws TimiException;
|
||||||
|
|
||||||
|
void appendItems(AppendRequest request) throws TimiException;
|
||||||
|
|
||||||
|
String[] filterExistMoment(String[] md5s) throws TimiException;
|
||||||
|
|
||||||
|
List<Attachment> createMoment(String[] tempFileIds) throws TimiException;
|
||||||
|
|
||||||
|
List<Attachment> listMoment() throws TimiException;
|
||||||
|
|
||||||
|
void deleteMoment(Long[] thumbIds) throws TimiException;
|
||||||
|
|
||||||
|
void archiveMoment(ArchiveRequest request) throws TimiException;
|
||||||
|
|
||||||
|
Travel getTravel() throws TimiException;
|
||||||
|
|
||||||
|
void updateTravelLuggage(Travel.Luggage luggage) throws TimiException;
|
||||||
|
}
|
||||||
@ -0,0 +1,230 @@
|
|||||||
|
package com.imyeyu.api.modules.journal.service.implement;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.imyeyu.api.config.dbsource.TimiServerDBConfig;
|
||||||
|
import com.imyeyu.api.modules.common.bean.MediaAttach;
|
||||||
|
import com.imyeyu.api.modules.common.bean.SettingKey;
|
||||||
|
import com.imyeyu.api.modules.common.bean.TempFileMetaData;
|
||||||
|
import com.imyeyu.api.modules.common.entity.Attachment;
|
||||||
|
import com.imyeyu.api.modules.common.entity.Setting;
|
||||||
|
import com.imyeyu.api.modules.common.service.AttachmentService;
|
||||||
|
import com.imyeyu.api.modules.common.service.SettingService;
|
||||||
|
import com.imyeyu.api.modules.common.service.TempFileService;
|
||||||
|
import com.imyeyu.api.modules.common.vo.attachment.AttachmentRequest;
|
||||||
|
import com.imyeyu.api.modules.journal.bean.Travel;
|
||||||
|
import com.imyeyu.api.modules.journal.entity.Journal;
|
||||||
|
import com.imyeyu.api.modules.journal.mapper.JournalMapper;
|
||||||
|
import com.imyeyu.api.modules.journal.service.JournalService;
|
||||||
|
import com.imyeyu.api.modules.journal.vo.AppendRequest;
|
||||||
|
import com.imyeyu.api.modules.journal.vo.ArchiveRequest;
|
||||||
|
import com.imyeyu.api.modules.journal.vo.JournalPage;
|
||||||
|
import com.imyeyu.api.modules.journal.vo.JournalRequest;
|
||||||
|
import com.imyeyu.io.IO;
|
||||||
|
import com.imyeyu.java.TimiJava;
|
||||||
|
import com.imyeyu.java.bean.timi.TimiCode;
|
||||||
|
import com.imyeyu.java.bean.timi.TimiException;
|
||||||
|
import com.imyeyu.spring.bean.Page;
|
||||||
|
import com.imyeyu.spring.bean.PageResult;
|
||||||
|
import com.imyeyu.spring.mapper.BaseMapper;
|
||||||
|
import com.imyeyu.spring.service.AbstractEntityService;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.BeanUtils;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author 夜雨
|
||||||
|
* @since 2025-09-26 15:54
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class JournalServiceImplement extends AbstractEntityService<Journal, Long> implements JournalService {
|
||||||
|
|
||||||
|
private final Gson gson;
|
||||||
|
|
||||||
|
private final SettingService settingService;
|
||||||
|
private final TempFileService tempFileService;
|
||||||
|
private final AttachmentService attachmentService;
|
||||||
|
|
||||||
|
private final JournalMapper mapper;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected BaseMapper<Journal, Long> mapper() {
|
||||||
|
return mapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PageResult<Journal> page(JournalPage page) {
|
||||||
|
PageResult<Journal> result = new PageResult<>();
|
||||||
|
result.setTotal(mapper.countByType(page.getType()));
|
||||||
|
result.setList(mapper.listByType(page.getType(), page.getOffset(), page.getLimit()));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Long[] listDate() throws TimiException {
|
||||||
|
return mapper.listDate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional(TimiServerDBConfig.ROLLBACKER)
|
||||||
|
@Override
|
||||||
|
public void create(JournalRequest request) throws TimiException {
|
||||||
|
try {
|
||||||
|
Journal journal = new Journal();
|
||||||
|
BeanUtils.copyProperties(request, journal);
|
||||||
|
super.create(journal);
|
||||||
|
|
||||||
|
String[] tempFileIds = request.getTempFileIds();
|
||||||
|
if (TimiJava.isEmpty(tempFileIds)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < tempFileIds.length; i++) {
|
||||||
|
TempFileMetaData metadata = tempFileService.metadata(tempFileIds[i]);
|
||||||
|
File file = tempFileService.get(tempFileIds[i]);
|
||||||
|
|
||||||
|
AttachmentRequest sourceAttach = new AttachmentRequest();
|
||||||
|
sourceAttach.setName(metadata.getOriginalName());
|
||||||
|
sourceAttach.setBizType(Attachment.BizType.JOURNAL);
|
||||||
|
sourceAttach.setBizId(journal.getId());
|
||||||
|
sourceAttach.setInputStream(IO.getInputStream(file));
|
||||||
|
attachmentService.createMedia(sourceAttach);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("create journal error", e);
|
||||||
|
throw new TimiException(TimiCode.ERROR).msgKey("TODO create journal error");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void appendItems(AppendRequest request) throws TimiException {
|
||||||
|
TimiException.required(request.getTempFileIds(), "not found or empty tempFileIds");
|
||||||
|
try {
|
||||||
|
Journal journal = get(request.getId());
|
||||||
|
|
||||||
|
String[] tempFileIds = request.getTempFileIds();
|
||||||
|
for (int i = 0; i < tempFileIds.length; i++) {
|
||||||
|
TempFileMetaData metadata = tempFileService.metadata(tempFileIds[i]);
|
||||||
|
File file = tempFileService.get(tempFileIds[i]);
|
||||||
|
|
||||||
|
AttachmentRequest sourceAttach = new AttachmentRequest();
|
||||||
|
sourceAttach.setName(metadata.getOriginalName());
|
||||||
|
sourceAttach.setBizType(Attachment.BizType.JOURNAL);
|
||||||
|
sourceAttach.setBizId(journal.getId());
|
||||||
|
sourceAttach.setInputStream(IO.getInputStream(file));
|
||||||
|
attachmentService.createMedia(sourceAttach);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("create journal error", e);
|
||||||
|
throw new TimiException(TimiCode.ERROR).msgKey("TODO create journal error");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String[] filterExistMoment(String[] md5s) throws TimiException {
|
||||||
|
if (TimiJava.isEmpty(md5s)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Set<String> dbMD5 = attachmentService.listByMd5s(Attachment.BizType.JOURNAL_MOMENT, null, List.of(MediaAttach.Type.SOURCE), Arrays.asList(md5s))
|
||||||
|
.stream()
|
||||||
|
.map(Attachment::getMd5)
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
return Arrays.stream(md5s).filter(md5 -> !dbMD5.contains(md5)).toArray(String[]::new);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Attachment> createMoment(String[] tempFileIds) throws TimiException {
|
||||||
|
if (TimiJava.isEmpty(tempFileIds)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
List<Attachment> thumbResult = new ArrayList<>();
|
||||||
|
for (int i = 0; i < tempFileIds.length; i++) {
|
||||||
|
TempFileMetaData metadata = tempFileService.metadata(tempFileIds[i]);
|
||||||
|
File file = tempFileService.get(tempFileIds[i]);
|
||||||
|
|
||||||
|
AttachmentRequest sourceAttach = new AttachmentRequest();
|
||||||
|
sourceAttach.setName(metadata.getOriginalName());
|
||||||
|
sourceAttach.setBizType(Attachment.BizType.JOURNAL_MOMENT);
|
||||||
|
sourceAttach.setBizId(0L);
|
||||||
|
sourceAttach.setAttachTypeValue(MediaAttach.Type.SOURCE);
|
||||||
|
sourceAttach.setSize(file.length());
|
||||||
|
sourceAttach.setInputStream(IO.getInputStream(file));
|
||||||
|
thumbResult.add(attachmentService.createMedia(sourceAttach));
|
||||||
|
}
|
||||||
|
return thumbResult;
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("create moment error", e);
|
||||||
|
throw new TimiException(TimiCode.ERROR).msgKey("TODO create moment error");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Attachment> listMoment() throws TimiException {
|
||||||
|
Page page = new Page(0, Integer.MAX_VALUE);
|
||||||
|
LinkedHashMap<String, BaseMapper.OrderType> orderMap = new LinkedHashMap<>();
|
||||||
|
orderMap.put("created_at", BaseMapper.OrderType.DESC);
|
||||||
|
page.setOrderMap(orderMap);
|
||||||
|
return attachmentService.pageByBizId(Attachment.BizType.JOURNAL_MOMENT, 0L, List.of(MediaAttach.Type.THUMB), page).getList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deleteMoment(Long[] thumbIds) throws TimiException {
|
||||||
|
for (int i = 0; i < thumbIds.length; i++) {
|
||||||
|
attachmentService.deleteMedia(thumbIds[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void archiveMoment(ArchiveRequest request) throws TimiException {
|
||||||
|
try {
|
||||||
|
Journal journal = new Journal();
|
||||||
|
BeanUtils.copyProperties(request, journal);
|
||||||
|
super.create(journal);
|
||||||
|
|
||||||
|
Long[] thumbIds = request.getThumbIds();
|
||||||
|
if (TimiJava.isEmpty(thumbIds)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < thumbIds.length; i++) {
|
||||||
|
Attachment thumbAttach = attachmentService.get(thumbIds[i]);
|
||||||
|
thumbAttach.setBizType(Attachment.BizType.JOURNAL);
|
||||||
|
thumbAttach.setBizId(journal.getId());
|
||||||
|
attachmentService.update(thumbAttach);
|
||||||
|
|
||||||
|
MediaAttach.ExtData extData = gson.fromJson(thumbAttach.getExt(), MediaAttach.ExtData.class);
|
||||||
|
Attachment sourceAttach = attachmentService.get(extData.getSourceId());
|
||||||
|
sourceAttach.setBizType(Attachment.BizType.JOURNAL);
|
||||||
|
sourceAttach.setBizId(journal.getId());
|
||||||
|
attachmentService.update(sourceAttach);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("archive journal error", e);
|
||||||
|
throw new TimiException(TimiCode.ERROR).msgKey("TODO archive journal error");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Travel getTravel() throws TimiException {
|
||||||
|
return gson.fromJson(settingService.getAsJsonObject(SettingKey.JOURNAL_TRAVEL), Travel.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateTravelLuggage(Travel.Luggage luggage) throws TimiException {
|
||||||
|
Travel dbTravel = getTravel();
|
||||||
|
dbTravel.setLuggage(luggage);
|
||||||
|
Setting setting = settingService.getByKey(SettingKey.JOURNAL_TRAVEL);
|
||||||
|
setting.setValue(gson.toJson(dbTravel));
|
||||||
|
settingService.update(setting);
|
||||||
|
settingService.clearCache(SettingKey.JOURNAL_TRAVEL);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,47 @@
|
|||||||
|
package com.imyeyu.api.modules.journal.util;
|
||||||
|
|
||||||
|
import com.imyeyu.api.modules.common.bean.SettingKey;
|
||||||
|
import com.imyeyu.api.modules.common.service.SettingService;
|
||||||
|
import com.imyeyu.java.TimiJava;
|
||||||
|
import com.imyeyu.java.bean.timi.TimiCode;
|
||||||
|
import com.imyeyu.java.bean.timi.TimiException;
|
||||||
|
import com.imyeyu.spring.TimiSpring;
|
||||||
|
import jakarta.annotation.PostConstruct;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.lang.NonNull;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.servlet.HandlerInterceptor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author 夜雨
|
||||||
|
* @version 2023-11-23 17:09
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class JournalAPIInterceptor implements HandlerInterceptor {
|
||||||
|
|
||||||
|
public static final String PATH = "/journal/**";
|
||||||
|
|
||||||
|
private final SettingService settingService;
|
||||||
|
|
||||||
|
private String[] keys;
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
private void postConstruct() {
|
||||||
|
keys = settingService.getAsString(SettingKey.JOURNAL_KEY).split(",");
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean preHandle(@NonNull HttpServletRequest req, @NonNull HttpServletResponse resp, @NonNull Object handler) {
|
||||||
|
String key = TimiJava.firstNotEmpty(TimiSpring.getHeader("Key"), TimiSpring.getRequestArg("key"));
|
||||||
|
for (int i = 0; i < keys.length; i++) {
|
||||||
|
if (keys[i].equals(key)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new TimiException(TimiCode.ARG_MISS).msgKey("invalid.key");
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,15 @@
|
|||||||
|
package com.imyeyu.api.modules.journal.vo;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author 夜雨
|
||||||
|
* @since 2025-09-30 20:37
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class AppendRequest {
|
||||||
|
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
private String[] tempFileIds;
|
||||||
|
}
|
||||||
@ -0,0 +1,16 @@
|
|||||||
|
package com.imyeyu.api.modules.journal.vo;
|
||||||
|
|
||||||
|
import com.imyeyu.api.modules.journal.entity.Journal;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author 夜雨
|
||||||
|
* @since 2025-10-20 15:29
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public class ArchiveRequest extends Journal {
|
||||||
|
|
||||||
|
private Long[] thumbIds;
|
||||||
|
}
|
||||||
@ -0,0 +1,17 @@
|
|||||||
|
package com.imyeyu.api.modules.journal.vo;
|
||||||
|
|
||||||
|
import com.imyeyu.api.modules.journal.entity.Journal;
|
||||||
|
import com.imyeyu.spring.bean.Page;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author 夜雨
|
||||||
|
* @since 2025-10-09 18:48
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public class JournalPage extends Page {
|
||||||
|
|
||||||
|
private Journal.Type type;
|
||||||
|
}
|
||||||
@ -0,0 +1,18 @@
|
|||||||
|
package com.imyeyu.api.modules.journal.vo;
|
||||||
|
|
||||||
|
import com.imyeyu.api.modules.journal.entity.Journal;
|
||||||
|
import com.imyeyu.spring.annotation.table.Transient;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author 夜雨
|
||||||
|
* @since 2025-09-26 15:56
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public class JournalRequest extends Journal {
|
||||||
|
|
||||||
|
@Transient
|
||||||
|
private String[] tempFileIds;
|
||||||
|
}
|
||||||
@ -0,0 +1,19 @@
|
|||||||
|
package com.imyeyu.api.modules.journal.vo;
|
||||||
|
|
||||||
|
import com.imyeyu.api.modules.common.entity.Attachment;
|
||||||
|
import com.imyeyu.api.modules.journal.entity.Journal;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author 夜雨
|
||||||
|
* @since 2025-09-26 15:56
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public class JournalResponse extends Journal {
|
||||||
|
|
||||||
|
private List<Attachment> items;
|
||||||
|
}
|
||||||
@ -1,13 +1,13 @@
|
|||||||
package com.imyeyu.api.modules.system.controller;
|
package com.imyeyu.api.modules.system.controller;
|
||||||
|
|
||||||
import com.imyeyu.io.IO;
|
|
||||||
import com.imyeyu.java.bean.timi.TimiCode;
|
|
||||||
import com.imyeyu.java.bean.timi.TimiException;
|
|
||||||
import com.imyeyu.api.modules.common.service.AttachmentService;
|
import com.imyeyu.api.modules.common.service.AttachmentService;
|
||||||
import com.imyeyu.api.modules.common.vo.attachment.AttachmentRequest;
|
import com.imyeyu.api.modules.common.vo.attachment.AttachmentRequest;
|
||||||
import com.imyeyu.api.modules.system.bean.ServerStatus;
|
import com.imyeyu.api.modules.system.bean.ServerStatus;
|
||||||
import com.imyeyu.api.modules.system.service.SystemService;
|
import com.imyeyu.api.modules.system.service.SystemService;
|
||||||
import com.imyeyu.api.modules.system.vo.TempAttachRequest;
|
import com.imyeyu.api.modules.system.vo.TempAttachRequest;
|
||||||
|
import com.imyeyu.io.IO;
|
||||||
|
import com.imyeyu.java.bean.timi.TimiCode;
|
||||||
|
import com.imyeyu.java.bean.timi.TimiException;
|
||||||
import com.imyeyu.spring.annotation.AOPLog;
|
import com.imyeyu.spring.annotation.AOPLog;
|
||||||
import jakarta.validation.constraints.NotNull;
|
import jakarta.validation.constraints.NotNull;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|||||||
@ -47,7 +47,8 @@ public class GsonSerializerAdapter implements JsonSerializer<Object> {
|
|||||||
if (TimiJava.isNotEmpty(multiLangId)) {
|
if (TimiJava.isNotEmpty(multiLangId)) {
|
||||||
Long langId = Long.parseLong(multiLangId);
|
Long langId = Long.parseLong(multiLangId);
|
||||||
if (redisMultilingual.map(TimiServerAPI.getUserLanguage()) instanceof RedisLanguage rl) {
|
if (redisMultilingual.map(TimiServerAPI.getUserLanguage()) instanceof RedisLanguage rl) {
|
||||||
Ref.setFieldValue(value, field, rl.textArgs(langId, (Object) multiField.args()));
|
// TODO 支持插值参数
|
||||||
|
Ref.setFieldValue(value, field, rl.text(langId));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,18 +3,18 @@ package com.imyeyu.api.util;
|
|||||||
import com.google.gson.JsonArray;
|
import com.google.gson.JsonArray;
|
||||||
import com.google.gson.JsonElement;
|
import com.google.gson.JsonElement;
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import com.imyeyu.java.ref.Ref;
|
|
||||||
import com.imyeyu.lang.mapper.AbstractLanguageMapper;
|
|
||||||
import com.imyeyu.api.TimiServerAPI;
|
import com.imyeyu.api.TimiServerAPI;
|
||||||
import com.imyeyu.api.modules.common.bean.SettingKey;
|
import com.imyeyu.api.modules.common.bean.SettingKey;
|
||||||
import com.imyeyu.api.modules.common.entity.Multilingual;
|
import com.imyeyu.api.modules.common.entity.Multilingual;
|
||||||
import com.imyeyu.api.modules.common.entity.Setting;
|
import com.imyeyu.api.modules.common.entity.Setting;
|
||||||
import com.imyeyu.api.modules.common.service.SettingService;
|
import com.imyeyu.api.modules.common.service.SettingService;
|
||||||
import com.imyeyu.api.modules.system.bean.ServerFile;
|
import com.imyeyu.api.modules.system.bean.ServerFile;
|
||||||
|
import com.imyeyu.java.ref.Ref;
|
||||||
|
import com.imyeyu.lang.mapper.AbstractLanguageMapper;
|
||||||
import com.imyeyu.spring.util.GlobalReturnHandler;
|
import com.imyeyu.spring.util.GlobalReturnHandler;
|
||||||
import com.imyeyu.spring.util.Redis;
|
import com.imyeyu.spring.util.Redis;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.eclipse.jgit.api.ArchiveCommand;
|
import org.eclipse.jgit.api.ArchiveCommand;
|
||||||
import org.eclipse.jgit.archive.TarFormat;
|
import org.eclipse.jgit.archive.TarFormat;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
@ -81,9 +81,9 @@ public class InitApplication implements ApplicationRunner {
|
|||||||
|
|
||||||
private void initMultilingual() {
|
private void initMultilingual() {
|
||||||
// redisLanguage.flushAll();
|
// redisLanguage.flushAll();
|
||||||
globalReturnHandler.setMultilingualHeader(key -> {
|
globalReturnHandler.setMultilingualHeader(mapping -> {
|
||||||
AbstractLanguageMapper map = redisMultilingual.map(TimiServerAPI.getUserLanguage());
|
AbstractLanguageMapper map = redisMultilingual.map(TimiServerAPI.getUserLanguage());
|
||||||
return map.text(key);
|
return map.textArgs(mapping.getMsgKey(), mapping.getMsgArgs());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
42
src/main/java/com/imyeyu/api/util/JavaCV.java
Normal file
42
src/main/java/com/imyeyu/api/util/JavaCV.java
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
package com.imyeyu.api.util;
|
||||||
|
|
||||||
|
import org.bytedeco.javacv.FFmpegFrameGrabber;
|
||||||
|
import org.bytedeco.javacv.Frame;
|
||||||
|
import org.bytedeco.javacv.Java2DFrameConverter;
|
||||||
|
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @author 夜雨
|
||||||
|
* @since 2025-10-23 17:05
|
||||||
|
*/
|
||||||
|
public class JavaCV {
|
||||||
|
|
||||||
|
public static ByteArrayOutputStream captureThumbnail(InputStream stream, double targetSeconds) throws Exception {
|
||||||
|
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
|
||||||
|
try (FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(stream)) {
|
||||||
|
grabber.start();
|
||||||
|
long targetMillis = (long) (targetSeconds * 1000);
|
||||||
|
grabber.setTimestamp(targetMillis);
|
||||||
|
Frame frame;
|
||||||
|
while ((frame = grabber.grabImage()) != null) {
|
||||||
|
if (grabber.getTimestamp() >= targetMillis) {
|
||||||
|
Java2DFrameConverter converter = new Java2DFrameConverter();
|
||||||
|
try (converter) {
|
||||||
|
BufferedImage bi = converter.getBufferedImage(frame);
|
||||||
|
if (bi != null) {
|
||||||
|
ImageIO.write(bi, "png", outStream);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return outStream;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,14 +1,10 @@
|
|||||||
package com.imyeyu.api.util;
|
package com.imyeyu.api.util;
|
||||||
|
|
||||||
import com.imyeyu.java.TimiJava;
|
|
||||||
import com.imyeyu.java.bean.Language;
|
|
||||||
import com.imyeyu.lang.mapper.AbstractLanguageMapper;
|
|
||||||
import com.imyeyu.api.TimiServerAPI;
|
import com.imyeyu.api.TimiServerAPI;
|
||||||
import com.imyeyu.api.modules.common.service.MultilingualService;
|
import com.imyeyu.api.modules.common.service.MultilingualService;
|
||||||
|
import com.imyeyu.java.bean.Language;
|
||||||
|
import com.imyeyu.lang.mapper.AbstractLanguageMapper;
|
||||||
import org.jcodec.api.NotSupportedException;
|
import org.jcodec.api.NotSupportedException;
|
||||||
import org.springframework.lang.Nullable;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author 夜雨
|
* @author 夜雨
|
||||||
@ -45,33 +41,7 @@ public class RedisLanguage extends AbstractLanguageMapper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public String text(String key, String def) {
|
|
||||||
String result = text(key);
|
|
||||||
return result.equals(key) ? def : result;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String textArgs(String key, Object... args) {
|
|
||||||
String result = text(key);
|
|
||||||
if (result.equals(key)) {
|
|
||||||
// 没有映射值
|
|
||||||
return result + Arrays.toString(args);
|
|
||||||
}
|
|
||||||
FORMAT.applyPattern(result);
|
|
||||||
return FORMAT.format(args);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String text(Long id) {
|
public String text(Long id) {
|
||||||
return TimiServerAPI.applicationContext.getBean(MultilingualService.class).get(language, id);
|
return TimiServerAPI.applicationContext.getBean(MultilingualService.class).get(language, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String textArgs(Long id, @Nullable Object... args) {
|
|
||||||
String result = text(id);
|
|
||||||
if (TimiJava.isEmpty(args)) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
FORMAT.applyPattern(result);
|
|
||||||
return FORMAT.format(args);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,15 +2,66 @@
|
|||||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
|
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
|
||||||
<mapper namespace="com.imyeyu.api.modules.common.mapper.AttachmentMapper">
|
<mapper namespace="com.imyeyu.api.modules.common.mapper.AttachmentMapper">
|
||||||
<sql id="table">attachment</sql>
|
<sql id="table">attachment</sql>
|
||||||
<select id="listByAttachType" resultType="com.imyeyu.api.modules.common.entity.Attachment">
|
<select id="listByBizId" resultType="com.imyeyu.api.modules.common.entity.Attachment">
|
||||||
SELECT
|
SELECT
|
||||||
*
|
*
|
||||||
FROM
|
FROM
|
||||||
<include refid="table" />
|
attachment
|
||||||
WHERE
|
WHERE
|
||||||
biz_type = #{bizType}
|
biz_type = #{bizType}
|
||||||
|
<if test="bizId != null">
|
||||||
AND biz_id = #{bizId}
|
AND biz_id = #{bizId}
|
||||||
<if test="attachTypes != null and 0 < attachTypes.length">
|
</if>
|
||||||
|
<if test="attachTypes != null and 0 < attachTypes.size()">
|
||||||
|
AND attach_type IN
|
||||||
|
<foreach collection="attachTypes" item="item" open="(" separator="," close=")">
|
||||||
|
#{item}
|
||||||
|
</foreach>
|
||||||
|
</if>
|
||||||
|
AND deleted_at IS NULL
|
||||||
|
AND destroy_at IS NULL
|
||||||
|
<if test="page != null">
|
||||||
|
<if test="page.orderMap != null and !page.orderMap.isEmpty()">
|
||||||
|
ORDER BY
|
||||||
|
<foreach collection="page.orderMap" index="key" item="value" separator=",">
|
||||||
|
${key} ${value}
|
||||||
|
</foreach>
|
||||||
|
</if>
|
||||||
|
LIMIT
|
||||||
|
#{page.offset},
|
||||||
|
#{page.limit}
|
||||||
|
</if>
|
||||||
|
</select>
|
||||||
|
<select id="countByBizId" resultType="long">
|
||||||
|
SELECT
|
||||||
|
COUNT(1)
|
||||||
|
FROM
|
||||||
|
attachment
|
||||||
|
WHERE
|
||||||
|
biz_type = #{bizType}
|
||||||
|
<if test="bizId != null">
|
||||||
|
AND biz_id = #{bizId}
|
||||||
|
</if>
|
||||||
|
<if test="attachTypes != null and 0 < attachTypes.size()">
|
||||||
|
AND attach_type IN
|
||||||
|
<foreach collection="attachTypes" item="item" open="(" separator="," close=")">
|
||||||
|
#{item}
|
||||||
|
</foreach>
|
||||||
|
</if>
|
||||||
|
AND deleted_at IS NULL
|
||||||
|
AND destroy_at IS NULL
|
||||||
|
</select>
|
||||||
|
<select id="listByMd5s" resultType="com.imyeyu.api.modules.common.entity.Attachment">
|
||||||
|
SELECT
|
||||||
|
*
|
||||||
|
FROM
|
||||||
|
attachment
|
||||||
|
WHERE
|
||||||
|
biz_type = #{bizType}
|
||||||
|
<if test="bizId != null">
|
||||||
|
AND biz_id = #{bizId}
|
||||||
|
</if>
|
||||||
|
<if test="attachTypes != null and 0 < attachTypes.size()">
|
||||||
AND attach_type IN
|
AND attach_type IN
|
||||||
<foreach collection="attachTypes" item="item" open="(" separator="," close=")">
|
<foreach collection="attachTypes" item="item" open="(" separator="," close=")">
|
||||||
#{item}
|
#{item}
|
||||||
|
|||||||
Reference in New Issue
Block a user