Browse Source
- 新增 BigDecimalDeserializer 自定义反序列化器,处理 null值和空字符串 - 添加 DatabaseFixController 控制器,用于检查和修复数据库中的 null值问题 - 修改 ShopUserCouponController 中的查询逻辑,确保 BigDecimal 字段不为 null - 更新 ShopCoupon 和 ShopUserCoupon 实体类,为 BigDecimal 字段添加 JsonSerialize 和 JsonInclude 注解 - 新增 SQL 脚本 fix_bigdecimal_null_values.sql,用于修复数据库中的 null 值问题- 修改 application.yml,配置 Jackson序列化和反序列化相关参数main
8 changed files with 419 additions and 13 deletions
@ -0,0 +1,41 @@ |
|||
package com.gxwebsoft.common.core.config; |
|||
|
|||
import com.fasterxml.jackson.core.JsonParser; |
|||
import com.fasterxml.jackson.databind.DeserializationContext; |
|||
import com.fasterxml.jackson.databind.JsonDeserializer; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
|
|||
import java.io.IOException; |
|||
import java.math.BigDecimal; |
|||
|
|||
/** |
|||
* BigDecimal 自定义反序列化器 |
|||
* 处理null值和空字符串,避免反序列化异常 |
|||
* |
|||
* @author WebSoft |
|||
* @since 2025-01-15 |
|||
*/ |
|||
@Slf4j |
|||
public class BigDecimalDeserializer extends JsonDeserializer<BigDecimal> { |
|||
|
|||
@Override |
|||
public BigDecimal deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { |
|||
String value = p.getValueAsString(); |
|||
|
|||
if (value == null || value.trim().isEmpty() || "null".equals(value)) { |
|||
return null; |
|||
} |
|||
|
|||
try { |
|||
return new BigDecimal(value); |
|||
} catch (NumberFormatException e) { |
|||
log.warn("无法解析BigDecimal值: {}, 返回null", value); |
|||
return null; |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public BigDecimal getNullValue(DeserializationContext ctxt) { |
|||
return null; |
|||
} |
|||
} |
@ -0,0 +1,204 @@ |
|||
package com.gxwebsoft.common.core.controller; |
|||
|
|||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; |
|||
import com.gxwebsoft.common.core.web.ApiResult; |
|||
import com.gxwebsoft.common.core.web.BaseController; |
|||
import com.gxwebsoft.shop.entity.ShopCoupon; |
|||
import com.gxwebsoft.shop.entity.ShopUserCoupon; |
|||
import com.gxwebsoft.shop.service.ShopCouponService; |
|||
import com.gxwebsoft.shop.service.ShopUserCouponService; |
|||
import io.swagger.v3.oas.annotations.Operation; |
|||
import io.swagger.v3.oas.annotations.tags.Tag; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; |
|||
import org.springframework.web.bind.annotation.*; |
|||
|
|||
import java.math.BigDecimal; |
|||
import java.util.HashMap; |
|||
import java.util.List; |
|||
import java.util.Map; |
|||
|
|||
/** |
|||
* 数据库修复工具控制器 |
|||
* 仅在开发环境启用,用于修复数据库问题 |
|||
* |
|||
* @author WebSoft |
|||
* @since 2025-01-15 |
|||
*/ |
|||
@Slf4j |
|||
@Tag(name = "数据库修复工具") |
|||
@RestController |
|||
@RequestMapping("/api/database-fix") |
|||
// @ConditionalOnProperty(name = "spring.profiles.active", havingValue = "dev")
|
|||
public class DatabaseFixController extends BaseController { |
|||
|
|||
@Autowired |
|||
private ShopUserCouponService shopUserCouponService; |
|||
|
|||
@Autowired |
|||
private ShopCouponService shopCouponService; |
|||
|
|||
@Operation(summary = "检查BigDecimal null值问题") |
|||
@GetMapping("/check-bigdecimal-nulls") |
|||
public ApiResult<Map<String, Object>> checkBigDecimalNulls() { |
|||
try { |
|||
Map<String, Object> result = new HashMap<>(); |
|||
|
|||
// 检查用户优惠券表
|
|||
List<ShopUserCoupon> userCoupons = shopUserCouponService.list(); |
|||
long userCouponNullReducePrice = userCoupons.stream() |
|||
.mapToLong(c -> c.getReducePrice() == null ? 1 : 0) |
|||
.sum(); |
|||
long userCouponNullMinPrice = userCoupons.stream() |
|||
.mapToLong(c -> c.getMinPrice() == null ? 1 : 0) |
|||
.sum(); |
|||
|
|||
// 检查优惠券模板表
|
|||
List<ShopCoupon> coupons = shopCouponService.list(); |
|||
long couponNullReducePrice = coupons.stream() |
|||
.mapToLong(c -> c.getReducePrice() == null ? 1 : 0) |
|||
.sum(); |
|||
long couponNullMinPrice = coupons.stream() |
|||
.mapToLong(c -> c.getMinPrice() == null ? 1 : 0) |
|||
.sum(); |
|||
|
|||
Map<String, Object> userCouponStats = new HashMap<>(); |
|||
userCouponStats.put("totalRecords", userCoupons.size()); |
|||
userCouponStats.put("nullReducePrice", userCouponNullReducePrice); |
|||
userCouponStats.put("nullMinPrice", userCouponNullMinPrice); |
|||
|
|||
Map<String, Object> couponStats = new HashMap<>(); |
|||
couponStats.put("totalRecords", coupons.size()); |
|||
couponStats.put("nullReducePrice", couponNullReducePrice); |
|||
couponStats.put("nullMinPrice", couponNullMinPrice); |
|||
|
|||
result.put("shopUserCoupon", userCouponStats); |
|||
result.put("shopCoupon", couponStats); |
|||
result.put("needsFix", userCouponNullReducePrice > 0 || userCouponNullMinPrice > 0 || |
|||
couponNullReducePrice > 0 || couponNullMinPrice > 0); |
|||
|
|||
return success("检查完成", result); |
|||
|
|||
} catch (Exception e) { |
|||
log.error("检查BigDecimal null值失败", e); |
|||
return fail("检查失败: " + e.getMessage(),null); |
|||
} |
|||
} |
|||
|
|||
@Operation(summary = "修复BigDecimal null值问题") |
|||
@PostMapping("/fix-bigdecimal-nulls") |
|||
public ApiResult<Map<String, Object>> fixBigDecimalNulls() { |
|||
try { |
|||
Map<String, Object> result = new HashMap<>(); |
|||
int userCouponFixed = 0; |
|||
int couponFixed = 0; |
|||
|
|||
// 修复用户优惠券表
|
|||
List<ShopUserCoupon> userCoupons = shopUserCouponService.list(); |
|||
for (ShopUserCoupon userCoupon : userCoupons) { |
|||
boolean needUpdate = false; |
|||
|
|||
if (userCoupon.getReducePrice() == null) { |
|||
userCoupon.setReducePrice(BigDecimal.ZERO); |
|||
needUpdate = true; |
|||
} |
|||
|
|||
if (userCoupon.getMinPrice() == null) { |
|||
userCoupon.setMinPrice(BigDecimal.ZERO); |
|||
needUpdate = true; |
|||
} |
|||
|
|||
if (needUpdate) { |
|||
shopUserCouponService.updateById(userCoupon); |
|||
userCouponFixed++; |
|||
} |
|||
} |
|||
|
|||
// 修复优惠券模板表
|
|||
List<ShopCoupon> coupons = shopCouponService.list(); |
|||
for (ShopCoupon coupon : coupons) { |
|||
boolean needUpdate = false; |
|||
|
|||
if (coupon.getReducePrice() == null) { |
|||
coupon.setReducePrice(BigDecimal.ZERO); |
|||
needUpdate = true; |
|||
} |
|||
|
|||
if (coupon.getMinPrice() == null) { |
|||
coupon.setMinPrice(BigDecimal.ZERO); |
|||
needUpdate = true; |
|||
} |
|||
|
|||
if (needUpdate) { |
|||
shopCouponService.updateById(coupon); |
|||
couponFixed++; |
|||
} |
|||
} |
|||
|
|||
result.put("userCouponFixed", userCouponFixed); |
|||
result.put("couponFixed", couponFixed); |
|||
result.put("totalFixed", userCouponFixed + couponFixed); |
|||
|
|||
log.info("BigDecimal null值修复完成: 用户优惠券{}条, 优惠券模板{}条", userCouponFixed, couponFixed); |
|||
|
|||
return success("修复完成", result); |
|||
|
|||
} catch (Exception e) { |
|||
log.error("修复BigDecimal null值失败", e); |
|||
return fail("修复失败: " + e.getMessage(), null); |
|||
} |
|||
} |
|||
|
|||
@Operation(summary = "测试优惠券接口") |
|||
@GetMapping("/test-coupon-api") |
|||
public ApiResult<Map<String, Object>> testCouponApi() { |
|||
try { |
|||
Map<String, Object> result = new HashMap<>(); |
|||
|
|||
// 测试查询用户优惠券
|
|||
List<ShopUserCoupon> userCoupons = shopUserCouponService.list( |
|||
new QueryWrapper<ShopUserCoupon>().last("LIMIT 5") |
|||
); |
|||
|
|||
// 测试查询优惠券模板
|
|||
List<ShopCoupon> coupons = shopCouponService.list( |
|||
new QueryWrapper<ShopCoupon>().last("LIMIT 5") |
|||
); |
|||
|
|||
result.put("userCouponsCount", userCoupons.size()); |
|||
result.put("couponsCount", coupons.size()); |
|||
result.put("userCouponsSample", userCoupons); |
|||
result.put("couponsSample", coupons); |
|||
result.put("testStatus", "SUCCESS"); |
|||
|
|||
return success("测试成功", result); |
|||
|
|||
} catch (Exception e) { |
|||
log.error("测试优惠券接口失败", e); |
|||
Map<String, Object> errorResult = new HashMap<>(); |
|||
errorResult.put("testStatus", "FAILED"); |
|||
errorResult.put("errorMessage", e.getMessage()); |
|||
errorResult.put("errorType", e.getClass().getSimpleName()); |
|||
|
|||
return fail("测试失败: " + e.getMessage(), errorResult); |
|||
} |
|||
} |
|||
|
|||
@Operation(summary = "获取修复指南") |
|||
@GetMapping("/guide") |
|||
public ApiResult<Map<String, String>> getFixGuide() { |
|||
Map<String, String> guide = new HashMap<>(); |
|||
|
|||
guide.put("step1", "GET /api/database-fix/check-bigdecimal-nulls - 检查null值问题"); |
|||
guide.put("step2", "POST /api/database-fix/fix-bigdecimal-nulls - 修复null值问题"); |
|||
guide.put("step3", "GET /api/database-fix/test-coupon-api - 测试修复效果"); |
|||
guide.put("step4", "重启应用,验证优惠券功能正常"); |
|||
|
|||
guide.put("note1", "此工具仅在开发环境可用"); |
|||
guide.put("note2", "修复前建议备份数据库"); |
|||
guide.put("note3", "修复完成后可以删除此控制器"); |
|||
|
|||
return success("获取成功", guide); |
|||
} |
|||
} |
@ -0,0 +1,107 @@ |
|||
-- 修复BigDecimal字段的null值问题 |
|||
-- 将null值替换为0.00,避免JSON序列化异常 |
|||
|
|||
-- ======================================== |
|||
-- 1. 修复用户优惠券表的null值 |
|||
-- ======================================== |
|||
|
|||
-- 检查当前null值情况 |
|||
SELECT |
|||
'shop_user_coupon null值检查' as table_name, |
|||
COUNT(*) as total_records, |
|||
COUNT(CASE WHEN reduce_price IS NULL THEN 1 END) as null_reduce_price, |
|||
COUNT(CASE WHEN min_price IS NULL THEN 1 END) as null_min_price |
|||
FROM shop_user_coupon; |
|||
|
|||
-- 修复reduce_price字段的null值 |
|||
UPDATE shop_user_coupon |
|||
SET reduce_price = 0.00 |
|||
WHERE reduce_price IS NULL; |
|||
|
|||
-- 修复min_price字段的null值 |
|||
UPDATE shop_user_coupon |
|||
SET min_price = 0.00 |
|||
WHERE min_price IS NULL; |
|||
|
|||
-- ======================================== |
|||
-- 2. 修复优惠券模板表的null值 |
|||
-- ======================================== |
|||
|
|||
-- 检查当前null值情况 |
|||
SELECT |
|||
'shop_coupon null值检查' as table_name, |
|||
COUNT(*) as total_records, |
|||
COUNT(CASE WHEN reduce_price IS NULL THEN 1 END) as null_reduce_price, |
|||
COUNT(CASE WHEN min_price IS NULL THEN 1 END) as null_min_price |
|||
FROM shop_coupon; |
|||
|
|||
-- 修复reduce_price字段的null值 |
|||
UPDATE shop_coupon |
|||
SET reduce_price = 0.00 |
|||
WHERE reduce_price IS NULL; |
|||
|
|||
-- 修复min_price字段的null值 |
|||
UPDATE shop_coupon |
|||
SET min_price = 0.00 |
|||
WHERE min_price IS NULL; |
|||
|
|||
-- ======================================== |
|||
-- 3. 设置字段默认值(可选) |
|||
-- ======================================== |
|||
|
|||
-- 为用户优惠券表字段设置默认值 |
|||
ALTER TABLE shop_user_coupon |
|||
MODIFY COLUMN reduce_price DECIMAL(10,2) DEFAULT 0.00 COMMENT '满减券-减免金额'; |
|||
|
|||
ALTER TABLE shop_user_coupon |
|||
MODIFY COLUMN min_price DECIMAL(10,2) DEFAULT 0.00 COMMENT '最低消费金额'; |
|||
|
|||
-- 为优惠券模板表字段设置默认值 |
|||
ALTER TABLE shop_coupon |
|||
MODIFY COLUMN reduce_price DECIMAL(10,2) DEFAULT 0.00 COMMENT '满减券-减免金额'; |
|||
|
|||
ALTER TABLE shop_coupon |
|||
MODIFY COLUMN min_price DECIMAL(10,2) DEFAULT 0.00 COMMENT '最低消费金额'; |
|||
|
|||
-- ======================================== |
|||
-- 4. 验证修复结果 |
|||
-- ======================================== |
|||
|
|||
-- 检查修复后的情况 |
|||
SELECT |
|||
'shop_user_coupon 修复后检查' as table_name, |
|||
COUNT(*) as total_records, |
|||
COUNT(CASE WHEN reduce_price IS NULL THEN 1 END) as null_reduce_price, |
|||
COUNT(CASE WHEN min_price IS NULL THEN 1 END) as null_min_price, |
|||
MIN(reduce_price) as min_reduce_price, |
|||
MIN(min_price) as min_min_price |
|||
FROM shop_user_coupon; |
|||
|
|||
SELECT |
|||
'shop_coupon 修复后检查' as table_name, |
|||
COUNT(*) as total_records, |
|||
COUNT(CASE WHEN reduce_price IS NULL THEN 1 END) as null_reduce_price, |
|||
COUNT(CASE WHEN min_price IS NULL THEN 1 END) as null_min_price, |
|||
MIN(reduce_price) as min_reduce_price, |
|||
MIN(min_price) as min_min_price |
|||
FROM shop_coupon; |
|||
|
|||
-- ======================================== |
|||
-- 5. 检查其他可能的BigDecimal字段 |
|||
-- ======================================== |
|||
|
|||
-- 检查订单相关表的BigDecimal字段 |
|||
SELECT |
|||
'shop_order BigDecimal字段检查' as check_type, |
|||
COUNT(*) as total_records, |
|||
COUNT(CASE WHEN order_price IS NULL THEN 1 END) as null_order_price, |
|||
COUNT(CASE WHEN pay_price IS NULL THEN 1 END) as null_pay_price |
|||
FROM shop_order; |
|||
|
|||
-- 如果发现null值,可以执行以下修复 |
|||
/* |
|||
UPDATE shop_order SET order_price = 0.00 WHERE order_price IS NULL; |
|||
UPDATE shop_order SET pay_price = 0.00 WHERE pay_price IS NULL; |
|||
*/ |
|||
|
|||
SELECT 'BigDecimal null值修复完成!' as result; |
Loading…
Reference in new issue