Fms-Java版开发实录:40 重构下载功能和编写About页面

Fms-Java版开发实录:40 重构下载功能和编写About页面

终于得空搞好了About页面,系统更加完整了。

目前的下载功能,是由业务层直接返回一个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文件的功能也分离出来,但是我懒得弄了。

按照项目下载数据

这里我依次进行了如下工作,代码就不放了:

  1. 业务层中添加public ByteArrayOutputStream getSingleProjectDownloadData(int pid)方法
  2. 在控制器中添加public ResponseEntity<byte[]> downloadAll(@PathVariable int id)方法
  3. Project类中添加下载URL生成方法
  4. 在项目详情页的右侧添加一个下载项目数据的链接
  5. 将原来项目列表页的“下载数据”按钮改成“下载全部数据”按钮

这样在列表页可以下载全部台账数据,点到每个项目中,可以下载该项目单独的数据,方便使用。

编写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">&nbsp;</div>
                <div class="col">&nbsp;</div>
            </div>
            <h5 class="m-2">
                <span class="badge rounded-circle bg-success border">&nbsp;</span>
            </h5>
            <div class="row h-50">
                <div class="col border-end">&nbsp;</div>
                <div class="col">&nbsp;</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">&nbsp;</div>
                <div class="col">&nbsp;</div>
            </div>
            <h5 class="m-2">
                <span class="badge rounded-circle bg-success border">&nbsp;</span>
            </h5>
            <div class="row h-50">
                <div class="col border-end">&nbsp;</div>
                <div class="col">&nbsp;</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">&nbsp;</div>
                <div class="col">&nbsp;</div>
            </div>
            <h5 class="m-2">
                <span class="badge rounded-circle bg-success border">&nbsp;</span>
            </h5>
            <div class="row h-50">
                <div class="col border-end">&nbsp;</div>
                <div class="col">&nbsp;</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">&nbsp;</div>
                <div class="col">&nbsp;</div>
            </div>
            <h5 class="m-2">
                <span class="badge rounded-circle bg-success border">&nbsp;</span>
            </h5>
            <div class="row h-50">
                <div class="col border-end">&nbsp;</div>
                <div class="col">&nbsp;</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">&nbsp;</div>
                <div class="col">&nbsp;</div>
            </div>
            <h5 class="m-2">
                <span class="badge rounded-circle border bg-primary">&nbsp;</span>
            </h5>
            <div class="row h-50">
<!--                控制每一行圆球下边的竖线-->
                <div class="col">&nbsp;</div>
                <div class="col">&nbsp;</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>

这里其实要关注第一个,中间的那些和最后一个的左侧圆点的上下竖线是如何控制的,以及更改背景和卡片边框的类。其实都比较简单,总结如下:

  1. 每个item里两组h-50类中的col类所在的div,第一组用来控制上边的竖线,第二组用来控制下边的竖线。
  2. span元素的背景用来控制圆点
  3. card类所在的div用来控制卡片的背景

好了,我现在就去把VPS上的系统更新到最新的1.0.4版。

LICENSED UNDER CC BY-NC-SA 4.0
Comment