# mercury-spring-boot-starter **Repository Path**: ITEater/mercury-spring-boot-starter ## Basic Information - **Project Name**: mercury-spring-boot-starter - **Description**: 货币相关计算与格式化相关的spring-boot-starter - **Primary Language**: Java - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 0 - **Created**: 2019-02-20 - **Last Updated**: 2025-06-06 ## Categories & Tags **Categories**: Uncategorized **Tags**: 金钱, 计算 ## README # mercury-spring-boot-starter 一个货币计算相关处理的神奇starter ## 前言 1. 后续版本将升级为0.4.0,支持springboot3版本,同时将包路径替换为``top.codef`` ## 介绍 对于跟多系统中对于金钱的计算是必不可少的,而且关于钱的计算,就连最基础的程序猿也知道不能用基础的加减乘除计算。网上关于钱的计算解决方案也很多,本框架主要基于JSR-354的一个实现框架:org.javamoney.moneta的基础上建立了一整套的javamoney的使用,序列化与持久化处理;同时,还支持了mongodb、gson、redis等序列化与存储 ## 版本说明 #### 当前版本 ![version](https://img.shields.io/badge/version-0.1.5-red?style=for-the-badge&logo=appveyor) #### 依赖版本 ![java](https://img.shields.io/badge/java-11%2B-red?style=for-the-badge&logo=appveyor) ![spring](https://img.shields.io/badge/spring--boot-2.6.3%2B-red?style=for-the-badge&logo=appveyor) ![maven版本](https://img.shields.io/badge/maven-3.2.5%2B-red.svg?style=for-the-badge&logo=appveyor) #### 软件架构 - JavaMoney是Java™平台以及相关项目和库的新货币API。API(JSR 354)提供了用于处理货币模型的可移植且可扩展的API,而Moneta提供了可用于生产的参考实现。货币API是基于ISO 4217标准而指定的,JavaMoney库添加了在API之上构建的其他功能,例如 1. 货币转换 2. 货币映射和命名空间 3. 基本财务计算 4. 扩展格式(可用于任意类型) 5. 区域API,引入区域,国家和地区组织的处理 6. 有效性API,允许管理任意数据的有效性以及与时间(历史)相关的关系 - ISO 4217用于代表货币和资金。本标准规定了一个三个字母的字母代码和相当于3位数的代码来代表货币和资金。对于那些小单位货币,它也显示了这些单位和货币本身的十进制关系。对于ISO 4217具体信息请参照百度百科 [https://baike.baidu.com/item/ISO%204217/11018231?fromtitle=ISO4217&fromid=11174838&fr=aladdin](https://baike.baidu.com/item/ISO%204217/11018231?fromtitle=ISO4217&fromid=11174838&fr=aladdin) - 本框架主要基于Moneta而实现了在web-mvc与jpa中的对外的数据格式化以及对内货币使用,主要包含了3个大块,分别是: 1. spring-formatter模块:实现货币到具体MonetaryAmount的解析 2. json-serializer模块:基于fasterxml的jason序列化与反序列化解析 3. persist-convert模块:将数据库类型转换成money类型 4. mongo支撑:实现不同数据库间数据信息的一致性 5. gson支持:实现gson工具处理money相关 #### 最快上手 - 将此工程通过``mvn clean install``打包到本地仓库中。 - 在你的spring-boot(web工程)项目的``pom.xml``中引入: ``` com.kuding mercury-spring-boot-starter 0.1.5 ``` - 在``application.properties(yml)``区域信息 ``` mercury.money.locale=simplified-chinese ``` - 创建一个pojo类,例如: ``` public class MyPocket { private Long id; @Money private MonetaryAmount money; //getters and setters } ``` ``@Money(com.kuding.anno.Money)``是本框架的核心注解,用户解析请求中金钱相关的数据结构,``MonetaryAmount``是``javamoney``中货币的基础数据结构 - 创建一个controller,例如: ``` @RestController @RequestMapping("/money") public class MoneyTestController { @Autowired private MercuryProperties mercuryProperties; @PostMapping("/getMoney") public MyPocket genericPocket() { MyPocket myPocket = new MyPocket(1L, FastMoney.of(new BigDecimal(1111111L), Monetary.getCurrency(mercuryProperties.currentLocale()))); return myPocket; } } ``` - 调用接口就可以出现如下结果: ![getMoney](/src/main/resources/getMoney.png) 返回的结果中,``money``返回值为``"CNY1,111,111.00"``,其中``CNY``表示的是ISO4217标准中人民币的对应代码(人民币 China Yuan Renminbi (CNY)),后面的数字表示的是货币金额的标准化输出(三位逗号分隔,保留两位小数) - 在controller层再加入一个请求接口: ``` @PostMapping("/createMoneyByBody") public MyPocket createPocket(@RequestBody MyPocket myPocket) { return myPocket; } ``` - 调用接口后会有如下效果: ![bodyrequest](/src/main/resources/body.png) - 在controller中再加入一个接口: ``` @PostMapping("/createMoney") public MyPocket createPocket(@RequestParam @ApiParam(value = "id", required = true) Long id, @RequestParam @Money @ApiParam MonetaryAmount money) { MyPocket myPocket = new MyPocket(id, money); return myPocket; } ``` 调用接口会有如下结果: ![bodyrequest](/src/main/resources/param.png) ## 使用说明 ### 配置说明 - 目前配置只有三项: ``` mercury.money.locale=simplified-chinese mercury.money.strict-currency=false mercury.money.pattern=#0.00 ``` - ``mercury.money.locale``表示货币的区域选择,目前只包含了Locale中常见区域选择 - ``strict-currency``表示是否是严格的货币单位,对于假如解析货币的过程中没有匹配到对应的货币单位,就会抛出异常 - ``pattern``表示的是货币格式化的表达式,主要是通过``java.text.DecimalFormat``进行的解析,类似于正则表达式,具体的一些符号与意义如下表 |符号|表示位置|是否是局部使用|说明| |:-:|:-:|:-:|:-:| |0|数字|是|表示一个数字,没有的话用0占位| |#|数字|是|表示一个数字,没有的话不显示| |.|数字|是|表示小数点| |-|数字|是|表示负号| |,|数字|是|表示数字分组| |E|数字|是|科学技术法标识符| |;|子表达式边界符号|是|用来区分正数与负数表达式的| |%|前缀或后缀|是|百分数表示(格式化输出数会乘以100)| |‰(\u2030)|前缀或后缀|是|千分数表示| |¤ (\u00A4)|前缀或后缀|否|货币符号(重要)| 例如: 在配置中:``mercury.money.pattern=#,##0.00``表示的是:每三位用`,`分隔,保留两位小数,`0`格式化为`0.00`。 - 这里需要特别说明一下,对于不同的``Locale``所展现的格式是不一样的,``pattern``与``locale``配置之间存在冲突,所以这里有这样一个优先级:**优先比配``pattern``** ### 注解说明 - 目前框架中只有一个注解: ``` @Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER }) @Retention(RetentionPolicy.RUNTIME) public @interface Money { MoneyFormatStyle value() default MoneyFormatStyle.DEFAULT; MoneyFormatStyle in() default MoneyFormatStyle.DEFAULT; MoneyFormatStyle out() default MoneyFormatStyle.DEFAULT; } ``` ``@Money``注解主要用于controller层的参数传入与结果输出的格式化问题,目前格式化风格包含三种: 1. 默认格式化类型 2. 数字类型 3. 对象类型 - 默认格式化类型是通过全局的配置进行的货币格式化标准输出与输入。例如: 对于某个字段: ``` @Money private MonetaryAmount money; ``` 配置项如下(yml): ``` mercury: money: locale: simplified-chinese pattern: '¤#0.00' strict-currency: false server: port: 9001 ``` 返回结果如下: `` { ... "money": "CNY12345678.90" } `` 若只需要数字,只需要将注解变为``@Money(MoneyFormatStyle.NUM_ONLY)``,输出就会变为``"money": "12345678.90000"``,实际上若需要显示货币金额且要有一定格式化的话,可以通过``pattern``进行处理,如``pattern: '#,##0.00'``,``@Money(MoneyFormatStyle.DEFAULT)``, 则返回结果为:``"money": "12,345,678.90"`` ### jpa说明 前面的所有的处理主要面向的是服务端请求的输入与输出问题,主要是基于``fasterxml``序列化框架而开发(spring web引用),服务端向数据层的输入与输出主要依靠``spring data jpa``,其底层则是基于``JPA(Java Persistence API)``规范,由hibernate实现。所以这里就是将``MonetaryAmount``结构类型与数据库的基本类型进行了对接,主要是通过``TypeContributor``与``BasicJavaDescriptor``来实现,具体实现可以看本项目源码。 - 同样的处理方式,需要在``application.properties(yml)``开启money类型的的配置项: ``` mercury: money: persist: open-monetary-basic-type-persist: true money-data-type: bigint persist-on-multiply100: true #表示数据库数值与服务中的数值差100倍,即存入数据库前会把money的数值乘以100 ``` - 开启了persis模块后,就可以通过``@Entity``注解使用了 ``` @Getter @Setter @Entity public class Pocket { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private Long personId; private MonetaryAmount moneyAmount; private LocalDateTime createTime = LocalDateTime.now(); } ``` #### 配置property - 要开启jpa持久化,需要做如下配置 |名称|参数类型|说明|必要配置| |:-:|:-:|:-:|:-:| |open-monetary-basic-type-persist|boolean|用于开启项目配置,属于总控开关(默认false)|是| |money-data-type|enum|数据库字段类型(enum),目前支持三种:DECIMAL,VARCHAR,BIGINT|是| |persist-on-multiply100|boolean|在存入数据前是否乘以100?默认为(false)|否|