Home 项目

今天在看 《阿里巴巴开发规范》的OOP规约时,发现一个对于我来说很陌生的浮点数类型

BigDecimal

这个数据类型我见过,但无法准确的描述和理解其具体含义,因此趁今天碰到了,特此记录

通过百度百科发现,它的作用是巨大的,当浮点数计算追求完美精度的时候(金融),不可以使用Double和Float

那么 我们一起来看看,为什么要用BigDecimal?怎么用BigDecimal吧?

首先,我们来猜测一下下列输出结果

在未了解BigDecimal类之前,我会觉得这些输出跟我们现实中得到的值一样,可是结果却是

那为什么会出现这种情况呢?

因为不论是float 还是double都是浮点数,而计算机是二进制的,浮点数会失去一定的精确度。

根本原因是:十进制值通常没有完全相同的二进制表示形式;十进制数的二进制表示形式可能不精确。只能无限接近于那个值。

但是,在项目中,我们不可能让这种情况出现,特别是金融项目,因为涉及金额的计算都必须十分精确,你想想,如果你的支付宝账户余额显示193.99999999999998,那是一种怎么样的体验?

【BigDecimal是什么?】

1、简介
Java在java.math包中提供的API类BigDecimal,用来对超过16位有效位的数进行精确的运算。双精度浮点型变量double可以处理16位有效数。在实际应用中,需要对更大或者更小的数进行运算和处理。float和double只能用来做科学计算或者是工程计算,在商业计算中要用java.math.BigDecimal。BigDecimal所创建的是对象,我们不能使用传统的+、-、*、/等算术运算符直接对其对象进行数学运算,而必须调用其相对应的方法。方法中的参数也必须是BigDecimal的对象。构造器是类的特殊方法,专门用来创建对象,特别是带有参数的对象。

2、构造器描述
BigDecimal(int) 创建一个具有参数所指定整数值的对象。
BigDecimal(double) 创建一个具有参数所指定双精度值的对象。 //不推荐使用
BigDecimal(long) 创建一个具有参数所指定长整数值的对象。
BigDecimal(String) 创建一个具有参数所指定以字符串表示的数值的对象。//推荐使用

3、方法描述
add(BigDecimal) BigDecimal对象中的值相加,然后返回这个对象。
subtract(BigDecimal) BigDecimal对象中的值相减,然后返回这个对象。
multiply(BigDecimal) BigDecimal对象中的值相乘,然后返回这个对象。
divide(BigDecimal) BigDecimal对象中的值相除,然后返回这个对象。
toString() 将BigDecimal对象的数值转换成字符串。
doubleValue() 将BigDecimal对象中的值以双精度数返回。
floatValue() 将BigDecimal对象中的值以单精度数返回。
longValue() 将BigDecimal对象中的值以长整数返回。
intValue() 将BigDecimal对象中的值以整数返回。

特别说明一下,为什么BigDecimal(double) 不推荐使用

看上面代码运行结果,你就应该知道为什么不推荐使用了,因为用这种方式也会导致计算有问题

为什么会出现这种情况呢?

JDK的描述:1、参数类型为double的构造方法的结果有一定的不可预知性。有人可能认为在Java中写入newBigDecimal(0.1)所创建的BigDecimal正好等于 0.1(非标度值 1,其标度为 1),但是它实际上等于0.1000000000000000055511151231257827021181583404541015625。这是因为0.1无法准确地表示为 double(或者说对于该情况,不能表示为任何有限长度的二进制小数)。这样,传入到构造方法的值不会正好等于 0.1(虽然表面上等于该值)。

2、另一方面,String 构造方法是完全可预知的:写入 newBigDecimal(“0.1”) 将创建一个 BigDecimal,它正好等于预期的 0.1。因此,比较而言,通常建议优先使用String构造方法

当double必须用作BigDecimal的源时,请使用Double.toString(double)转成String,然后使用String构造方法,或使用BigDecimal的静态方法valueOf,如下

【Decimal怎么用?】

直接上代码,都挺简单的,最基本的加减乘除,应该能看的懂

这边特别提一下,如果进行除法运算的时候,结果不能整除,有余数,这个时候会报java.lang.ArithmeticException:

