修复人设接口国际化查询与未登录访问

This commit is contained in:
2026-04-01 15:11:50 +08:00
parent 9d4e86535a
commit 7a4086547d
16 changed files with 286 additions and 97 deletions

BIN
.DS_Store vendored

Binary file not shown.

BIN
src/main/.DS_Store vendored

Binary file not shown.

View File

@@ -87,6 +87,7 @@ public class SaTokenConfigure implements WebMvcConfigurer {
"/ai-companion/report", "/ai-companion/report",
"/apple/notification", "/apple/notification",
"/appVersions/checkUpdate", "/appVersions/checkUpdate",
"/character/detailWithNotLogin"
}; };
} }
@Bean @Bean

View File

@@ -1,30 +1,19 @@
package com.yolo.keyborad.controller; package com.yolo.keyborad.controller;
import cn.dev33.satoken.stp.StpUtil; import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import com.yolo.keyborad.common.BaseResponse; import com.yolo.keyborad.common.BaseResponse;
import com.yolo.keyborad.common.ErrorCode;
import com.yolo.keyborad.common.ResultUtils; import com.yolo.keyborad.common.ResultUtils;
import com.yolo.keyborad.exception.BusinessException;
import com.yolo.keyborad.model.dto.userCharacter.KeyboardUserCharacterAddDTO; import com.yolo.keyborad.model.dto.userCharacter.KeyboardUserCharacterAddDTO;
import com.yolo.keyborad.model.dto.userCharacter.KeyboardUserCharacterDTO;
import com.yolo.keyborad.model.dto.userCharacter.KeyboardUserCharacterSortUpdateDTO; import com.yolo.keyborad.model.dto.userCharacter.KeyboardUserCharacterSortUpdateDTO;
import com.yolo.keyborad.model.entity.KeyboardCharacter;
import com.yolo.keyborad.model.entity.KeyboardTag;
import com.yolo.keyborad.model.entity.KeyboardUserCharacter;
import com.yolo.keyborad.model.vo.character.KeyboardCharacterRespVO; import com.yolo.keyborad.model.vo.character.KeyboardCharacterRespVO;
import com.yolo.keyborad.model.vo.character.KeyboardUserCharacterVO; import com.yolo.keyborad.model.vo.character.KeyboardUserCharacterVO;
import com.yolo.keyborad.model.vo.tags.TagsRespVO;
import com.yolo.keyborad.service.KeyboardCharacterService; import com.yolo.keyborad.service.KeyboardCharacterService;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import javax.validation.constraints.NotNull;
import java.util.List; import java.util.List;
/* /*
@@ -42,26 +31,36 @@ public class CharacterController {
@GetMapping("/list") @GetMapping("/list")
@Operation(summary = "人设列表", description = "人设列表接口按 rank 排名") @Operation(summary = "人设列表", description = "人设列表接口按 rank 排名")
public BaseResponse<List<KeyboardCharacterRespVO>> list() { public BaseResponse<List<KeyboardCharacterRespVO>> list(
return ResultUtils.success(characterService.selectListWithRank()); @RequestHeader(value = "Accept-Language", required = false) String acceptLanguage
) {
return ResultUtils.success(characterService.selectListWithRank(acceptLanguage));
} }
@GetMapping("/detail") @GetMapping("/detail")
@Operation(summary = "人设详情", description = "人设详情接口") @Operation(summary = "人设详情", description = "人设详情接口")
public BaseResponse<KeyboardCharacterRespVO> detail(@RequestParam("id") Long id) { public BaseResponse<KeyboardCharacterRespVO> detail(
return ResultUtils.success(characterService.getDetailById(id)); @RequestParam("id") Long id,
@RequestHeader(value = "Accept-Language", required = false) String acceptLanguage
) {
return ResultUtils.success(characterService.getDetailById(id, acceptLanguage));
} }
@GetMapping("/listByTag") @GetMapping("/listByTag")
@Operation(summary = "按标签查询人设列表", description = "按标签查询人设列表接口") @Operation(summary = "按标签查询人设列表", description = "按标签查询人设列表接口")
public BaseResponse<List<KeyboardCharacterRespVO>> listByTag(@RequestParam("tagId") Long tagId) { public BaseResponse<List<KeyboardCharacterRespVO>> listByTag(
return ResultUtils.success(characterService.selectListByTag(tagId)); @RequestParam("tagId") Long tagId,
@RequestHeader(value = "Accept-Language", required = false) String acceptLanguage
) {
return ResultUtils.success(characterService.selectListByTag(tagId, acceptLanguage));
} }
@GetMapping("/listByUser") @GetMapping("/listByUser")
@Operation(summary = "用户人设列表", description = "用户人设列表接口") @Operation(summary = "用户人设列表", description = "用户人设列表接口")
public BaseResponse<List<KeyboardUserCharacterVO>> userList() { public BaseResponse<List<KeyboardUserCharacterVO>> userList(
return ResultUtils.success(characterService.selectListByUserId()); @RequestHeader(value = "Accept-Language", required = false) String acceptLanguage
) {
return ResultUtils.success(characterService.selectListByUserId(acceptLanguage));
} }
@@ -89,20 +88,27 @@ public class CharacterController {
@GetMapping("/listWithNotLogin") @GetMapping("/listWithNotLogin")
@Operation(summary = "未登录用户人设列表", description = "未登录用户人设列表接口按 rank 排名") @Operation(summary = "未登录用户人设列表", description = "未登录用户人设列表接口按 rank 排名")
public BaseResponse<List<KeyboardCharacterRespVO>> listWithNotLogin() { public BaseResponse<List<KeyboardCharacterRespVO>> listWithNotLogin(
return ResultUtils.success(characterService.selectListWithNotLoginRank()); @RequestHeader(value = "Accept-Language", required = false) String acceptLanguage
) {
return ResultUtils.success(characterService.selectListWithNotLoginRank(acceptLanguage));
} }
@GetMapping("/detailWithNotLogin") @GetMapping("/detailWithNotLogin")
@Operation(summary = "未登录用户人设详情", description = "未登录用户人设详情接口") @Operation(summary = "未登录用户人设详情", description = "未登录用户人设详情接口")
public BaseResponse<KeyboardCharacterRespVO> detailWithNotLogin(@RequestParam("id") Long id) { public BaseResponse<KeyboardCharacterRespVO> detailWithNotLogin(
KeyboardCharacter character = characterService.getById(id); @RequestParam("id") Long id,
return ResultUtils.success(BeanUtil.copyProperties(character, KeyboardCharacterRespVO.class)); @RequestHeader(value = "Accept-Language", required = false) String acceptLanguage
) {
return ResultUtils.success(characterService.getDetailById(id, acceptLanguage));
} }
@GetMapping("/listByTagWithNotLogin") @GetMapping("/listByTagWithNotLogin")
@Operation(summary = "未登录用户按标签查询人设列表", description = "未登录用户按标签查询人设列表接口") @Operation(summary = "未登录用户按标签查询人设列表", description = "未登录用户按标签查询人设列表接口")
public BaseResponse<List<KeyboardCharacterRespVO>> listByTagWithNotLogin(@RequestParam("tagId") Long tagId) { public BaseResponse<List<KeyboardCharacterRespVO>> listByTagWithNotLogin(
return ResultUtils.success(characterService.selectListByTagWithNotLogin(tagId)); @RequestParam("tagId") Long tagId,
@RequestHeader(value = "Accept-Language", required = false) String acceptLanguage
) {
return ResultUtils.success(characterService.selectListByTagWithNotLogin(tagId, acceptLanguage));
} }
} }

View File

@@ -20,7 +20,7 @@ import java.util.concurrent.TimeUnit;
@Slf4j @Slf4j
public class CharacterCacheInitializer implements ApplicationRunner { public class CharacterCacheInitializer implements ApplicationRunner {
private static final String CHARACTER_CACHE_KEY = "character:"; private static final String CHARACTER_CACHE_KEY_PREFIX = "character:";
@Resource @Resource
private KeyboardCharacterService characterService; private KeyboardCharacterService characterService;
@@ -34,7 +34,7 @@ public class CharacterCacheInitializer implements ApplicationRunner {
log.info("开始缓存人设列表到Redis..."); log.info("开始缓存人设列表到Redis...");
List<KeyboardCharacter> characters = characterService.list(); List<KeyboardCharacter> characters = characterService.list();
for (KeyboardCharacter character : characters) { for (KeyboardCharacter character : characters) {
String key = CHARACTER_CACHE_KEY + character.getId(); String key = CHARACTER_CACHE_KEY_PREFIX + character.getId();
redisTemplate.opsForValue().set(key, character, 5, TimeUnit.MINUTES); redisTemplate.opsForValue().set(key, character, 5, TimeUnit.MINUTES);
} }
log.info("人设列表缓存完成,共缓存 {} 条记录", characters.size()); log.info("人设列表缓存完成,共缓存 {} 条记录", characters.size());

View File

@@ -0,0 +1,12 @@
package com.yolo.keyborad.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.yolo.keyborad.model.entity.KeyboardCharacterI18n;
/*
* @author: ziin
* @date: 2026/4/1 14:13
*/
public interface KeyboardCharacterI18nMapper extends BaseMapper<KeyboardCharacterI18n> {
}

