报错返回语言适配

This commit is contained in:
litianxiang
2026-06-03 16:25:53 +08:00
parent aa824f6e32
commit 6d9ac6f393
9 changed files with 729 additions and 45 deletions

View File

@@ -30,7 +30,7 @@ public class InternalOnlyAspect {
public Object validateInternalCall(ProceedingJoinPoint joinPoint) throws Throwable {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if (attributes == null) {
throw new BusinessException("禁止外部直接访问此接口");
throw new BusinessException("forbidden.external.access");
}
HttpServletRequest request = attributes.getRequest();
@@ -38,7 +38,7 @@ public class InternalOnlyAspect {
if (!CommonConstants.INTERNAL_CALL_VALUE.equals(internalCall)) {
log.warn("Unauthorized external access attempt to internal-only endpoint: {}",
((MethodSignature) joinPoint.getSignature()).getMethod().getName());
throw new BusinessException("禁止外部直接访问此接口");
throw new BusinessException("forbidden.external.access");
}
return joinPoint.proceed();

View File

@@ -1,9 +1,17 @@
package com.aida.seller.common.exception;
import com.aida.seller.common.context.UserContext;
import com.aida.seller.model.vo.AuthPrincipalVo;
import com.aida.seller.common.result.ResultEnum;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.PropertyResourceBundle;
import java.util.ResourceBundle;
/**
* @author: dwjian
* @description: 业务异常
@@ -12,31 +20,64 @@ import lombok.extern.slf4j.Slf4j;
@Slf4j
public class BusinessException extends RuntimeException {
private static final long serialVersionUID = 1L;
private Integer code;
private String msg;
public BusinessException(ResultEnum resultEnum) {
this.code = resultEnum.getCode();
this.msg = resultEnum.getMsg();
this.msg = getMessageFromResource(resultEnum.getMsg(), getUserLocale());
}
public BusinessException(String msg) {
this.code = ResultEnum.FAIL.getCode();
this.msg = msg;
this.msg = getMessageFromResource(msg, getUserLocale());
}
public BusinessException(String msg, Integer code) {
this.code = code;
this.msg = msg;
this.msg = getMessageFromResource(msg, getUserLocale());
}
public BusinessException(Throwable cause) {
this.code = ResultEnum.FAIL.getCode();
this.msg = cause.getMessage();
this.msg = getMessageFromResource(cause.getMessage(), getUserLocale());
}
public BusinessException(ResultEnum resultEnum, String customMsg) {
this.code = resultEnum.getCode();
this.msg = customMsg;
this.msg = getMessageFromResource(customMsg, getUserLocale());
}
private static String getUserLocale() {
try {
AuthPrincipalVo userInfo = UserContext.getUserHolder();
if (userInfo == null) return "en";
String lang = userInfo.getLanguage();
if (lang == null) return "en";
if ("CHINESE_SIMPLIFIED".equalsIgnoreCase(lang)) return "zh";
if ("ENGLISH".equalsIgnoreCase(lang)) return "en";
return "en";
} catch (Exception e) {
return "en";
}
}
public static String getMessageFromResource(String msg, String locale) {
if (msg == null) return null;
try (InputStream is = BusinessException.class.getClassLoader()
.getResourceAsStream("messages_" + locale + ".properties")) {
if (is != null) {
ResourceBundle bundle = new PropertyResourceBundle(
new InputStreamReader(is, StandardCharsets.UTF_8));
if (bundle.containsKey(msg)) {
return bundle.getString(msg);
}
}
} catch (Exception e) {
log.warn("Failed to load messages_{}.properties: {}", locale, e.getMessage());
}
return msg;
}
}

View File

@@ -71,7 +71,7 @@ public class DesignerServiceImpl extends ServiceImpl<DesignerMapper, DesignerEnt
);
if (existDesigner != null) {
throw new BusinessException("该用户已提交过申请或已入驻");
throw new BusinessException("designer.already.applied");
}
DesignerEntity entity = new DesignerEntity();
@@ -147,11 +147,11 @@ public class DesignerServiceImpl extends ServiceImpl<DesignerMapper, DesignerEnt
.last("LIMIT 1")
);
if (entity == null) {
throw new BusinessException("申请记录不存在");
throw new BusinessException("designer.application.not.found");
}
if (!DesignerApplyStatusEnum.PENDING.getCode().equals(entity.getApplyStatus())) {
throw new BusinessException("当前状态不支持审核操作");
throw new BusinessException("current.status.not.support.review");
}
entity.setApplyStatus(dto.getAuditStatus());
@@ -184,7 +184,7 @@ public class DesignerServiceImpl extends ServiceImpl<DesignerMapper, DesignerEnt
.last("LIMIT 1")
);
if (entity == null) {
throw new BusinessException("设计师记录不存在");
throw new BusinessException("designer.record.not.found");
}
if (dto.getShopName() != null) {
@@ -227,7 +227,7 @@ public class DesignerServiceImpl extends ServiceImpl<DesignerMapper, DesignerEnt
.last("LIMIT 1")
);
if (entity == null) {
throw new BusinessException("设计师记录不存在");
throw new BusinessException("designer.record.not.found");
}
DesignerDTO dto = new DesignerDTO();
@@ -252,7 +252,7 @@ public class DesignerServiceImpl extends ServiceImpl<DesignerMapper, DesignerEnt
.last("LIMIT 1")
);
if (designer == null) {
throw new BusinessException("设计师记录不存在");
throw new BusinessException("designer.record.not.found");
}
Long sellerId = designer.getId();
@@ -385,7 +385,7 @@ public class DesignerServiceImpl extends ServiceImpl<DesignerMapper, DesignerEnt
.last("LIMIT 1")
);
if (entity == null) {
throw new BusinessException("设计师不存在");
throw new BusinessException("designer.not.found");
}
DesignerShopVO vo = new DesignerShopVO();
vo.setShopName(entity.getShopName());

View File

@@ -45,7 +45,7 @@ public class FileUploadController {
Long userId = UserContext.getUserId();
if (file.isEmpty()) {
throw new BusinessException("文件不能为空");
throw new BusinessException("file.cannot.be.empty");
}
// 验证文件类型
String contentType = file.getContentType();
@@ -58,12 +58,12 @@ public class FileUploadController {
}
}
if (!validType) {
throw new BusinessException("不支持的文件类型: " + contentType);
throw new BusinessException("file.type.unsupported");
}
}
// 验证文件大小
if (file.getSize() > maxFileSize * 1024 * 1024) {
throw new BusinessException("文件大小超出限制: " + maxFileSize + " MB");
throw new BusinessException("file.size.exceed.limit");
}
try {
// 计算文件MD5可选用于文件完整性校验
@@ -78,7 +78,7 @@ public class FileUploadController {
return Response.success(minioUtil.processMinioResource(filePath, CommonConstants.MINIO_PATH_TIMEOUT));
} catch (IOException e) {
log.error("文件上传失败: {}", e.getMessage(), e);
throw new BusinessException("文件上传失败");
throw new BusinessException("file.upload.fail");
}
}

View File

@@ -65,7 +65,7 @@ public class ListingServiceImpl extends ServiceImpl<ListingMapper, ListingEntity
if (dto.getDesignFor() != null && DesignForEnum.of(dto.getDesignFor()) == null) {
throw new BusinessException("designFor 只能为 male/female");
throw new BusinessException("design.for.only.male.or.female");
}
if (entity.getViewCount() == null) {
@@ -85,7 +85,7 @@ public class ListingServiceImpl extends ServiceImpl<ListingMapper, ListingEntity
.eq(ListingEntity::getSellerId, sellerId)
.eq(ListingEntity::getDeleted, 0));
if (existing == null) {
throw new BusinessException("商品不存在");
throw new BusinessException("product.not.found");
}
entity.setCreateTime(existing.getCreateTime());
this.updateById(entity);
@@ -139,7 +139,7 @@ public class ListingServiceImpl extends ServiceImpl<ListingMapper, ListingEntity
.eq(ListingEntity::getId, id)
.eq(ListingEntity::getDeleted, 0));
if (entity == null) {
throw new BusinessException("商品不存在");
throw new BusinessException("product.not.found");
}
ListingSaveDTO dto = new ListingSaveDTO();
@@ -194,7 +194,7 @@ public class ListingServiceImpl extends ServiceImpl<ListingMapper, ListingEntity
.eq(ListingEntity::getSellerId, sellerId)
.eq(ListingEntity::getDeleted, 0));
if (existing == null) {
throw new BusinessException("商品不存在");
throw new BusinessException("product.not.found");
}
ListingEntity update = new ListingEntity();
update.setId(id);
@@ -252,7 +252,7 @@ public class ListingServiceImpl extends ServiceImpl<ListingMapper, ListingEntity
for (String category : requiredCategories) {
if (!presentCategories.contains(category)) {
throw new BusinessException("category [" + category + "] is required");
throw new BusinessException("category.required");
}
}
@@ -260,7 +260,7 @@ public class ListingServiceImpl extends ServiceImpl<ListingMapper, ListingEntity
String category = img.getCategory();
if (requiredCategories.contains(category)) {
if (!StringUtils.hasText(img.getImageUrl())) {
throw new BusinessException(category + " category imageUrl cannot be null or empty");
throw new BusinessException("category.imageUrl.cannot.be.empty");
}
}
}
@@ -337,26 +337,26 @@ public class ListingServiceImpl extends ServiceImpl<ListingMapper, ListingEntity
*/
private void validateListingFields(ListingSaveDTO dto) {
if (!StringUtils.hasText(dto.getTitle())) {
throw new BusinessException("商品标题不能为空");
throw new BusinessException("product.title.cannot.be.empty");
}
if (!StringUtils.hasText(dto.getDescription())) {
throw new BusinessException("商品描述不能为空");
throw new BusinessException("product.description.cannot.be.empty");
}
if (dto.getPrice() == null) {
throw new BusinessException("商品价格不能为空");
throw new BusinessException("product.price.cannot.be.empty");
}
if (!StringUtils.hasText(dto.getDesignFor())) {
throw new BusinessException("适用性别不能为空");
throw new BusinessException("product.gender.cannot.be.empty");
}
if (DesignForEnum.of(dto.getDesignFor()) == null) {
throw new BusinessException("适用性别只能为 male/female");
throw new BusinessException("product.gender.must.be.male.or.female");
}
if (CollectionUtils.isEmpty(dto.getProductCategory())) {
throw new BusinessException("商品分类不能为空");
throw new BusinessException("product.category.cannot.be.empty");
}
for (String category : dto.getProductCategory()) {
if (ProductCategoryEnum.of(category) == null) {
throw new BusinessException("商品分类只能为 outwear/trousers/blouse/dress/skirt/others/tops/bottoms");
throw new BusinessException("product.category.must.be.valid");
}
}
}
@@ -368,7 +368,7 @@ public class ListingServiceImpl extends ServiceImpl<ListingMapper, ListingEntity
queryWrapper.eq(ListingEntity::getSellerId, sellerId);
DesignForEnum designForEnum = DesignForEnum.of(designFor);
if (designForEnum == null) {
throw new BusinessException("designFor 只能为 female/male/all");
throw new BusinessException("design.for.only.female.male.or.all");
}
if (designForEnum != DesignForEnum.ALL) {
queryWrapper.eq(ListingEntity::getDesignFor, designForEnum.getCode());

View File

@@ -215,7 +215,7 @@ public class ListingMallServiceImpl extends ServiceImpl<ListingMallMapper, Listi
.eq(ListingEntity::getStatus, 1)
.eq(ListingEntity::getDeleted, 0));
if (entity == null) {
throw new BusinessException("商品不存在");
throw new BusinessException("product.not.found");
}
this.baseMapper.incrementViewCount(id);
@@ -336,7 +336,7 @@ public class ListingMallServiceImpl extends ServiceImpl<ListingMallMapper, Listi
.selectByListingIdAndBuyerIdWithOrderStatus(id, buyerId);
if (snapshots.isEmpty()) {
throw new BusinessException("该商品尚未被购买,无法查看");
throw new BusinessException("product.not.purchased.yet");
}
return snapshots.stream()

View File

@@ -216,13 +216,13 @@ public class OrderServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfoEnti
@Transactional(rollbackFor = Exception.class)
public CreateOrderResultVO createOrder(CreateOrderDTO dto) {
if (CollectionUtils.isEmpty(dto.getListingIds())) {
throw new BusinessException("商品ID列表不能为空");
throw new BusinessException("product.id.list.cannot.be.empty");
}
if (dto.getBuyerId() == null) {
throw new BusinessException("买家ID不能为空");
throw new BusinessException("buyer.id.cannot.be.empty");
}
if (!StringUtils.hasText(dto.getBuyerUsername())) {
throw new BusinessException("买家账号不能为空");
throw new BusinessException("buyer.account.cannot.be.empty");
}
List<Long> purchasedListingIds = getPurchasedListingIds(dto.getListingIds(), dto.getBuyerId());
@@ -230,13 +230,13 @@ public class OrderServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfoEnti
.filter(id -> !purchasedListingIds.contains(id))
.collect(Collectors.toList());
if (CollectionUtils.isEmpty(unpurchasedListingIds)) {
throw new BusinessException("所有商品均已购买,无需重复下单");
throw new BusinessException("all.products.already.purchased");
}
dto.setListingIds(unpurchasedListingIds);
List<ListingEntity> listings = listingMapper.selectBatchIds(dto.getListingIds());
if (CollectionUtils.isEmpty(listings)) {
throw new BusinessException("未找到对应的商品");
throw new BusinessException("product.not.found");
}
Map<Long, List<ListingEntity>> listingsBySeller = listings.stream()
@@ -334,13 +334,13 @@ public class OrderServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfoEnti
public void updateOrderStatus(UpdateOrderStatusDTO dto) {
log.info(dto.toString());
if (dto == null) {
throw new BusinessException("订单信息为空");
throw new BusinessException("order.info.cannot.be.empty");
}
if (dto.getStatus() == null) {
throw new BusinessException("订单状态不能为空");
throw new BusinessException("order.status.cannot.be.empty");
}
if (dto.getPaymentId() == null && (dto.getOrderIds() == null || dto.getOrderIds().isEmpty())) {
throw new BusinessException("订单ID列表不能为空");
throw new BusinessException("order.id.list.cannot.be.empty");
}
boolean updated;
@@ -355,7 +355,7 @@ public class OrderServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfoEnti
updated = this.update(updateWrapper);
if (!updated) {
throw new BusinessException("订单不存在或无权修改");
throw new BusinessException("order.not.found.or.no.permission");
} else {
log.info("[Order] PaymentId:{} / OrderId:{}, 更新订单状态", dto.getPaymentId(), dto.getOrderIds());
@@ -390,7 +390,7 @@ public class OrderServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfoEnti
@Override
public IPage<AssetsItemVO> getAssetsPage(AssetsDTO dto) {
if (dto.getBuyerId() == null) {
throw new BusinessException("买家ID不能为空");
throw new BusinessException("buyer.id.cannot.be.empty");
}
long page = dto.getPage();
long size = dto.getSize();
@@ -425,7 +425,7 @@ public class OrderServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfoEnti
@Override
public void updatePaymentIdByIds(List<Long> orderIds, Long paymentId) {
if (CollectionUtils.isEmpty(orderIds)) {
throw new BusinessException("订单ID列表不能为空");
throw new BusinessException("order.id.list.cannot.be.empty");
}
LambdaUpdateWrapper<OrderInfoEntity> updateWrapper = new LambdaUpdateWrapper<>();
updateWrapper.in(OrderInfoEntity::getId, orderIds)