目前的下载功能,是由业务层直接返回一个Http
响应,控制器什么也没干。我这里打算再分离一下,就是让业务层仅仅只返回打包好的数据,让控制器去干设置响应的事情。这样就更加清晰一些。
重构下载功能
核心就是只保留业务层生成那个数据流的功能。之后的处理响应让控制器来做即可。
业务层精简内容
既然是返回数据,业务层的所有下载方法,只需要返回ByteArrayOutputStream
即可。所以就把原来的方法简化一些。
首先把
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
SimpleDateFormat formatMonth = new SimpleDateFormat("yyyy-MM");
这两个玩意拿到业务类里,变成public static final当两个工具类就行了,运行一次后边就反复用了。写到这里发现以后还得编写几个工具类。
然后就精简函数,修改成如下:
@Transactional
public ByteArrayOutputStream getAllProjectDownloadData() {
XSSFWorkbook result = new XSSFWorkbook();
// 创建项目数据工作表并写入数据
XSSFSheet sheet = result.createSheet("项目数据");
List<ProjectData> projectDataList = new ArrayList<>();
projectService.findAllProjects().forEach(project -> projectDataList.add(projectService.getProjectDataById(project.getId())));
......
......
\\将生成的工作簿写入到字节流中
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
try (outputStream) {
result.write(outputStream);
} catch (IOException e) {
e.printStackTrace();
}
return outputStream;
}
修改控制器
在控制器这里,由于知道拿到的都是字节流,因此我们写一个类里的方法,专门用来生成Http响应就完事了。这个方法其实就是原来业务方法里剩下的部分,如下:
private ResponseEntity<byte[]> wrapDataToHttpResponse(ByteArrayOutputStream outputStream, String name) {
HttpHeaders httpHeaders = new HttpHeaders();
Date date = new Date();
String fileName = new String((name + DownloadService.format.format(date) + ".xlsx").getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1);
httpHeaders.setContentDispositionFormData("attachment", fileName);
httpHeaders.setContentType(MediaType.APPLICATION_OCTET_STREAM);
return new ResponseEntity<>(outputStream.toByteArray(), httpHeaders, HttpStatus.CREATED);
}
之后再修改一下下载的控制器:
@GetMapping("/all")
public ResponseEntity<byte[]> downloadAll() throws IOException {
return wrapDataToHttpResponse(downloadService.getAllProjectDownloadData(),"合同台账");
}
你可能已经猜到我分离了文件名出来要做什么,其实就是为了将来编写更细的功能,比如按照项目来下载一个项目的台账。这个功能其实也很简单,我直接就给写完了,不过这里真的想到应该继续优化,需要把组装Excel
文件的功能也分离出来,但是我懒得弄了。
按照项目下载数据
这里我依次进行了如下工作,代码就不放了:
- 业务层中添加
public ByteArrayOutputStream getSingleProjectDownloadData(int pid)
方法 - 在控制器中添加
public ResponseEntity<byte[]> downloadAll(@PathVariable int id)
方法 Project
类中添加下载URL
生成方法- 在项目详情页的右侧添加一个下载项目数据的链接
- 将原来项目列表页的“下载数据”按钮改成“下载全部数据”按钮
这样在列表页可以下载全部台账数据,点到每个项目中,可以下载该项目单独的数据,方便使用。
编写About
页面
现在终于可以来搞一下About
页面了。在导航条中添加链接和控制器的代码就不再放了。关键是页面,这里我从一个Pure Bootstrap 5 Timeline no Custom css
视频里抄了代码,发现果然好用。这个视频里是用上下两个方块,一个圆,下边再两个方块,侧面排一个card
组件来实现的。如果需要调节上下两边的线条,就加上类即可,还可以自定义圆点的背景和卡片的边框,也确实做到了视频标题里所说的不添加任何自定义的样式。
代码如下:
<main class="container">
<h2 class="font-weight-light text-center text-muted py-3">
系统版本说明
</h2>
<!-- Time line item -->
<div class="row">
<div class="col-auto text-center flex-column d-none d-sm-flex">
<div class="row h-50 ">
<div class="col"> </div>
<div class="col"> </div>
</div>
<h5 class="m-2">
<span class="badge rounded-circle bg-success border"> </span>
</h5>
<div class="row h-50">
<div class="col border-end"> </div>
<div class="col"> </div>
</div>
</div>
<div class="col py-2">
<div class="card border-success">
<div class="card-body ">
<div class="float-end">2021-10-22</div>
<h4 class="card-title text-muted">1.0.4</h4>
<p class="card-text text-muted">在项目详情页面添加下载某个项目全部数据的功能。上线本页面。</p>
</div>
</div>
</div>
</div>
<!-- Time line item -->
<div class="row">
<div class="col-auto text-center flex-column d-none d-sm-flex">
<div class="row h-50 ">
<div class="col border-end"> </div>
<div class="col"> </div>
</div>
<h5 class="m-2">
<span class="badge rounded-circle bg-success border"> </span>
</h5>
<div class="row h-50">
<div class="col border-end"> </div>
<div class="col"> </div>
</div>
</div>
<div class="col py-2">
<div class="card border-success">
<div class="card-body ">
<div class="float-end">2021-10-20</div>
<h4 class="card-title text-muted">1.0.3</h4>
<p class="card-text text-muted">在下载数据中增加自动计算出的印花税金额。</p>
</div>
</div>
</div>
</div>
<!-- Time line item -->
<div class="row">
<div class="col-auto text-center flex-column d-none d-sm-flex">
<div class="row h-50 ">
<div class="col border-end"> </div>
<div class="col"> </div>
</div>
<h5 class="m-2">
<span class="badge rounded-circle bg-success border"> </span>
</h5>
<div class="row h-50">
<div class="col border-end"> </div>
<div class="col"> </div>
</div>
</div>
<div class="col py-2">
<div class="card border-success">
<div class="card-body">
<div class="float-end">2020-10-11</div>
<h4 class="card-title text-muted">1.0.2</h4>
<p class="card-text text-muted">新增合同编号的时候自动将全角括号替换为半角括号。修改判断合同总价,不含税价和税额的BUG。添加显示某个项目的全部合同列表的功能。</p>
</div>
</div>
</div>
</div>
<!-- Time line item -->
<div class="row">
<div class="col-auto text-center flex-column d-none d-sm-flex">
<div class="row h-50 ">
<div class="col border-end"> </div>
<div class="col"> </div>
</div>
<h5 class="m-2">
<span class="badge rounded-circle bg-success border"> </span>
</h5>
<div class="row h-50">
<div class="col border-end"> </div>
<div class="col"> </div>
</div>
</div>
<div class="col py-2">
<div class="card border-success">
<div class="card-body">
<div class="float-end">2020-10-08</div>
<h4 class="card-title text-muted">1.0.1</h4>
<p class="card-text text-muted">在下载数据中增加印花税税目。</p>
</div>
</div>
</div>
</div>
<!-- Time line item -->
<div class="row">
<div class="col-auto text-center flex-column d-none d-sm-flex">
<div class="row h-50 ">
<!-- 控制每一行圆球上边的竖线-->
<div class="col border-end"> </div>
<div class="col"> </div>
</div>
<h5 class="m-2">
<span class="badge rounded-circle border bg-primary"> </span>
</h5>
<div class="row h-50">
<!-- 控制每一行圆球下边的竖线-->
<div class="col"> </div>
<div class="col"> </div>
</div>
</div>
<div class="col py-2">
<div class="card border-primary">
<div class="card-body">
<div class="float-end">2020-09-10</div>
<h4 class="card-title text-muted text-primary">1.0.0</h4>
<p class="card-text text-muted">1.0版本上线,包含完整用户功能,管理员配置功能和合同台账功能。</p>
</div>
</div>
</div>
</div>
</main>
这里其实要关注第一个,中间的那些和最后一个的左侧圆点的上下竖线是如何控制的,以及更改背景和卡片边框的类。其实都比较简单,总结如下:
- 每个
item
里两组h-50
类中的col
类所在的div,第一组用来控制上边的竖线,第二组用来控制下边的竖线。 span
元素的背景用来控制圆点card
类所在的div
用来控制卡片的背景
好了,我现在就去把VPS上的系统更新到最新的1.0.4版。