查询的关键是查找哪些,现在我们有如下数据对象:
- 项目
- 预算
- 合同
- 收款和付款结算记录
- 明细记录
其实真正需要的,就是两个层级的内容,一个是项目,一个是合同,而且合同肯定是最经常查询的,为了方便,就把明细记录的说明也带上,这样就是需要查询三个内容:即项目名称,合同的名称,供应商等和明细记录的描述。
写到这里的时候我想到,由于目前导航条上有个搜索功能,但这个搜索功能很宽泛,最好还是单独使用一个搜索功能,那就继续给pms
包下边添加搜索功能,创建对应的控制器等。
Dao
类编写
查询需要一个SearchService
,很显然这个业务类需要用到项目、合同和明细记录的Dao
,所以一并包含进来,还需要在Dao
中添加查询方法。
JPA
的模糊查询
JPA
的模糊查询,使用的关键字是Containing
,而且要注意,如果使用Or
来连接多个字段,那么还需要为查询方法提供对应数量的参数。
在查询项目的时候,希望根据项目的名称和项目经理来查询,那么在ProjectDao
中编写的方法如下:
Set<Project> findAllByProjectNameContainingOrProjectManager(String t1, String t2);
这里的关键就是ProjectNameContaining
和ProjectAddressContaining
,中间用Or
关键字连接,两个字段的查找,需要传递两个参数。一开始我总是报错,就是卡在这个参数数量上。
知道了模糊查询,就可以很方便的在ContractDao
和JournalDao
中也添加上类似的方法,合同类中需要查询名称和四个供应商,所以方法很长:
Set<Contract> findAllByNameContainingOrSupplierContainingOrSecondarySupplier1ContainingOrSecondarySupplier2ContainingOrSecondarySupplier3Containing(
String t1, String t2, String t3, String t4, String t5);
明细记录就仅仅根据description
字段来进行搜索:
Set<Journal> findAllByDescriptionContaining(String target);
编写好Dao
之后,业务类的代码就省略了,下边来编写控制器。
控制器
控制器的代码比较简单,就是根据查询字符串来返回结果,这里就不用Post
请求了:
// 查询
@GetMapping("/pms/search")
public String searchResult(@RequestParam(value = "q", required = false) String target, Model model, RedirectAttributes attributes) {
if (target == null || target.trim().length() == 0) {
attributes.addFlashAttribute("error", "请输入非空白的内容");
return "pms/search/searchPage";
}
Set<Project> projects = projectService.projectSearchResult(target);
Set<Contract> contracts = contractService.contractSearchResult(target);
Set<Journal> journals = journalService.journalSearchResult(target);
model.addAttribute("projects", projects);
model.addAttribute("contracts", contracts);
model.addAttribute("journals", journals);
model.addAttribute("count", projects.size() + contracts.size() + journals.size());
return "pms/search/searchResult";
}
逻辑就是把查询字符串交给三个业务类查询,之后渲染到页面上就可以了。
页面编写
页面分为两个,一个搜索页,一个结果页,其实差不多。
搜索页
这个页面很简单:
<main class="container">
<nav style="--bs-breadcrumb-divider: '>';" aria-label="breadcrumb" class="mt-3">
<ol class="breadcrumb">
<li class="breadcrumb-item" aria-current="page"><a href="/pms/project/list" th:href="@{/pms/project/list}"
class="link-secondary">项目管理</a></li>
<li class="breadcrumb-item" aria-current="page"><a href="/pms/project/list" th:href="@{/pms/search}"
class="link-secondary">搜索</a></li>
</ol>
</nav>
<div class="row py-1">
<div class="col-sm-4"></div>
<div th:if="${error}" class="text-center alert alert-danger col-12 col-sm-4" role="alert">
[[${error}]]
</div>
<div class="col-sm-4"></div>
</div>
<div class="py-5 text-center row">
<h2>搜索 项目管理</h2>
<p class="lead">
可搜索项目名称、供应商、合同名称,明细记录说明
</p>
<div class="col-sm-2"></div>
<div class="col-sm-8">
<form method="get" th:action="@{/pms/search}" class="input-group mb-3">
<input type="text" class="form-control" name="q" aria-describedby="submit-button" required>
<button class="btn btn-outline-success" type="submit"><i class="fas fa-search"></i> 搜索</button>
</form>
</div>
<div class="col-sm-2"></div>
</div>
</main>
结果页面
这个页面其实就加上了展示结果,以及几个判断,设计页面的美术能力不太行,这里就用了三个列表直接列出来完事:
<main class="container">
<div class="row py-1">
<div class="col-sm-4"></div>
<div th:if="${error}" class="text-center alert alert-danger col-12 col-sm-4" role="alert">
[[${error}]]
</div>
<div class="col-sm-4"></div>
</div>
<nav style="--bs-breadcrumb-divider: '>';" aria-label="breadcrumb" class="mt-3">
<ol class="breadcrumb">
<li class="breadcrumb-item" aria-current="page"><a href="/pms/project/list" th:href="@{/pms/project/list}"
class="link-secondary">项目管理</a></li>
<li class="breadcrumb-item" aria-current="page"><a href="/pms/project/list" th:href="@{/pms/search}"
class="link-secondary">搜索</a></li>
</ol>
</nav>
<div class="py-5 text-center row">
<div class="col-sm-2"></div>
<div class="col-sm-8">
<div class="row text-center" th:if="${count==0}">
<h3>未找到任何数据</h3>
</div>
<div class="row text-center" th:if="${count!=0}">
<h3>搜索结果</h3>
</div>
<form method="get" th:action="@{/pms/search}" class="input-group mb-3">
<input type="text" class="form-control" name="q" aria-describedby="submit-button" required>
<button class="btn btn-outline-success" type="submit"><i class="fas fa-search"></i></button>
</form>
</div>
<div class="col-sm-2"></div>
<Hr th:if="${count!=0}">
<div class="row" th:if="${count!=0}">
<div class="col-md-6 col-sm-12 mb-2" th:if="${projects.size()!=0}">
<h3>项目</h3>
<ul class="list-group">
<li th:each="project: ${projects}" class="list-group-item"><a href="#" th:href="${project.absoluteUrl()}" th:text="${project.projectName}"></a></li>
</ul>
</div>
<div class="col-md-6 col-sm-12 mb-2" th:if="${contracts.size()!=0}">
<h3>合同</h3>
<ul class="list-group">
<li th:each="contract: ${contracts}" class="list-group-item"><a href="#" th:href="${contract.absoluteUrl()}" th:text="${contract.name}"></a></li>
</ul>
</div>
<div class="col-md-6 col-sm-12 mb-2" th:if="${journals.size()!=0}">
<h3>明细记录</h3>
<ul class="list-group">
<li th:each="journal: ${journals}" class="list-group-item"><a href="#" th:href="${journal.absoluteUrl()}" th:text="${journal.description}"></a></li>
</ul>
</div>
</div>
</div>
</main>
查询结果的页面样式如下:
用一个count
来控制是否找到结果。
然后再把导航条调整一下,将其调整为快速搜索功能:
<form class="d-flex" method="get" th:action="@{/pms/search}" action="/pms/search">
<input class="form-control me-2" name="q" type="search" placeholder="快速搜索">
<button class="btn btn-outline-success" type="submit"><i class="fas fa-search"></i></button>
</form>
这样就写好了搜索功能。也是目前项目管理功能的最后一块拼图了。
修改印花税的初始化功能
我在打包成jar
包之后,在测试的时候发现,有印花税中的汉字写入到数据库中,会出现乱码,这可能是每个人的环境不同,为了保证能够成功,我就把初始化印花税的代码转移到了初始化的时候注册管理员的控制器中。详细如下:
Stamp
中添加构造器
注意Hibernate
需要一个无参构造器,这里添加构造器如下:
public Stamp(String type, BigDecimal rate) {
this.type = type;
this.rate = rate;
}
public Stamp() {
}
修改控制器
在InitializationController
中的adminRegister
方法中,添加如下代码:
// 写入印花税信息
if (stampService.count() == 0) {
stampService.saveStamp(new Stamp("购销合同", new BigDecimal("0.00030")));
stampService.saveStamp(new Stamp("加工承揽合同", new BigDecimal("0.00050")));
stampService.saveStamp(new Stamp("建设工程勘察设计合同", new BigDecimal("0.00050")));
stampService.saveStamp(new Stamp("建筑安装工程承包合同", new BigDecimal("0.00030")));
stampService.saveStamp(new Stamp("财产租赁合同", new BigDecimal("0.00100")));
stampService.saveStamp(new Stamp("货物运输合同", new BigDecimal("0.00050")));
stampService.saveStamp(new Stamp("仓储保管合同", new BigDecimal("0.00100")));
stampService.saveStamp(new Stamp("借款合同", new BigDecimal("0.00005")));
stampService.saveStamp(new Stamp("财产保险合同", new BigDecimal("0.00003")));
stampService.saveStamp(new Stamp("技术合同", new BigDecimal("0.00030")));
stampService.saveStamp(new Stamp("产权转移书据", new BigDecimal("0.00050")));
stampService.saveStamp(new Stamp("无需缴纳", new BigDecimal("0.00000")));
}
关于计数,可以直接使用StampDao
提供的方法:
@Transactional
public long count() {
return stampDao.count();
}
最后就是在dataInitialize.sql
中删除印花税的内容。
至此终于算告一段落了。