From d82c5200e7f8b1ab2ec130af6d0402521d95e48d Mon Sep 17 00:00:00 2001 From: Timi Date: Mon, 15 Dec 2025 10:30:45 +0800 Subject: [PATCH] refactor travel --- .../journal/controller/TravelController.java | 97 +++++++++++++ .../controller/TravelLocationController.java | 136 ++++++++++++++++++ .../api/modules/journal/entity/Travel.java | 83 +++++++++++ .../journal/entity/TravelLocation.java | 87 +++++++++++ .../journal/mapper/TravelLocationMapper.java | 17 +++ .../modules/journal/mapper/TravelMapper.java | 32 +++++ .../service/TravelLocationService.java | 26 ++++ .../journal/service/TravelService.java | 13 ++ .../TravelLocationServiceImplement.java | 111 ++++++++++++++ .../implement/TravelServiceImplement.java | 40 ++++++ 10 files changed, 642 insertions(+) create mode 100644 src/main/java/com/imyeyu/api/modules/journal/controller/TravelController.java create mode 100644 src/main/java/com/imyeyu/api/modules/journal/controller/TravelLocationController.java create mode 100644 src/main/java/com/imyeyu/api/modules/journal/entity/Travel.java create mode 100644 src/main/java/com/imyeyu/api/modules/journal/entity/TravelLocation.java create mode 100644 src/main/java/com/imyeyu/api/modules/journal/mapper/TravelLocationMapper.java create mode 100644 src/main/java/com/imyeyu/api/modules/journal/mapper/TravelMapper.java create mode 100644 src/main/java/com/imyeyu/api/modules/journal/service/TravelLocationService.java create mode 100644 src/main/java/com/imyeyu/api/modules/journal/service/TravelService.java create mode 100644 src/main/java/com/imyeyu/api/modules/journal/service/implement/TravelLocationServiceImplement.java create mode 100644 src/main/java/com/imyeyu/api/modules/journal/service/implement/TravelServiceImplement.java diff --git a/src/main/java/com/imyeyu/api/modules/journal/controller/TravelController.java b/src/main/java/com/imyeyu/api/modules/journal/controller/TravelController.java new file mode 100644 index 0000000..0f8a684 --- /dev/null +++ b/src/main/java/com/imyeyu/api/modules/journal/controller/TravelController.java @@ -0,0 +1,97 @@ +package com.imyeyu.api.modules.journal.controller; + +import com.imyeyu.api.modules.common.service.AttachmentService; +import com.imyeyu.api.modules.journal.entity.Travel; +import com.imyeyu.api.modules.journal.service.TravelService; +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.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; + +/** + * 旅行计划接口 + * + * @author 夜雨 + * @since 2025-12-12 14:50 + */ +@Slf4j +@RestController +@RequiredArgsConstructor +@RequestMapping("/journal/travel") +public class TravelController { + + private final TravelService service; + private final AttachmentService attachmentService; + + /** + * 创建旅行计划 + * + * @param travel 旅行计划 + */ + @AOPLog + @RequestRateLimit + @PostMapping("/create") + public void create(@RequestBody @Valid Travel travel) { + service.create(travel); + } + + /** + * 更新旅行计划 + * + * @param travel 旅行计划 + */ + @AOPLog + @RequestRateLimit + @PostMapping("/update") + public void update(@RequestBody @Valid Travel travel) { + service.update(travel); + } + + /** + * 删除旅行计划(级联删除关联地点和附件) + * + * @param id 旅行 ID + */ + @AOPLog + @RequestRateLimit + @PostMapping("/delete") + public void delete(@RequestSingleParam Long id) { + service.delete(id); + } + + /** + * 查询旅行计划详情 + * + * @param id 旅行 ID + * @return 旅行计划 + */ + @AOPLog + @RequestRateLimit + @GetMapping("/{id}") + public Travel detail(@PathVariable Long id) { + return service.get(id); + } + + /** + * 旅行计划列表 + * + * @param page 分页参数 + * @return 旅行列表 + */ + @AOPLog + @RequestRateLimit + @PostMapping("/list") + public PageResult list(@RequestBody Page page) { + return service.page(page); + } +} diff --git a/src/main/java/com/imyeyu/api/modules/journal/controller/TravelLocationController.java b/src/main/java/com/imyeyu/api/modules/journal/controller/TravelLocationController.java new file mode 100644 index 0000000..0351564 --- /dev/null +++ b/src/main/java/com/imyeyu/api/modules/journal/controller/TravelLocationController.java @@ -0,0 +1,136 @@ +package com.imyeyu.api.modules.journal.controller; + +import com.imyeyu.api.bean.PreviewPage; +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.service.TravelLocationService; +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.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; + +/** + * 旅行地点接口 + * + * @author 夜雨 + * @since 2025-12-12 14:50 + */ +@Slf4j +@RestController +@RequiredArgsConstructor +@RequestMapping("/journal/travel/location") +public class TravelLocationController { + + private final AttachmentService attachmentService; + private final TravelLocationService service; + + /** + * 创建旅行地点 + * + * @param location 旅行地点 + */ + @AOPLog + @RequestRateLimit + @PostMapping("/create") + public void create(@RequestBody @Valid TravelLocation location) { + service.create(location); + } + + /** + * 更新旅行地点 + * + * @param location 旅行地点 + */ + @AOPLog + @RequestRateLimit + @PostMapping("/update") + public void update(@RequestBody @Valid TravelLocation location) { + service.update(location); + } + + /** + * 删除旅行地点(级联删除附件) + * + * @param id 地点 ID + */ + @AOPLog + @RequestRateLimit + @PostMapping("/delete") + public void delete(@RequestSingleParam 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 list(@RequestBody PreviewPage page) { + PageResult result = service.page(page); + for (TravelLocation location : result.getList()) { + Page 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(1); // 列表接口只允许预览 + location.setItems(attachmentService.page(attachPage).getList()); + } + return result; + } + + @AOPLog + @RequestRateLimit + @PostMapping("/list/ids") + public List listByIds(@RequestBody Long[] ids) { + List locationList = service.listByIds(ids); + for (TravelLocation location : locationList) { + Page 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; + } +} diff --git a/src/main/java/com/imyeyu/api/modules/journal/entity/Travel.java b/src/main/java/com/imyeyu/api/modules/journal/entity/Travel.java new file mode 100644 index 0000000..033184a --- /dev/null +++ b/src/main/java/com/imyeyu/api/modules/journal/entity/Travel.java @@ -0,0 +1,83 @@ +package com.imyeyu.api.modules.journal.entity; + +import com.imyeyu.spring.annotation.table.PageIgnore; +import com.imyeyu.spring.entity.Entity; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 旅行计划 + * + * @author 夜雨 + * @since 2025-12-12 14:30 + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class Travel extends Entity { + + /** + * 交通类型 + * + * @author 夜雨 + * @since 2025-12-12 14:30 + */ + public enum TransportationType { + + /** 飞机 */ + PLANE, + + /** 火车 */ + TRAIN, + + /** 汽车 */ + CAR, + + /** 轮船 */ + SHIP, + + /** 自驾 */ + SELF_DRIVING, + + /** 其他 */ + OTHER + } + + /** + * 旅行状态 + * + * @author 夜雨 + * @since 2025-12-12 14:30 + */ + public enum Status { + + /** 计划中 */ + PLANNING, + + /** 进行中 */ + ONGOING, + + /** 已完成 */ + COMPLETED, + } + + /** 交通类型 */ + @PageIgnore + private TransportationType transportationType; + + /** 标题 */ + private String title; + + /** 内容 */ + @PageIgnore + private String content; + + /** 出行时间 */ + private Long travelAt; + + /** 天数 */ + @PageIgnore + private Integer days; + + /** 状态 */ + private Status status; +} diff --git a/src/main/java/com/imyeyu/api/modules/journal/entity/TravelLocation.java b/src/main/java/com/imyeyu/api/modules/journal/entity/TravelLocation.java new file mode 100644 index 0000000..fdc6210 --- /dev/null +++ b/src/main/java/com/imyeyu/api/modules/journal/entity/TravelLocation.java @@ -0,0 +1,87 @@ +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 lombok.Data; +import lombok.EqualsAndHashCode; + +import java.math.BigDecimal; +import java.util.List; + +/** + * 旅行地点 + * + * @author 夜雨 + * @since 2025-12-12 14:30 + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class TravelLocation extends Entity { + + /** + * 地点类型 + * + * @author 夜雨 + * @since 2025-12-12 14:30 + */ + public enum Type { + + /** 景点 */ + ATTRACTION, + + /** 酒店 */ + HOTEL, + + /** 餐厅 */ + RESTAURANT, + + /** 交通站点 */ + TRANSPORT, + + /** 购物 */ + SHOPPING, + + /** 其他 */ + OTHER + } + + /** 旅行计划 ID */ + private Long travelId; + + /** 类型 */ + private Type type; + + /** 标题 */ + private String title; + + /** 说明 */ + private String description; + + /** 纬度 */ + private Double lat; + + /** 经度 */ + private Double lng; + + /** 位置 */ + private String location; + + /** 费用 */ + private BigDecimal amount; + + /** true 为需要身份证 */ + private Boolean requireIdCard; + + /** 必要评分 */ + private Integer score; + + @Transient + private Long[] attachmentIds; + + @Transient + private String[] tempFileIds; + + @Transient + private List items; +} diff --git a/src/main/java/com/imyeyu/api/modules/journal/mapper/TravelLocationMapper.java b/src/main/java/com/imyeyu/api/modules/journal/mapper/TravelLocationMapper.java new file mode 100644 index 0000000..5a3e022 --- /dev/null +++ b/src/main/java/com/imyeyu/api/modules/journal/mapper/TravelLocationMapper.java @@ -0,0 +1,17 @@ +package com.imyeyu.api.modules.journal.mapper; + +import com.imyeyu.api.modules.journal.entity.TravelLocation; +import com.imyeyu.spring.mapper.BaseMapper; + +import java.util.List; + +/** + * 旅行地点 Mapper + * + * @author 夜雨 + * @since 2025-12-12 14:35 + */ +public interface TravelLocationMapper extends BaseMapper { + + List listByIds(Long[] ids); +} diff --git a/src/main/java/com/imyeyu/api/modules/journal/mapper/TravelMapper.java b/src/main/java/com/imyeyu/api/modules/journal/mapper/TravelMapper.java new file mode 100644 index 0000000..0f221b5 --- /dev/null +++ b/src/main/java/com/imyeyu/api/modules/journal/mapper/TravelMapper.java @@ -0,0 +1,32 @@ +package com.imyeyu.api.modules.journal.mapper; + +import com.imyeyu.api.modules.journal.entity.Travel; +import com.imyeyu.spring.mapper.BaseMapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 旅行计划 Mapper + * + * @author 夜雨 + * @since 2025-12-12 14:35 + */ +public interface TravelMapper extends BaseMapper { + + /** + * 根据 ID 列表查询 + * + * @param ids ID 列表 + * @return 旅行列表 + */ + List listByIds(@Param("ids") Long[] ids); + + /** + * 根据状态查询 + * + * @param status 状态 + * @return 旅行列表 + */ + List listByStatus(@Param("status") Travel.Status status); +} diff --git a/src/main/java/com/imyeyu/api/modules/journal/service/TravelLocationService.java b/src/main/java/com/imyeyu/api/modules/journal/service/TravelLocationService.java new file mode 100644 index 0000000..261f19a --- /dev/null +++ b/src/main/java/com/imyeyu/api/modules/journal/service/TravelLocationService.java @@ -0,0 +1,26 @@ +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 { + + List listByIds(Long... ids); + + /** + * 根据旅行 ID 删除所有地点 + * + * @param travelId 旅行 ID + * @throws TimiException 服务异常 + */ + void deleteByTravelId(Long travelId) throws TimiException; +} diff --git a/src/main/java/com/imyeyu/api/modules/journal/service/TravelService.java b/src/main/java/com/imyeyu/api/modules/journal/service/TravelService.java new file mode 100644 index 0000000..4aef024 --- /dev/null +++ b/src/main/java/com/imyeyu/api/modules/journal/service/TravelService.java @@ -0,0 +1,13 @@ +package com.imyeyu.api.modules.journal.service; + +import com.imyeyu.api.modules.journal.entity.Travel; +import com.imyeyu.spring.service.BaseService; + +/** + * 旅行计划服务 + * + * @author 夜雨 + * @since 2025-12-12 14:40 + */ +public interface TravelService extends BaseService { +} diff --git a/src/main/java/com/imyeyu/api/modules/journal/service/implement/TravelLocationServiceImplement.java b/src/main/java/com/imyeyu/api/modules/journal/service/implement/TravelLocationServiceImplement.java new file mode 100644 index 0000000..4e3daea --- /dev/null +++ b/src/main/java/com/imyeyu/api/modules/journal/service/implement/TravelLocationServiceImplement.java @@ -0,0 +1,111 @@ +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.bean.TempFileMetaData; +import com.imyeyu.api.modules.common.entity.Attachment; +import com.imyeyu.api.modules.common.service.AttachmentService; +import com.imyeyu.api.modules.common.service.TempFileService; +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.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.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * 旅行地点服务实现 + * + * @author 夜雨 + * @since 2025-12-12 14:45 + */ +@Slf4j +@Service +@RequiredArgsConstructor +public class TravelLocationServiceImplement extends AbstractEntityService implements TravelLocationService { + + private final TempFileService tempFileService; + private final AttachmentService attachmentService; + + private final TravelLocationMapper mapper; + + @Override + protected BaseMapper mapper() { + return mapper; + } + + @Transactional(TimiServerDBConfig.ROLLBACKER) + @Override + public void create(TravelLocation travelLocation) { + super.create(travelLocation); + for (String tempFileId : travelLocation.getTempFileIds()) { + TempFileMetaData metadata = tempFileService.metadata(tempFileId); + + Attachment attach = new Attachment(); + attach.setName(metadata.getOriginalName()); + attach.setBizType(Attachment.BizType.JOURNAL_TRAVEL); + attach.setBizId(travelLocation.getId()); + attach.setInputStream(tempFileService.getInputStream(tempFileId)); + attachmentService.createMedia(attach); + } + } + + @Transactional(TimiServerDBConfig.ROLLBACKER) + @Override + public void update(TravelLocation travelLocation) { + super.update(travelLocation); + // 删除 + Set dbAttachSet = attachmentService.listByBizId(Attachment.BizType.JOURNAL_TRAVEL, travelLocation.getId(), MediaAttach.Type.THUMB) + .stream() + .map(Attachment::getId) + .collect(Collectors.toSet()); + Set retainIds = Set.of(TimiJava.firstNotEmpty(travelLocation.getAttachmentIds(), new Long[0])); + dbAttachSet.removeAll(retainIds); + for (Long removeId : dbAttachSet) { + attachmentService.deleteMedia(removeId); + } + // 新增 + for (String tempFileId : TimiJava.firstNotNull(travelLocation.getTempFileIds(), new String[0])) { + TempFileMetaData metadata = tempFileService.metadata(tempFileId); + + Attachment attach = new Attachment(); + attach.setName(metadata.getOriginalName()); + attach.setBizType(Attachment.BizType.JOURNAL_TRAVEL); + attach.setBizId(travelLocation.getId()); + attach.setInputStream(tempFileService.getInputStream(tempFileId)); + attachmentService.createMedia(attach); + } + } + + @Transactional(TimiServerDBConfig.ROLLBACKER) + @Override + public void delete(Long id) { + super.delete(id); + attachmentService.deleteByBizId(Attachment.BizType.JOURNAL_TRAVEL, id); + } + + @Override + public List 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 locationList = mapper.selectAllByExample(example); + for (TravelLocation location : locationList) { + delete(location.getId()); + } + } +} diff --git a/src/main/java/com/imyeyu/api/modules/journal/service/implement/TravelServiceImplement.java b/src/main/java/com/imyeyu/api/modules/journal/service/implement/TravelServiceImplement.java new file mode 100644 index 0000000..590b27c --- /dev/null +++ b/src/main/java/com/imyeyu/api/modules/journal/service/implement/TravelServiceImplement.java @@ -0,0 +1,40 @@ +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; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +/** + * 旅行计划服务实现 + * + * @author 夜雨 + * @since 2025-12-12 14:45 + */ +@Slf4j +@Service +@RequiredArgsConstructor +public class TravelServiceImplement extends AbstractEntityService implements TravelService { + + private final TravelMapper mapper; + private final TravelLocationService travelLocationService; + + @Override + protected BaseMapper mapper() { + return mapper; + } + + @Transactional(TimiServerDBConfig.ROLLBACKER) + @Override + public void delete(Long id) { + super.delete(id); + travelLocationService.deleteByTravelId(id); + } +}