这边我们要避免这个错误产生,在进行除法运算的时候,针对可能出现的小数产生的计算,必须要多传两个参数

divide(BigDecimal,保留小数点后几位小数,舍入模式)

原文链接:(转载并整理自)https://blog.csdn.net/qq_35868412/article/details/89029288

0 24

https://blog.csdn.net/qh870754310/article/details/83780812

开始在使用Maven时,总是会听到nexus这个词,一会儿maven,一会儿nexus,当时很是困惑,nexus是什么呢,为什么它总是和maven一起被提到呢?

我们一步一步来了解吧。

 一、了解Maven,Maven用来干什么呢

1. 优秀的构建工具

通过简单的命令,能够完成清理、编译、测试、打包、部署等一系列过程。同时,不得不提的是,Maven是跨平台的无论是在Windows、还是在Linux或Mac上,都可以使用同样的命令。

2. 依赖管理工具

项目依赖的第三方的开源类库,都可以通过依赖的方式引入到项目中来。代替了原来需要首先下载第三方jar,再加入到项目中的方式。从而更好的解决了合作开发中依赖增多、版本不一致、版本冲突、依赖臃肿等问题。

具体是怎么实现的呢?Maven通过坐标系统准确的定位每一个构件,即通过坐标找到对应的Java类库。

3. 项目信息管理工具

能够管理项目描述、开发者列表、版本控制系统地址、许可证等一些比较零散的项目信息。除了直接的项目信息,通过Maven自动生成的站点,以及一些已有的插件,还能够轻松获得项目文档、测试报告、静态分析报告、源码版本、日志报告等非常具有价值的项目信息。

二、 Maven与Nexus

这个问题从Maven的第二个用处说起,依赖管理,通过在Pom中指定坐标的形式将jar引入到项目中。那这个过程,要经历怎样一个流程呢?从哪里寻找jar?下载的jar放到哪里?

将这个问题顺下来,就知道nexus和maven的关系了。

从哪里找到jar?项目用到的jar又存放在哪里?这引出了仓库的概念,maven通过仓库来统一管理各种构件。Maven的仓库分为本地仓库远程仓库。

当Maven根据坐标寻找构件时,它首先会查看本地仓库如果本地仓库存在此构件,则直接使用;如果本地仓库不存在此构件,或者需要查看是否有更新的构件版本,Maven会去远程仓库查找,发现需要的构件之后,下载到本地仓库再使用

到了这里,问题的答案也就出来了。

首先,Nexus是一种远程仓库,根据上段的介绍,我们已经知道远程仓库的作用。在远程仓库中,默认的是中央仓库,中央仓库是Maven核心自带的远程仓库。那就使用中央仓库不就得了吗,为什么我们要安装Nexus呢?

我们从项目实际开发来看:

1.一些无法从外部仓库下载的构件,例如内部的项目还能部署到私服上,以便供其他依赖项目使用

2. 为了节省带宽和时间,在局域网内架设一个私有的仓库服务器,用其代理所有外部的远程仓库当本地Maven项目需要下载构件时先去私服请求,如果私服没有,则再去远程仓库请求,从远程仓库下载构件后,把构件缓存在私服。这样,即使暂时没有Internet链接,由于私服已经缓存了大量构件,整个项目还是可以正常使用的。同时,也降低了中央仓库的负荷。

Nexus仅仅是私服的一种。

0 15

基础功能模块发开完成了,接下来则是将我所写的功能模块组装到公司的OA系统上

首先,将子模块gqt导入OA模块所在文件夹导入子模块之后,在父模块的pom文件中将gqt功能模块添加到项目中

注意:此时要将gqt功能模块打成jar包如果没有添加到本机项目的依赖仓库里,则手动复制过去

项目开发,难免遇到与其他模块的交互,那么当我们要引入其他模块的类或者功能时,同样的在子功能项目的包中引入依赖同样的,其他子模块如果需要引入我们所写的功能模块,也需要同样的引入jar包

此时即可正常运行!!!

0 26

历经千辛万苦,主模块终于跑起来了,进入swagger文档,仔细阅读了相关的接口,然后测试,截图发给领导,走人

开启第二篇,功能开发

 

领导这次给我的任务是通过开发文档来建立数据库表

由于项目涉及的数据量不大,所以不需要考虑索引,又因为是设计单表,所以总的来说并不难

