refactor all

This commit is contained in:
Timi
2026-07-31 01:03:53 +08:00
parent 4e7f340cc6
commit e45809a0db
512 changed files with 14620 additions and 13519 deletions
@@ -3,9 +3,9 @@ package com.imyeyu.api.modules.journal.controller;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.imyeyu.api.bean.PreviewPage;
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.bean.attachment.MediaAttach;
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.journal.bean.RequiredUploadPermission;
@@ -48,251 +48,251 @@ import java.util.List;
@RequiredArgsConstructor
@RequestMapping("/journal")
public class JournalController {
private final JournalService service;
private final SettingService settingService;
private final AttachmentService attachmentService;
private final ObjectMapper jackson;
private final JournalAPIInterceptor apiInterceptor;
/**
* 初始化用户 OpenId
*
* @param code 微信授权码
* @return OpenId
*/
@AOPLog
@RequestRateLimit
@PostMapping("/openid")
public String initOpenId(@RequestBody 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");
String response = org.apache.hc.client5.http.fluent.Request.get(args.toURL("https://api.weixin.qq.com/sns/jscode2session"))
.execute()
.returnContent()
.asString();
InitCodeResponse resp = jackson.readValue(response, InitCodeResponse.class);
return resp.getOpenid();
} catch (Exception e) {
log.error("init WeChat openId error", e);
throw new TimiException(TimiCode.ERROR, "init openId error", e);
}
}
@PostMapping("/can-upload")
public boolean canUpload() {
return apiInterceptor.canUploadKey();
}
@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
@RequiredUploadPermission
@PostMapping("/create")
public void create(@RequestBody JournalRequest request) {
service.create(request);
}
/**
* 更新记录(支持附件差分保存)
*
* @param request 更新请求,包含 id、基本信息、保留的附件 ID 列表和新上传的临时文件 ID 列表
*/
@AOPLog
@RequestRateLimit
@RequiredUploadPermission
@PostMapping("/update")
public void update(@RequestBody @Valid UpdateRequest request) {
service.update(request);
}
/**
* 删除记录
*
* @param id 记录 ID
*/
@AOPLog
@RequiredUploadPermission
@PostMapping("/delete")
public void delete(@RequestBody Long id) {
service.delete(id);
}
/**
* 记录列表
*
* @param page 查询页面
* @return
*/
@AOPLog
@RequestRateLimit
@RequestMapping("/list")
public PageResult<JournalResponse> list(@RequestBody PreviewPage<Journal> 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();
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());
return result;
}
@AOPLog
@RequestRateLimit
@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() {
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;
}
/**
* 创建瞬间(上传的临时文件持久化储存,微信限制单次上传数量)
*
* @param tempFileIds
* @return
*/
@AOPLog
@RequestRateLimit
@RequiredUploadPermission
@PostMapping("/moment/create")
public List<Attachment> createMoment(@RequestBody String[] tempFileIds) {
return service.createMoment(tempFileIds);
}
/**
* 瞬间列表
*
* @return
*/
@AOPLog
@RequestRateLimit
@PostMapping("/moment/list")
public List<Attachment> 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")
public String[] filterExistMoment(@RequestBody String[] md5s) {
return service.filterExistMoment(md5s);
}
/**
* 删除瞬间
*
* @param thumbIds 缩略图附件 ID 列表
*/
@AOPLog
@RequestRateLimit
@RequiredUploadPermission
@PostMapping("/moment/delete")
public void deleteMoment(@RequestBody Long[] thumbIds) {
service.deleteMoment(thumbIds);
}
/**
* 归档瞬间,归档记录 ID 不为空时表示归档到指定记录
*
* @param request
*/
@AOPLog
@RequestRateLimit
@RequiredUploadPermission
@PostMapping("/moment/archive")
public void archiveMoment(@RequestBody ArchiveRequest request) {
service.archiveMoment(request);
}
//
// private final JournalService service;
// private final SettingService settingService;
// private final AttachmentService attachmentService;
// private final ObjectMapper jackson;
//
// private final JournalAPIInterceptor apiInterceptor;
//
// /**
// * 初始化用户 OpenId
// *
// * @param code 微信授权码
// * @return OpenId
// */
// @AOPLog
// @RequestRateLimit
// @PostMapping("/openid")
// public String initOpenId(@RequestBody String code) {
// try {
// ArgMap<String, String> args = new ArgMap<>();
// args.put("appid", settingService.getSystem(Setting.Module.Journal.APP_ID).asString());
// args.put("secret", settingService.getSystem(Setting.Module.Journal.APP_SECRET).asString());
// args.put("js_code", code);
// args.put("grant_type", "authorization_code");
// String response = org.apache.hc.client5.http.fluent.Request.get(args.toURL("https://api.weixin.qq.com/sns/jscode2session"))
// .execute()
// .returnContent()
// .asString();
// InitCodeResponse resp = jackson.readValue(response, InitCodeResponse.class);
// return resp.getOpenid();
// } catch (Exception e) {
// log.error("init WeChat openId error", e);
// throw new TimiException(TimiCode.ERROR, "init openId error", e);
// }
// }
//
// @PostMapping("/can-upload")
// public boolean canUpload() {
// return apiInterceptor.canUploadKey();
// }
//
// @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
// @RequiredUploadPermission
// @PostMapping("/create")
// public void create(@RequestBody JournalRequest request) {
// service.create(request);
// }
//
// /**
// * 更新记录(支持附件差分保存)
// *
// * @param request 更新请求,包含 id、基本信息、保留的附件 ID 列表和新上传的临时文件 ID 列表
// */
// @AOPLog
// @RequestRateLimit
// @RequiredUploadPermission
// @PostMapping("/update")
// public void update(@RequestBody @Valid UpdateRequest request) {
// service.update(request);
// }
//
// /**
// * 删除记录
// *
// * @param id 记录 ID
// */
// @AOPLog
// @RequiredUploadPermission
// @PostMapping("/delete")
// public void delete(@RequestBody Long id) {
// service.delete(id);
// }
//
// /**
// * 记录列表
// *
// * @param page 查询页面
// * @return
// */
// @AOPLog
// @RequestRateLimit
// @RequestMapping("/list")
// public PageResult<JournalResponse> list(@RequestBody PreviewPage<Journal> 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();
// 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());
// return result;
// }
//
// @AOPLog
// @RequestRateLimit
// @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() {
// 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;
// }
//
// /**
// * 创建瞬间(上传的临时文件持久化储存,微信限制单次上传数量)
// *
// * @param tempFileIds
// * @return
// */
// @AOPLog
// @RequestRateLimit
// @RequiredUploadPermission
// @PostMapping("/moment/create")
// public List<Attachment> createMoment(@RequestBody String[] tempFileIds) {
// return service.createMoment(tempFileIds);
// }
//
// /**
// * 瞬间列表
// *
// * @return
// */
// @AOPLog
// @RequestRateLimit
// @PostMapping("/moment/list")
// public List<Attachment> 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")
// public String[] filterExistMoment(@RequestBody String[] md5s) {
// return service.filterExistMoment(md5s);
// }
//
// /**
// * 删除瞬间
// *
// * @param thumbIds 缩略图附件 ID 列表
// */
// @AOPLog
// @RequestRateLimit
// @RequiredUploadPermission
// @PostMapping("/moment/delete")
// public void deleteMoment(@RequestBody Long[] thumbIds) {
// service.deleteMoment(thumbIds);
// }
//
// /**
// * 归档瞬间,归档记录 ID 不为空时表示归档到指定记录
// *
// * @param request
// */
// @AOPLog
// @RequestRateLimit
// @RequiredUploadPermission
// @PostMapping("/moment/archive")
// public void archiveMoment(@RequestBody ArchiveRequest request) {
// service.archiveMoment(request);
// }
}
@@ -1,6 +1,5 @@
package com.imyeyu.api.modules.journal.controller;
import com.imyeyu.api.modules.common.bean.SettingKey;
import com.imyeyu.api.modules.common.entity.Setting;
import com.imyeyu.api.modules.common.service.SettingService;
import com.imyeyu.api.modules.journal.bean.RequiredUploadPermission;
@@ -26,13 +25,13 @@ public class ToolController {
@GetMapping("/memo")
public String getMemo() {
return settingService.getAsString(SettingKey.JOURNAL_MEMO);
return settingService.getSystem(Setting.Module.Journal.MEMO).asString();
}
@RequiredUploadPermission
@PostMapping("/memo/update")
public void updateMemo(@RequestBodyValue String data) {
Setting setting = settingService.getByKey(SettingKey.JOURNAL_MEMO);
Setting setting = settingService.getSystem(Setting.Module.Journal.MEMO);
setting.setValue(data);
settingService.update(setting);
}
@@ -66,7 +66,7 @@ public class TravelController {
@RequestRateLimit
@RequiredUploadPermission
@PostMapping("/delete")
public void delete(@RequestBody Long id) {
public void delete(@RequestBody String id) {
service.delete(id);
}
@@ -79,7 +79,7 @@ public class TravelController {
@AOPLog
@RequestRateLimit
@GetMapping("/{id}")
public Travel detail(@PathVariable Long id) {
public Travel detail(@PathVariable String id) {
return service.get(id);
}
@@ -1,28 +1,10 @@
package com.imyeyu.api.modules.journal.controller;
import com.imyeyu.api.bean.PreviewPage;
import com.imyeyu.api.modules.common.bean.MediaAttach;
import com.imyeyu.api.modules.common.entity.Attachment;
import com.imyeyu.api.modules.common.service.AttachmentService;
import com.imyeyu.api.modules.journal.bean.RequiredUploadPermission;
import com.imyeyu.api.modules.journal.entity.TravelLocation;
import com.imyeyu.api.modules.journal.service.TravelLocationService;
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 jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
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.List;
/**
* 旅行地点接口
*
@@ -34,108 +16,4 @@ import java.util.List;
@RequiredArgsConstructor
@RequestMapping("/journal/travel/location")
public class TravelLocationController {
private final AttachmentService attachmentService;
private final TravelLocationService service;
/**
* 创建旅行地点
*
* @param location 旅行地点
*/
@AOPLog
@RequestRateLimit
@RequiredUploadPermission
@PostMapping("/create")
public void create(@RequestBody @Valid TravelLocation location) {
service.create(location);
}
/**
* 更新旅行地点
*
* @param location 旅行地点
*/
@AOPLog
@RequestRateLimit
@RequiredUploadPermission
@PostMapping("/update")
public void update(@RequestBody @Valid TravelLocation location) {
service.update(location);
}
/**
* 删除旅行地点(级联删除附件)
*
* @param id 地点 ID
*/
@AOPLog
@RequestRateLimit
@RequiredUploadPermission
@PostMapping("/delete")
public void delete(@RequestBody Long id) {
service.delete(id);
}
/**
* 查询旅行地点详情
*
* @param id 地点 ID
* @return 旅行地点
*/
@AOPLog
@RequestRateLimit
@GetMapping("/{id}")
public TravelLocation detail(@PathVariable Long id) {
TravelLocation location = service.get(id);
location.setItems(attachmentService.listByBizId(Attachment.BizType.JOURNAL_TRAVEL, location.getId()));
return location;
}
/**
* 旅行地点列表
*
* @param page 分页参数
* @return 地点列表
*/
@AOPLog
@RequestRateLimit
@PostMapping("/list")
public PageResult<TravelLocation> list(@RequestBody PreviewPage<TravelLocation> page) {
PageResult<TravelLocation> result = service.page(page);
for (TravelLocation location : result.getList()) {
Page<Attachment> attachPage = new Page<>();
{
Attachment example = new Attachment();
example.setBizType(Attachment.BizType.JOURNAL_TRAVEL);
example.setBizId(location.getId());
example.setAttachTypeValue(MediaAttach.Type.THUMB);
attachPage.setEqualsExample(example);
}
attachPage.setIndex(0);
attachPage.setSize(1); // 列表接口只允许预览
location.setItems(attachmentService.page(attachPage).getList());
}
return result;
}
@AOPLog
@RequestRateLimit
@PostMapping("/list/ids")
public List<TravelLocation> listByIds(@RequestBody Long[] ids) {
List<TravelLocation> locationList = service.listByIds(ids);
for (TravelLocation location : locationList) {
Page<Attachment> attachPage = new Page<>();
{
Attachment example = new Attachment();
example.setBizType(Attachment.BizType.JOURNAL_TRAVEL);
example.setBizId(location.getId());
attachPage.setEqualsExample(example);
}
attachPage.setIndex(0);
attachPage.setSize(Long.MAX_VALUE);
location.setItems(attachmentService.page(attachPage).getList());
}
return locationList;
}
}
@@ -1,6 +1,6 @@
package com.imyeyu.api.modules.journal.entity;
import com.imyeyu.spring.entity.Entity;
import com.imyeyu.spring.entity.UUIDEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
@@ -10,7 +10,7 @@ import lombok.EqualsAndHashCode;
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class Journal extends Entity {
public class Journal extends UUIDEntity {
/**
*
@@ -1,7 +1,7 @@
package com.imyeyu.api.modules.journal.entity;
import com.imyeyu.spring.annotation.table.PageIgnore;
import com.imyeyu.spring.entity.Entity;
import com.imyeyu.spring.entity.UUIDEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
@@ -13,7 +13,7 @@ import lombok.EqualsAndHashCode;
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class Travel extends Entity {
public class Travel extends UUIDEntity {
/**
* 交通类型
@@ -1,13 +1,10 @@
package com.imyeyu.api.modules.journal.entity;
import com.imyeyu.api.modules.common.entity.Attachment;
import com.imyeyu.spring.annotation.table.Transient;
import com.imyeyu.spring.entity.Entity;
import com.imyeyu.spring.entity.UUIDEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.math.BigDecimal;
import java.util.List;
/**
* 旅行地点
@@ -17,7 +14,7 @@ import java.util.List;
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class TravelLocation extends Entity {
public class TravelLocation extends UUIDEntity {
/**
* 地点类型
@@ -53,7 +50,7 @@ public class TravelLocation extends Entity {
}
/** 旅行计划 ID */
private Long travelId;
private String travelId;
/** 类型 */
private Type type;
@@ -88,12 +85,4 @@ public class TravelLocation extends Entity {
/** 重要程度 */
private Integer importance;
@Transient
private Long[] attachmentIds;
@Transient
private String[] tempFileIds;
@Transient
private List<Attachment> items;
}
@@ -9,7 +9,7 @@ import java.util.List;
* @author 夜雨
* @since 2025-09-26 15:54
*/
public interface JournalMapper extends BaseMapper<Journal, Long> {
public interface JournalMapper extends BaseMapper<Journal, String> {
List<Journal> listByIds(Long[] ids);
}
@@ -11,7 +11,7 @@ import java.util.List;
* @author 夜雨
* @since 2025-12-12 14:35
*/
public interface TravelLocationMapper extends BaseMapper<TravelLocation, Long> {
public interface TravelLocationMapper extends BaseMapper<TravelLocation, String> {
List<TravelLocation> listByIds(Long[] ids);
}
@@ -12,7 +12,7 @@ import java.util.List;
* @author 夜雨
* @since 2025-12-12 14:35
*/
public interface TravelMapper extends BaseMapper<Travel, Long> {
public interface TravelMapper extends BaseMapper<Travel, String> {
/**
* 根据 ID 列表查询
@@ -1,41 +1,11 @@
package com.imyeyu.api.modules.journal.service;
import com.imyeyu.api.modules.common.entity.Attachment;
import com.imyeyu.api.modules.journal.entity.Journal;
import com.imyeyu.api.modules.journal.vo.journal.ArchiveRequest;
import com.imyeyu.api.modules.journal.vo.journal.JournalRequest;
import com.imyeyu.api.modules.journal.vo.journal.UpdateRequest;
import com.imyeyu.java.bean.timi.TimiException;
import com.imyeyu.spring.service.DeletableService;
import com.imyeyu.spring.service.GettableService;
import com.imyeyu.spring.service.PageableService;
import java.util.List;
import com.imyeyu.spring.service.BaseService;
/**
* @author 夜雨
* @since 2025-09-26 15:53
*/
public interface JournalService extends PageableService<Journal>, GettableService<Journal, Long>, DeletableService<Long> {
void create(JournalRequest 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;
void deleteMoment(Long[] thumbIds) throws TimiException;
void archiveMoment(ArchiveRequest request) throws TimiException;
public interface JournalService extends BaseService<Journal, String> {
}
@@ -1,26 +1,13 @@
package com.imyeyu.api.modules.journal.service;
import com.imyeyu.api.modules.journal.entity.TravelLocation;
import com.imyeyu.java.bean.timi.TimiException;
import com.imyeyu.spring.service.BaseService;
import java.util.List;
/**
* 旅行地点服务
*
* @author 夜雨
* @since 2025-12-12 14:40
*/
public interface TravelLocationService extends BaseService<TravelLocation, Long> {
List<TravelLocation> listByIds(Long... ids);
/**
* 根据旅行 ID 删除所有地点
*
* @param travelId 旅行 ID
* @throws TimiException 服务异常
*/
void deleteByTravelId(Long travelId) throws TimiException;
public interface TravelLocationService extends BaseService<TravelLocation, String> {
}
@@ -9,5 +9,5 @@ import com.imyeyu.spring.service.BaseService;
* @author 夜雨
* @since 2025-12-12 14:40
*/
public interface TravelService extends BaseService<Travel, Long> {
public interface TravelService extends BaseService<Travel, String> {
}
@@ -1,35 +1,13 @@
package com.imyeyu.api.modules.journal.service.implement;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.imyeyu.api.config.dbsource.TimiServerDBConfig;
import com.imyeyu.api.modules.common.bean.MediaAttach;
import com.imyeyu.api.modules.common.bean.Metadata;
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.common.service.TempFileService;
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.journal.ArchiveRequest;
import com.imyeyu.api.modules.journal.vo.journal.JournalRequest;
import com.imyeyu.api.modules.journal.vo.journal.UpdateRequest;
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.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.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
/**
* @author 夜雨
@@ -38,169 +16,12 @@ import java.util.stream.Collectors;
@Slf4j
@Service
@RequiredArgsConstructor
public class JournalServiceImplement extends AbstractEntityService<Journal, Long> implements JournalService {
private final ObjectMapper jackson;
private final SettingService settingService;
private final TempFileService tempFileService;
private final AttachmentService attachmentService;
public class JournalServiceImplement extends AbstractEntityService<Journal, String> implements JournalService {
private final JournalMapper mapper;
@Override
protected BaseMapper<Journal, Long> mapper() {
protected BaseMapper<Journal, String> mapper() {
return mapper;
}
@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++) {
Attachment tempFileAttach = attachmentService.getByMongoId(tempFileIds[i]);
Attachment sourceAttach = new Attachment();
sourceAttach.setName(tempFileAttach.getName());
sourceAttach.setBizType(Attachment.BizType.JOURNAL);
sourceAttach.setBizId(journal.getId());
sourceAttach.setInputStream(tempFileAttach.openInputStream());
attachmentService.createMedia(sourceAttach);
}
} catch (Exception e) {
log.error("create journal error", e);
throw new TimiException(TimiCode.ERROR).msgKey("TODO create journal error");
}
}
@Transactional(TimiServerDBConfig.ROLLBACKER)
@Override
public void update(UpdateRequest request) throws TimiException {
TimiException.required(request.getId(), "not found request.id");
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);
}
// 新增
for (String tempFileId : TimiJava.defaultIfNull(request.getTempFileIds(), new String[0])) {
Attachment tempFileAttach = attachmentService.getByMongoId(tempFileId);
Attachment sourceAttach = new Attachment();
sourceAttach.setName(tempFileAttach.getName());
sourceAttach.setBizType(Attachment.BizType.JOURNAL);
sourceAttach.setBizId(journal.getId());
sourceAttach.setInputStream(tempFileAttach.openInputStream());
attachmentService.createMedia(sourceAttach);
}
}
@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)) {
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++) {
Attachment tempFileAttach = attachmentService.getByMongoId(tempFileIds[i]);
Attachment sourceAttach = new Attachment();
sourceAttach.setName(tempFileAttach.getName());
sourceAttach.setBizType(Attachment.BizType.JOURNAL_MOMENT);
sourceAttach.setBizId(0L);
sourceAttach.setAttachTypeValue(MediaAttach.Type.SOURCE);
sourceAttach.setSize(tempFileAttach.getSize());
sourceAttach.setInputStream(tempFileAttach.openInputStream());
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 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;
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;
}
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);
Metadata.ThumbImage thumbMetadata = jackson.convertValue(thumbAttach.getMetadata(), Metadata.ThumbImage.class);
Attachment sourceAttach = attachmentService.get(thumbMetadata.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");
}
}
}
@@ -1,26 +1,14 @@
package com.imyeyu.api.modules.journal.service.implement;
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.service.AttachmentService;
import com.imyeyu.api.modules.journal.entity.TravelLocation;
import com.imyeyu.api.modules.journal.mapper.TravelLocationMapper;
import com.imyeyu.api.modules.journal.service.TravelLocationService;
import com.imyeyu.api.modules.journal.service.TravelService;
import com.imyeyu.java.TimiJava;
import com.imyeyu.java.bean.timi.TimiException;
import com.imyeyu.spring.mapper.BaseMapper;
import com.imyeyu.spring.service.AbstractEntityService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
/**
* 旅行地点服务实现
@@ -31,88 +19,12 @@ import java.util.stream.Collectors;
@Slf4j
@Service
@RequiredArgsConstructor(onConstructor_ = {@Lazy})
public class TravelLocationServiceImplement extends AbstractEntityService<TravelLocation, Long> implements TravelLocationService {
private final TravelService travelService;
private final AttachmentService attachmentService;
public class TravelLocationServiceImplement extends AbstractEntityService<TravelLocation, String> implements TravelLocationService {
private final TravelLocationMapper mapper;
@Override
protected BaseMapper<TravelLocation, Long> mapper() {
protected BaseMapper<TravelLocation, String> mapper() {
return mapper;
}
@Transactional(TimiServerDBConfig.ROLLBACKER)
@Override
public void create(TravelLocation travelLocation) {
super.create(travelLocation);
for (String tempFileId : travelLocation.getTempFileIds()) {
Attachment tempFileAttach = attachmentService.getByMongoId(tempFileId);
Attachment attach = new Attachment();
attach.setName(tempFileAttach.getName());
attach.setBizType(Attachment.BizType.JOURNAL_TRAVEL);
attach.setBizId(travelLocation.getId());
attach.setInputStream(tempFileAttach.openInputStream());
attachmentService.createMedia(attach);
}
// 更新操作时间以保证排序
travelService.update(travelService.get(travelLocation.getTravelId()));
}
@Transactional(TimiServerDBConfig.ROLLBACKER)
@Override
public void update(TravelLocation travelLocation) {
// 使用 update 以允许设置 score 和 importance 为 null
mapper.update(travelLocation);
// 删除
if (TimiJava.isNotEmpty(travelLocation.getAttachmentIds())) {
Set<Long> dbAttachSet = attachmentService.listByBizId(Attachment.BizType.JOURNAL_TRAVEL, travelLocation.getId(), MediaAttach.Type.THUMB)
.stream()
.map(Attachment::getId)
.collect(Collectors.toSet());
Set<Long> retainIds = Set.of(travelLocation.getAttachmentIds());
dbAttachSet.removeAll(retainIds);
for (Long removeId : dbAttachSet) {
attachmentService.deleteMedia(removeId);
}
}
// 新增
for (String tempFileId : TimiJava.defaultIfNull(travelLocation.getTempFileIds(), new String[0])) {
Attachment tempFileAttach = attachmentService.getByMongoId(tempFileId);
Attachment attach = new Attachment();
attach.setName(tempFileAttach.getName());
attach.setBizType(Attachment.BizType.JOURNAL_TRAVEL);
attach.setBizId(travelLocation.getId());
attach.setInputStream(tempFileAttach.openInputStream());
attachmentService.createMedia(attach);
}
// 更新操作时间以保证排序
travelService.update(travelService.get(travelLocation.getTravelId()));
}
@Transactional(TimiServerDBConfig.ROLLBACKER)
@Override
public void delete(Long id) {
super.delete(id);
attachmentService.deleteByBizId(Attachment.BizType.JOURNAL_TRAVEL, id);
}
@Override
public List<TravelLocation> listByIds(Long... ids) {
return mapper.listByIds(ids);
}
@Transactional(TimiServerDBConfig.ROLLBACKER)
@Override
public void deleteByTravelId(Long travelId) throws TimiException {
TravelLocation example = new TravelLocation();
example.setTravelId(travelId);
List<TravelLocation> locationList = mapper.selectAllByExample(example);
for (TravelLocation location : locationList) {
delete(location.getId());
}
}
}
@@ -1,9 +1,7 @@
package com.imyeyu.api.modules.journal.service.implement;
import com.imyeyu.api.config.dbsource.TimiServerDBConfig;
import com.imyeyu.api.modules.journal.entity.Travel;
import com.imyeyu.api.modules.journal.mapper.TravelMapper;
import com.imyeyu.api.modules.journal.service.TravelLocationService;
import com.imyeyu.api.modules.journal.service.TravelService;
import com.imyeyu.spring.mapper.BaseMapper;
import com.imyeyu.spring.service.AbstractEntityService;
@@ -11,7 +9,6 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
/**
* 旅行计划服务实现
@@ -22,27 +19,12 @@ import org.springframework.transaction.annotation.Transactional;
@Slf4j
@Service
@RequiredArgsConstructor(onConstructor_ = {@Lazy})
public class TravelServiceImplement extends AbstractEntityService<Travel, Long> implements TravelService {
public class TravelServiceImplement extends AbstractEntityService<Travel, String> implements TravelService {
private final TravelMapper mapper;
private final TravelLocationService travelLocationService;
@Override
protected BaseMapper<Travel, Long> mapper() {
protected BaseMapper<Travel, String> mapper() {
return mapper;
}
@Transactional(TimiServerDBConfig.ROLLBACKER)
@Override
public void update(Travel travel) {
// 使用 update 以允许设置 travelAt 和 days 为 null
mapper.update(travel);
}
@Transactional(TimiServerDBConfig.ROLLBACKER)
@Override
public void delete(Long id) {
super.delete(id);
travelLocationService.deleteByTravelId(id);
}
}
@@ -1,6 +1,6 @@
package com.imyeyu.api.modules.journal.util;
import com.imyeyu.api.modules.common.bean.SettingKey;
import com.imyeyu.api.modules.common.entity.Setting;
import com.imyeyu.api.modules.common.service.SettingService;
import com.imyeyu.api.modules.journal.bean.RequiredUploadPermission;
import com.imyeyu.java.TimiJava;
@@ -32,12 +32,11 @@ public class JournalAPIInterceptor implements HandlerInterceptor {
private final SettingService settingService;
private Set<String> keys, openIds;
private Set<String> keys;
@PostConstruct
private void postConstruct() {
keys = Set.of(settingService.getAsString(SettingKey.JOURNAL_KEY).split(","));
openIds = Set.of(settingService.getAsString(SettingKey.JOURNAL_OPEN_ID_WHITE_LIST).split(","));
// keys = settingService.getSystem(Setting.Module.Journal.KEY).asSet();
}
public boolean preHandle(@NonNull HttpServletRequest req, @NonNull HttpServletResponse resp, @NonNull Object handler) {