refactor: 统一业务异常处理,标准化结果码和错误响应
1. 新增并完善ResultCode枚举,补充标准HTTP状态码对应的业务状态码 2. 重构BusinessException,新增基于ResultCode的构造函数和ThrowIf扩展方法 3. 替换所有硬编码的HTTP状态码为统一的ResultCode枚举 4. 优化全局异常中间件,根据业务状态码映射对应HTTP状态码并规范化JSON响应 5. 修复OssImageHelper和AutoDotCodeConsumer中的OSS文件处理逻辑 6. 新增用户答题快照实体类 7. 清理废弃的宠物模块迁移脚本
This commit is contained in:
@ -223,12 +223,12 @@ public class PetService(
|
||||
|
||||
if (input.PetId <= 0)
|
||||
{
|
||||
throw new BusinessException("宠物Id不能为空", 400);
|
||||
throw new BusinessException("宠物Id不能为空", ResultCode.BAD_REQUEST);
|
||||
}
|
||||
|
||||
if (input.GrowthPoints <= 0)
|
||||
{
|
||||
throw new BusinessException("成长值必须大于0", 400);
|
||||
throw new BusinessException("成长值必须大于0", ResultCode.BAD_REQUEST);
|
||||
}
|
||||
|
||||
// 查询宠物
|
||||
@ -236,21 +236,21 @@ public class PetService(
|
||||
if (pet == null || pet.IsDeleted)
|
||||
{
|
||||
logger.LogWarning("喂养失败,宠物不存在,PetId: {PetId}", input.PetId);
|
||||
throw new BusinessException("宠物不存在", 404);
|
||||
throw new BusinessException("宠物不存在", ResultCode.NOT_FOUND);
|
||||
}
|
||||
|
||||
// 校验宠物归属
|
||||
if (pet.UserId != userId)
|
||||
{
|
||||
logger.LogWarning("喂养失败,无权操作该宠物,UserId: {UserId}, PetUserId: {PetUserId}", userId, pet.UserId);
|
||||
throw new BusinessException("无权操作该宠物", 403);
|
||||
throw new BusinessException("无权操作该宠物", ResultCode.FORBIDDEN);
|
||||
}
|
||||
|
||||
// 校验宠物状态
|
||||
if (pet.Status != (int)UserPetStatusEnum.Active)
|
||||
{
|
||||
logger.LogWarning("喂养失败,宠物未激活,PetId: {PetId}, Status: {Status}", input.PetId, pet.Status);
|
||||
throw new BusinessException("宠物未激活,无法喂养", 400);
|
||||
throw new BusinessException("宠物未激活,无法喂养", ResultCode.BAD_REQUEST);
|
||||
}
|
||||
FeedPetOutput result = new FeedPetOutput();
|
||||
// 事务保证一致性
|
||||
@ -273,13 +273,13 @@ public class PetService(
|
||||
// 查询宠物
|
||||
var pet = await petRepository.GetByIdAsync(input.PetId);
|
||||
if (pet == null || pet.IsDeleted)
|
||||
throw new BusinessException("宠物不存在", 404);
|
||||
throw new BusinessException("宠物不存在", ResultCode.NOT_FOUND);
|
||||
|
||||
if (pet.UserId != userId)
|
||||
throw new BusinessException("无权操作该宠物", 403);
|
||||
throw new BusinessException("无权操作该宠物", ResultCode.FORBIDDEN);
|
||||
|
||||
if (pet.Status != (int)UserPetStatusEnum.Active)
|
||||
throw new BusinessException("宠物未激活,无法喂养", 400);
|
||||
throw new BusinessException("宠物未激活,无法喂养", ResultCode.BAD_REQUEST);
|
||||
|
||||
var growthBefore = pet.GrowthPoints;
|
||||
var growthAfter = growthBefore + input.GrowthPoints;
|
||||
@ -297,7 +297,7 @@ public class PetService(
|
||||
|
||||
if (updateResult <= 0)
|
||||
{
|
||||
throw new BusinessException("更新宠物成长值失败", 500);
|
||||
throw new BusinessException("更新宠物成长值失败", ResultCode.GLOBAL_ERROR);
|
||||
}
|
||||
|
||||
// 进化检查:查找下一阶段进化形态(PreviousEvolutionId 类型为 long?)
|
||||
@ -348,7 +348,7 @@ public class PetService(
|
||||
var insertResult = await feedingRecordRepository.InsertAsync(record);
|
||||
if (!insertResult)
|
||||
{
|
||||
throw new BusinessException("写入喂养记录失败", 500);
|
||||
throw new BusinessException("写入喂养记录失败", ResultCode.GLOBAL_ERROR);
|
||||
}
|
||||
|
||||
logger.LogInformation("喂养宠物成功,PetId: {PetId}, 成长值: {Before} -> {After}, 进化: {HasEvolved}",
|
||||
@ -402,10 +402,10 @@ public class PetService(
|
||||
public async Task<PetTemplateOutput> CreateTemplateAsync(PetTemplateInput input)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(input.Name))
|
||||
throw new BusinessException("模板名称不能为空", 400);
|
||||
throw new BusinessException("模板名称不能为空", ResultCode.BAD_REQUEST);
|
||||
|
||||
if (input.Evolutions == null || input.Evolutions.Count == 0)
|
||||
throw new BusinessException("至少需要一个进化阶段", 400);
|
||||
throw new BusinessException("至少需要一个进化阶段", ResultCode.BAD_REQUEST);
|
||||
|
||||
PetTemplate template = null!;
|
||||
|
||||
@ -430,7 +430,7 @@ public class PetService(
|
||||
|
||||
var inserted = await petTemplateRepository.InsertAsync(template);
|
||||
if (!inserted)
|
||||
throw new BusinessException("创建宠物模板失败", 500);
|
||||
throw new BusinessException("创建宠物模板失败", ResultCode.GLOBAL_ERROR);
|
||||
|
||||
// 2. 按 StageLevel 排序,依次创建进化阶段
|
||||
var sortedEvolutions = input.Evolutions.OrderBy(e => e.StageLevel).ToList();
|
||||
@ -458,7 +458,7 @@ public class PetService(
|
||||
|
||||
var evoInserted = await petEvolutionRepository.InsertAsync(evolution);
|
||||
if (!evoInserted)
|
||||
throw new BusinessException($"创建进化阶段 [{evoInput.StageName}] 失败", 500);
|
||||
throw new BusinessException($"创建进化阶段 [{evoInput.StageName}] 失败", ResultCode.GLOBAL_ERROR);
|
||||
|
||||
// 记录初始阶段(第一个)
|
||||
if (previousEvolution == null)
|
||||
@ -560,10 +560,10 @@ public class PetService(
|
||||
{
|
||||
var template = await petTemplateRepository.GetByIdAsync(id);
|
||||
if (template == null || template.IsDeleted)
|
||||
throw new BusinessException("宠物模板不存在", 404);
|
||||
throw new BusinessException("宠物模板不存在", ResultCode.NOT_FOUND);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(input.Name))
|
||||
throw new BusinessException("模板名称不能为空", 400);
|
||||
throw new BusinessException("模板名称不能为空", ResultCode.BAD_REQUEST);
|
||||
|
||||
template.Name = input.Name.Trim();
|
||||
template.Description = input.Description;
|
||||
@ -575,7 +575,7 @@ public class PetService(
|
||||
|
||||
var result = await petTemplateRepository.UpdateAsync(template);
|
||||
if (!result)
|
||||
throw new BusinessException("更新宠物模板失败", 500);
|
||||
throw new BusinessException("更新宠物模板失败", ResultCode.GLOBAL_ERROR);
|
||||
|
||||
logger.LogInformation("更新宠物模板成功,Id: {Id}", id);
|
||||
return BuildTemplateOutput(template);
|
||||
@ -588,18 +588,18 @@ public class PetService(
|
||||
{
|
||||
var template = await petTemplateRepository.GetByIdAsync(id);
|
||||
if (template == null || template.IsDeleted)
|
||||
throw new BusinessException("宠物模板不存在", 404);
|
||||
throw new BusinessException("宠物模板不存在", ResultCode.NOT_FOUND);
|
||||
|
||||
|
||||
if (template.Type == PetTemplateTypeEnum.Default)
|
||||
throw new BusinessException("默认模板不允许删除", 400);
|
||||
throw new BusinessException("默认模板不允许删除", ResultCode.BAD_REQUEST);
|
||||
|
||||
|
||||
// 校验是否有用户宠物实例关联
|
||||
var hasUserPet = petRepository.Context.Queryable<UserPet>()
|
||||
.Any(p => p.TemplateId == id && !p.IsDeleted);
|
||||
if (hasUserPet)
|
||||
throw new BusinessException("该模板下存在用户宠物实例,无法删除", 400);
|
||||
throw new BusinessException("该模板下存在用户宠物实例,无法删除", ResultCode.BAD_REQUEST);
|
||||
|
||||
template.IsDeleted = true;
|
||||
template.UpdatedBy = "System";
|
||||
@ -616,7 +616,7 @@ public class PetService(
|
||||
{
|
||||
var template = await petTemplateRepository.GetByIdAsync(id);
|
||||
if (template == null || template.IsDeleted)
|
||||
throw new BusinessException("宠物模板不存在", 404);
|
||||
throw new BusinessException("宠物模板不存在", ResultCode.NOT_FOUND);
|
||||
|
||||
return BuildTemplateOutput(template);
|
||||
}
|
||||
@ -663,7 +663,7 @@ public class PetService(
|
||||
{
|
||||
var template = await petTemplateRepository.GetByIdAsync(id);
|
||||
if (template == null || template.IsDeleted)
|
||||
throw new BusinessException("宠物模板不存在", 404);
|
||||
throw new BusinessException("宠物模板不存在", ResultCode.NOT_FOUND);
|
||||
|
||||
template.Status = template.Status == (int)DefaultStatusEnum.Active
|
||||
? (int)DefaultStatusEnum.Inactive
|
||||
@ -703,16 +703,16 @@ public class PetService(
|
||||
public async Task<PetEvolutionOutput> CreateEvolutionAsync(PetEvolutionInput input)
|
||||
{
|
||||
if (input.TemplateId <= 0)
|
||||
throw new BusinessException("模板Id不能为空", 400);
|
||||
throw new BusinessException("模板Id不能为空", ResultCode.BAD_REQUEST);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(input.StageName))
|
||||
throw new BusinessException("阶段名称不能为空", 400);
|
||||
throw new BusinessException("阶段名称不能为空", ResultCode.BAD_REQUEST);
|
||||
|
||||
// 校验模板是否存在
|
||||
var templateExists = petTemplateRepository.Context.Queryable<PetTemplate>()
|
||||
.Any(t => t.Id == input.TemplateId && !t.IsDeleted);
|
||||
if (!templateExists)
|
||||
throw new BusinessException("宠物模板不存在", 404);
|
||||
throw new BusinessException("宠物模板不存在", ResultCode.NOT_FOUND);
|
||||
|
||||
var evolution = new PetEvolution
|
||||
{
|
||||
@ -732,7 +732,7 @@ public class PetService(
|
||||
|
||||
var result = await petEvolutionRepository.InsertAsync(evolution);
|
||||
if (!result)
|
||||
throw new BusinessException("创建进化阶段失败", 500);
|
||||
throw new BusinessException("创建进化阶段失败", ResultCode.GLOBAL_ERROR);
|
||||
|
||||
logger.LogInformation("创建进化阶段成功,Id: {Id}, StageName: {StageName}", evolution.Id, evolution.StageName);
|
||||
return BuildEvolutionOutput(evolution);
|
||||
@ -745,10 +745,10 @@ public class PetService(
|
||||
{
|
||||
var evolution = await petEvolutionRepository.GetByIdAsync(id);
|
||||
if (evolution == null || evolution.IsDeleted)
|
||||
throw new BusinessException("进化阶段不存在", 404);
|
||||
throw new BusinessException("进化阶段不存在", ResultCode.NOT_FOUND);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(input.StageName))
|
||||
throw new BusinessException("阶段名称不能为空", 400);
|
||||
throw new BusinessException("阶段名称不能为空", ResultCode.BAD_REQUEST);
|
||||
|
||||
evolution.TemplateId = input.TemplateId;
|
||||
evolution.StageName = input.StageName.Trim();
|
||||
@ -761,7 +761,7 @@ public class PetService(
|
||||
|
||||
var result = await petEvolutionRepository.UpdateAsync(evolution);
|
||||
if (!result)
|
||||
throw new BusinessException("更新进化阶段失败", 500);
|
||||
throw new BusinessException("更新进化阶段失败", ResultCode.GLOBAL_ERROR);
|
||||
|
||||
logger.LogInformation("更新进化阶段成功,Id: {Id}", id);
|
||||
return BuildEvolutionOutput(evolution);
|
||||
@ -774,13 +774,13 @@ public class PetService(
|
||||
{
|
||||
var evolution = await petEvolutionRepository.GetByIdAsync(id);
|
||||
if (evolution == null || evolution.IsDeleted)
|
||||
throw new BusinessException("进化阶段不存在", 404);
|
||||
throw new BusinessException("进化阶段不存在", ResultCode.NOT_FOUND);
|
||||
|
||||
// 校验是否有用户宠物处于该形态
|
||||
var hasUserPet = petRepository.Context.Queryable<UserPet>()
|
||||
.Any(p => p.CurrentEvolutionId == id && !p.IsDeleted);
|
||||
if (hasUserPet)
|
||||
throw new BusinessException("有用户宠物正处于该形态,无法删除", 400);
|
||||
throw new BusinessException("有用户宠物正处于该形态,无法删除", ResultCode.BAD_REQUEST);
|
||||
|
||||
evolution.IsDeleted = true;
|
||||
evolution.UpdatedBy = "System";
|
||||
@ -797,7 +797,7 @@ public class PetService(
|
||||
{
|
||||
var evolution = await petEvolutionRepository.GetByIdAsync(id);
|
||||
if (evolution == null || evolution.IsDeleted)
|
||||
throw new BusinessException("进化阶段不存在", 404);
|
||||
throw new BusinessException("进化阶段不存在", ResultCode.NOT_FOUND);
|
||||
|
||||
return BuildEvolutionOutput(evolution);
|
||||
}
|
||||
@ -861,16 +861,16 @@ public class PetService(
|
||||
public async Task<PetSkinOutput> CreateSkinAsync(PetSkinInput input)
|
||||
{
|
||||
if (input.TemplateId <= 0)
|
||||
throw new BusinessException("模板Id不能为空", 400);
|
||||
throw new BusinessException("模板Id不能为空", ResultCode.BAD_REQUEST);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(input.Name))
|
||||
throw new BusinessException("皮肤名称不能为空", 400);
|
||||
throw new BusinessException("皮肤名称不能为空", ResultCode.BAD_REQUEST);
|
||||
|
||||
// 校验模板是否存在
|
||||
var templateExists = petTemplateRepository.Context.Queryable<PetTemplate>()
|
||||
.Any(t => t.Id == input.TemplateId && !t.IsDeleted);
|
||||
if (!templateExists)
|
||||
throw new BusinessException("宠物模板不存在", 404);
|
||||
throw new BusinessException("宠物模板不存在", ResultCode.NOT_FOUND);
|
||||
|
||||
var skin = new PetSkin
|
||||
{
|
||||
@ -890,7 +890,7 @@ public class PetService(
|
||||
|
||||
var result = await petSkinRepository.InsertAsync(skin);
|
||||
if (!result)
|
||||
throw new BusinessException("创建皮肤失败", 500);
|
||||
throw new BusinessException("创建皮肤失败", ResultCode.GLOBAL_ERROR);
|
||||
|
||||
// 搬运封面图到正式目录
|
||||
if (OssImageHelper.IsTempImage(skin.CoverImageUrl))
|
||||
@ -911,10 +911,10 @@ public class PetService(
|
||||
{
|
||||
var skin = await petSkinRepository.GetByIdAsync(id);
|
||||
if (skin == null || skin.IsDeleted)
|
||||
throw new BusinessException("皮肤不存在", 404);
|
||||
throw new BusinessException("皮肤不存在", ResultCode.NOT_FOUND);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(input.Name))
|
||||
throw new BusinessException("皮肤名称不能为空", 400);
|
||||
throw new BusinessException("皮肤名称不能为空", ResultCode.BAD_REQUEST);
|
||||
|
||||
skin.TemplateId = input.TemplateId;
|
||||
skin.Name = input.Name.Trim();
|
||||
@ -937,7 +937,7 @@ public class PetService(
|
||||
|
||||
var result = await petSkinRepository.UpdateAsync(skin);
|
||||
if (!result)
|
||||
throw new BusinessException("更新皮肤失败", 500);
|
||||
throw new BusinessException("更新皮肤失败", ResultCode.GLOBAL_ERROR);
|
||||
|
||||
logger.LogInformation("更新皮肤成功,Id: {Id}", id);
|
||||
|
||||
@ -957,13 +957,13 @@ public class PetService(
|
||||
{
|
||||
var skin = await petSkinRepository.GetByIdAsync(id);
|
||||
if (skin == null || skin.IsDeleted)
|
||||
throw new BusinessException("皮肤不存在", 404);
|
||||
throw new BusinessException("皮肤不存在", ResultCode.NOT_FOUND);
|
||||
|
||||
// 校验是否有用户宠物正在使用该皮肤
|
||||
var inUse = petRepository.Context.Queryable<UserPet>()
|
||||
.Any(p => p.CurrentSkinId == id && !p.IsDeleted);
|
||||
if (inUse)
|
||||
throw new BusinessException("有用户宠物正在使用该皮肤,无法删除", 400);
|
||||
throw new BusinessException("有用户宠物正在使用该皮肤,无法删除", ResultCode.BAD_REQUEST);
|
||||
|
||||
skin.IsDeleted = true;
|
||||
skin.UpdatedBy = "System";
|
||||
@ -980,7 +980,7 @@ public class PetService(
|
||||
{
|
||||
var skin = await petSkinRepository.GetByIdAsync(id);
|
||||
if (skin == null || skin.IsDeleted)
|
||||
throw new BusinessException("皮肤不存在", 404);
|
||||
throw new BusinessException("皮肤不存在", ResultCode.NOT_FOUND);
|
||||
|
||||
var images = await petSkinImageRepository.Queryable()
|
||||
.Where(i => i.SkinId == id && !i.IsDeleted)
|
||||
@ -1072,19 +1072,19 @@ public class PetService(
|
||||
public async Task<PetSkinImageOutput> CreateSkinImageAsync(PetSkinImageInput input)
|
||||
{
|
||||
if (input.SkinId <= 0)
|
||||
throw new BusinessException("皮肤Id不能为空", 400);
|
||||
throw new BusinessException("皮肤Id不能为空", ResultCode.BAD_REQUEST);
|
||||
|
||||
if (input.EvolutionStageId <= 0)
|
||||
throw new BusinessException("进化阶段Id不能为空", 400);
|
||||
throw new BusinessException("进化阶段Id不能为空", ResultCode.BAD_REQUEST);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(input.ImageUrl))
|
||||
throw new BusinessException("图片地址不能为空", 400);
|
||||
throw new BusinessException("图片地址不能为空", ResultCode.BAD_REQUEST);
|
||||
|
||||
// 校验皮肤是否存在
|
||||
var skinExists = petSkinRepository.Context.Queryable<PetSkin>()
|
||||
.Any(s => s.Id == input.SkinId && !s.IsDeleted);
|
||||
if (!skinExists)
|
||||
throw new BusinessException("皮肤不存在", 404);
|
||||
throw new BusinessException("皮肤不存在", ResultCode.NOT_FOUND);
|
||||
|
||||
var image = new PetSkinImage
|
||||
{
|
||||
@ -1102,7 +1102,7 @@ public class PetService(
|
||||
|
||||
var result = await petSkinImageRepository.InsertAsync(image);
|
||||
if (!result)
|
||||
throw new BusinessException("创建皮肤图片失败", 500);
|
||||
throw new BusinessException("创建皮肤图片失败", ResultCode.GLOBAL_ERROR);
|
||||
|
||||
// 搬运图片到正式目录
|
||||
if (OssImageHelper.IsTempImage(image.ImageUrl))
|
||||
@ -1123,10 +1123,10 @@ public class PetService(
|
||||
{
|
||||
var image = await petSkinImageRepository.GetByIdAsync(id);
|
||||
if (image == null || image.IsDeleted)
|
||||
throw new BusinessException("皮肤图片不存在", 404);
|
||||
throw new BusinessException("皮肤图片不存在", ResultCode.NOT_FOUND);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(input.ImageUrl))
|
||||
throw new BusinessException("图片地址不能为空", 400);
|
||||
throw new BusinessException("图片地址不能为空", ResultCode.BAD_REQUEST);
|
||||
|
||||
image.SkinId = input.SkinId;
|
||||
image.EvolutionStageId = input.EvolutionStageId;
|
||||
@ -1147,7 +1147,7 @@ public class PetService(
|
||||
|
||||
var result = await petSkinImageRepository.UpdateAsync(image);
|
||||
if (!result)
|
||||
throw new BusinessException("更新皮肤图片失败", 500);
|
||||
throw new BusinessException("更新皮肤图片失败", ResultCode.GLOBAL_ERROR);
|
||||
|
||||
logger.LogInformation("更新皮肤图片成功,Id: {Id}", id);
|
||||
return BuildSkinImageOutput(image);
|
||||
@ -1160,7 +1160,7 @@ public class PetService(
|
||||
{
|
||||
var image = await petSkinImageRepository.GetByIdAsync(id);
|
||||
if (image == null || image.IsDeleted)
|
||||
throw new BusinessException("皮肤图片不存在", 404);
|
||||
throw new BusinessException("皮肤图片不存在", ResultCode.NOT_FOUND);
|
||||
|
||||
image.IsDeleted = true;
|
||||
image.UpdatedBy = "System";
|
||||
@ -1208,7 +1208,7 @@ public class PetService(
|
||||
public async Task<List<PetEvolutionOutput>> GetEvolutionsByTemplateIdAsync(long templateId)
|
||||
{
|
||||
if (templateId <= 0)
|
||||
throw new BusinessException("模板Id不能为空", 400);
|
||||
throw new BusinessException("模板Id不能为空", ResultCode.BAD_REQUEST);
|
||||
|
||||
var list = await petEvolutionRepository.Queryable()
|
||||
.Where(e => e.TemplateId == templateId && !e.IsDeleted)
|
||||
@ -1224,7 +1224,7 @@ public class PetService(
|
||||
public async Task<List<PetSkinOutput>> GetSkinsByTemplateIdAsync(long templateId)
|
||||
{
|
||||
if (templateId <= 0)
|
||||
throw new BusinessException("模板Id不能为空", 400);
|
||||
throw new BusinessException("模板Id不能为空", ResultCode.BAD_REQUEST);
|
||||
|
||||
var list = await petSkinRepository.Queryable()
|
||||
.Where(s => s.TemplateId == templateId && !s.IsDeleted)
|
||||
@ -1276,12 +1276,12 @@ public class PetService(
|
||||
public async Task<List<SkinEvolutionStageOutput>> GetSkinImagesGroupedBySkinIdAsync(long skinId)
|
||||
{
|
||||
if (skinId <= 0)
|
||||
throw new BusinessException("皮肤Id不能为空", 400);
|
||||
throw new BusinessException("皮肤Id不能为空", ResultCode.BAD_REQUEST);
|
||||
|
||||
// 1. 获取皮肤信息
|
||||
var skin = await petSkinRepository.GetByIdAsync(skinId);
|
||||
if (skin == null || skin.IsDeleted)
|
||||
throw new BusinessException("皮肤不存在", 404);
|
||||
throw new BusinessException("皮肤不存在", ResultCode.NOT_FOUND);
|
||||
|
||||
// 2. 获取该模板的所有进化阶段(按阶段等级排序)
|
||||
var evolutions = await petEvolutionRepository.Queryable()
|
||||
|
||||
Reference in New Issue
Block a user