但我同样受益匪浅

 

首先 明确了unid的作用,某些项目开发时会维护一个或多个系统表,这些系统表类似于身份证系统,而unid就是身份证号码每产生一个新的数据库所定义的对象实体,就给他发一个独特的身份证号码—unid

 

比如在OA系统中,团组织是一个对象,团组织的书记也是一个对象

当我们创建了一个具体的团组织的时候,给它创建分配一个独特的unid,而设置一个书记(在数据库表中表现为新增一条数据)的时候,也给书记这个人,分配一个独特的unid,如下图

这样,我们在进行操作的时候,统一通过unid来进行,方便开发

同时,为了更好的实施开发,我制作了简约的思维导图

接下来就是代码的编写了,此处我学到的知识点许多(主要是swagger注解及其他),特此记录

 

@Data
@AllArgsConstructor     //有参构造
@NoArgsConstructor      //无参构造
@Accessors(chain = true)    //开启链式编程
@ApiModel("团组织信息")      //Swagger 模型
@JsonSerialize(using = ToStringSerializer.class)    //Long 数据类型 防止前后端传递时被截取

@TableId(value = “unid”) //mybatis-plus 主键(不加可能出现查询结果字段为null的现象)
@ApiModel:在实体类上边使用,标记类时swagger的解析类。 提供有关swagger模型的其它信息,类将在操作中用作类型时自动内省。
@ApiModelProperty()用于方法,字段; 表示对model属性的说明或者数据操作更改  如果Mapper.xml文件找不到有可能是编译之后 Mapper接口Mapper.xml不在同一个包中,可以通过target查看 接下来是Mybatis 动态SQL知识点,以及 SQL注入相关知识(需要继续补充) <resultMap>这里面property对应的是结果集的字段或属性,column对应的是数据库的列名或别名。 当然,它的功能远不止此https://www.jb51.net/article/162387.htm

<sql>+<include>实现SQL语句复用

未完待续…

0 28

2021.6.28入职

2021.6.29学习视频

2021.6.30正式开始开发(emmm,哭,把我实习生当正式工用了)

 

可以说这是本人第一次搭建企业级项目,一路上磕磕绊绊,总算在今天下午把自己写的功能模块成功合并到主模块上,并且通过了swagger的测试,必须记录下来,警醒自己还有很多的不足!

首先放上成功截图!

项目结构图

 

 

开发过程

当我作为一个实习生,正准备接下来的一个月摸鱼划水看文档的时候,亲爱的雨哥找到我,说

雨:“Springboot熟悉吗?”

我(这不得装一手?):“熟悉,写过三个项目,包括mybatis,redis,mq这些也还行,都用过”

雨:“很好,那你上手开发吧,明天把环境配一下”

我:???实习生入职第三天就开发,路子这么野的吗?环境?此时天真的我以为是配置Springboot开发环境,(毕竟咱之前不都是配个Springboot,自己电脑上数据库,redis什么的啥都有就上手开发了)

 

第二天

我踌躇满志,小小的配置环境能难得倒我吗?开玩笑,来吧

或许程序员大佬话都少吧,雨哥让我搭环境,前前后后,总共就这么几句话(我发誓我一句都没少,总共就这么几句)

Ok,文件接收完了,Git地址账号给了,雨哥不说话了,我要开始开发了

 

emmmmm,这对于我一个大三刚实习的学生来说是不是太残酷了点,真的不手把手带着我吗?

没办法,硬着头皮上吧

首先我使用了SourceTree去拉取GitLab上的项目代码,这个跟Git上拉取没什么不同,都是拉下来直接用解压,用idea打开就可以了,结构如下

Ok,启动IDEA,运行,成功,到此结束

当然不是,md,头一次见到微服务架构,震撼一百年,完全搞不懂入口在哪,真的是哪里亮了点哪里,就这样点

笑死,根本行不通,一片爆红

右侧Maven,找不到依赖

pom.xml文件就不用说了,也是一片红

启动类也没好到哪去

 

 

Maven爆红是因为Maven仓库里没有对应的依赖,或者没有导入,我可以理解,但是为什么启动类也爆红呢?

这就涉及到@ComponentScan 注解 的作用:

