SpringMVC
第一章 SpringMVC与JSON交互
json数据是咱们企业级开发数据交互经常使用的一种方式,它比较轻量级,格式比较清晰
交互:前端和后端的互动
前端传递json字符串到后台,后台如何能够自动转换为pojo对象
后台return 对象,能否前端直接接收到json格式的字符串。
SpringMVC默认使用JackSon进行JSON的序列化和反序列化
1.1 Ajax请求参数普通文本数据
sendAjaxText:function(){
axios({
method:"POST",
url:"/ajaxJson/sendPojo.do",
params:{
username:"zhangsan",
password:"123456"
}
}).then(response=>{
console.log(response.data);
}).catch();
}
@RequestMapping("sendText")
public String sendText(String username, String password){
System.out.println("username = " + username);
System.out.println("password = " + password);
return "1234567890";
}
异步请求的返回值结果为字符串是,MVC认为是一个视图名字,会寻找同名的视图文件。既然是异步请求,不希望出现页面跳转的现象,服务器应该返回一个JSON格式的数据。
@ResponseBody注解
使用@ResponseBody注解告诉 SpringMVC:请你拿当前方法的返回值转成JSON个数数据作为响应体,不要再找视图.
但是如果我们类中所有的方法,全部使用字符串作为
@RequestMapping("sendText")
public @ResponseBody String sendText(String username, String password){
System.out.println("username = " + username);
System.out.println("password = " + password);
return "1234567890";
}
1.2 请求参数是JSON格式数据-pojo
new Vue({
el:"#app",
data:{
user:{
username: "张三",
password: "123456"
}
},
methods:{
sendAjax:function(){
axios.post("/ajaxJson/sendPojo.do",this.user).then(resp=>{
console.log(resp.data);
});
}
)};
@RequestMapping("sendPojo")
public String sendPojo(User user){
System.out.println("user = " + user);
return "OK";
}
我们请求的JSON格式数据,在handler方法中,并没有存储到pojo对象。原因是我们并没有告诉SpringMVC框架,请求的参数格式为JSON
@RequestBody注解
@RequestBody主要用来接收前端传递给后端的json字符串中的数据的,注解只能加在方法的参数上。而且前端的请求方式必须为post,因为post请求方式才具有请求体数据。
@RequestMapping("sendPojo")
public String sendPojo(@requestBody User user){
System.out.println("user = " + user);
return "OK";
}
1.3 请求参数是JSON格式数据-List
data:{
user:{
username: "张三",
password: "123456"
},
userArray:["张三","李四","王五"],
userMap:{
username:"jack",
password:"123456",
address:"北京市",
telephone:"13700137000"
}
}
sendAjaxList:function(){
axios.post("/ajaxJson/sendList.do",this.userArray).then(resp=>{
console.log(resp.data);
}).catch();
}
@RequestMapping("sendList")
public String sendList(@RequestBody List<String> list){
for(String s : list){
System.out.println(s);
}
return "OK";
}
1.4 请求参数是JSON格式数据-Map
data:{
user:{
username: "张三",
password: "123456"
},
userArray:["张三","李四","王五"],
userMap:{
username:"jack",
password:"123456",
address:"北京市",
telephone:"13700137000"
}
}
sendAjaxMap:function(){
axios.post("/ajaxJson/sendMap.do",this.userMap).then(resp=>{
console.log(resp.data);
}).catch();
}
@RequestMapping("sendMap")
public String sendMap(@RequestBody Map<String,Object> map){
for(String key : map.keySet()){
System.out.println(key+"=="+map.get(key));
}
return "OK";
}
第二章 阿里巴巴FastJson
1.1 FastJson介绍
FastJson 是阿里巴巴的开源JSON解析库,它可以解析 JSON 格式的字符串,支持将 Java Bean 序列化为 JSON 字符串,也可以从 JSON 字符串反序列化到 JavaBean。
Fastjson 的优点
- 速度快
fastjson相对其他JSON库的特点是快,从2011年fastjson发布1.1.x版本之后,其性能从未被其他Java实现的JSON库超越。 - 使用广泛
fastjson在阿里巴巴大规模使用,在数万台服务器上部署,fastjson在业界被广泛接受。在2012年被开源中国评选为最受欢迎的国产开源软件之一。 - 测试完备
fastjson有非常多的testcase,在1.2.11版本中,testcase超过3321个。每次发布都会进行回归测试,保证质量稳定。 - 使用简单
fastjson的 API 十分简洁。 - 功能完备
支持泛型,支持流处理超大文本,支持枚举,支持序列化和反序列化扩展
1.2 FastJSON序列化API
序列化 : 是指将Java对象转成json格式字符串的过程.JavaBean对象,List集合对象,Map集合,为应用最广泛的.
JSON.toJSONString
- 序列化Java对象
public void objectToJson(){
Student student = new Student();
student.setId(1);
student.setName("张三");
student.setAge(20);
student.setAddress("北京市");
student.setEmail("zs@sina.com");
String jsonString = JSON.toJSONString(student);
System.out.println(jsonString);
}
JSON.toJSONString
- 序列化List集合
public void listToJson(){
Student student = new Student();
student.setId(1);
student.setName("张三");
student.setAge(20);
student.setAddress("北京市");
student.setEmail("zs@sina.com");
Student student2 = new Student();
student2.setId(2);
student2.setName("张三2");
student2.setAge(22);
student2.setAddress("北京市2");
student2.setEmail("zs2@sina.com");
List<Student> list = new ArrayList<Student>();
list.add(student);
list.add(student2);
String jsonString = JSON.toJSONString(list);
System.out.println(jsonString);
}
JSON.toJSONString
- 序列化Map集合
public void mapToJson(){
Student student = new Student();
student.setId(1);
student.setName("张三");
student.setAge(20);
student.setAddress("北京市");
student.setEmail("zs@sina.com");
Student student2 = new Student();
student2.setId(2);
student2.setName("张三2");
student2.setAge(22);
student2.setAddress("北京市2");
student2.setEmail("zs2@sina.com");
Map<String,Student> map = new HashMap<String, Student>();
map.put("s1",student);
map.put("s2",student2);
String jsonString = JSON.toJSONString(map);
System.out.println(jsonString);
}
1.3 FastJSON反序列化API
JSON.parseObject
- 反序列化Java对象
public void jsonToObject(){
String jsonString = "{\"address\":\"北京市\",\"age\":20,\"email\":\"zs@sina.com\",\"id\":1,\"name\":\"张三\"}";
Student student = JSON.parseObject(jsonString, Student.class);
System.out.println(student);
}
JSON.parseArray
- 反序列化List集合
public void jsonToList(){
String jsonString = "[{\"address\":\"北京市\",\"age\":20,\"email\":\"zs@sina.com\",\"id\":1,\"name\":\"张三\"},{\"address\":\"北京市2\",\"age\":22,\"email\":\"zs2@sina.com\",\"id\":2,\"name\":\"张三2\"}]";
List<Student> list = JSON.parseArray(jsonString,Student.class);
for (int i = 0; i < list.size(); i++) {
Student student = list.get(i);
System.out.println(student);
}
}
JSON.parseObject
- 反序列化Map集合
public void jsonToMap(){
String jsonString = "{\"s1\":{\"address\":\"北京市\",\"age\":20,\"email\":\"zs@sina.com\",\"id\":1,\"name\":\"张三\"},\"s2\":{\"address\":\"北京市2\",\"age\":22,\"email\":\"zs2@sina.com\",\"id\":2,\"name\":\"张三2\"}}";
Map<String,Student> parse = JSON.parseObject(jsonString,new TypeReference<Map<String,Student>>(){});
for(String s : parse.keySet()){
System.out.println(s + ":::"+parse.get(s));
}
}
1.4 SerializerFeature枚举
该枚举支持序列化的一些特性数据定义,在对象序列化的方法中,可以传递该枚举类型的数组
枚举常量 WriteMapNullValue 序列化为null的字段
public void testSerializerFeature(){
Student student = new Student();
student.setId(1);
student.setName("张三");
student.setAge(20);
//student.setAddress("北京市");
student.setEmail("zs@sina.com");
String jsonString = JSON.toJSONString(student, SerializerFeature.WriteMapNullValue);
System.out.println(jsonString);
}
枚举常量 WriteNullStringAsEmpty 字段为null,序列化为””
public void testSerializerFeature(){
Student student = new Student();
student.setId(1);
student.setName("张三");
student.setAge(20);
//student.setAddress("北京市");
student.setEmail("zs@sina.com");
String jsonString = JSON.toJSONString(student, SerializerFeature.WriteNullStringAsEmpty);
System.out.println(jsonString);
}
枚举常量 WriteNullNumberAsZero 字段为null,序列化为0
public void testSerializerFeature(){
Student student = new Student();
student.setId(1);
student.setName("张三");
//student.setAge(20);
student.setAddress("北京市");
student.setEmail("zs@sina.com");
String jsonString = JSON.toJSONString(student, SerializerFeature.WriteNullNumberAsZero);
System.out.println(jsonString);
}
枚举常量 WriteDateUseDateFormat 格式化日期格式
枚举常量 PrettyFormat格式化输出
public void testSerializerFeature2(){
Person person = new Person();
//person.setFlag(true);
person.setDate(new Date());
String jsonString = JSON.toJSONString(person,SerializerFeature.WriteNullBooleanAsFalse,
SerializerFeature.WriteDateUseDateFormat,SerializerFeature.PrettyFormat);
System.out.println(jsonString);
}
1.5 @JSonField注解
该注解作用于方法上,字段上和参数上.可在序列化和反序列化时进行特性功能定制.
- 注解属性 : name 序列化后的名字
- 注解属性 : ordinal序列化后的顺序
- 注解属性 : serialize 是否序列化该字段
- 注解属性 : deserialize 是否反序列化该字段
- 注解属性 : serialzeFeatures 序列化时的特性定义
1.6 @JSonType注解
该注解作用于类上,对该类的字段进行序列化和反序列化时的特性功能定制.
- 注解属性 : includes 要被序列化的字段.
- 注解属性 : orders 序列化后的顺序.
- 注解属性 : serialzeFeatures 序列化时的特性定义
1.7 SpringMVC集成FastJSON
SpringMVC框架中,默认使用的json序列化工具是jackson,我们需要在SpringMVM的配置文件中,配置消息转换器,由jackson切换到FastJson.
<mvc:annotation-driven>
<mvc:message-converters register-defaults="false">
<bean class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>application/json;charset=utf-8</value>
</list>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
第三章 数据校验
1.1 数据校验概述
在 Web 应用三层架构体系中,表述层负责接收浏览器提交的数据,业务逻辑层负责数据的处理。为了能够让业务逻辑层基于正确的数据进行处理,我们需要在表述层对数据进行检查,将错误的数据隔绝在业务逻辑层之外。
JSR 303 是 Java 为 Bean 数据合法性校验提供的标准框架,它已经包含在 JavaEE 6.0 标准中。JSR 303 通过在 Bean 属性上标注类似于 @NotNull、@Max 等标准的注解指定校验规则,并通过标准的验证接口对Bean进行验证。
1.2 服务器端数据验证的必要性
对于客户端可以使用js进行数据校验,将合法的数据提交到服务器端。为什么服务器端还要进行数据的校验工作呢,目的还是为了保证数据的安全性。对服务器发起请求,不仅仅只有客户端通过表单来实现,也可以通过地址栏直接输入服务器请求地址,并添加非法参数,从而逃过客户端的js数据校验。因此服务器端数据校验也是必要的。
1.3 导入依赖jar包
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.2.0.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator-annotation-processor</artifactId>
<version>6.2.0.Final</version>
</dependency>
1.4 数据校验的相关注解
通过@Validated注解对Bean进行验证。
注解 | 规则 |
---|---|
@Null | 标注值必须为 null |
@NotNull | 标注值不可为 null |
@AssertTrue | 标注值必须为 true |
@AssertFalse | 标注值必须为 false |
@Min(value) | 标注值必须大于或等于 value |
@Max(value) | 标注值必须小于或等于 value |
@DecimalMin(value) | 标注值必须大于或等于 value |
@DecimalMax(value) | 标注值必须小于或等于 value |
@Size(max,min) | 集合长度,标注值大小必须在 max 和 min 限定的范围内 |
@Digits(integer,fratction) | 标注值值必须是一个数字,且必须在可接受的范围内,integer整数精度,fratction小数精度 |
@Past | 标注值只能用于日期型,且必须是过去的日期,或者当天 |
@Future | 标注值只能用于日期型,且必须是将来的日期,不能是当天 |
@Pattern(value) | 标注值必须符合指定的正则表达式 |
标注值必须是格式正确的 Email 地址 | |
@Length | 标注值字符串大小必须在指定的范围内 |
@NotEmpty | 标注值字符串不能是空字符串 |
第四章 异常映射
1.1 异常映射概述
将异常类型和某个具体的视图关联起来,建立映射关系。好处是可以通过 SpringMVC 框架来帮助我们管理异常。
- 声明式管理异常:在配置文件中指定异常类型和视图之间的对应关系。在配置文件或注解类中统一管理。
- 编程式管理异常:需要我们自己手动 try … catch … 捕获异常,然后再手动跳转到某个页面。
1.3 异常的处理思路
系统中异常包括两类:预期异常和运行时异常 RuntimeException,前者通过捕获异常从而获取异常信息,
后者主要通过规范代码开发、测试通过手段减少运行时异常的发生。
系统的 dao、service、controller 出现都通过 throws Exception 向上抛出,最后由 springmvc 前端控制器交由异常处理器进行异常处理。
1.4 自定义异常
public class MyException extends Exception {
private String message;
public MyException(String message){
super(message);
this.message = message;
}
@Override
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
1.5 自定义异常处理器
@Component
public class MyExceptionResolver implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {
String message = null;
if (e instanceof MyException){
message = ((MyException)e).getMessage();
}
else {
message = e.getMessage();
}
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("message",message);
modelAndView.setViewName("error");
return modelAndView;
}
}