搭建完一个spring-boot的接口服务后,可以在前段通过ajax异步请求后台接口数据,一般ajax通过传递json对象给后台接口,后台接收数据转化为Bean对象,处理逻辑完成后,将返回的数据转为json回送给前台调用者;
1.前台ajax参数格式为:
var param1={
id:1234,
name:'名称',
path:'路径',
createdDate:'2017-01-05 12:45:32'
}
2.ajax 调用
$.get("http://***********/ajaxApi/getOfBean",param, function(result){
console.info("result:"+JSON.stringify(result));
});
3.后台接收参数的Bean实体类
public class Ajax implements Serializable{
private Long id;
private String name;
private String path;
private Date createdDate;
}
4.后台spring-boot提供的接口:
@RestController
@RequestMapping(value="ajaxApi")
@Api(value = "/ajaxApi", description = "异步接口测试API",tags={"/ajaxApi"})
public class AjaxController {
private static final Logger logger = LoggerFactory.getLogger(AjaxController.class);
/***
* 异步参数接收
* @return
*/
@RequestMapping(value = "/getOfBean")
@ApiOperation("Bean实体参数")
public Ajax getOfBean(Ajax ajax) throws Exception{
logger.info("异步参数接收:{}",ajax.toString());//打印接收的对象
return ajax;
}
}
接口接收参数为AjaxBean实体类,结束后返回该实体类给前台;启动项目,触发ajax请求,报错:
【org.springframework.validation.BindException】
<span style="font-size:18px;color:#ff0000;">Failed to convert property value of type 'java.lang.String' to required type 'java.util.Date' for property 'createdDate';
nested exception is org.springframework.core.convert.ConversionFailedException:
Failed to convert from type [java.lang.String] to type [java.util.Date] for value '2017-01-05 12:45:32';
nested exception is java.lang.IllegalArgumentException</span>
【报错原因】:
ajax使用json字符串将日期字符串发送到后台接口,后台无法将字符串转为日期类型,缺少转换器;
【解决方法】:
增加日期类型转换器,方式有四种:
第一种:在Bean实体字段或参数上增加@DateTimeFormat注解
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createdDate;
第二种:在接收参数的的Controller中增加@InitBinder转化方法
@InitBinder
protected void initBinder(WebDataBinder binder) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, true));
}
【*】此种方式只对当前controller起作用
第三种:配置全局的日期转换器
/**
* 转换解析器
* @author wangqingguo 2017/9/25
*/
@Configuration
public class MappingConverterAdapter {
/***
* 日期参数接收转换器,将json字符串转为日期类型
* @return
*/
@Bean
public Converter<String, Date> DateConvert() {
return new Converter<String, Date>() {
@Override
public Date convert(String source) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = null;
try {
date = sdf.parse((String) source);
} catch (Exception e) {
e.printStackTrace();
}
return date;
}
};
}
}
【*】此处定义的dateConvert用来转换Date类型,如果是LocalDate、LocalDateTime类型,则将Date
类型换成相应的类型即可,注意java8的日期类型需要用Formatter格式化:
/**
* 转换解析器
* @author wangqingguo 2017/9/25
*/
@Configuration
public class MappingConverterAdapter {
/***
* 日期参数接收转换器,将json字符串转为日期类型
* @return
*/
@Bean
public Converter<String, LocalDateTime> LocalDateTimeConvert() {
return new Converter<String, LocalDateTime>() {
@Override
public LocalDateTime convert(String source) {
DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime date = null;
try {
date = LocalDateTime.parse((String) source,df);
} catch (Exception e) {
e.printStackTrace();
}
return date;
}
};
}
}
第四种:配置Formatter日期转换器
/**
* 日期转换器
* @author LiMeng 2017/11/7
*/
@Configuration
public class DateConfig {
/***
* Date日期类型转换器
* @return
*/
@Bean
public Formatter<Date> dateFormatter() {
return new Formatter<Date>() {
@Override
public Date parse(String text, Locale locale) throws ParseException {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = null;
try {
date = sdf.parse(text);
} catch (Exception e) {
e.printStackTrace();
}
return date;
}
@Override
public String print(Date object, Locale locale) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return sdf.format(object);
}
};
}
}
【*】如果是LocalDate、LocalDateTime类型,则将Date类型换成相应的类型即可,
注意java8的日期类型需要用Formatter格式化:
/**
* 日期转换器
* @author LiMeng 2017/11/7
*/
@Configuration
public class DateConfig {
/***
* Date日期类型转换器
* @return
*/
@Bean
public Formatter<Date> dateFormatter() {
return new Formatter<Date>() {
@Override
public Date parse(String text, Locale locale) throws ParseException {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = null;
try {
date = sdf.parse(text);
} catch (Exception e) {
e.printStackTrace();
}
return date;
}
@Override
public String print(Date object, Locale locale) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return sdf.format(object);
}
};
}
@Bean
public Formatter<LocalDate> localDateFormatter() {
return new Formatter<LocalDate>() {
@Override
public LocalDate parse(String text, Locale locale) throws ParseException {
return LocalDate.parse(text, DateTimeFormatter.ISO_LOCAL_DATE);
}
@Override
public String print(LocalDate object, Locale locale) {
return DateTimeFormatter.ISO_LOCAL_DATE.format(object);
}
};
}
@Bean
public Formatter<LocalDateTime> localDateTimeFormatter() {
return new Formatter<LocalDateTime>() {
@Override
public String print(LocalDateTime localDateTime, Locale locale) {
DateTimeFormatter formatter=DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
return formatter.format(localDateTime);
}
@Override
public LocalDateTime parse(String text, Locale locale) throws ParseException {
DateTimeFormatter formatter=DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
return LocalDateTime.parse(text, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
}
};
}
}
OK,启动系统,可以正常访问,但这时发现后台返回前台的数据为:
{"id":1234,"name":"名称","path":"路径","createdDate":1483545600000}
发现后台可以正常接收日期类型,但返回后前台接收的日期成了时间戳;理想情况下前台接收到时间的格式化字符串数据;
之所以出现这个问题,是因为项目没有对返回的JSON进行处理解析;
【报错原因】:
java中的日期类型,在转为JSON字符串时没有进行日期格式化;
【解决方法】:
解决方式有以下几种
第一种:在Bean实体属性增加 @JsonFormat注解
@JsonFormat( pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
private Date createdDate;
@JsonFormat( pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime createdTime;
【*】注:Date类型的使用注解 会出现事件相差8小时的情况,需要设定timezone属性指定时区;LocalDateTime类型没有发现此问题,所以没有加此属性;
另外LocalDateTime只加此注解,还是无法解析,需要增加jackson-datatype-jsr310jar包才管用
compile group: 'com.fasterxml.jackson.datatype', name: 'jackson-datatype-jsr310', version: '2.9.3'
第二种:增加MappingJackson2HttpMessageConverterAdapter 转换器,对日期类型进行格式化转换:
/**
* JSON解析器
* @author wangqingguo 2017/9/25
*/
@Configuration
public class MappingJackson2HttpMessageConverterAdapter {
/***
* 配置JSON解析器内容
* @return
*/
@Bean
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
MappingJackson2HttpMessageConverter a= new MappingJackson2HttpMessageConverter();
/***
* 头格式
*/
List<MediaType> supportedMediaTypes=new ArrayList<>();
supportedMediaTypes.add(MediaType.APPLICATION_JSON_UTF8);
supportedMediaTypes.add(MediaType.TEXT_HTML);
supportedMediaTypes.add(MediaType.TEXT_PLAIN);
a.setSupportedMediaTypes(supportedMediaTypes);
/***
* 日期格式化,解决返回的日期类型格式化
*/
ObjectMapper objectMapper = a.getObjectMapper();
DateFormat dateFormat=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
objectMapper.setDateFormat(dateFormat);
a.setObjectMapper(objectMapper);
return a;
}
}
【*】注:此种方式只对Date类型起作用,Java8的LocalDateTime类型不起作用,LocalDateTime类型还是需要用@JsonFormat注解的形式;