Vue前端页面日期时间控件修改以及后端Java程序相关修改
一 项目架构说明
新手直接上手项目,前端采用Vue框架+后端springboot架构。硬着头皮边学边用,天天都是瓶颈。
二 问题说明
在前面记录分享的两个案例中「Vue前端页面错误[Vue warn]: Invalid prop: custom validator check failed for prop “value”.解决
前端页面上使用的是日期控件:<a-range-picker></a-range-picker>。这样,当前端选择起始时间和终止时间相同的话,则后端Java程序收到的SQL语句类似于:
2021-06-28 17:24:55.716 [http-nio-7083-exec-8] DEBUG org.postgresql.jdbc.PgConnection - - - - setAutoCommit = false 2021-06-28 17:24:55.717 [http-nio-7083-exec-8] DEBUG com.onlyou.sam.flow.mapper.SamInterfaceRelMapper.countOperationLogByCondition - - - - ==> Preparing: SELECT id FROM t_es_sam_interface_rel WHERE 1 = 1 AND create_ts between ? and ? 2021-06-28 17:24:55.737 [http-nio-7083-exec-8] DEBUG com.onlyou.sam.flow.mapper.SamInterfaceRelMapper.countOperationLogByCondition - - - - ==> Parameters: 2021-04-27 08:00:00.0(Timestamp), 2021-04-27 08:00:00.0(Timestamp) 2021-06-28 17:24:55.742 [http-nio-7083-exec-8] DEBUG com.onlyou.sam.flow.mapper.SamInterfaceRelMapper.countOperationLogByCondition - - - - <== Total: 0 2021-06-28 17:24:55.744 [http-nio-7083-exec-8] DEBUG org.postgresql.jdbc.PgConnection - - - - setAutoCommit = true
那么问题就来了,如果我们的数据库中有满足条件的数据,结果却查询不到数据。因为,从后台程序可以日志可以看到,前端页面上选择的时间,最后传递过来变成了:2021-04-27 08:00:00.0(Timestamp), 2021-04-27 08:00:00.0(Timestamp)。
三 分析问题
1 从后端来看,首先是前端传递过来的参数格式没有带时分秒格式
chrome控制台上看到传递给后端的参数:控制台选择network选项卡,点击请求页面地址,选择Headers,在最下方查看。
{pageSize: 10, currentPage: 1, keyWord: "", condition: {beginDt: "2021-06-28", endDt: "2021-06-28"}}
condition: {beginDt: "2021-06-28", endDt: "2021-06-28"}
beginDt: "2021-06-28"
endDt: "2021-06-28"
currentPage: 1
keyWord: ""
pageSize: 10
2 更改前端页面空间,可以输入时分秒
搜索引擎搜索,或者ant design官网,搜索:datepicker
https://www.antdv.com/components/date-picker-cn/#DatePicker-
找到有可以输入日期+时间的控件,看看示例的源代码,然后,结合我们当前的页面,进行对应的更改。
//示例代码: <template> <div> <a-date-picker show-time placeholder="Select Time" @change="onChange" @ok="onOk" /> <br /> <a-range-picker :show-time="{ format: 'HH:mm' }" format="YYYY-MM-DD HH:mm" :placeholder="['Start Time', 'End Time']" @change="onChange" @ok="onOk" /> </div> </template> <script> export default { methods: { onChange(value, dateString) { console.log('Selected Time: ', value); console.log('Formatted Selected Time: ', dateString); }, onOk(value) { console.log('onOk: ', value); }, }, }; </script>
//我的代码 <a-form-model-item > <a-range-picker v-model="searchDates" format="YYYY-MM-DD " class="select-col" :placeholder="['创建开始时间', '结束时间']" allowClear /> </a-form-model-item>
这样,我照着官网的实例,将我的代码format=”YYYY-MM-DD “改为format=”YYYY-MM-DD HH:mm:ss”。然后保存代码,在chrome页面,时间控件上,就可以选择时间了。
但是,此时,传递给后端的时间格式还是没有时分秒的。
3 控制前端页面可以传递时分秒给后端Java
分析代码之后,看到watch监控代码中,控制时间组件的方法:
watch: { searchDates: { handler(dates) { //如果清除掉日期,dates的值为空数组 if (!Array.isArray(dates)) { this.searchPage.beginDt = '' this.searchPage.endDt = '' return } if (dates.length > 0) { //因为目前antd返回的是 moment类型,所以需要进行格式化 let startDateMoment = this.$moment(dates[0]) let endDateMoment = this.$moment(dates[1]) this.searchPage.beginDt = startDateMoment.format('YYYY-MM-DD') this.searchPage.endDt = endDateMoment.format('YYYY-MM-DD') } else { this.searchPage.beginDt = ''; this.searchPage.endDt = ''; } }, }, },
将其中的2行代码:
this.searchPage.beginDt = startDateMoment.format('YYYY-MM-DD'), this.searchPage.endDt = endDateMoment.format('YYYY-MM-DD')
改为:
this.searchPage.beginDt = startDateMoment.format('YYYY-MM-DD HH:mm:ss'), this.searchPage.endDt = endDateMoment.format('YYYY-MM-DD HH:mm:ss')
都加上时间格式就好了,这样前端传递给后台的数据中,时间就包含了年月日时分秒的格式了。
{pageSize: 10, currentPage: 1, keyWord: "",…}
condition: {beginDt: "2021-06-29 10:00:12", endDt: "2021-06-29 10:00:12"}
beginDt: "2021-06-29 10:00:12"
endDt: "2021-06-29 10:00:12"
currentPage: 1
keyWord: ""
pageSize: 10
四 Java后端修改
前端的日期数据格式处理好了之后,接下来开始处理后端Java程序了。
1 后端接收到的数据处理格式报错
2021-06-29 10:00:37.370 [http-nio-7083-exec-3] WARN org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver - - - - Resolved [org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot deserialize value of type `java.util.Date` from String "2021-06-29 10:00:12": not a valid representation (error: Failed to parse Date value '2021-06-29 10:00:12': Cannot parse date "2021-06-29 10:00:12": while it seems to fit format 'yyyy-MM-dd'T'HH:mm:ss.SSSZ', parsing fails (leniency? null)); nested exception is com.fasterxml.jackson.databind.exc.InvalidFormatException: Cannot deserialize value of type `java.util.Date` from String "2021-06-29 10:00:12": not a valid representation (error: Failed to parse Date value '2021-06-29 10:00:12': Cannot parse date "2021-06-29 10:00:12": while it seems to fit format 'yyyy-MM-dd'T'HH:mm:ss.SSSZ', parsing fails (leniency? null))
at [Source: (PushbackInputStream); line: 1, column: 68] (through reference chain: com.onlyou.sam.common.vo.PageVO["condition"]->com.onlyou.sam.flow.vo.InterfaceRelVO["beginDt"])]
从Google搜索引擎上获取相关的参考:
于是找到后端Java代码里对应的View Object类,将其对应接收数据的属性,加上响应的注解:
2 修改Java类上相关字段添加JSON注解
修改前:
/** * 添加带时间范围查询字段 * 2021.06.25 Asher Huang */ private Date beginDt; private Date endDt;
修改后:
/** * 添加带时间范围查询字段 * 2021.06.25 Asher Huang */ //添加@JsonFormat解决前端传递过来的时间格式,之前传递的是日期,现在改为时间日期格式。 @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss") private Date beginDt; @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss") private Date endDt
修改后,测试发现,后端执行了下述的SQL语句,没有返回任何数据给前端。
2021-06-29 10:12:40.922 [http-nio-7083-exec-2] DEBUG com.onlyou.sam.flow.mapper.SamInterfaceRelMapper.countOperationLogByCondition - - - - ==> Preparing: SELECT id FROM t_es_sam_interface_rel WHERE 1 = 1 AND create_ts between ? and ?
2021-06-29 10:12:40.924 [http-nio-7083-exec-2] DEBUG com.onlyou.sam.flow.mapper.SamInterfaceRelMapper.countOperationLogByCondition - - - - ==> Parameters: 2021-06-29 18:00:12.0(Timestamp), 2021-06-29 18:00:12.0(Timestamp)
2021-06-29 10:12:40.926 [http-nio-7083-exec-2] DEBUG com.onlyou.sam.flow.mapper.SamInterfaceRelMapper.countOperationLogByCondition - - - - <== Total: 0
2021-06-29 10:12:40.927 [http-nio-7083-exec-2] DEBUG org.postgresql.jdbc.PgConnection - - - - setAutoCommit = true
究其原因是,前端发送的时间数据是:”2021-06-29 10:00:12″,后端接收到的数据是:2021-06-29 18:00:12.0(Timestamp),差了8个时区,进而导致数据不对。
3 Java类字段添加JSON的时区注解
继续Google之后,发现给VO类的时间字段的json注解,添加时区属性即可。
/** * 添加带时间范围查询字段 * 2021.06.25 Asher Huang */ //添加@JsonFormat解决前端传递过来的时间格式,之前传递的是日期,现在改为时间日期格式。带上时区,解决时差8小时的问题 @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss",timezone = "GMT+8") private Date beginDt; @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss",timezone = "GMT+8") private Date endDt;
然后,经过测试,后端程序接收到的数据就正常了,和前端发送的数据保持一致了。
4 有没有更优雅的办法
当前情形是,在每个后端要用到的VO上,都需要手工添加json的注解。如果用到的VO少还好处理,如果多的话,岂不是比较麻烦。看到有网友提供的方案,在全局配置文件:application.properties配置文件中加配置。
https://www.jianshu.com/p/d616d31c75d6
## default config spring: jackson: time-zone: "GMT+8" date-format: "yyyy-MM-dd HH:mm:ss"
经过测试验证,该方案并不生效。即使用该全局配置,在VO上注释掉@JsonFormat注解。会报错,进而说明,该方法不对,或者我的环境上还有其它的配置没有修改过来。暂时,先到这儿吧。先记下来,后面找到更好的方案时,再来完善总结更新。
五 小结
新手学前端Vue,学着写后端Java,遇到错误,自己动手尝试解决,请教同事,积累成长,还蛮有意思的的。