开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第29天,点击查看活动详情
前言
本文将为大家对 【SpringMVC教程】核心技术篇 的相关内容详进行介绍,下面具体将对设定字符集
,返回json数据(序列化)
,获取请求中的json数据
,数据转化
,数据校验
等SpringMVC相关核心技术进行详尽介绍~
👉Java全栈学习路线可参考: 【Java全栈学习路线】最全的Java学习路线及知识清单,Java自学方向指引,内含最全Java全栈学习技术清单~
👉算法刷题路线可参考: 算法刷题路线总结与相关资料分享,内含最详尽的算法刷题路线指南及相关资料分享~
↩️本文上接:最全面的SpringMVC教程——视图和模型拆分、重定向与转发、RequestMapping注解、URL模式匹配与传参
一、设定字符集
springmvc内置了一个统一的字符集处理过滤器,我们只要在web.xml中配置即可:
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
二、返回json数据(序列化)
我们经常需要使用ajax请求后台获取数据,而不需要访问任何的页面,这种场景在前后分离的项目当中尤其重要。
这种做法其实很简单,大致步骤如下:
- 将我们的对象转化为json字符串。
- 将返回的内容直接写入响应体,不走视图解析器。
- 然后将Content-Type设置为
application/json
即可。
为了实现这个目的,我们可以引入fastjson:
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.68</version>
</dependency>
// produces指定了响应的Content-Type
@RequestMapping(value = "getUsers",produces = {"application/json;charset=utf-8"})
@ResponseBody // 将返回的结果直接写入响应体,不走视图解析器
public String getUsers(){
List<User> users = new ArrayList<User>(){{
add(new User("Tom","2222"));
add(new User("jerry","333"));
}};
return JSONArray.toJSONString(users);
}
测试: 成功!
注意:@ResponseBody能将返回的结果直接放在响应体中,不走视图解析器。
浏览器中添加插件json viewer可以有如上显示。
当然springmvc也考虑到了,每次这样写也其实挺麻烦,我们还可以向容器注入一个专门处理消息转换的bean。
这个转化器的作用就是:当不走视图解析器时,如果发现【返回值是一个对象】,就会自动将返回值转化为json字符序列:
<mvc:annotation-driven >
<mvc:message-converters>
<bean id="fastjson" class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<!-- 这里顺序不能反,一定先写text/html,不然ie下会出现下载提示 -->
<value>text/html;charset=UTF-8</value>
<value>application/json;charset=UTF-8</value>
</list>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
以后我们的controller就可以写成下边的样子了:
@RequestMapping(value = "getUsersList")
@ResponseBody
public List<User> getUsersList(){
return new ArrayList<User>(){{
add(new User("邸智伟","2222"));
add(new User("刘展鹏","333"));
}};
}
当然我们还可以使用一个更加流行的组件jackson来处理,他的工作和fastjson一致
首先需要引入以下依赖:
<!--jackson-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
我们还可以对序列化的过程进行额外的一些配置:
public class CustomObjectMapper extends ObjectMapper {
public CustomObjectMapper() {
super();
//去掉默认的时间戳格式
configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
//设置为东八区
setTimeZone(TimeZone.getTimeZone("GMT+8"));
//设置日期转换yyyy-MM-dd HH:mm:ss
setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
// 设置输入:禁止把POJO中值为null的字段映射到json字符串中
configure(SerializationFeature.WRITE_NULL_MAP_VALUES, false);
// 空值不序列化
setSerializationInclusion(JsonInclude.Include.NON_NULL);
// 反序列化时,属性不存在的兼容处理
getDeserializationConfig().withoutFeatures(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
// 序列化枚举是以toString()来输出,默认false,即默认以name()来输出
configure(SerializationFeature.WRITE_ENUMS_USING_TO_STRING, true);
}
}
编写配置文件:
<mvc:annotation-driven>
<mvc:message-converters>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<!-- 自定义Jackson的objectMapper -->
<property name="objectMapper" ref="customObjectMapper" />
<property name="supportedMediaTypes">
<list>
<value>text/plain;charset=UTF-8</value>
<value>application/json;charset=UTF-8</value>
</list>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
<!--注入我们写的对jackson的配置的bean-->
<bean name="customObjectMapper" class="com.ydlclass.CustomObjectMapper"/>
测试: 成功!
三、获取请求中的json数据
在前端发送的数据中可能会如如下情况,Contetn-Type是application/json,请求体中是json格式数据:
@RequestBody注解可以【直接获取请求体的数据】。
如果我们配置了消息转化器,消息转化器会将请求体中的json数据反序列化成目标对象,如下所示:
@PostMapping("insertUser")
public String insertUser(@RequestBody User user) {
System.out.println(user);
return "user";
}
当然,我们可以把消息转化器注解掉,直接使用一个String来接收请求体的内容。
四、数据转化
假如有如下场景,前端传递过来一个日期字符串,但是后端需要使用Date类型进行接收,这时就需要一个类型转化器进行转化。
自定义的类型转化器只支持从requestParam获取的参数进行转化,我们可以定义如下,其实学习spring时我们已经接触过这个Converter接口:
public class StringToDateConverter implements Converter<String, Date> {
@Override
public Date convert(String source) {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy_MM_dd hh,mm,ss");
try {
return simpleDateFormat.parse(source);
} catch (ParseException e) {
e.printStackTrace();
}
return null;
}
}
然后,我们需要在配置文件中进行配置:
<!-- 开启mvc的注解 -->
<mvc:annotation-driven conversion-service="conversionService" />
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<bean id="stringToDateConverter" class="cn.itnanls.convertors.StringToDateConverter"/>
</set>
</property>
</bean>
对于时间类型的处理,springmvc给我们提供了一个比较完善的解决方案,使用注解@DateTimeFormat
,同时配合jackson提供的@JsonFormat
注解几乎可以满足我们的所有需求。
@DateTimeFormat
:当从requestParam中获取string参数并需要转化为Date类型时,会根据此注解的参数pattern的格式进行转化。@JsonFormat
:当从请求体中获取json字符序列,需要反序列化为对象时,时间类型会按照这个注解的属性内容进行处理。
这两个注解需要加在实体类的对应字段上即可:
// 对象和json互相转化的过程当中按照此转化方式转哈
@JsonFormat(
pattern = "yyyy年MM月dd日",
timezone = "GMT-8"
)
// 从requestParam中获取参数并且转化
@DateTimeFormat(pattern = "yyyy年MM月dd日")
private Date birthday;
处理的过程大致如下:
五、数据校验
- JSR 303 是 Java 为 Bean 数据合法性校验提供的标准框架,它包含在 JavaEE 6.0 中。
- JSR 303 通过在 Bean 属性上标注类似于 @NotNull、@Max 等标准的注解指定校验规则,并通过标准的验证接口对 Bean 进行验证。
Constraint | 详细信息 |
---|---|
@Null | 被注解的元素必须为 null |
@NotNull | 被注解的元素必须不为 null |
@AssertTrue | 被注解的元素必须为 true |
@AssertFalse | 被注解的元素必须为 false |
@Min(value) | 被注解的元素必须是一个数字,其值必须大于等于指定的最小值 |
@Max(value) | 被注解的元素必须是一个数字,其值必须小于等于指定的最大值 |
@DecimalMin(value) | 被注解的元素必须是一个数字,其值必须大于等于指定的最小值 |
@DecimalMax(value) | 被注解的元素必须是一个数字,其值必须小于等于指定的最大值 |
@Size(max, min) | 被注解的元素的大小必须在指定的范围内 |
@Digits (integer, fraction) | 被注解的元素必须是一个数字,其值必须在可接受的范围内 |
@Past | 被注解的元素必须是一个过去的日期 |
@Future | 被注解的元素必须是一个将来的日期 |
@Pattern(value) | 被注解的元素必须符合指定的正则表达式 |
🍀Hibernate Validator 扩展注解
Hibernate Validator 是 JSR 303 的一个参考实现,除支持所有标准的校验注解外,它还支持以下的扩展注解(Hibernate Validator 附加的 constraint):
Constraint | 详细信息 |
---|---|
被注解的元素必须是电子邮箱地址 | |
@Length | 被注解的字符串的大小必须在指定的范围内 |
@NotEmpty | 被注解的字符串的必须非空 |
@Range | 被注解的元素必须在合适的范围内 |
🍀Spring MVC 数据校验
Spring MVC 可以对表单参数进行校验,并将结果保存到对应的【BindingResult】或 【Errors 】对象中。
要实现数据校验,需要引入已下依赖:
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.1.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.0.9.Final</version>
</dependency>
并在实体类加上特定注解:
@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserVO {
@NotNull(message = "用户名不能为空")
private String username;
@NotNull(message = "用户名不能为空")
private String password;
@Min(value = 0, message = "年龄不能小于{value}")
@Max(value = 120,message = "年龄不能大于{value}")
private int age;
@JsonFormat(
pattern = "yyyy-MM-dd",
timezone = "GMT-8"
)
@DateTimeFormat(pattern = "yyyy-MM-dd")
@Past(message = "生日不能大于今天")
private Date birthday;
@Pattern(regexp = "^1([358][0-9]|4[579]|66|7[0135678]|9[89])[0-9]{8}$", message = "手机号码不正确")
private String phone;
@Email
private String email;
}
在配置文件中配置如下内容,增加hibernate校验:
<bean id="localValidator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
<property name="providerClass" value="org.hibernate.validator.HibernateValidator"/>
</bean>
<!--注册注解驱动-->
<mvc:annotation-driven validator="localValidator"/>
controller使用@Validated
标识验证的对象,紧跟着的BindingResult获取错误信息
@PostMapping("insert")
public String insert(@Validated UserVO user, BindingResult br) {
List<ObjectError> allErrors = br.getAllErrors();
Iterator<ObjectError> iterator = allErrors.iterator();
// 打印以下错误结果
while (iterator.hasNext()){
ObjectError error = iterator.next();
log.error("user数据校验错误:{}",error.getDefaultMessage());
}
if(allErrors.size() > 0){
return "error";
}
System.out.println(user);
return "user";
}
注意: 永远不要相信用户的输入,我们开发的系统凡是涉及到用户输入的地方,都要进行校验,这里的校验分为前台校验和后台校验,前台校验通常由javascript来完成,后台校验主要由java来负责,这里我们可以通过spring mvc+hibernate validator完成。
后记
本文呢本文为大家对 【SpringMVC教程】核心技术篇 的相关内容详进行介绍,具体对设定字符集
,返回json数据(序列化)
,获取请求中的json数据
,数据转化
,数据校验
等SpringMVC相关核心技术进行了详尽介绍~
希望本文的内容能够使你有所收获,如果你想继续深入的学习数据结构与算法相关的知识,或想深入的学习Java相关的知识与技术,可以参考:
👉Java全栈学习路线可参考: 【Java全栈学习路线】最全的Java学习路线及知识清单,Java自学方向指引,内含最全Java全栈学习技术清单~
👉算法刷题路线可参考: 算法刷题路线总结与相关资料分享,内含最详尽的算法刷题路线指南及相关资料分享~