欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Spring Boot 通過 Mvc 擴(kuò)展方便進(jìn)行貨幣單位轉(zhuǎn)換的代碼詳解

 更新時(shí)間:2020年12月10日 11:16:26   作者:carl-zhao  
這篇文章主要介紹了Spring Boot 通過 Mvc 擴(kuò)展方便進(jìn)行貨幣單位轉(zhuǎn)換,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下

由于公司是支付平臺,所以很多項(xiàng)目都涉及到金額,業(yè)務(wù)方轉(zhuǎn)遞過來的金額是單位是元,而我們數(shù)據(jù)庫保存的金額單位是分。一般金額的流向有以下幾個(gè)方向:

  • 外部業(yè)務(wù)方請求我們服務(wù),傳遞過來的金額單位是元,需要把元轉(zhuǎn)換成分。比如:下單接口。
  • 內(nèi)部系統(tǒng)之間的流轉(zhuǎn),不管是向下傳遞還是向上傳遞系統(tǒng)間的流程都是分,不需要扭轉(zhuǎn)。比如:調(diào)用支付引擎(向下傳遞),支付引擎回調(diào)收單業(yè)務(wù)(向上傳遞)。
  • 向業(yè)務(wù)方返回?cái)?shù)據(jù),這個(gè)時(shí)候需要把分轉(zhuǎn)換成元。比如:商戶調(diào)用查詢訂單接口。
  • 內(nèi)部系統(tǒng)的展示,這個(gè)時(shí)候需要把分轉(zhuǎn)換成元。比如:顯示收入金額的報(bào)表。

如果我們對于請求參數(shù)是金額類型的參數(shù)逐一處理,這樣重復(fù)的操作就會顯得相當(dāng)?shù)牟粌?yōu)雅。對于請求參數(shù)我們可以使用 Spring MVC 提供的擴(kuò)展擴(kuò)展。對于金額操作我們可以分為:

  • 業(yè)務(wù)方傳入金額單位為元,需要把業(yè)務(wù)方傳入的元轉(zhuǎn)換成分,可以使用 Spring MVC Restful 請求參數(shù)擴(kuò)展 RequestBodyAdvice 接口。
  • 業(yè)務(wù)方需要查詢數(shù)據(jù),需要把數(shù)據(jù)庫保存的分轉(zhuǎn)換成元,可以使用 Spring MVC Restful 響應(yīng)參數(shù)擴(kuò)展 ResponseBodyAdvice 接口。

下面我們就來看一下代碼實(shí)現(xiàn)。

1、FenToYuan.java

定義一個(gè)標(biāo)注注解,用于標(biāo)注到需要把元轉(zhuǎn)換成分的 BigDecimal 類型的參數(shù)上面。

FenToYuan.java

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FenToYuan {

}

2、YuanToFenRequestBodyAdvice.java

實(shí)現(xiàn) Spring MVC Restful 請求參數(shù)擴(kuò)展類,如果請求參數(shù)標(biāo)注了 @RequestBody 注解,并且請求參數(shù)的字段類型為 BigDecimal 就會把傳入的參數(shù)由元轉(zhuǎn)換成分。

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);
  }

}

3、YuanToFen.java

標(biāo)注注解,當(dāng)響應(yīng)參數(shù)需要由分轉(zhuǎn)換成元的時(shí)候,就標(biāo)注這個(gè)注解。響應(yīng)值就會把數(shù)據(jù)庫或者下游傳遞過來的金額為分的參數(shù)轉(zhuǎn)換成元。

YuanToFen.java

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface YuanToFen {

}

4、FenToYuanResponseBodyAdvice.java

當(dāng) Spring MVC 方法上標(biāo)注了 ResponseBody 或者類上標(biāo)注了 RestController 注解時(shí),如果響應(yīng)對象的 BigDecimal 標(biāo)注了 @YuanToFen 注解就會進(jìn)行金額分轉(zhuǎn)換成元。

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;
  }

}

5、AmountUtils.java

金錢工具類,提供了金錢的元轉(zhuǎn)分以及分轉(zhuǎn)元這兩個(gè)功能。

AmountUtils.java

public abstract class AmountUtils {

  /**
   * 金額單位元轉(zhuǎn)分
   */
  public static BigDecimal yuan2Fen(BigDecimal amount) {
    if (amount == null) {
      return BigDecimal.ZERO;
    }
    return amount.movePointRight(2).setScale(0, BigDecimal.ROUND_DOWN);
  }

  /**
   * 金額單位分轉(zhuǎn)元
   */
  public static BigDecimal fen2yuan(BigDecimal amount) {
    return null2Zero(amount).movePointLeft(2).setScale(2, BigDecimal.ROUND_HALF_UP);
  }

