这篇文章给大家介绍Spring Boot中的货币单位怎么利用Mvc 扩展进行转换,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。
1、FenToYuan.java
定义一个标注注解,用于标注到需要把元转换成分的 BigDecimal
类型的参数上面。
FenToYuan.java
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FenToYuan {
}
实现 Spring MVC Restful 请求参数扩展类,如果请求参数标注了 @RequestBody
注解,并且请求参数的字段类型为 BigDecimal
就会把传入的参数由元转换成分。
YuanToFenRequestBodyAdvice.java
@Slf4j
@ControllerAdvice
public class YuanToFenRequestBodyAdvice extends RequestBodyAdviceAdapter {
@Override
public boolean supports(MethodParameter methodParameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
return methodParameter.hasParameterAnnotation(RequestBody.class);
}
@Override
public Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
if(body == null) {
return null;
}
Class<?> clazz = body.getClass();
PropertyDescriptor[] propertyDescriptors = BeanUtils.getPropertyDescriptors(clazz);
for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
String name = propertyDescriptor.getName();
if("class".equals(name)){
continue;
}
Field field = ReflectionUtils.findField(clazz, name);
Class<?> fieldClazz = field.getType();
if(!fieldClazz.equals(BigDecimal.class) ){
continue;
}
if(!field.isAnnotationPresent(YuanToFen.class)) {
continue;
}
Method readMethod = propertyDescriptor.getReadMethod();
Method writeMethod = propertyDescriptor.getWriteMethod();
try {
BigDecimal yuanAmount = (BigDecimal) readMethod.invoke(body);
BigDecimal fenAmount = AmountUtils.yuan2Fen(yuanAmount);
writeMethod.invoke(body, fenAmount);
} catch (Exception e) {
log.error("amount convert yuan to fen fail", e);
}
}
return super.afterBodyRead(body, inputMessage, parameter, targetType, converterType);
}
}
标注注解,当响应参数需要由分转换成元的时候,就标注这个注解。响应值就会把数据库或者下游传递过来的金额为分的参数转换成元。
YuanToFen.java
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface YuanToFen {
}
当 Spring MVC 方法上标注了 ResponseBody
或者类上标注了 RestController
注解时,如果响应对象的 BigDecimal
标注了 @YuanToFen
注解就会进行金额分转换成元。
FenToYuanResponseBodyAdvice.java
@Slf4j
@ControllerAdvice
public class FenToYuanResponseBodyAdvice implements ResponseBodyAdvice {
@Override
public boolean supports(MethodParameter returnType, Class converterType) {
return returnType.hasParameterAnnotation(ResponseBody.class)
|| returnType.getDeclaringClass().isAnnotationPresent(RestController.class);
}
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
if(body == null) {
return null;
}
Class<?> clazz = body.getClass();
PropertyDescriptor[] propertyDescriptors = BeanUtils.getPropertyDescriptors(clazz);
for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
String name = propertyDescriptor.getName();
if("class".equals(name)){
continue;
}
Field field = ReflectionUtils.findField(clazz, name);
Class<?> fieldClazz = field.getType();
if(!fieldClazz.equals(BigDecimal.class) ){
continue;
}
if(!field.isAnnotationPresent(FenToYuan.class)) {
continue;
}
Method readMethod = propertyDescriptor.getReadMethod();
Method writeMethod = propertyDescriptor.getWriteMethod();
try {
BigDecimal fenAmount = (BigDecimal) readMethod.invoke(body);
BigDecimal yuanAmount = AmountUtils.fen2yuan(fenAmount);
writeMethod.invoke(body, yuanAmount);
} catch (Exception e) {
log.error("amount convert fen to yuan fail", e);
}
}
return body;
}
}
金钱工具类,提供了金钱的元转分以及分转元这两个功能。
AmountUtils.java
public abstract class AmountUtils {
/**
* 金额单位元转分
*/
public static BigDecimal yuan2Fen(BigDecimal amount) {
if (amount == null) {
return BigDecimal.ZERO;
}
return amount.movePointRight(2).setScale(0, BigDecimal.ROUND_DOWN);
}
/**
* 金额单位分转元
*/
public static BigDecimal fen2yuan(BigDecimal amount) {
return null2Zero(amount).movePointLeft(2).setScale(2, BigDecimal.ROUND_HALF_UP);
}
/**
* 把 null 当作 0 处理
*/
public static BigDecimal null2Zero(Number amount) {
if (amount == null) {
return BigDecimal.ZERO;
}
if (amount instanceof BigDecimal) {
return (BigDecimal) amount;
} else {
return new BigDecimal(amount.toString());
}
}
}
实体类,用于接收请求对象以及响应测试金额转换。
Order.java
@Data
public class Order {
private String orderId;
private String productName;
@FenToYuan
@YuanToFen
private BigDecimal orderAmount;
}
订单控制类,提供了两个方法:订单创建(/order/apply)标注了 @RequestBody
,会把传入的金额由元转换成分,然后打印到控制台。订单查询(order/query) 声明方法的类上标注了 @RestController
,通过关键字 new
创建一个订单金额为 1000
分的订单。
OrderController.java
@RestController
@RequestMapping("order")
public class OrderController {
@RequestMapping("apply")
public void apply(@RequestBody Order order) {
System.out.println(JSON.toJSONString(order));
}
@RequestMapping("query/{id}")
public Order query(@PathVariable String id) {
Order order = new Order();
order.setOrderId(id);
order.setOrderAmount(new BigDecimal("1000"));
order.setProductName("test");
return order;
}
}
使用工具 Postman 发送 http 进行功能测试。
8.1 元转分测试
通过 postman 请求 http:localhost:8080/order/apply
发送以下请求:
控制台打印如下:
业务方传入金额为 1 元,控制台打印的结果是 100 分。
8.2 测试分转元
通过 postman 请求 http:localhost:8080/order/query/1
发送以下请求:
这个时候得到订单金额为 10 元。查询订单的逻辑如下:
这个时候订单的金额是 1000 分,转换成 10 元完成了我们的目标功能。
当然这种方式是有一个缺陷的,就是它不能递归的进行金额转换,后面可以借鉴 Hibernate 的递归校验逻辑来进行递归金额参数的转换。
关于Spring Boot中的货币单位怎么利用Mvc 扩展进行转换就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。
亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。