最近在开发React UmiJS前端项目,后端是springboot。
简要记录下开发流程。
下方代码的名称有的是框架固定的,有的是自己起的。
一、需求
需要在列表页新增2个筛选条件框,以及在列表页新增1列。
要筛选出学员公司(tree,一级是公司,二级是分公司,多选)、学员类型(多选);要在列表页新增"学员类型"列(学员公司列之前就已经展示出来了)。
二、开发过程
1.下载Visual Studio Code,打开待开发项目。(推荐用这个工具,搜索文件与代码很快;之前试着用Hbuilder开发,搜索太慢了,实在影响效率)
2.找到列表页所在的js文件,有以下几种方法:
(1)搜索页面中文关键字,可以找到zh-CN.js文件;
'StudentPage.studentName': '学生姓名',
然后再搜索"StudentPage.studentName",就能找到页面所在的js文件了,例如某个目录下的querySimple.js;
<FormItem label={<FormattedMessage id="StudentPage.studentName" />}>
{getFieldDecorator('studentName_equals',{
initialValue: queryPara.studentName_equals,
})(
<Input
placeholder={
formatMessage({id: 'global.input.placeholder' }) +
formatMessage({id: 'StudentPage.studentName' })
}
allowClear
autoComplete="off"
/>
)}
</FormItem>
这段代码对应页面上的一个学生姓名input输入框。
(2)可以搜索文件:项目路径/config/router.config.js,其中有前端页面的url。(如果格式规范的话,url中的名称对应页面js的名称)
3.按照上方的方法,找到了筛选条件框的页面,querySimple.js,然后增加2个筛选条件框,一个是包含TreeSelect的复选框,一个是普通Select复选框;代码如下:
<FormItem label={<FormattedMessage id="StudentPage.studentCom" />}>
{getFieldDecorator('studentCom_in',{
initialValue: queryPara.studentCom_in,
})(
<TreeSelect
dropdownStyle={(maxHeight: 400, overflow: 'auto')}
treeData={codeselect.managecomTreeData}
treeCheckable
showCheckedStrategy={SHOW_PARENT}
allowClear
treeDefaultExpandedKeys={[
codeselect.managecomTreeData[0] ? codeselect.managecomTreeData[0].key : null,
]}
placeholder={
formatMessage({id: 'global.input.placeholder' }) +
formatMessage({id: 'StudentPage.studentCom' })
}
/>
)}
</FormItem>
<FormItem label={<FormattedMessage id="StudentPage.studentType" />}>
{getFieldDecorator('studentType_in',{
initialValue: queryPara.studentType_in,
})(
<Select
showSearch
mode="multiple"
optionFilterProp="children"
filterOption={ (input,option) =>
option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0
}
placeholder={
formatMessage({id: 'global.input.placeholder' }) +
formatMessage({id: 'StudentPage.studentType' })
}
onChange={this.handleChange}
>
{codeselect.studentType.map(item => (
<Select.Option key ={item.codeValue}>{item.codeName}</Select.Option>
))}
</Select>
)}
</FormItem>
需要注意,其中"_in"是有含义的,多选用;如果是单选框,就用"_equals",也有含义。下方会讲解。
同时,这个文件中还修改了其它内容,记录如下:
//增加TreeSelect
import {Form, Input, DatePicker, Select, TreeSelect, Button, Icon} from 'antd';
//增加const
const {SHOW_PARENT} = TreeSelect;
4.按照上方方法,找到列表页所在的js文件,某个目录下的homeTable.js,增加了内容,记录如下:
{
title: formatMessage({ id: 'StudentPage.studentType' }),
dataIndex: 'studentType',
align: 'center',
width: 100,
render: (text) => {
return this.parseStudentType(text)
}
}
还增加了方法parseStudentType(),记录如下:
parseStudentType = (value) => {
if( value==null || value== "" || value == undefined || value == "undefined" ){
return "其它";
}
const {codeselect} = this.props
const arr = value.split(",")
const strArr = []
// eslint-disable-next-line no-plusplus
for(let i = 0; i < arr.length; i++){
// eslint-disable-next-line no-plusplus
for(let j = 0; j < codeselect.studentType.length; j++){
if(arr[i] === codeselect.studentType[j].codeValue){
strArr.push(
codeselect.studentType[j].codeName
)
}
}
}
return strArr.join(",")
}
5.修改java后台代码,springboot,通过搜索请求url找到后台代码要修改的文件;对应代码记录如下:
@GetMapping("/stu-msg-search")
@Timed
public ResponseEntity<List<StudentDTO>> getAllStudent(StudentCriteria criteria, Pageable pageable){
log.debug("REST request to get AllStudent by criteria: {}", criteria);
Page<StudentDTO> page = studentService.findByCriteria(criteria, pageable);
HttpHeaders headers = PaginationUtil.generatePaginationHttpHeaders(page, "/api/stu-msg-search");
return ResponseEntity.ok().headers(headers).body(page.getContent());
}
6.查看第5步中的StudentCriteria.java类,发现其中有两类变量:
public class StudentCriteria implements Serializable {
private LongFilter id;
private StringFilter studentName;
private InstantFilter dueStartTime;
private InstantFilter dueFinishTime;
private StringFilter studentType;
}
其中,LongFilter是接收数字的对象;InstantFilter是接收时间的对象;StringFilter是接收字符串的对象;
(1)例如,前端传键值对,参数为:
dueFinishTime.greaterOrEqualThan: 2021-04-08T16:00:00.000Z
dueFinishTime.lessOrEqualThan: 2021-04-09T18:00:00.000Z
studentType.equals: xxx
studentType.in[0]: 1
studentType.in[1]: 3
studentType.in[2]: 9
(2)后台查看StudentCriteria对象,可以发现其中的studentName变量中的equals变量中有内容,为xxx;
其中的dueFinishTime中的变量中的greaterOrEqualThan与lessOrEqualThan变量有内容,为传入的时间(Instant类型)
其中的studentType变量中的in变量中有值,为传入的数组1,3,9.
(3)所以在前端代码中,"_in"的意思就是最后发出".in"的键值对,后台才能正常接收;相应的也可以写"_equals",发出的键值对就为".equals"。
(4)后台后续处理为,将StudentCriteria对象转为Specification对象,然后把Specification对象传入数据库查询jpa方法中;后台数据库查询方法是hibernate,Specification对象在spring-data-jpa-2.0.12.RELEASE.jar包中。
Specification<Student> specification = Specification.where(null);
if(studentCriteria != null){
if(studentCriteria.getDueFinishTime() != null) {
//Range,注意这个是buildRangeSpecification,是jhipster-framework-2.0.29.jar中的方法
specification = specification.and(buildRangeSpecification(studentCriteria.getDueFinishTime(), Student_.dueFinishTime));
}
if(studentCriteria.getStudentName() != null) {
//String,注意这个是buildStringSpecification,是jhipster-framework-2.0.29.jar中的方法
specification = specification.and(buildStringSpecification(studentCriteria.getStudentName(), Student_.studentName));
}
}
return studentRepository.findAll(specification, page).map(studentMapper::toDto);
三、总结
本项目前端是React UmiJS;
后端是springboot,用到了hibernate、jpa、jhipster等;
有些地方本人也没有看懂,因此以日记形式记录一下,后续有空再完善。
需要记录的几点:
1.UmiJS中的"导出"按钮与"选择展示的列"按钮不需要特殊处理,当本人在代码中增加了显示的列后,这两个按钮也会自动增加相应的列。
2.下拉菜单中展示的内容、展示的tree树,都是在数据库中配置的,没有在前端写死。
3.UmiJS中的"查询"按钮与"重置"按钮也没有特殊修改,当本人在代码中增加了2个筛选条件框后,"查询"可以将增加的值传给后台,"重置"也可以重置新增的筛选框。