Compare commits

...

8 Commits

Author SHA1 Message Date
81c1a14228 add JournalController.listByIds 2025-12-10 13:37:44 +08:00
fdfb0439d9 update Journal 2025-12-09 17:43:54 +08:00
e2a3c193d8 remove pageByBizId and add deleteByBizId 2025-12-09 17:43:27 +08:00
40760ed517 fix GsonHandler dbConfig 2025-12-08 16:59:11 +08:00
6839dafdb9 update Page.size to long 2025-12-08 16:58:42 +08:00
bc2c920705 update timi-lang 2025-12-08 16:58:13 +08:00
59b0153f3e fix not match key exception code 2025-12-08 16:34:13 +08:00
ffaf7f84b4 upper GsonHandler.java to timi-spring 2025-12-05 15:33:29 +08:00
35 changed files with 397 additions and 620 deletions

View File

@ -40,13 +40,13 @@ public class TimiServerAPI implements OS.FileSystem, ApplicationContextAware {
TimiServerAPI.applicationContext = applicationContext;
}
public static Language getUserLanguage() {
Language userLanguage = TimiSpring.getLanguage();
public static Language.Enum getUserLanguage() {
Language.Enum userLanguage = TimiSpring.getLanguage();
Environment env = applicationContext.getBean(Environment.class);
if (env.containsProperty(DEV_LANG_CONFIG)) {
String property = env.getProperty(DEV_LANG_CONFIG);
if (TimiJava.isNotEmpty(property)) {
userLanguage = Ref.toType(Language.class, property);
userLanguage = Ref.toType(Language.Enum.class, property);
}
}
return userLanguage;

View File

@ -78,7 +78,7 @@ public class GiteaDBConfig {
"com.imyeyu.api.modules.gitea.entity",
};
String[] typeHandlers = {
"com.imyeyu.api.handler"
"com.imyeyu.spring.handler"
};
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();

View File

@ -81,6 +81,7 @@ public class TimiServerDBConfig {
mapperLocations.add("classpath:mapper/blog/**/*.xml");
mapperLocations.add("classpath:mapper/common/**/*.xml");
mapperLocations.add("classpath:mapper/system/**/*.xml");
mapperLocations.add("classpath:mapper/journal/**/*.xml");
mapperLocations.add("classpath:mapper/minecraft/**/*.xml");
for (int i = 0; i < mapperLocations.size(); i++) {
resources.addAll(List.of(resourceResolver.getResources(mapperLocations.get(i))));
@ -98,7 +99,7 @@ public class TimiServerDBConfig {
"com.imyeyu.api.modules.minecraft.entity"
};
String[] typeHandlers = {
"com.imyeyu.api.handler"
"com.imyeyu.spring.handler"
};
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();

View File

@ -1,57 +0,0 @@
package com.imyeyu.api.handler;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import com.imyeyu.java.TimiJava;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* MySQL JSON 数据类型处理器
*
* @author 夜雨
* @since 2021-07-04 09:36
*/
public class GsonHandler extends BaseTypeHandler<JsonElement> {
@Override
public void setNonNullParameter(PreparedStatement ps, int i, JsonElement parameter, JdbcType jdbcType) throws SQLException {
ps.setString(i, String.valueOf(parameter.toString()));
}
@Override
public JsonElement getNullableResult(ResultSet rs, String columnName) throws SQLException {
return toElement(rs.getString(columnName));
}
@Override
public JsonElement getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
return toElement(rs.getString(columnIndex));
}
@Override
public JsonElement getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
return toElement(cs.getNString(columnIndex));
}
private JsonElement toElement(String json) {
if (TimiJava.isNotEmpty(json)) {
JsonElement el = JsonParser.parseString(json);
if (el.isJsonObject()) {
return el.getAsJsonObject();
}
if (el.isJsonArray()) {
return el.getAsJsonArray();
}
if (el.isJsonPrimitive()) {
return el.getAsJsonPrimitive();
}
}
return null;
}
}

View File

@ -23,7 +23,7 @@ public interface ArticleMapper extends BaseMapper<Article, Long> {
long countByKeyword(String keyword);
List<Article> selectByKeyword(String keyword, Long offset, int limit);
List<Article> selectByKeyword(String keyword, Long offset, long limit);
@Select("UPDATE `article` SET `likes` = `likes` + 1 WHERE `id` = #{articleId}")
void like(Long articleId);

View File

@ -376,12 +376,25 @@ public class CommonController {
}
}
/**
* 上传临时文件
*
* @param files
* @return
*/
@AOPLog
@PostMapping("/temp/file/upload")
public List<TempFileResponse> uploadFile(@RequestParam("file") List<MultipartFile> files) {
return tempFileService.store(files);
}
/**
* 读取临时文件
*
* @param fileId
* @param req
* @param resp
*/
@AOPLog
@RequestRateLimit
@IgnoreGlobalReturn
@ -406,6 +419,13 @@ public class CommonController {
resp.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
}
}
/**
* 下载临时文件
*
* @param fileId
* @param resp
*/
@AOPLog
@RequestRateLimit
@IgnoreGlobalReturn

View File

@ -1,14 +1,14 @@
package com.imyeyu.api.modules.common.entity;
import com.imyeyu.java.bean.timi.TimiCode;
import com.imyeyu.java.bean.timi.TimiException;
import com.imyeyu.java.ref.Ref;
import com.imyeyu.api.TimiServerAPI;
import com.imyeyu.spring.entity.Entity;
import com.imyeyu.java.bean.Language;
import com.imyeyu.spring.entity.Creatable;
import com.imyeyu.spring.entity.Deletable;
import com.imyeyu.spring.entity.IDEntity;
import com.imyeyu.spring.entity.Updatable;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.lang.reflect.Field;
import java.io.Serializable;
/**
* @author 夜雨
@ -16,52 +16,13 @@ import java.lang.reflect.Field;
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class Multilingual extends Entity {
public class Multilingual extends Language implements Serializable, IDEntity<Long>, Creatable, Updatable, Deletable {
protected String key;
protected Long id;
protected String zhCN;
protected Long createdAt;
protected String zhTW;
protected Long updatedAt;
protected String enUS;
protected String ruRU;
protected String koKR;
protected String jaJP;
protected String deDE;
/** @return 根据用户环境获取语言值 */
public String getValue() {
try {
Field field = Ref.getField(getClass(), TimiServerAPI.getUserLanguage().toString().replace("_", ""));
if (field == null) {
throw new TimiException(TimiCode.RESULT_NULL).msgKey("TODO not support language");
}
return Ref.getFieldValue(this, field, String.class);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
/**
* 获取指定语言值
*
* @param language 指定语言
* @return 值
*/
public String getValue(com.imyeyu.java.bean.Language language) {
try {
Field field = Ref.getField(getClass(), language.toString().replace("_", ""));
if (field == null) {
throw new TimiException(TimiCode.RESULT_NULL).msgKey("TODO not support language");
}
return Ref.getFieldValue(this, field, String.class);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
protected Long deletedAt;
}

View File

@ -36,11 +36,11 @@ public interface CommentMapper extends BaseMapper<Comment, Long> {
long countAll(Comment.BizType bizType, Long bizId);
List<CommentView> list(Comment.BizType bizType, Long bizId, Long offset, int limit, LinkedHashMap<String, OrderType> orderMap);
List<CommentView> list(Comment.BizType bizType, Long bizId, Long offset, long limit, LinkedHashMap<String, OrderType> orderMap);
long countByUserId(Long userId);
List<CommentView> listByUserId(Long userId, Long offset, int limit, LinkedHashMap<String, OrderType> orderMap);
List<CommentView> listByUserId(Long userId, Long offset, long limit, LinkedHashMap<String, OrderType> orderMap);
@Update("UPDATE comment SET deleted_at = FLOOR(UNIX_TIMESTAMP(NOW(3)) * 1000) WHERE user_id = #{userId} ")
void deleteByUserId(Long userId);

View File

@ -25,7 +25,7 @@ public interface CommentReplyMapper extends BaseMapper<CommentReply, Long> {
long countByBizType(CommentReplyPage.BizType bizType, Long bizId);
@Select("SELECT * FROM comment_reply WHERE ${bizType.column} = #{bizId} AND ignored_at IS NULL" + NOT_DELETE + PAGE)
List<CommentReplyView> listByBizType(CommentReplyPage.BizType bizType, Long bizId, Long offset, int limit);
List<CommentReplyView> listByBizType(CommentReplyPage.BizType bizType, Long bizId, Long offset, long limit);
@Update("UPDATE comment_reply SET deleted_at = " + UNIX_TIME + " WHERE sender_id = #{userId} OR receiver_id = #{userId}")
void deleteByUserId(Long userId);

View File

@ -21,15 +21,15 @@ public interface IconMapper extends BaseMapper<Icon, Long> {
long countByName(String name);
@Select("SELECT * FROM icon WHERE name LIKE CONCAT('%', #{name}, '%')" + PAGE)
List<Icon> listByName(String name, long offset, int limit);
List<Icon> listByName(String name, long offset, long limit);
long countByLabel(String lang, String label);
List<Icon> listByLabel(String lang, String label, long offset, int limit);
List<Icon> listByLabel(String lang, String label, long offset, long limit);
@Select("SELECT COUNT(1) FROM icon WHERE unicode = #{unicode}" + NOT_DELETE)
long countByUnicode(String unicode);
@Select("SELECT * FROM icon WHERE unicode = #{unicode}" + PAGE)
List<Icon> listByUnicode(String unicode, long offset, int limit);
List<Icon> listByUnicode(String unicode, long offset, long limit);
}

View File

@ -4,8 +4,6 @@ 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.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.DestroyableService;
import com.imyeyu.spring.service.GettableService;
@ -81,5 +79,5 @@ public interface AttachmentService extends GettableService<Attachment, Long>, Pa
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;
void deleteByBizId(Attachment.BizType bizType, long bizId, Enum<?> ...attachTypes);
}

View File

@ -16,9 +16,9 @@ public interface MultilingualService extends UpdatableService<Multilingual> {
Long createIfNotExist(String key, String zhCN);
String get(Language language, Long id);
String get(Language.Enum language, Long id);
String getByKey(Language language, String key);
String getByKey(Language.Enum language, String key);
List<Multilingual> listByNotTranslate();
}

View File

@ -15,8 +15,6 @@ 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.bean.Page;
import com.imyeyu.spring.bean.PageResult;
import com.imyeyu.spring.mapper.BaseMapper;
import com.imyeyu.spring.service.AbstractEntityService;
import com.imyeyu.utils.Time;
@ -244,10 +242,17 @@ public class AttachmentServiceImplement extends AbstractEntityService<Attachment
}
@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;
public void deleteByBizId(Attachment.BizType bizType, long bizId, Enum<?>... attachTypes) {
Attachment example = new Attachment();
example.setBizType(bizType);
example.setBizId(bizId);
if (TimiJava.isEmpty(attachTypes)) {
mapper.deleteAllByExample(example);
} else {
for (int i = 0; i < attachTypes.length; i++) {
example.setAttachTypeValue(attachTypes[i]);
mapper.deleteAllByExample(example);
}
}
}
}

View File

@ -59,7 +59,7 @@ public class MultilingualServiceImplement extends AbstractEntityService<Multilin
}
@Override
public String get(Language language, Long id) {
public String get(Language.Enum language, Long id) {
Multilingual result = redisLanguage.get(id);
if (result == null) {
result = mapper.select(id);
@ -72,7 +72,7 @@ public class MultilingualServiceImplement extends AbstractEntityService<Multilin
}
@Override
public String getByKey(Language language, String key) {
public String getByKey(Language.Enum language, String key) {
Long languageId = redisLanguageMap.get(key);
if (languageId == null) {
Multilingual result = mapper.selectByKey(key);

View File

@ -50,16 +50,16 @@ public class MultilingualTranslateTask {
@AllArgsConstructor
public enum BaiduLanguage {
ZH(Language.zh_CN),
EN(Language.en_US),
JP(Language.ja_JP),
KOR(Language.ko_KR),
RU(Language.ru_RU),
DE(Language.de_DE),
CHT(Language.zh_TW);
ZH(Language.Enum.zh_CN),
EN(Language.Enum.en_US),
JP(Language.Enum.ja_JP),
KOR(Language.Enum.ko_KR),
RU(Language.Enum.ru_RU),
DE(Language.Enum.de_DE),
CHT(Language.Enum.zh_TW);
/** 标准映射 */
final Language language;
final Language.Enum language;
/**
* 获取排除语言列表
@ -104,7 +104,7 @@ public class MultilingualTranslateTask {
Map<String, String> result = doTranslate(sb.toString(), languageList.get(j));
for (Map.Entry<String, String> item : result.entrySet()) {
Multilingual multilingual = cnMap.get(item.getKey());
Language lang = languageList.get(j).language;
Language.Enum lang = languageList.get(j).language;
String value = multilingual.getValue(lang);
if (TimiJava.isEmpty(value)) {
Ref.setFieldValue(multilingual, lang.toString().replace("_", ""), item.getValue());

View File

@ -31,5 +31,5 @@ public interface IssueMapper extends BaseMapper<Issue, Long> {
* @param limit 数据量
* @return 反馈列表
*/
List<Issue> listByIssuePage(@Param("issuePage") IssuePage issuePage, long offset, int limit);
List<Issue> listByIssuePage(@Param("issuePage") IssuePage issuePage, long offset, long limit);
}

View File

@ -19,5 +19,5 @@ public interface MergeMapper extends BaseMapper<Merge, Long> {
long countByMergePage(@Param("mergePage") MergePage mergePage);
List<Merge> listByMergePage(@Param("mergePage") MergePage mergePage, long offset, int limit);
List<Merge> listByMergePage(@Param("mergePage") MergePage mergePage, long offset, long limit);
}

View File

@ -16,7 +16,7 @@ public interface ReleaseMapper extends BaseMapper<Release, Long> {
@Select("SELECT COUNT(1) FROM git_release WHERE repository_id = #{repositoryId}" + NOT_DELETE)
long countByRepositoryId(long repositoryId);
List<ReleaseView> listByRepositoryId(long repositoryId, long offset, int limit);
List<ReleaseView> listByRepositoryId(long repositoryId, long offset, long limit);
@Select("SELECT * FROM git_release WHERE repository_id = #{repositoryId}" + NOT_DELETE + "ORDER BY created_at DESC" + LIMIT_1)
Release queryLatestByRepositoryId(long repositoryId);

View File

@ -1,10 +1,10 @@
package com.imyeyu.api.modules.git.vo.issue;
import com.imyeyu.api.modules.common.entity.Comment;
import com.imyeyu.spring.bean.Page;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import com.imyeyu.api.modules.common.entity.Comment;
import com.imyeyu.spring.bean.Page;
/**
* @author 夜雨
@ -13,7 +13,7 @@ import com.imyeyu.spring.bean.Page;
@Data
@AllArgsConstructor
@EqualsAndHashCode(callSuper = true)
public class CommentPage extends Page {
public class CommentPage extends Page<Comment> {
private Comment.BizType bizType;

View File

@ -12,5 +12,5 @@ public interface ActionMapper {
long count(Long repoId, String branch, ActionLogDTO.Operation operation);
List<ActionLogDTO> list(Long repoId, String branch, ActionLogDTO.Operation operation, long offset, int limit);
List<ActionLogDTO> list(Long repoId, String branch, ActionLogDTO.Operation operation, long offset, long limit);
}

View File

@ -0,0 +1,30 @@
package com.imyeyu.api.modules.journal.bean;
import com.imyeyu.api.modules.journal.entity.Journal;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 经纬度位置
*
* @author 夜雨
* @since 2025-12-05 15:26
*/
@Data
@NoArgsConstructor
public class Location {
/** 经度 */
private Double lng;
/** 维度 */
private Double lat;
private String text;
public Location(Journal journal) {
this.lat = journal.getLat();
this.lng = journal.getLng();
this.text = journal.getLocation();
}
}

View File

@ -1,6 +1,5 @@
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;
@ -10,11 +9,11 @@ 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.api.modules.journal.vo.UpdateRequest;
import com.imyeyu.java.bean.timi.TimiCode;
import com.imyeyu.java.bean.timi.TimiException;
import com.imyeyu.network.ArgMap;
@ -22,19 +21,25 @@ 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.Page;
import com.imyeyu.spring.bean.PageResult;
import jakarta.validation.Valid;
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.PathVariable;
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.ArrayList;
import java.util.List;
/**
* 微信小程序糕雨日记接口
*
* @author 夜雨
* @since 2025-09-26 15:55
*/
@ -44,11 +49,16 @@ import java.util.List;
@RequestMapping("/journal")
public class JournalController {
private final Gson gson;
private final JournalService service;
private final SettingService settingService;
private final AttachmentService attachmentService;
/**
* 初始化用户 OpenId
*
* @param code 微信授权码
* @return OpenId
*/
@AOPLog
@RequestRateLimit
@PostMapping("/openid")
@ -67,6 +77,31 @@ public class JournalController {
}
}
@AOPLog
@RequestRateLimit
@RequestMapping("/{id}")
public JournalResponse detail(@PathVariable Long id) {
Journal journal = service.get(id);
JournalResponse resp = new JournalResponse();
Page<Attachment> attachPage = new Page<>();
{
Attachment example = new Attachment();
example.setBizType(Attachment.BizType.JOURNAL);
example.setBizId(journal.getId());
attachPage.setEqualsExample(example);
}
attachPage.setIndex(0);
attachPage.setSize(Long.MAX_VALUE);
resp.setItems(attachmentService.page(attachPage).getList());
BeanUtils.copyProperties(journal, resp);
return resp;
}
/**
* 创建记录
*
* @param request
*/
@AOPLog
@RequestRateLimit
@PostMapping("/create")
@ -74,17 +109,35 @@ public class JournalController {
service.create(request);
}
@PostMapping("/append")
public void append(@RequestBody AppendRequest request) {
service.appendItems(request);
/**
* 更新记录(支持附件差分保存)
*
* @param request 更新请求,包含 id、基本信息、保留的附件 ID 列表和新上传的临时文件 ID 列表
*/
@AOPLog
@RequestRateLimit
@PostMapping("/update")
public void update(@RequestBody @Valid UpdateRequest request) {
service.update(request);
}
/**
* 删除记录
*
* @param id 记录 ID
*/
@AOPLog
@PostMapping("/delete")
public void delete(@RequestBody Long thumbId) {
attachmentService.deleteMedia(thumbId);
public void delete(@RequestBody Long id) {
service.delete(id);
}
/**
* 记录列表
*
* @param page 查询页面
* @return
*/
@AOPLog
@RequestRateLimit
@RequestMapping("/list")
@ -95,7 +148,19 @@ public class JournalController {
result.setTotal(pageResult.getTotal());
result.setList(pageResult.getList().stream().map(item -> {
JournalResponse resp = new JournalResponse();
resp.setItems(attachmentService.listByBizId(Attachment.BizType.JOURNAL, item.getId()));
Page<Attachment> attachPage = new Page<>();
{
Attachment example = new Attachment();
example.setBizType(Attachment.BizType.JOURNAL);
example.setBizId(item.getId());
attachPage.setEqualsExample(example);
}
attachPage.setIndex(0);
attachPage.setSize(switch (page.getType()) {
case NORMAL -> Long.MAX_VALUE;
case PREVIEW -> 2; // 原图缩略图并存
});
resp.setItems(attachmentService.page(attachPage).getList());
BeanUtils.copyProperties(item, resp);
return resp;
}).toList());
@ -104,11 +169,35 @@ public class JournalController {
@AOPLog
@RequestRateLimit
@GetMapping("/list/date")
public Long[] listDate() {
return service.listDate();
@PostMapping("/list/ids")
public List<JournalResponse> listByIds(@RequestBody Long[] ids) {
List<JournalResponse> result = new ArrayList<>();
List<Journal> journals = service.listByIds(ids);
for (int i = 0; i < journals.size(); i++) {
Journal journal = journals.get(i);
JournalResponse resp = new JournalResponse();
Page<Attachment> attachPage = new Page<>();
{
Attachment example = new Attachment();
example.setBizType(Attachment.BizType.JOURNAL);
example.setBizId(journal.getId());
attachPage.setEqualsExample(example);
}
attachPage.setIndex(0);
attachPage.setSize(Long.MAX_VALUE);
resp.setItems(attachmentService.page(attachPage).getList());
BeanUtils.copyProperties(journal, resp);
result.add(resp);
}
return result;
}
/**
* 已记录照片、视频数量
*
* @return
*/
@RequestRateLimit
@GetMapping("/total")
public long total() {
@ -117,6 +206,11 @@ public class JournalController {
return journal + journalTravel;
}
/**
*
*
* @return
*/
@RequestRateLimit
@GetMapping("/travel")
public Travel getTravel() {
@ -130,6 +224,12 @@ public class JournalController {
service.updateTravelLuggage(luggage);
}
/**
* 创建瞬间(上传的临时文件持久化储存,微信限制单次上传数量)
*
* @param tempFileIds
* @return
*/
@AOPLog
@RequestRateLimit
@PostMapping("/moment/create")
@ -137,13 +237,34 @@ public class JournalController {
return service.createMoment(tempFileIds);
}
/**
* 瞬间列表
*
* @return
*/
@AOPLog
@RequestRateLimit
@PostMapping("/moment/list")
public List<Attachment> listMoment() {
return service.listMoment();
Page<Attachment> page = new Page<>();
{
Attachment example = new Attachment();
example.setBizType(Attachment.BizType.JOURNAL_MOMENT);
example.setBizId(0L);
example.setAttachTypeValue(MediaAttach.Type.THUMB);
page.setEqualsExample(example);
}
page.setIndex(0);
page.setSize(Long.MAX_VALUE);
return attachmentService.page(page).getList();
}
/**
* 检查待上传文件是否已存在
*
* @param md5s
* @return 不存在的文件 md5 列表
*/
@AOPLog
@RequestRateLimit
@PostMapping("/moment/filter")
@ -151,6 +272,11 @@ public class JournalController {
return service.filterExistMoment(md5s);
}
/**
* 删除瞬间
*
* @param thumbIds 缩略图附件 ID 列表
*/
@AOPLog
@RequestRateLimit
@PostMapping("/moment/delete")
@ -158,6 +284,11 @@ public class JournalController {
service.deleteMoment(thumbIds);
}
/**
* 归档瞬间,归档记录 ID 不为空时表示归档到指定记录
*
* @param request
*/
@AOPLog
@RequestRateLimit
@PostMapping("/moment/archive")

View File

@ -2,7 +2,6 @@ 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;
@ -12,12 +11,5 @@ import java.util.List;
*/
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();
List<Journal> listByIds(Long[] ids);
}

View File

@ -3,13 +3,13 @@ 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.api.modules.journal.vo.UpdateRequest;
import com.imyeyu.java.bean.timi.TimiException;
import com.imyeyu.spring.bean.PageResult;
import com.imyeyu.spring.service.DeletableService;
import com.imyeyu.spring.service.GettableService;
import com.imyeyu.spring.service.PageableService;
import java.util.List;
@ -17,22 +17,25 @@ 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;
public interface JournalService extends PageableService<Journal>, GettableService<Journal, Long>, DeletableService<Long> {
void create(JournalRequest request) throws TimiException;
void appendItems(AppendRequest request) throws TimiException;
void update(UpdateRequest request) throws TimiException;
List<Journal> listByIds(Long... ids);
/**
* 过滤已存在瞬间
*
* @param md5s 原图文件 MD5 列表
* @return 未持久化储存的 MD5 列表
* @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;

View File

@ -15,16 +15,13 @@ 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.api.modules.journal.vo.UpdateRequest;
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;
@ -36,7 +33,6 @@ 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;
@ -63,19 +59,6 @@ public class JournalServiceImplement extends AbstractEntityService<Journal, Long
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 {
@ -105,30 +88,58 @@ public class JournalServiceImplement extends AbstractEntityService<Journal, Long
}
}
@Transactional(TimiServerDBConfig.ROLLBACKER)
@Override
public void appendItems(AppendRequest request) throws TimiException {
TimiException.required(request.getTempFileIds(), "not found or empty tempFileIds");
public void update(UpdateRequest request) throws TimiException {
TimiException.required(request.getId(), "not found request.id");
try {
Journal journal = get(request.getId());
BeanUtils.copyProperties(request, journal);
super.update(journal);
// 删除
Set<Long> dbAttachSet = attachmentService.listByBizId(Attachment.BizType.JOURNAL, journal.getId(), MediaAttach.Type.THUMB)
.stream()
.map(Attachment::getId)
.collect(Collectors.toSet());
Set<Long> retainIds = Set.of(TimiJava.firstNotEmpty(request.getAttachmentIds(), new Long[0]));
dbAttachSet.removeAll(retainIds);
for (Long removeId : dbAttachSet) {
attachmentService.deleteMedia(removeId);
}
// 新增
String[] tempFileIds = request.getTempFileIds();
for (int i = 0; i < tempFileIds.length; i++) {
TempFileMetaData metadata = tempFileService.metadata(tempFileIds[i]);
File file = tempFileService.get(tempFileIds[i]);
if (TimiJava.isNotEmpty(tempFileIds)) {
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);
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");
log.error("update journal error", e);
throw new TimiException(TimiCode.ERROR).msgKey("TODO update journal error");
}
}
@Transactional(TimiServerDBConfig.ROLLBACKER)
@Override
public void delete(Long id) {
super.delete(id);
attachmentService.deleteByBizId(Attachment.BizType.JOURNAL, id);
}
@Override
public List<Journal> listByIds(Long... ids) {
return mapper.listByIds(ids);
}
@Override
public String[] filterExistMoment(String[] md5s) throws TimiException {
if (TimiJava.isEmpty(md5s)) {
@ -168,15 +179,6 @@ public class JournalServiceImplement extends AbstractEntityService<Journal, Long
}
}
@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++) {
@ -187,10 +189,16 @@ public class JournalServiceImplement extends AbstractEntityService<Journal, Long
@Override
public void archiveMoment(ArchiveRequest request) throws TimiException {
try {
Journal journal = new Journal();
BeanUtils.copyProperties(request, journal);
super.create(journal);
Journal journal;
if (request.getId() == null) {
// 归档为新纪录
journal = new Journal();
BeanUtils.copyProperties(request, journal);
super.create(journal);
} else {
// 归档到指定记录
journal = get(request.getId());
}
Long[] thumbIds = request.getThumbIds();
if (TimiJava.isEmpty(thumbIds)) {
return;

View File

@ -42,6 +42,6 @@ public class JournalAPIInterceptor implements HandlerInterceptor {
return true;
}
}
throw new TimiException(TimiCode.ARG_MISS).msgKey("invalid.key");
throw new TimiException(TimiCode.PERMISSION_MISS).msgKey("invalid.key");
}
}

View File

@ -1,15 +0,0 @@
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;
}

View File

@ -2,6 +2,8 @@ package com.imyeyu.api.modules.journal.vo;
import com.imyeyu.api.modules.journal.entity.Journal;
import com.imyeyu.spring.bean.Page;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import lombok.EqualsAndHashCode;
@ -10,8 +12,23 @@ import lombok.EqualsAndHashCode;
* @since 2025-10-09 18:48
*/
@Data
@Valid
@EqualsAndHashCode(callSuper = true)
public class JournalPage extends Page {
public class JournalPage extends Page<Journal> {
private Journal.Type type;
/**
*
*
* @author 夜雨
* @since 2025-12-08 16:01
*/
public enum Type {
NORMAL,
PREVIEW
}
@NotNull
private Type type;
}

View File

@ -6,6 +6,8 @@ import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 创建日志记录
*
* @author 夜雨
* @since 2025-09-26 15:56
*/
@ -13,6 +15,7 @@ import lombok.EqualsAndHashCode;
@EqualsAndHashCode(callSuper = true)
public class JournalRequest extends Journal {
/** 临时文件 ID 列表 */
@Transient
private String[] tempFileIds;
}

View File

@ -0,0 +1,25 @@
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-12-08
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class UpdateRequest extends Journal {
/** 临时文件 ID 列表(新上传的附件) */
@Transient
private String[] tempFileIds;
/** 保留的附件 ID 列表(用于差分删除) */
@Transient
private Long[] attachmentIds;
}

View File

@ -12,7 +12,7 @@ import org.jcodec.api.NotSupportedException;
*/
public class RedisLanguage extends AbstractLanguageMapper {
public RedisLanguage(Language language) {
public RedisLanguage(Language.Enum language) {
super(language);
}

View File

@ -1,10 +1,10 @@
package com.imyeyu.api.util;
import jakarta.annotation.PostConstruct;
import lombok.RequiredArgsConstructor;
import com.imyeyu.api.modules.common.service.MultilingualService;
import com.imyeyu.java.bean.Language;
import com.imyeyu.lang.multi.Multilingual;
import com.imyeyu.api.modules.common.service.MultilingualService;
import jakarta.annotation.PostConstruct;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
/**
@ -19,7 +19,7 @@ public class RedisMultilingual extends Multilingual {
@PostConstruct
private void postConstruct() {
Language[] languages = Language.values();
Language.Enum[] languages = Language.Enum.values();
for (int i = 0; i < languages.length; i++) {
add(languages[i], new RedisLanguage(languages[i]));
}

View File

@ -67,6 +67,12 @@
#{item}
</foreach>
</if>
<if test="md5s != null and 0 &lt; md5s.size()">
AND `md5` IN
<foreach collection="md5s" item="md5" open="(" separator="," close=")">
#{md5}
</foreach>
</if>
AND deleted_at IS NULL
AND destroy_at IS NULL
</select>

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.imyeyu.api.modules.journal.mapper.JournalMapper">
<sql id="table">journal</sql>
<select id="listByIds" resultType="com.imyeyu.api.modules.journal.entity.Journal">
SELECT
*
FROM
<include refid="table" />
WHERE
1 = 1
<if test="ids != null and 0 &lt; ids.length">
AND `id` IN
<foreach collection="ids" item="id" open="(" separator="," close=")">
#{id}
</foreach>
</if>
AND deleted_at IS NULL
</select>
</mapper>

View File

@ -1,371 +0,0 @@
package test;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.imyeyu.io.IO;
import com.imyeyu.java.TimiJava;
import com.imyeyu.java.bean.CallbackArgReturn;
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.TimiServerAPI;
import com.imyeyu.api.modules.common.entity.Multilingual;
import com.imyeyu.api.modules.common.mapper.MultilingualMapper;
import com.imyeyu.utils.Digest;
import com.imyeyu.utils.Encoder;
import com.imyeyu.utils.Time;
import lombok.AllArgsConstructor;
import org.apache.hc.client5.http.fluent.Request;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.io.File;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
@SpringBootTest(classes = TimiServerAPI.class)
@RunWith(SpringRunner.class)
public class SpringLang {
@Autowired
private MultilingualMapper mapper;
private static final String API = "http://api.fanyi.baidu.com/api/trans/vip/translate?";
@Test
public void temp() throws Exception {
List<Multilingual> multilinguals = mapper.selectByKeyLike(".exception.");
for (int i = 0; i < multilinguals.size(); i++) {
Multilingual item = multilinguals.get(i);
item.setKey(item.getKey().replaceAll("exception", "tips"));
mapper.update(item);
}
}
@Test
public void addLang() throws Exception {
Map<String, String> map = new HashMap<>();
for (Map.Entry<String, String> item : map.entrySet()) {
Multilingual exist = mapper.selectByKey(item.getKey());
if (exist != null) {
System.err.println("exist key: " + item.getKey());
continue;
}
Multilingual multilingual = new Multilingual();
multilingual.setKey(item.getKey());
multilingual.setZhCN(item.getValue());
multilingual.setCreatedAt(Time.now());
mapper.insert(multilingual);
}
}
@Test
public void addLang4File() throws Exception {
Properties properties = new Properties();
properties.load(IO.getInputStream(new File("newLang.properties")));
for (Map.Entry<Object, Object> item : properties.entrySet()) {
Multilingual exist = mapper.selectByKey(item.getKey().toString());
if (exist != null) {
System.err.println("exist key: " + item.getKey());
continue;
}
Multilingual multilingual = new Multilingual();
multilingual.setKey(item.getKey().toString());
multilingual.setZhCN(item.getValue().toString());
multilingual.setCreatedAt(Time.now());
mapper.insert(multilingual);
}
}
@Test
public void appendTranslateResult4Path() throws Exception {
String path = "";
// DB_KEY, FILE_KEY
Map<String, String> keyMap = new HashMap<>();
keyMap.put("", "");
for (Map.Entry<String, String> item : keyMap.entrySet()) {
Language[] languages = Language.values();
for (int i = 0; i < languages.length; i++) {
if (languages[i] == Language.zh_CN) {
continue;
}
Properties properties = new Properties();
File file = new File(path + "%s.lang".formatted(languages[i].toString()));
if (!file.exists()) {
System.err.println(languages[i] + " not exist");
continue;
}
properties.load(IO.getInputStream(file));
Multilingual multilingual = mapper.selectByKey(item.getKey());
String fieldName = languages[i].toString().replace("_", "");
Ref.setFieldValue(multilingual, fieldName, properties.getProperty(item.getValue()));
mapper.update(multilingual);
}
}
}
@Test
public void upper() {
List<Multilingual> list = mapper.list(0, 9999);
for (int i = 0; i < list.size(); i++) {
Multilingual multilingual = list.get(i);
multilingual.setEnUS(String.valueOf(multilingual.getEnUS().charAt(0)).toUpperCase() + multilingual.getEnUS().substring(1));
mapper.update(multilingual);
}
}
@Test
public void translate() throws Exception {
List<Multilingual> data = mapper.selectByNotTranslate();
Map<String, Multilingual> cnMap = new HashMap<>();
for (int i = 0; i < data.size(); i++) {
StringBuilder sb = new StringBuilder();
for (int j = 0; j < Math.min(data.size() - i, 20); j++, i++) {
Multilingual multilingual = data.get(i);
sb.append(multilingual.getZhCN()).append("\r\n");
cnMap.put(multilingual.getZhCN(), multilingual);
}
i--;
System.out.println("translate " + sb);
List<BaiduLanguage> languageList = BaiduLanguage.valuesWithout(BaiduLanguage.ZH);
for (int j = 0; j < languageList.size(); j++) {
Map<String, String> result = doTranslate(languageList.get(j), sb.toString());
for (Map.Entry<String, String> item : result.entrySet()) {
Multilingual multilingual = cnMap.get(item.getKey());
Language lang = languageList.get(j).language;
String value = multilingual.getValue(lang);
if (TimiJava.isEmpty(value)) {
Ref.setFieldValue(multilingual, lang.toString().replace("_", ""), item.getValue());
}
mapper.update(multilingual);
}
}
Thread.sleep(1000);
}
}
// 数据库查重
// SELECT * FROM multilingual WHERE zh_cn IN (SELECT zh_cn FROM multilingual GROUP BY zh_cn HAVING COUNT(zh_cn) > 1);
// SELECT * FROM multilingual WHERE key IN (SELECT key FROM multilingual GROUP BY key HAVING COUNT(key) > 1);
@Test
public void export() throws Exception {
Pattern compile = Pattern.compile("\\.(text|textArgs)\\(\"(.*?)\"");
File scanDir = new File("E:\\IDEAProject\\ForeverMC\\src");
File outDir = new File("E:\\IDEAProject\\ForeverMC\\src\\main\\resources\\lang");
// 排除键
// String[] excludePath = {};
String[] excludePath = {"E:\\IDEAProject\\timi-fx-ui\\src\\main\\resources\\lang\\timi-fx-ui"};
Set<String> excludeKeys = new HashSet<>();
if (excludePath.length != 0) {
for (int i = 0; i < excludePath.length; i++) {
InputStream is = IO.getInputStream(new File(excludePath[i] + "\\zh_CN.lang"));
Properties properties = new Properties();
properties.load(is);
Map<Object, Object> map = new HashMap<>(properties);
excludeKeys.addAll(map.keySet().stream().map(Object::toString).collect(Collectors.toSet()));
}
}
// 扫描文件获取键
List<File> files = IO.listFile(scanDir);
Set<String> keySet = new HashSet<>();
for (int i = 0; i < files.size(); i++) {
File file = files.get(i);
if (file.isDirectory()) {
continue;
}
if (!file.getName().endsWith(".java")) {
continue;
}
String fileData = IO.toString(file);
Matcher matcher = compile.matcher(fileData);
while (matcher.find()) {
String key = matcher.group(2);
if (!excludeKeys.contains(key)) {
keySet.add(key);
}
}
}
StringBuilder notFoundKey = new StringBuilder();
List<String> keyList = new ArrayList<>(keySet);
keyList.sort(Comparator.naturalOrder());
List<Multilingual> result = mapper.selectByKeyList(keyList);
{
List<String> deepQueryKeyList;
CallbackArgReturn<List<Multilingual>, List<String>> newKeyList = mList -> {
List<String> arr = new ArrayList<>();
for (int i = 0; i < mList.size(); i++) {
if (mList.get(i).getZhCN().startsWith("@")) {
String newKey = mList.get(i).getZhCN().substring(1);
if (!keyList.contains(newKey)) {
arr.add(newKey);
}
}
}
return arr;
};
deepQueryKeyList = newKeyList.handler(result);
do {
List<Multilingual> deepResult = new ArrayList<>();
for (int i = 0; i < deepQueryKeyList.size(); i++) {
Multilingual r = mapper.selectByKey(deepQueryKeyList.get(i));
if (r == null) {
notFoundKey.append("[deep]").append(deepQueryKeyList.get(i)).append('\n');
} else {
deepResult.add(r);
}
}
result.addAll(deepResult);
deepQueryKeyList = newKeyList.handler(deepResult);
} while (!deepQueryKeyList.isEmpty());
}
result.sort(Comparator.comparing(Multilingual::getKey));
Set<String> resultKey = result.stream().map(Multilingual::getKey).collect(Collectors.toSet());
for (String key : keyList) {
if (!resultKey.contains(key)) {
notFoundKey.append(key).append('\n');
}
}
if (!notFoundKey.isEmpty()) {
System.err.printf("not found key in db: %n------%n%s------%n", notFoundKey);
} else {
// 输出文件
Language[] languages = Language.values();
for (int i = 0; i < languages.length; i++) {
String fieldName = languages[i].toString().replace("_", "");
File file = IO.file(IO.fitPath(outDir.getAbsolutePath()) + languages[i] + ".lang");
StringBuilder sb = new StringBuilder();
for (int j = 0; j < result.size(); j++) {
String value = Ref.getFieldValue(result.get(j), fieldName, String.class).trim();
value = value.replaceAll("\n", "\\\\n\\\\\n");
sb.append(result.get(j).getKey()).append("=").append(value);
sb.append('\n');
}
IO.toFile(file, sb.toString());
}
System.out.println("write successful");
}
}
/**
* 文本翻译
*
* @param text 原文本
* @param to 目标语言
* @return Map&lt;原数据,翻译结果&gt;
* @throws Exception 翻译异常
*/
private synchronized Map<String, String> doTranslate(BaiduLanguage to, String text) throws Exception {
String random = String.valueOf(System.currentTimeMillis());
String appId = "20180920000210118";
String key = "MfI4Iu0go3541Ryx3f6K";
FormMap<String, Object> args = new FormMap<>();
args.put("q", text);
args.put("from", "ZH".toLowerCase());
args.put("to", to.toString().toLowerCase());
args.put("appid", appId);
args.put("salt", random);
args.put("sign", Digest.md5(appId + text + random + key));
String response = Request.post(API + Encoder.urlArgs(args)).bodyForm(args.build()).execute().returnContent().asString();
JsonObject jo = JsonParser.parseString(response).getAsJsonObject();
if (jo.has("error_code")) {
System.err.println(jo);
throw new TimiException(TimiCode.ERROR, jo.get("error_msg").getAsString());
}
JsonArray ja = jo.get("trans_result").getAsJsonArray();
JsonObject resultJO;
Map<String, String> result = new HashMap<>();
for (int i = 0; i < ja.size(); i++) {
resultJO = ja.get(i).getAsJsonObject();
result.put(resultJO.get("src").getAsString(), resultJO.get("dst").getAsString());
}
wait(200);
return result;
}
@AllArgsConstructor
public enum BaiduLanguage {
ZH(Language.zh_CN),
EN(Language.en_US),
JP(Language.ja_JP),
KOR(Language.ko_KR),
RU(Language.ru_RU),
DE(Language.de_DE),
CHT(Language.zh_TW);
/** 标准映射 */
final Language language;
/**
* 根据映射查找
*
* @param language 映射
* @return 枚举对象
*/
static BaiduLanguage fromMapping(Language language) {
for (BaiduLanguage type : BaiduLanguage.values()) {
if (type.language.toString().equalsIgnoreCase(language.toString())) {
return type;
}
}
return null;
}
/**
* 获取排除语言列表
*
* @param baiduLanguage 排除语言
* @return 语言列表
*/
static List<BaiduLanguage> valuesWithout(BaiduLanguage... baiduLanguage) {
Set<BaiduLanguage> outList = Set.of(baiduLanguage);
List<BaiduLanguage> result = new ArrayList<>();
BaiduLanguage[] values = values();
for (int i = 0; i < values.length; i++) {
if (!outList.contains(values[i])) {
result.add(values[i]);
}
}
return result;
}
}
}