基于 Spring Boot 的四则运算 API
一、产品说明
1. 简介
该四则运算API支持任意位数的数字之间的四则运算,支持小数运算。
它没有数据溢出或精度丢失问题。
(用它计算0.2+0.1,结果是0.3,Amazing!)
2. 使用方法
在计算器界面的输入框中输入符合运算法则的数字,点击“提交"即可在网页上得到运算结果。
以下是使用过程中会出现的一些特殊情况:
(1) 如果用户在输入框中输入的不是纯数字,或者什么也没输入,则会提醒用户“请输入数字捏”。
(2) 如果用户输入的除数为0,则会提醒用户“不能除以0哦”。
(非常的人性化,对吧)
二、学习历程
1. 基本功能实现
第一次培训上学习了加法的API,遂照葫芦画瓢写出了四则运算的API,完工!
当然,这样的API是不完美的,尤其是它计算0.2+0.1会得到0.30000000000000004,也就是说,它存在精度丢失问题。
通过查询资料,我找到了两种解决该问题的方式:
(1) 将可能出现误差的位舍去,简单粗暴。
(2) 使用java.math包中的BigDecimal类进行高精度运算。
后者不仅能提升精度,还能解决数据溢出问题,属于是一举两得,因此我选择了这种方式。
为避免double类型导致的数据精度丢失,BigDecimal类的构造方法最好用String类型的参数。于是,我把用户输入的数据类型改成了String。接下来的问题是,如果用户输入的不是纯数字或者根本没输东西,会出现异常。怎么能在页面上提示用户输入正确的数字呢?
一开始,我想用try catch实现这个功能,但我Controller里面的方法返回值类型是double,要catch异常并返回一句提示的话,返回值得是String才行。在我即将对我的代码进行大刀阔斧的改革的时候,我发现了这个东西:
@ExceptionHandler
哦,我的上帝,这个注解真的太棒了,省去了我修改代码的时间,也让代码更简洁了。虽然我也不明白它是怎么让方法的返回值显示在屏幕上的,但我并不关心这个,好用就行(
至于用户输入的除数为0导致的异常,我决定先加一个判断除数是否为0的步骤,若除数不是0再进行除法。这样除数为0就不会抛异常,不会由@ExceptionHandler来处理。也就是说,除数为0时的提示语可以单独设置,这下更人性化了。
在我测试数据的时候,又发现了新的问题:
使用BigDecimal类的除法如果得到的是无限循环小数,会出现异常。
一开始,我并不知道异常产生的原因。有的测试数据得出的是正确的结果,有的数据则是异常,让我困惑不已。查询资料后才发现是无限循环小数的问题,解决方法是保留固定位数小数。在设置固定位数后,计算结果本身若没有精确到设定的小数位数,后面会跟一堆0,解决方法也很简单,stripTrailingZeros方法即可去除多余的0。
至此,基本功能已经实现的差不多了。探索更优解的道路上充满了曲折,其间遇见了一些我解决不了的问题,但在不断地尝试与搜集资料下,终于突破阻碍,拨云见日。
2. 稍微完善一下
首先,按照群里的模版写(抄)了一个前端,并用舍友传授给我的CSS知识美化了一下界面。(纯粹是我闲的,并没有在卷视觉效果)
然后,把页面上显示的运算结果改成了运算式,这样看起来会好一些,也许。
至于GET注入,在这个API里是不存在的,因为输入的数据如果不是纯数字就会抛异常并提醒用户。
最后,对于作业要求里的生成接口文档,我尝试了一下,链接在这:
显然,它并不完善。嗯,就这样吧,忙大作业去了。
Goodbye.
走之前把代码留下吧。
三、代码
1. MainController 类
package com.example.demo.controller;
import com.example.demo.service.MainService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.math.BigDecimal;
@RestController
public class MainController {
@Autowired
MainService mainService;
private String str = "请输入数字捏";
@ExceptionHandler(Exception.class)
public String exceptionHandler() {
return str;
}
// 若用户输入的不是纯数字或什么也没输入,提示用户输入数字
@GetMapping("/add")
public String add(@RequestParam String a, @RequestParam String b) {
return mainService.add(a, b);
}
@GetMapping("/subtract")
public String subtract(@RequestParam String a, @RequestParam String b) {
return mainService.subtract(a, b);
}
// 用户输入的数据类型为String,方便BigDecimal函数的构造
@GetMapping("/multiply")
public String multiply(@RequestParam String a, @RequestParam String b) {
return mainService.multiply(a, b);
}
@GetMapping("/divide")
public String divide(@RequestParam String a, @RequestParam String b) {
return mainService.divide(a, b);
}
}
2. MainService 类
package com.example.demo.service;
import com.sun.jdi.event.ExceptionEvent;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestParam;
import java.math.BigDecimal;
@Service
public class MainService {
public String add(String a, String b) {
return a + "+" + b + "=" + new BigDecimal(a).add(new BigDecimal(b)).toString();
}
public String subtract(String a, String b) {
return a + "-" + b + "=" + new BigDecimal(a).subtract(new BigDecimal(b)).toString();
}
public String multiply(String a, String b) {
return a + "×" + b + "=" + new BigDecimal(a).multiply(new BigDecimal(b)).toString();
}
private String str = "不能除以0哦";
public String divide(String a, String b) {
BigDecimal valOfB = new BigDecimal(b);
if (valOfB.compareTo(BigDecimal.ZERO) == 0) {
return str;
// 若用户输入的除数为0,提示用户不能除以0
} else {
BigDecimal result = new BigDecimal(a).divide(valOfB, 10, BigDecimal.ROUND_HALF_UP);
// 保留10位小数,四舍五入。若无保留位数,运算结果出现无限循环小数时会报错
return a + "÷" + b + "=" + result.stripTrailingZeros().toPlainString();
// 去掉小数点后多余的0,toPlainString避免科学计数法
}
}
}
3. 前端页面
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>四则运算</title>
<style>
form,input {
font-size: large;
}
h1 {
margin: 20px 0px;
display: inline-block;
}
#p1,
#p2 {
display: flex;
justify-content: space-evenly;
}
#p1 {
margin: 20px 0px;
}
input {
margin-top: 20px;
}
</style>
</head>
<body>
<div id="p1">
<div>
<h1>加法</h1>
<form action="http://localhost:8080/add" method="get">
第一个加数:<input type="text" name="a"><br>
第二个加数:<input type="text" name="b"><br>
<input type="submit" value="提交">
</form>
</div>
<div>
<h1>减法</h1>
<form action="http://localhost:8080/subtract" method="get">
被 减 数:<input type="text" name="a"><br>
减 数:<input type="text" name="b"><br>
<input type="submit" value="提交">
</form>
</div>
</div>
<div id="p2">
<div>
<h1>乘法</h1>
<form action="http://localhost:8080/multiply" method="get">
第一个乘数:<input type="text" name="a"><br>
第二个乘数:<input type="text" name="b"><br>
<input type="submit" value="提交">
</form>
</div>
<div>
<h1>除法</h1>
<form action="http://localhost:8080/divide" method="get">
被 除 数:<input type="text" name="a"><br>
除 数:<input type="text" name="b"><br>
<input type="submit" value="提交">
</form>
</div>
</div>
</body>
</html>
Goodbye again.