简版:@ComponentScan 的作用就是根据定义的扫描路径,把符合扫描规则的类装配到spring容器中,注解定义如下。到这咱们就明白了,没有引入子模块,扫描子模块的包又怎么可行呢?

 

我所开发的这个项目相当于已经集成了,可以把这些用不上的先注释,只添加自己需要的模块就可以跑起来测试接口,因此,我第一次求助雨哥

得到了: 不需要用的模块就先注释(实际开发,如果是微服务架构,肯定用得上!因为是分组开发,所有有些模块咱们没有权限,也引入不了)

于是我把pom.xml里用不到的注释掉,又把启动类上扫描对应的包也注释,这样总算是不爆红了

 

 

就在此处,我学到了第一个重大的知识点

Maven仓库配置

可能是我才疏学浅,一直以来对Maven仓库都是不怎么管的,毕竟在学校导入的包和各种配置完全比不上企业级开发,导致我在学校的时候,从来!从来没配置过Maven仓库,吃了大亏!!!

项目开发要引入包,如果是网上的包,比如什么mybatis,spring的包,我们都知道,直接去Maven官网找,复制到自己项目的pom文件即可,如下图

这样,IDEA就会乖乖帮我们把需要的依赖添加到本机的maven仓库,一般来说没什么问题

但是,如果遇到要添加自用的包,例如公司的依赖,同事的依赖, 这个时候在网上搜索不到,怎么办?或者说需要咱们自己查看项目依赖所在的repository,就需要了解相关的maven仓库配置问题!!!

配置Maven仓库并不复杂,但必须要细致,配置Maven详情 https://www.cnblogs.com/phpdragon/p/7216626.html

简单流程:(只显示了在IDEA层面操作的,实际上还要添加环境变量,配置setting.xml文件)

通过Local repository我们可以找到项目的依赖来源,即仓库具体地址,settings.xml设置的是自动下载jar包的存放地址

如果我们需要手动的修改Maven仓库里的东西,就在这里修改

言归正传,当我终于导好了项目所需要依赖时,再次点击运行,终于成功了!

未完待续…

今天在公司学习项目代码的时候看到了

private static final long serialVersionUID = 1L;
特此记录


1、首先谈谈为什么要序列化对象

– 把对象转换为字节序列的过程称为对象的序列化。
– 把字节序列恢复为对象的过程称为对象的反序列化。

对象的序列化主要有两种用途:
1) 把对象的字节序列永久地保存到硬盘上,通常存放在一个文件中;
2) 在网络上传送对象的字节序列。

在很多应用中,需要对某些对象进行序列化,让它们离开内存空间,入住物理硬盘,以便长期保存。比如最常见的是Web服务器中的Session对象,当有 10万用户并发访问,就有可能出现10万个Session对象,内存可能吃不消,于是Web容器就会把一些seesion先序列化到硬盘中,等要用了,再把保存在硬盘中的对象还原到内存中。

当两个进程在进行远程通信时,彼此可以发送各种类型的数据。无论是何种类型的数据,都会以二进制序列的形式在网络上传送。发送方需要把这个Java对象转换为字节序列,才能在网络上传送;接收方则需要把字节序列再恢复为Java对象

2、为什么要使用SerialversionUID呢

简单看一下 Serializable接口的说明

If a serializable class does not explicitly declare a serialVersionUID,
then the serialization runtime will calculate a default
serialVersionUID value for that class based on various aspects of the class,
as described in the Java(TM) Object Serialization Specification.

如果用户没有自己声明一个serialVersionUID,接口会默认生成一个serialVersionUID
However, it is stronglyrecommended that all serializable classes explicitly declareserialVersionUID values, since the default serialVersionUID computation is highly sensitive to class details that may vary depending on compiler implementations, and can thus result in unexpectedInvalidClassExceptions during deserialization.
但是强烈建议用户自定义一个serialVersionUID,因为默认的serialVersinUID对于class的细节非常敏感反序列化时可能会导致InvalidClassException这个异常。

其实也可以这样理解,相当于快递的打包和拆包,里面的东西要保持一致,不能人为的去改变他,不然就交易不成功。
序列化与反序列化也是一样,而版本号的存在就是要是里面内容要是不一致,不然就报错。像一个防伪码一样。