View File

@@ -14,7 +14,7 @@ import java.util.List;
public interface KeyboardUserCharacterMapper extends BaseMapper<KeyboardUserCharacter> { public interface KeyboardUserCharacterMapper extends BaseMapper<KeyboardUserCharacter> {
List<KeyboardUserCharacterVO> selectByUserId(@Param("loginId") long loginId); List<KeyboardUserCharacterVO> selectByUserId(@Param("loginId") long loginId, @Param("locale") String locale);
void updateSortByIdAndUserId(@Param("sort") Integer[] sort,@Param("userId") long userId); void updateSortByIdAndUserId(@Param("sort") Integer[] sort,@Param("userId") long userId);

View File

@@ -21,14 +21,6 @@ public class KeyboardCharacter {
@Schema(description="主键 Id") @Schema(description="主键 Id")
private Long id; private Long id;
@TableField(value = "character_name")
@Schema(description="标题")
private String characterName;
@TableField(value = "\"character_background\"")
@Schema(description="背景描述")
private String characterBackground;
@TableField(value = "avatar_url") @TableField(value = "avatar_url")
@Schema(description="角色头像") @Schema(description="角色头像")
private String avatarUrl; private String avatarUrl;

View File

@@ -0,0 +1,71 @@
package com.yolo.keyborad.model.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.v3.oas.annotations.media.Schema;
import java.util.Date;
import lombok.Data;
/*
* @author: ziin
* @date: 2026/4/1 14:13
*/
/**
* 键盘人设国际化内容表
*/
@Schema(description="键盘人设国际化内容表")
@Data
@TableName(value = "keyboard_character_i18n")
public class KeyboardCharacterI18n {
/**
* 主键 Id
*/
@TableId(value = "id", type = IdType.AUTO)
@Schema(description="主键 Id")
private Long id;
/**
* 角色主表id
*/
@TableField(value = "character_id")
@Schema(description="角色主表id")
private Long characterId;
/**
* 语言标识,如 zh-CN/en-US/ja-JP
*/
@TableField(value = "\"locale\"")
@Schema(description="语言标识,如 zh-CN/en-US/ja-JP")
private String locale;
/**
* 标题
*/
@TableField(value = "character_name")
@Schema(description="标题")
private String characterName;
/**
* 背景描述
*/
@TableField(value = "character_background")
@Schema(description="背景描述")
private String characterBackground;
/**
* 创建时间
*/
@TableField(value = "created_at")
@Schema(description="创建时间")
private Date createdAt;
/**
* 更新时间
*/
@TableField(value = "updated_at")
@Schema(description="更新时间")
private Date updatedAt;
}

View File

@@ -0,0 +1,13 @@
package com.yolo.keyborad.service;
import com.yolo.keyborad.model.entity.KeyboardCharacterI18n;
import com.baomidou.mybatisplus.extension.service.IService;
/*
* @author: ziin
* @date: 2026/4/1 14:13
*/
public interface KeyboardCharacterI18nService extends IService<KeyboardCharacterI18n>{
}

View File

@@ -18,11 +18,11 @@ import java.util.List;
public interface KeyboardCharacterService extends IService<KeyboardCharacter>{ public interface KeyboardCharacterService extends IService<KeyboardCharacter>{
List<KeyboardCharacterRespVO> selectListWithRank(); List<KeyboardCharacterRespVO> selectListWithRank(String acceptLanguage);
List<KeyboardCharacterRespVO> selectListByTag(Long tagId); List<KeyboardCharacterRespVO> selectListByTag(Long tagId, String acceptLanguage);
List<KeyboardUserCharacterVO> selectListByUserId(); List<KeyboardUserCharacterVO> selectListByUserId(String acceptLanguage);
void updateSort(KeyboardUserCharacterSortUpdateDTO sortUpdateDTO); void updateSort(KeyboardUserCharacterSortUpdateDTO sortUpdateDTO);
@@ -30,11 +30,11 @@ public interface KeyboardCharacterService extends IService<KeyboardCharacter>{
void removeUserCharacter(Long id); void removeUserCharacter(Long id);
List<KeyboardCharacterRespVO> selectListWithNotLoginRank(); List<KeyboardCharacterRespVO> selectListWithNotLoginRank(String acceptLanguage);
List<KeyboardCharacterRespVO> selectListByTagWithNotLogin(Long tagId); List<KeyboardCharacterRespVO> selectListByTagWithNotLogin(Long tagId, String acceptLanguage);
void addDefaultUserCharacter(Long userId); void addDefaultUserCharacter(Long userId);
KeyboardCharacterRespVO getDetailById(Long id); KeyboardCharacterRespVO getDetailById(Long id, String acceptLanguage);
} }

View File

@@ -0,0 +1,18 @@
package com.yolo.keyborad.service.impl;
import org.springframework.stereotype.Service;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.List;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yolo.keyborad.model.entity.KeyboardCharacterI18n;
import com.yolo.keyborad.mapper.KeyboardCharacterI18nMapper;
import com.yolo.keyborad.service.KeyboardCharacterI18nService;
/*
* @author: ziin
* @date: 2026/4/1 14:13
*/
@Service
public class KeyboardCharacterI18nServiceImpl extends ServiceImpl<KeyboardCharacterI18nMapper, KeyboardCharacterI18n> implements KeyboardCharacterI18nService{
}

View File

@@ -2,31 +2,35 @@ package com.yolo.keyborad.service.impl;
import cn.dev33.satoken.stp.StpUtil; import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.yolo.keyborad.common.ErrorCode; import com.yolo.keyborad.common.ErrorCode;
import com.yolo.keyborad.exception.BusinessException; import com.yolo.keyborad.exception.BusinessException;
import com.yolo.keyborad.mapper.KeyboardCharacterMapper; import com.yolo.keyborad.mapper.KeyboardCharacterMapper;
import com.yolo.keyborad.mapper.KeyboardCharacterI18nMapper;
import com.yolo.keyborad.mapper.KeyboardUserCharacterMapper; import com.yolo.keyborad.mapper.KeyboardUserCharacterMapper;
import com.yolo.keyborad.mapper.KeyboardUserSortMapper; import com.yolo.keyborad.mapper.KeyboardUserSortMapper;
import com.yolo.keyborad.model.dto.userCharacter.KeyboardUserCharacterAddDTO; import com.yolo.keyborad.model.dto.userCharacter.KeyboardUserCharacterAddDTO;
import com.yolo.keyborad.model.dto.userCharacter.KeyboardUserCharacterSortUpdateDTO; import com.yolo.keyborad.model.dto.userCharacter.KeyboardUserCharacterSortUpdateDTO;
import com.yolo.keyborad.model.entity.KeyboardUser;
import com.yolo.keyborad.model.entity.KeyboardUserCharacter; import com.yolo.keyborad.model.entity.KeyboardUserCharacter;
import com.yolo.keyborad.model.entity.KeyboardCharacterI18n;
import com.yolo.keyborad.model.vo.character.KeyboardCharacterRespVO; import com.yolo.keyborad.model.vo.character.KeyboardCharacterRespVO;
import com.yolo.keyborad.model.vo.character.KeyboardUserCharacterVO; import com.yolo.keyborad.model.vo.character.KeyboardUserCharacterVO;
import com.yolo.keyborad.utils.RequestLocaleUtils;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yolo.keyborad.model.entity.KeyboardCharacter; import com.yolo.keyborad.model.entity.KeyboardCharacter;
import com.yolo.keyborad.service.KeyboardCharacterService; import com.yolo.keyborad.service.KeyboardCharacterService;
import org.springframework.util.StringUtils;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.stream.Stream; import java.util.stream.Stream;
@@ -38,7 +42,9 @@ import java.util.stream.Stream;
@Service @Service
public class KeyboardCharacterServiceImpl extends ServiceImpl<KeyboardCharacterMapper, KeyboardCharacter> implements KeyboardCharacterService{ public class KeyboardCharacterServiceImpl extends ServiceImpl<KeyboardCharacterMapper, KeyboardCharacter> implements KeyboardCharacterService{
private static final String CHARACTER_CACHE_KEY = "character:"; private static final String CHARACTER_CACHE_KEY_PREFIX = "character:";
private static final String CHARACTER_LIST_CACHE_KEY = "character:list:all";
private static final String CHARACTER_TAG_CACHE_KEY_PREFIX = "character:list:tag:";
@Resource @Resource
private KeyboardCharacterMapper keyboardCharacterMapper; private KeyboardCharacterMapper keyboardCharacterMapper;
@@ -49,12 +55,15 @@ public class KeyboardCharacterServiceImpl extends ServiceImpl<KeyboardCharacterM
@Resource @Resource
private KeyboardUserSortMapper keyboardUserSortMapper; private KeyboardUserSortMapper keyboardUserSortMapper;
@Resource
private KeyboardCharacterI18nMapper keyboardCharacterI18nMapper;
@Resource(name = "objectRedisTemplate") @Resource(name = "objectRedisTemplate")
private RedisTemplate<String, Object> redisTemplate; private RedisTemplate<String, Object> redisTemplate;
@Override @Override
public KeyboardCharacter getById(java.io.Serializable id) { public KeyboardCharacter getById(java.io.Serializable id) {
String key = CHARACTER_CACHE_KEY + id; String key = CHARACTER_CACHE_KEY_PREFIX + id;
KeyboardCharacter character = (KeyboardCharacter) redisTemplate.opsForValue().get(key); KeyboardCharacter character = (KeyboardCharacter) redisTemplate.opsForValue().get(key);
if (character == null) { if (character == null) {
character = super.getById(id); character = super.getById(id);
@@ -72,12 +81,11 @@ public class KeyboardCharacterServiceImpl extends ServiceImpl<KeyboardCharacterM
* @return 人设响应列表,包含是否已添加的标记 * @return 人设响应列表,包含是否已添加的标记
*/ */
@Override @Override
public List<KeyboardCharacterRespVO> selectListWithRank() { public List<KeyboardCharacterRespVO> selectListWithRank(String acceptLanguage) {
// 获取当前登录用户ID // 获取当前登录用户ID
long userId = StpUtil.getLoginIdAsLong(); long userId = StpUtil.getLoginIdAsLong();
// 定义缓存key用于存储所有人设列表 String cacheKey = CHARACTER_LIST_CACHE_KEY;
String cacheKey = "character:list:all";
// 尝试从Redis缓存中获取人设列表 // 尝试从Redis缓存中获取人设列表
List<KeyboardCharacter> keyboardCharacters = (List<KeyboardCharacter>) redisTemplate.opsForValue().get(cacheKey); List<KeyboardCharacter> keyboardCharacters = (List<KeyboardCharacter>) redisTemplate.opsForValue().get(cacheKey);
@@ -95,17 +103,12 @@ public class KeyboardCharacterServiceImpl extends ServiceImpl<KeyboardCharacterM
} }
// 查询当前用户已添加的人设列表 // 查询当前用户已添加的人设列表
List<KeyboardUserCharacterVO> userCharacterVOList = keyboardUserCharacterMapper.selectByUserId(userId); List<KeyboardUserCharacterVO> userCharacterVOList = keyboardUserCharacterMapper.selectByUserId(userId, null);
// 将KeyboardCharacter实体列表转换为KeyboardCharacterRespVO响应对象列表 // 将KeyboardCharacter实体列表转换为KeyboardCharacterRespVO响应对象列表
List<KeyboardCharacterRespVO> keyboardCharacterRespVOS = BeanUtil.copyToList(keyboardCharacters, KeyboardCharacterRespVO.class); List<KeyboardCharacterRespVO> keyboardCharacterRespVOS = buildCharacterRespList(keyboardCharacters, acceptLanguage);
// 遍历人设列表,标记每个人设是否已被当前用户添加 markAddedCharacters(keyboardCharacterRespVOS, userCharacterVOList);
keyboardCharacterRespVOS.forEach(character -> {
// 检查用户已添加列表中是否存在该人设ID
character.setAdded(userCharacterVOList.stream().anyMatch(userCharacter ->
userCharacter.getCharacterId().equals(character.getId())));
});
return keyboardCharacterRespVOS; return keyboardCharacterRespVOS;
} }
@@ -118,9 +121,8 @@ public class KeyboardCharacterServiceImpl extends ServiceImpl<KeyboardCharacterM
* @return 人设响应列表,包含是否已添加的标记 * @return 人设响应列表,包含是否已添加的标记
*/ */
@Override @Override
public List<KeyboardCharacterRespVO> selectListByTag(Long tagId) { public List<KeyboardCharacterRespVO> selectListByTag(Long tagId, String acceptLanguage) {
// 构建缓存key用于存储指定标签的人设列表 String cacheKey = CHARACTER_TAG_CACHE_KEY_PREFIX + tagId;
String cacheKey = "character:list:tag:" + tagId;
// 尝试从Redis缓存中获取指定标签的人设列表 // 尝试从Redis缓存中获取指定标签的人设列表
List<KeyboardCharacter> keyboardCharacters = (List<KeyboardCharacter>) redisTemplate.opsForValue().get(cacheKey); List<KeyboardCharacter> keyboardCharacters = (List<KeyboardCharacter>) redisTemplate.opsForValue().get(cacheKey);
@@ -142,25 +144,21 @@ public class KeyboardCharacterServiceImpl extends ServiceImpl<KeyboardCharacterM
long userId = StpUtil.getLoginIdAsLong(); long userId = StpUtil.getLoginIdAsLong();
// 查询当前用户已添加的人设列表 // 查询当前用户已添加的人设列表
List<KeyboardUserCharacterVO> userCharacterVOList = keyboardUserCharacterMapper.selectByUserId(userId); List<KeyboardUserCharacterVO> userCharacterVOList = keyboardUserCharacterMapper.selectByUserId(userId, null);
// 将KeyboardCharacter实体列表转换为KeyboardCharacterRespVO响应对象列表 // 将KeyboardCharacter实体列表转换为KeyboardCharacterRespVO响应对象列表
List<KeyboardCharacterRespVO> keyboardCharacterRespVOS = BeanUtil.copyToList(keyboardCharacters, KeyboardCharacterRespVO.class); List<KeyboardCharacterRespVO> keyboardCharacterRespVOS = buildCharacterRespList(keyboardCharacters, acceptLanguage);
// 遍历人设列表,标记每个人设是否已被当前用户添加 markAddedCharacters(keyboardCharacterRespVOS, userCharacterVOList);
keyboardCharacterRespVOS.forEach(character -> {
// 检查用户已添加列表中是否存在该人设ID
character.setAdded(userCharacterVOList.stream().anyMatch(userCharacter ->
userCharacter.getCharacterId().equals(character.getId())));
});
return keyboardCharacterRespVOS; return keyboardCharacterRespVOS;
} }
@Override @Override
public List<KeyboardUserCharacterVO> selectListByUserId() { public List<KeyboardUserCharacterVO> selectListByUserId(String acceptLanguage) {
long loginId = StpUtil.getLoginIdAsLong(); long loginId = StpUtil.getLoginIdAsLong();
return keyboardUserCharacterMapper.selectByUserId(loginId); String locale = RequestLocaleUtils.resolveLanguage(acceptLanguage);
return keyboardUserCharacterMapper.selectByUserId(loginId, locale);
} }
@Override @Override
@@ -225,9 +223,8 @@ public class KeyboardCharacterServiceImpl extends ServiceImpl<KeyboardCharacterM
} }
@Override @Override
public List<KeyboardCharacterRespVO> selectListWithNotLoginRank() { public List<KeyboardCharacterRespVO> selectListWithNotLoginRank(String acceptLanguage) {
// 先从缓存获取所有人设列表 String cacheKey = CHARACTER_LIST_CACHE_KEY;
String cacheKey = "character:list:all";
List<KeyboardCharacter> keyboardCharacters = (List<KeyboardCharacter>) redisTemplate.opsForValue().get(cacheKey); List<KeyboardCharacter> keyboardCharacters = (List<KeyboardCharacter>) redisTemplate.opsForValue().get(cacheKey);
if (keyboardCharacters == null) { if (keyboardCharacters == null) {
@@ -240,13 +237,12 @@ public class KeyboardCharacterServiceImpl extends ServiceImpl<KeyboardCharacterM
redisTemplate.opsForValue().set(cacheKey, keyboardCharacters, 7, TimeUnit.DAYS); redisTemplate.opsForValue().set(cacheKey, keyboardCharacters, 7, TimeUnit.DAYS);
} }
} }
return BeanUtil.copyToList(keyboardCharacters, KeyboardCharacterRespVO.class); return buildCharacterRespList(keyboardCharacters, acceptLanguage);
} }
@Override @Override
public List<KeyboardCharacterRespVO> selectListByTagWithNotLogin(Long tagId) { public List<KeyboardCharacterRespVO> selectListByTagWithNotLogin(Long tagId, String acceptLanguage) {
// 先从缓存获取指定标签的人设列表 String cacheKey = CHARACTER_TAG_CACHE_KEY_PREFIX + tagId;
String cacheKey = "character:list:tag:" + tagId;
List<KeyboardCharacter> keyboardCharacters = (List<KeyboardCharacter>) redisTemplate.opsForValue().get(cacheKey); List<KeyboardCharacter> keyboardCharacters = (List<KeyboardCharacter>) redisTemplate.opsForValue().get(cacheKey);
if (keyboardCharacters == null) { if (keyboardCharacters == null) {
@@ -260,7 +256,7 @@ public class KeyboardCharacterServiceImpl extends ServiceImpl<KeyboardCharacterM
redisTemplate.opsForValue().set(cacheKey, keyboardCharacters, 7, TimeUnit.DAYS); redisTemplate.opsForValue().set(cacheKey, keyboardCharacters, 7, TimeUnit.DAYS);
} }
} }
return BeanUtil.copyToList(keyboardCharacters, KeyboardCharacterRespVO.class); return buildCharacterRespList(keyboardCharacters, acceptLanguage);
} }
@@ -276,7 +272,7 @@ public class KeyboardCharacterServiceImpl extends ServiceImpl<KeyboardCharacterM
KeyboardUserCharacterAddDTO keyboardUserCharacterAddDTO = new KeyboardUserCharacterAddDTO(); KeyboardUserCharacterAddDTO keyboardUserCharacterAddDTO = new KeyboardUserCharacterAddDTO();
// 获取所有人设列表未登录状态并限制取前5个 // 获取所有人设列表未登录状态并限制取前5个
Stream<KeyboardCharacterRespVO> limit = selectListWithNotLoginRank().stream().limit(5); Stream<KeyboardCharacterRespVO> limit = selectListWithNotLoginRank(null).stream().limit(5);
// 遍历前5个人设为用户添加默认人设 // 遍历前5个人设为用户添加默认人设
limit.forEach(character -> { limit.forEach(character -> {
@@ -290,20 +286,83 @@ public class KeyboardCharacterServiceImpl extends ServiceImpl<KeyboardCharacterM
} }
@Override @Override
public KeyboardCharacterRespVO getDetailById(Long id) { public KeyboardCharacterRespVO getDetailById(Long id, String acceptLanguage) {
// 根据ID获取人设信息优先从缓存获取 // 根据ID获取人设信息优先从缓存获取
KeyboardCharacter character = this.getById(id); KeyboardCharacter character = this.getById(id);
// 将实体对象转换为响应对象 // 将实体对象转换为响应对象
KeyboardCharacterRespVO respVO = BeanUtil.copyProperties(character, KeyboardCharacterRespVO.class); KeyboardCharacterRespVO respVO = BeanUtil.copyProperties(character, KeyboardCharacterRespVO.class);
// 判断当前用户是否已添加该人设 applyI18n(List.of(respVO), acceptLanguage);
if (!StpUtil.isLogin()) {
respVO.setAdded(false);
return respVO;
}
long userId = StpUtil.getLoginIdAsLong(); long userId = StpUtil.getLoginIdAsLong();
// 查询用户人设关联表,判断当前用户是否已添加该人设
KeyboardUserCharacter userCharacter = keyboardUserCharacterMapper.selectOne( KeyboardUserCharacter userCharacter = keyboardUserCharacterMapper.selectOne(
new LambdaQueryWrapper<KeyboardUserCharacter>() new LambdaQueryWrapper<KeyboardUserCharacter>()
.eq(KeyboardUserCharacter::getCharacterId, id) .eq(KeyboardUserCharacter::getCharacterId, id)
.eq(KeyboardUserCharacter::getUserId, userId)); .eq(KeyboardUserCharacter::getUserId, userId));
// 设置是否已添加的标记
respVO.setAdded(userCharacter != null); respVO.setAdded(userCharacter != null);
return respVO; return respVO;
} }
private List<KeyboardCharacterRespVO> buildCharacterRespList(List<KeyboardCharacter> keyboardCharacters, String acceptLanguage) {
if (keyboardCharacters == null || keyboardCharacters.isEmpty()) {
return Collections.emptyList();
}
List<KeyboardCharacterRespVO> respVOS = BeanUtil.copyToList(keyboardCharacters, KeyboardCharacterRespVO.class);
applyI18n(respVOS, acceptLanguage);
return respVOS;
}
private void applyI18n(List<KeyboardCharacterRespVO> respVOS, String acceptLanguage) {
if (respVOS == null || respVOS.isEmpty()) {
return;
}
String locale = RequestLocaleUtils.resolveLanguage(acceptLanguage);
if (!StringUtils.hasText(locale)) {
return;
}
List<Long> characterIds = respVOS.stream()
.map(KeyboardCharacterRespVO::getId)
.toList();
Map<Long, KeyboardCharacterI18n> i18nMap = loadI18nMap(characterIds, locale);
respVOS.forEach(respVO -> {
KeyboardCharacterI18n i18n = i18nMap.get(respVO.getId());
if (i18n == null) {
return;
}
respVO.setCharacterName(i18n.getCharacterName());
respVO.setCharacterBackground(i18n.getCharacterBackground());
});
}
private void markAddedCharacters(List<KeyboardCharacterRespVO> respVOS, List<KeyboardUserCharacterVO> userCharacterVOList) {
if (respVOS == null || respVOS.isEmpty()) {
return;
}
Set<Long> addedCharacterIds = new HashSet<>();
if (userCharacterVOList != null && !userCharacterVOList.isEmpty()) {
userCharacterVOList.forEach(userCharacter -> addedCharacterIds.add(userCharacter.getCharacterId()));
}
respVOS.forEach(character -> character.setAdded(addedCharacterIds.contains(character.getId())));
}
private Map<Long, KeyboardCharacterI18n> loadI18nMap(List<Long> characterIds, String locale) {
if (characterIds == null || characterIds.isEmpty()) {
return Collections.emptyMap();
}
List<KeyboardCharacterI18n> i18nList = keyboardCharacterI18nMapper.selectList(
new LambdaQueryWrapper<KeyboardCharacterI18n>()
.eq(KeyboardCharacterI18n::getLocale, locale)
.in(KeyboardCharacterI18n::getCharacterId, characterIds)
);
if (i18nList == null || i18nList.isEmpty()) {
return Collections.emptyMap();
}
Map<Long, KeyboardCharacterI18n> i18nMap = new LinkedHashMap<>();
i18nList.forEach(item -> i18nMap.put(item.getCharacterId(), item));
return i18nMap;
}
} }

View File

@@ -0,0 +1,19 @@
<?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.yolo.keyborad.mapper.KeyboardCharacterI18nMapper">
<resultMap id="BaseResultMap" type="com.yolo.keyborad.model.entity.KeyboardCharacterI18n">
<!--@mbg.generated-->
<!--@Table keyboard_character_i18n-->
<id column="id" jdbcType="BIGINT" property="id" />
<result column="character_id" jdbcType="BIGINT" property="characterId" />
<result column="locale" jdbcType="VARCHAR" property="locale" />
<result column="character_name" jdbcType="VARCHAR" property="characterName" />
<result column="character_background" jdbcType="VARCHAR" property="characterBackground" />
<result column="created_at" jdbcType="TIMESTAMP" property="createdAt" />
<result column="updated_at" jdbcType="TIMESTAMP" property="updatedAt" />
</resultMap>
<sql id="Base_Column_List">
<!--@mbg.generated-->
id, character_id, "locale", character_name, character_background, created_at, updated_at
</sql>
</mapper>

View File

@@ -4,8 +4,6 @@
<resultMap id="BaseResultMap" type="com.yolo.keyborad.model.entity.KeyboardCharacter"> <resultMap id="BaseResultMap" type="com.yolo.keyborad.model.entity.KeyboardCharacter">
<!--@Table keyboard_character--> <!--@Table keyboard_character-->
<id column="id" jdbcType="BIGINT" property="id" /> <id column="id" jdbcType="BIGINT" property="id" />
<result column="character_name" jdbcType="VARCHAR" property="characterName" />
<result column="character_background" jdbcType="VARCHAR" property="characterBackground" />
<result column="avatar_url" jdbcType="VARCHAR" property="avatarUrl" /> <result column="avatar_url" jdbcType="VARCHAR" property="avatarUrl" />
<result column="download" jdbcType="VARCHAR" property="download" /> <result column="download" jdbcType="VARCHAR" property="download" />
<result column="tag" jdbcType="BIGINT" property="tag" /> <result column="tag" jdbcType="BIGINT" property="tag" />
@@ -17,7 +15,6 @@
<result column="emoji" jdbcType="VARCHAR" property="emoji" /> <result column="emoji" jdbcType="VARCHAR" property="emoji" />
</resultMap> </resultMap>
<sql id="Base_Column_List"> <sql id="Base_Column_List">
id, character_name, "character_background", avatar_url, download, tag, deleted, created_at, id, avatar_url, download, tag, deleted, created_at, updated_at, prompt, "rank", emoji
updated_at, prompt, "rank",emoji
</sql> </sql>
</mapper> </mapper>

View File

@@ -9,13 +9,14 @@
SELECT SELECT
kuc.id, kuc.id,
kuc.character_id, kuc.character_id,
kc.character_name, kci.character_name,
kuc.emoji kuc.emoji
FROM keyboard_user_character kuc FROM keyboard_user_character kuc
JOIN keyboard_user_sort kus JOIN keyboard_user_sort kus
ON kus.user_id = kuc.user_id ON kus.user_id = kuc.user_id
LEFT JOIN keyboard_character kc LEFT JOIN keyboard_character_i18n kci
ON kuc.character_id = kc.id ON kuc.character_id = kci.character_id
AND kci."locale" = #{locale}
WHERE kuc.user_id = #{loginId} WHERE kuc.user_id = #{loginId}
AND kuc.deleted = FALSE AND kuc.deleted = FALSE
ORDER BY array_position(kus.user_characteu_id_sort, kuc.id) NULLS LAST; ORDER BY array_position(kus.user_characteu_id_sort, kuc.id) NULLS LAST;