SpringMVC

第一章 SpringMVC与JSON交互

json数据是咱们企业级开发数据交互经常使用的一种方式,它比较轻量级,格式比较清晰

交互:前端和后端的互动

前端传递json字符串到后台,后台如何能够自动转换为pojo对象

后台return 对象,能否前端直接接收到json格式的字符串。

SpringMVC默认使用JackSon进行JSON的序列化和反序列化

1.1 Ajax请求参数普通文本数据

  1. sendAjaxText:function(){
  2. axios({
  3. method:"POST",
  4. url:"/ajaxJson/sendPojo.do",
  5. params:{
  6. username:"zhangsan",
  7. password:"123456"
  8. }
  9. }).then(response=>{
  10. console.log(response.data);
  11. }).catch();
  12. }
@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

2.jpg

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 标注值必须是格式正确的 Email 地址
@Length 标注值字符串大小必须在指定的范围内
@NotEmpty 标注值字符串不能是空字符串

第四章 异常映射

1.1 异常映射概述

将异常类型和某个具体的视图关联起来,建立映射关系。好处是可以通过 SpringMVC 框架来帮助我们管理异常。

  • 声明式管理异常:在配置文件中指定异常类型和视图之间的对应关系。在配置文件或注解类中统一管理。
  • 编程式管理异常:需要我们自己手动 try … catch … 捕获异常,然后再手动跳转到某个页面。

1.3 异常的处理思路

系统中异常包括两类:预期异常和运行时异常 RuntimeException,前者通过捕获异常从而获取异常信息,
后者主要通过规范代码开发、测试通过手段减少运行时异常的发生。
系统的 dao、service、controller 出现都通过 throws Exception 向上抛出,最后由 springmvc 前端控制器交由异常处理器进行异常处理。

1.jpg

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;
    }
}