  /**
   * 把 null 當(dāng)作 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());
    }
  }

}

6、Order.java

實(shí)體類,用于接收請求對象以及響應(yīng)測試金額轉(zhuǎn)換。

Order.java

@Data
public class Order {

  private String orderId;

  private String productName;

  @FenToYuan
  @YuanToFen
  private BigDecimal orderAmount;

}

7、OrderController.java

訂單控制類,提供了兩個(gè)方法:訂單創(chuàng)建(/order/apply)標(biāo)注了 @RequestBody,會把傳入的金額由元轉(zhuǎn)換成分,然后打印到控制臺。訂單查詢(order/query) 聲明方法的類上標(biāo)注了 @RestController ,通過關(guān)鍵字 new 創(chuàng)建一個(gè)訂單金額為 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;
  }

}

8、測試

使用工具 Postman 發(fā)送 http 進(jìn)行功能測試。

8.1 元轉(zhuǎn)分測試

通過 postman 請求 http:localhost:8080/order/apply發(fā)送以下請求:

在這里插入圖片描述

控制臺打印如下:

在這里插入圖片描述

業(yè)務(wù)方傳入金額為 1 元,控制臺打印的結(jié)果是 100 分。

8.2 測試分轉(zhuǎn)元

通過 postman 請求 http:localhost:8080/order/query/1發(fā)送以下請求:

在這里插入圖片描述

這個(gè)時(shí)候得到訂單金額為 10 元。查詢訂單的邏輯如下:

在這里插入圖片描述

這個(gè)時(shí)候訂單的金額是 1000 分,轉(zhuǎn)換成 10 元完成了我們的目標(biāo)功能。

當(dāng)然這種方式是有一個(gè)缺陷的,就是它不能遞歸的進(jìn)行金額轉(zhuǎn)換,后面可以借鑒 Hibernate 的遞歸校驗(yàn)邏輯來進(jìn)行遞歸金額參數(shù)的轉(zhuǎn)換。

到此這篇關(guān)于Spring Boot 通過 Mvc 擴(kuò)展方便進(jìn)行貨幣單位轉(zhuǎn)換的文章就介紹到這了,更多相關(guān)Spring Boot貨幣單位轉(zhuǎn)換內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 基于Java實(shí)現(xiàn)Avro文件讀寫功能

    基于Java實(shí)現(xiàn)Avro文件讀寫功能

    大家好,本篇文章主要講的是基于Java實(shí)現(xiàn)Avro文件讀寫功能,感興趣的同學(xué)趕快來看一看吧,對你有幫助的話記得收藏一下
    2022-02-02
  • 關(guān)于dubbo的RPC和RESTful性能及對比

    關(guān)于dubbo的RPC和RESTful性能及對比

    這篇文章主要介紹了關(guān)于dubbo的RPC和RESTful性能及對比,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-12-12
  • Java應(yīng)該在哪里判斷List是否為空

    Java應(yīng)該在哪里判斷List是否為空

    在Java中,我們常用List來存儲數(shù)據(jù),但是我們怎么判斷它是否成功帶來了我們需要的數(shù)據(jù)呢?下面這篇文章主要給大家介紹了關(guān)于Java應(yīng)該在哪里判斷List是否為空的相關(guān)資料,需要的朋友可以參考下
    2022-02-02
  • IDEA 格式化SQL代碼技巧分享

    IDEA 格式化SQL代碼技巧分享

    這篇文章主要介紹了IDEA 格式化SQL代碼技巧分享,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-02-02
  • java生成驗(yàn)證碼步驟歸納總結(jié)

    java生成驗(yàn)證碼步驟歸納總結(jié)

    這篇文章主要為大家詳細(xì)介紹了java生成驗(yàn)證碼的步驟總結(jié),需要的朋友可以參考下
    2017-04-04
  • 關(guān)于spring屬性占位符用法

    關(guān)于spring屬性占位符用法

    這篇文章主要介紹了關(guān)于spring屬性占位符用法,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-11-11
  • SparkStreaming整合Kafka過程詳解

    SparkStreaming整合Kafka過程詳解

    這篇文章主要介紹了SparkStreaming整合Kafka過程,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧
    2023-01-01
  • Java反射與Fastjson的危險(xiǎn)反序列化詳解

    Java反射與Fastjson的危險(xiǎn)反序列化詳解

    在?Java?中,Computer.class是一個(gè)引用,它表示了?Computer?的字節(jié)碼對象(Class對象),這個(gè)對象被廣泛應(yīng)用于反射、序列化等操作中,那么為什么?parseObject?需要這個(gè)引用呢,帶著這個(gè)問題我們一起通過本文學(xué)習(xí)下吧
    2024-07-07
  • Spring boot集成RabbitMQ的示例代碼

    Spring boot集成RabbitMQ的示例代碼

    本篇文章主要介紹了Spring boot集成RabbitMQ的示例代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-05-05
  • 通過jstack分析解決進(jìn)程死鎖問題實(shí)例代碼

    通過jstack分析解決進(jìn)程死鎖問題實(shí)例代碼

    這篇文章主要介紹了通過jstack分析解決進(jìn)程死鎖問題實(shí)例代碼,具有一定借鑒價(jià)值,需要的朋友可以參考下
    2018-01-01

最新評論