Rsoft光器件仿真实战:从基础到复杂光子器件设计
2026/10/26 23:34:33
在金融、电商等涉及金额的项目中,我们经常需要对BigDecimal类型的金额字段统一保留指定小数位数。如果在每个业务方法中手动调用setScale方法,会造成大量代码冗余,且难以统一维护。
本文将介绍一种基于SpringBoot 拦截器 + 自定义注解的方案,实现金额字段的自动格式化,让代码更简洁、更易维护。
@AmountFormat,用于标记需要格式化的金额字段,并支持指定小数位数。AmountFormatInterceptor,在请求处理阶段,通过反射扫描被注解标记的字段。BigDecimal类型字段,按照注解指定的小数位数进行格式化处理。@AmountFormat该注解用于标记需要格式化的金额字段,支持通过scale属性指定小数位数,默认保留2位小数。
importjava.lang.annotation.ElementType;importjava.lang.annotation.Retention;importjava.lang.annotation.RetentionPolicy;importjava.lang.annotation.Target;/** * 金额格式化注解,用于标记需要统一处理小数位数的字段 */@Retention(RetentionPolicy.RUNTIME)// 注解在运行时生效,允许反射获取@Target(ElementType.FIELD)// 注解仅作用于类的字段public@interfaceAmountFormat{/** * 保留小数位数,默认2位 */intscale()default2;}拦截器实现HandlerInterceptor接口,在preHandle方法中完成核心逻辑:扫描目标类的字段,对被@AmountFormat标记的BigDecimal字段进行格式化。
importorg.springframework.web.method.HandlerMethod;importorg.springframework.web.servlet.HandlerInterceptor;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;importjava.lang.reflect.Field;importjava.math.BigDecimal;importjava.math.RoundingMode;/** * 金额格式化拦截器,自动处理被@AmountFormat标记的字段 */publicclassAmountFormatInterceptorimplementsHandlerInterceptor{@OverridepublicbooleanpreHandle(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler)throwsException{// 只处理 Controller 中的方法(HandlerMethod 类型)if(handlerinstanceofHandlerMethod){HandlerMethodhandlerMethod=(HandlerMethod)handler;// 获取目标类的实例ObjecttargetBean=handlerMethod.getBean();// 获取目标类的所有字段Field[]fields=targetBean.getClass().getDeclaredFields();for(Fieldfield:fields){// 判断字段是否被@AmountFormat注解标记if(field.isAnnotationPresent(AmountFormat.class)){// 设置私有字段可访问field.setAccessible(true);// 获取字段的值ObjectfieldValue=field.get(targetBean);// 仅处理BigDecimal类型的字段if(fieldValueinstanceofBigDecimal){AmountFormatannotation=field.getAnnotation(AmountFormat.class);intscale=annotation.scale();// 格式化金额:四舍五入,保留指定小数位数BigDecimalformattedValue=((BigDecimal)fieldValue).setScale(scale,RoundingMode.HALF_UP);// 将格式化后的值设置回字段field.set(targetBean,formattedValue);}}}}// 返回true,继续执行后续拦截器和Controller方法returntrue;}}关键说明:
preHandle方法在 Controller 方法执行前调用,保证格式化逻辑优先执行。field.setAccessible(true)来访问私有字段。RoundingMode.HALF_UP模式进行四舍五入,符合日常金额计算的需求。通过配置类WebConfig实现WebMvcConfigurer接口,注册拦截器并设置拦截范围。
importorg.springframework.context.annotation.Configuration;importorg.springframework.web.servlet.config.annotation.InterceptorRegistry;importorg.springframework.web.servlet.config.annotation.WebMvcConfigurer;/** * Web 配置类,用于注册拦截器 */@ConfigurationpublicclassWebConfigimplementsWebMvcConfigurer{@OverridepublicvoidaddInterceptors(InterceptorRegistryregistry){// 注册金额格式化拦截器registry.addInterceptor(newAmountFormatInterceptor())// 拦截所有请求.addPathPatterns("/**")// 排除不需要拦截的路径(可选).excludePathPatterns("/static/**","/error");}}在需要格式化的BigDecimal类型金额字段上添加@AmountFormat注解,即可实现自动格式化。
importjava.math.BigDecimal;/** * 商品实体类 */publicclassProduct{privateLongid;privateStringproductName;// 金额字段:默认保留2位小数@AmountFormatprivateBigDecimalprice;// 金额字段:自定义保留3位小数@AmountFormat(scale=3)privateBigDecimaldiscountPrice;// 省略 getter/setter 方法}SpringMVC 拦截器有三个核心方法,各自的执行时机不同:
BigDecimal类型的字段生效,其他类型(如Double)不会处理。建议金额字段统一使用BigDecimal,避免精度丢失。field.setAccessible(true),否则无法访问实体类的私有字段,会抛出IllegalAccessException异常。addPathPatterns和excludePathPatterns精准控制拦截范围,避免拦截静态资源、错误页面等不需要处理的请求。RoundingMode.HALF_UP,如果业务需要其他舍入模式(如向下取整),可以在注解中新增属性配置。setScale方法。scale参数,无需改动大量业务代码。通过拦截器 + 自定义注解的组合,我们可以优雅地解决项目中金额字段格式化的问题。这种方案不仅减少了代码冗余,还提高了代码的可维护性,特别适合金融、电商等对金额精度要求高的项目。
在实际开发中,我们还可以基于此思路扩展更多功能,比如对日期字段的统一格式化、对敏感字段的脱敏处理等。