游记服务的后台管理接口可以参考攻略服务
数据库
游记表
CREATE TABLE `travel` ( `id` bigint NOT NULL AUTO_INCREMENT, `dest_id` bigint DEFAULT NULL, `dest_name` varchar(255) DEFAULT NULL, `author_id` bigint DEFAULT NULL, `title` varchar(255) DEFAULT NULL, `summary` varchar(255) DEFAULT NULL, `cover_url` varchar(255) DEFAULT NULL, `travel_time` datetime DEFAULT NULL, `avg_consume` int DEFAULT NULL, `day` int DEFAULT NULL, `person` int DEFAULT NULL, `create_time` datetime DEFAULT NULL, `release_time` datetime DEFAULT NULL, `last_update_time` datetime DEFAULT NULL, `ispublic` int DEFAULT NULL, `viewnum` int DEFAULT NULL, `replynum` int DEFAULT NULL, `favornum` int DEFAULT NULL, `sharenum` int DEFAULT NULL, `thumbsupnum` int DEFAULT NULL, `state` int DEFAULT NULL, PRIMARY KEY (`id`) USING BTREE ) ENGINE=InnoDB AUTO_INCREMENT=17 DEFAULT CHARSET=utf8mb3 ROW_FORMAT=DYNAMIC;
|
实体类
找到模块:trip-article-api ,找到包com.swx.article.domain
,创建游记实体类
Travel
@Setter @Getter @TableName("travel") public class Travel implements Serializable {
public static final int STATE_NORMAL = 0; public static final int STATE_WAITING = 1; public static final int STATE_RELEASE = 2; public static final int STATE_REJECT = 3;
public static final int ISPUBLIC_NO = 0; public static final int ISPUBLIC_YES = 1;
@TableId(type = IdType.AUTO) private Long id; private Long destId; private String destName; private Long authorId; @TableField(exist = false) private UserInfoDTO author; private String title; private String summary; private String coverUrl; @DateTimeFormat(pattern = "yyyy-MM-dd") private Date travelTime; private Integer avgConsume; private Integer day; private Integer person; private Date createTime; private Date releaseTime; private Date lastUpdateTime; private Integer ispublic = ISPUBLIC_NO; private Integer viewnum; private Integer replynum; private Integer favornum; private Integer sharenum; private Integer thumbsupnum; private Integer state = STATE_NORMAL; @TableField(exist = false) private TravelContent content; }
|
基础服务
主键查询
接口信息
Controller
TravelController@RestController @RequestMapping("/travels") public class TravelController {
private final TravelService travelService;
public TravelController(TravelService travelService) { this.travelService = travelService; }
@GetMapping("/detail") public R<Travel> getById(Long id) { return R.ok(travelService.getById(id)); } }
|
保存游记
在保存攻略类型时,需要填充其对应目的地的名称
接口信息
Controller
TravelController@PostMapping("/save") public R<?> save(Travel travel) { travelService.save(travel); return R.ok(); }
|
更新游记
接口信息
Controller
TravelController@PostMapping("/update") public R<?> update(Travel travel) { travelService.updateById(travel); return R.ok(); }
|
删除游记
接口信息
Controller
TravelController@PostMapping("/delete/{id}") public R<?> delete(@PathVariable Long id) { travelService.removeById(id); return R.ok(); }
|
复杂分页查询
根据目的地分组查询类别
对应的前端页面如下:可以根据:出发时间、人均花费、出行天数过滤,根据时间和浏览量排序
接口信息
查询条件
使用了Map做映射,前端只需要传入序号,即可映射为过滤范围
找到模块:trip-article-api,创建包:com.swx.article.qo
,包下创建查询类:TravelQuery
TravelQuery@Getter @Setter public class TravelQuery extends QueryObject {
private final List<String> ALLOW_ORDER_BY_COLUMNS = Arrays.asList("viewnum", "create_time"); private final static Map<Integer, TravelRange> TRAVEL_TIME_MAP = new HashMap<>(); private final static Map<Integer, TravelRange> COST_MAP = new HashMap<>(); private final static Map<Integer, TravelRange> DAYS_MAP = new HashMap<>();
static { TRAVEL_TIME_MAP.put(1, new TravelRange(1, 2)); TRAVEL_TIME_MAP.put(2, new TravelRange(3, 4)); TRAVEL_TIME_MAP.put(3, new TravelRange(5, 6)); TRAVEL_TIME_MAP.put(4, new TravelRange(7, 8)); TRAVEL_TIME_MAP.put(5, new TravelRange(9, 10)); TRAVEL_TIME_MAP.put(6, new TravelRange(11, 12));
COST_MAP.put(1, new TravelRange(1, 999)); COST_MAP.put(2, new TravelRange(1000, 5999)); COST_MAP.put(3, new TravelRange(6000, 19999)); COST_MAP.put(4, new TravelRange(20000, Integer.MAX_VALUE));
DAYS_MAP.put(1, new TravelRange(1, 3)); DAYS_MAP.put(2, new TravelRange(4, 7)); DAYS_MAP.put(3, new TravelRange(8, 14)); DAYS_MAP.put(4, new TravelRange(15, 365)); }
private Long destId; private String orderBy; private TravelRange travelTimeRange; private TravelRange costRange; private TravelRange dayRange;
public void setTravelTimeType(Integer travelTimeType) { this.travelTimeRange = TRAVEL_TIME_MAP.get(travelTimeType); }
public void setConsumeType(Integer consumeType) { this.costRange = COST_MAP.get(consumeType); }
public void setDayType(Integer dayType) { this.dayRange = DAYS_MAP.get(dayType); }
public void setOrderBy(String orderBy) { if (ALLOW_ORDER_BY_COLUMNS.contains(orderBy)) { this.orderBy = orderBy; } } }
|
Service
找到:TravelService,定义分组查询方法
TravelServicepublic interface TravelService extends IService<Travel> {
Page<Travel> pageList(TravelQuery query); }
|
找到:TravelServiceImpl,实现上述方法
TravelServiceImpl@Slf4j @Service public class TravelServiceImpl extends ServiceImpl<TravelMapper, Travel> implements TravelService {
private final UserInfoFeignService userInfoFeignService; private final ThreadPoolExecutor bizThreadPoolExecutor; private final TravelContentMapper travelContentMapper;
public TravelServiceImpl(UserInfoFeignService userInfoFeignService, ThreadPoolExecutor bizThreadPoolExecutor, TravelContentMapper travelContentMapper) { this.userInfoFeignService = userInfoFeignService; this.bizThreadPoolExecutor = bizThreadPoolExecutor; this.travelContentMapper = travelContentMapper; }
@Override public Travel getById(Serializable id) { Travel travel = super.getById(id); if (travel == null) { return null; } TravelContent content = travelContentMapper.selectById(id); travel.setContent(content);
R<UserInfoDTO> result = userInfoFeignService.getById(travel.getAuthorId()); UserInfoDTO author = result.checkAndGet(); travel.setAuthor(author);
return travel; }
@Override public Page<Travel> pageList(TravelQuery query) { QueryWrapper<Travel> wrapper = Wrappers.<Travel>query() .eq(query.getDestId() != null, "dest_id", query.getDestId()); if (query.getTravelTimeRange() != null) { TravelRange timeRange = query.getTravelTimeRange(); wrapper.between("MONTH(travel_time)", timeRange.getMin(), timeRange.getMax()); } if (query.getCostRange() != null) { TravelRange costRange = query.getCostRange(); wrapper.between("avg_consume", costRange.getMin(), costRange.getMax()); } if (query.getDayRange() != null) { TravelRange dayRange = query.getDayRange(); wrapper.between("day", dayRange.getMin(), dayRange.getMax()); } wrapper.orderByDesc(query.getOrderBy() != null, query.getOrderBy());
LoginUser loginUser = AuthenticationUtil.getLoginUser(); if (loginUser == null) { wrapper.eq("ispublic", Travel.ISPUBLIC_YES) .eq("state", Travel.STATE_RELEASE); } else { wrapper.and(w -> w.eq("author_id", loginUser.getId()) .or(ww -> ww.eq("ispublic", Travel.ISPUBLIC_YES).eq("state", Travel.STATE_RELEASE)) ); }
Page<Travel> page = super.page(new Page<>(query.getCurrent(), query.getSize()), wrapper); List<Travel> travels = page.getRecords();
CountDownLatch latch = new CountDownLatch(travels.size()); for (Travel travel : travels) { bizThreadPoolExecutor.execute(() -> { try { R<UserInfoDTO> result = userInfoFeignService.getById(travel.getAuthorId()); if (result.getCode() != R.CODE_SUCCESS) { log.warn("[游记服务] 查询用户作者失败,返回数据异常: {}", JSON.toJSONString(result)); return; } travel.setAuthor(result.getData()); } finally { latch.countDown(); } }); } try { latch.await(10, TimeUnit.MINUTES); } catch (InterruptedException e) { e.printStackTrace(); } return page; } }
|
Controller
找到:TravelController,定义分页查询接口
TravelController@GetMapping("/query") public R<Page<Travel>> pageList(TravelQuery query) { return R.ok(travelService.pageList(query)); }
|
查询浏览量前三的游记
接口信息
Service
找到:TravelService,定义查询的方法
TravelService
List<Travel> findViewnumTop3(Long destId);
|
找到:TravelServiceImpl,实现查询的方法
TravelServiceImpl
@Override public List<Travel> findViewnumTop3(Long destId) { return super.list(Wrappers.<Travel>lambdaQuery() .eq(Travel::getDestId, destId) .orderByDesc(Travel::getViewnum) .last("limit 3") ); }
|
Controller
找到:TravelController,定义查询接口
TravelController@GetMapping("/viewnumTop3") public R<List<Travel>> viewnumTop3(Long destId) { return R.ok(travelService.findViewnumTop3(destId)); }
|