SpringMVC学习记录-Spring基础入门!

SpringMVC学习记录-Spring基础入门!


前言

SpringMVC是一种基于Java,实现了Web MVC设计模式,请求驱动类型的轻量级Web框架,即使用了MVC架构模式的思想,将Web层进行职责解耦。基于请求驱动指的就是使用请求-响应模型,框架的目的就是帮助我们简化开发,SpringMVC也是要简化我们日常Web开发。


SpringMVC简概述:SpringMVC技术与Servlet技术功能等同,均属于web层开发技术


SpringMVC简介

SpringMVC概述:

  • 回顾:Web程序的工作流程:

Web程序通过游览器访问页面;

前端页面使用异步提交的方式发送请求到后端服务器;

后端服务器采用表现层、业务层、数据层的三层架构的形式进行开发,页面发送的请求由表现层接收

获取用户的请求参数后,将参数传递到业务层

再由业务层访问数据层

得到用户需要访问的数据后,将数据返回给表现层

表现层拿到数据后将数据转化成Json格式

随后发送给前端页面

前端页面接收到数据后,解析数据并组织(渲染)成用户游览的最终页面信息

最终发送回给游览器


学习过程中,

数据层我们一开始用的是Jdbc,后来用了mybatis代替。

表现层采用的则是Servlet,现在来用Springmvc技术来代替。


  • SpringMVC是一种基于Java实现MVC模型的轻量级Web框架,

    也是一种表现层框架技术,用于进行表现层功能开发。

  • Spring的优点:

    • 使用简单,开发便捷(相比于Servlet)
    • 灵活性强

SpringMVC入门案例

入门案例

  1. 使用SpringMVC技术需要先导入SpringMVC坐标与Servlet坐标

    <dependency>
    	<groutId>javax.servlet</groutId>
        <artifactId>javax.servlet-api</artifactId>
        <version>3.1.0</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
    	<groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>5.2.10.RELEASE</version>
    </dependency>
    

  2. 创建SpringMVC控制器类(等同于Servlet功能)

    @Controller
    public class UserController{
       
        @RequestMapping("/save")
        @ResponseBody
        public String save(){
            System.out.println("user save ...");
            return "{'info':'springmvc'}";
        }
    }
    

  3. 初始化SpringMVC环境(同Spring环境),设定SpringMVC加载对应的bean

    @Configuration
    @ComponentScan("com.catalpa.controller")
    public class SpringMvcConfig{
        
    }
    

  4. 初始化Servlet容器,加载SpringMVC环境,并设置SpringMVC技术处理的请求

    public class ServletContainersInitConfig extends AbstractDispatcherServlertInitializer{
        protected WebApplicationContext createServletApplicationContext(){
            AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
            ctx.register(SpringMvcConfig.class);
            return ctx;
        }
        
        protected String[] getServletMappings(){
            return new String[]{"/"};
        }
        
        protected WebApplicationContext createRootApplicationContext(){
            return null;
        }
        
    }
    

注解解释

  • @Controller

    名称:@Controller

    类型:类注解

    位置:SpringMVC控制器定义上方

    作用:设定SpringMVC的核心控制器bean

    举例:

    @Controller
    public class UserController{
        
    }
    

  • @RequestMapping

    名称:@RequestMapping

    类型:方法注解

    位置:SpringMVC控制器方法定义上方

    作用:设置当前控制器方法请求访问的路径

    举例:

    @RequestMapping("/save")
    public void save(){
        System.out.println("ueser save ...");
    }
    

    相关属性:

    • value(默认):请求访问路径

  • @ResponseBody

    名称:@ResponseBody

    类型:方法注解

    位置:SpringMVC控制器方法定义上方

    作用:设置当前控制器方法的响应内容为当前的返回值,直接映射,无需解析

    举例:

    @RequestMapping("/save")
    @ResponseBody
    public String save(){
        System.out.println("user save ...");
        return "{'info':'springmvc'}";
    }
    

案例开发总结

  • 一次性工作
    • 创建工程,设置服务器,加载工程
    • 导入坐标
    • SpringMVC核心配置类(设置配置类,扫描controller包,加载Controller控制器bean)
    • 创建web容器启动类,加载SpringMVC配置,并设置SpringMVC请求拦截路径
  • 多次工作
    • 定义处理请求的控制器类
    • 定义处理请求的控制器方法,并配置映射路径(通过注解@RequestMapping)与返回json数据(@ResponseBody)

  • AbstractDispatcherServletInitializer

    AbstractDispatcherServletInitializer类是SpringMVC提供的快速初始化web3.0容器的抽象类

    AbstractDispatcherServletInitializer提供了三个接口方法供用户实现

    • createServletApplicationContext()方法,创建Servlet容器时,加载SpringMVC对应的bean并放入WebApplicationContext对象范围中,而WebApplicationContext的作用范围为ServletContext范围,即整个Web容器范围。

      protected WebApplicationContext createServletApplicationContext(){
              AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
              ctx.register(SpringMvcConfig.class);
              return ctx;
          }
      

    • getServletMappings()方法,设定SpringMVC对应的请求映射路径,设置为/,表示拦截所有请求,任意请求都将转入到SpringMVC进行处理。

      protected String[] getServletMappings(){
          return new String[]{"/"};
      }
      

    • createRootApplicationContext()方法,如果创建Servlet容器时需要加载非SpringMVC对应的bean,使用当前方法进行,使用方法同createServletApplicationContext()

      protected WebApplicationContext createRootApplicationContext(){
          return null;
      }
      


入门案例工作流程

分析:分为两个阶段

  • 启动服务器初始化过程
    1. 服务器启动,执行ServletContainersInitConfig类,初始化web容器
    2. 执行createServletApplicationContext方法,创建了WebApplicationContext对象(该对象其实是在ServletContext中的,被包含)
    3. 加载SpringMvcConfig
    4. 执行@ComponentScan加载对应的bean
    5. 加载UserController,每个@RequestMapping的名称对应一个具体的方法(载入进去)
    6. 执行gerServletMappings方法,定义所有的请求都通过SpringMVC
  • 单次请求过程
    1. 发送请求localhost/save
    2. web容器发现所有请求都结果SpringMVC,将请求交给SpringMVC处理
    3. 解析所有请求路径,如/save
    4. 由/save匹配执行对应的方法save()
    5. 执行save()
    6. 检测到有@ResponseBody直接将save()方法的返回值作为响应体返回给请求方

(可根据如下的图进行理解)

在这里插入图片描述


bean加载控制

当有一些bean我们不需要被载入时应该怎么办?

当有两个Config配置类,他们都对应配置着不同bean,扫描不同bean,这个时候我们需要如何划分呢?


一般情况下,SpringMVC和Spring控制的bean是不同的

  • SpringMVC相关bean:表现层bean
  • Spring控制的bean: 业务bean(Service)、功能bean(DataSource等)

在这里插入图片描述


SpringMVC相关bean加载控制

SpringMVC加载的bean对应的包均在com.catalpa.controller包内

Spring相关bean加载控制

方式一:Spring加载的bean设定扫描范围为com.catalpa,排除掉controller包内的bean

方式二:Spring加载的bean设定扫描范围为精确范围,例如service包、dao包等

方式三:不区分Spring与SpringMVC的环境,加载到同一个环境中

//方式一:
@Configuration
@ComponentScan(value="com.catalpa",
              excludeFilters = @ComponentScan.Filter(
                  type = FilterType.AnnOTATION,
                  classes = Controller.class               
        	)
		)
public class SpringConfig{
    
}

(type 表示根据什么进行排除,此处选择的ANNOTATION表示的是根据注解排除;

classes则是写注解的类型。)

以下这图是对@ComponentScan进行解释

在这里插入图片描述


这里我们还需要来看一下SpringMvcConfig的配置类:

//@Configuration
@ComponentScan("com.catalpa.controller")
public class SpringMvcConfig{
    
}

注意: 此处的@Configuration注解被注释掉是有原因的。 SpringMvcconfig由前面已知是对Controller的bean控制。

此处如果带上@Configuration注解的话,当SpringConfig在配置扫描的时候,会把这个配置类也扫描进行,那么即使原先的@Controller注解是成功被排除的,在此刻也会被重新配置进去,使得前面的排除失效。

故这里不带@Configuration注解,不让该配置类被扫描到。


举例看一下测试类:

public class Appp{
    public static void main(String[] args){
        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
        System.out.println(ctx.getBean(UserController.class));
    }
}

上面我们已经将第一种bean加载控制讲清楚了,下面我们来讲一下第二种,第二种就相对比较简单了。直接看代码就能理解了。

@Configuration
@ComponentScan({"com.catalpa.service","com.catalpa.dao"})
public class SpringConfig{
    
}

(第三种此处就不展开讲了。)


SpringMVC和Spring的配置载入

两者的载入是在AbstractDispatcherServletInitializer下实现的。

public class ServletContainersInitConfig extends AbstractDispatcherServlertInitializer{
    protected WebApplicationContext createServletApplicationContext(){
        AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
        ctx.register(SpringMvcConfig.class);
        return ctx;
    }
    
    protected String[] getServletMappings(){
        return new String[]{"/"};
    }
    
    protected WebApplicationContext createRootApplicationContext(){
        AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
        ctx.register(SpringConfig.class);
        return ctx;
    }
    
}

注意:两者的配置载入的方式都是一样的,都是通过AnnotationConfigWebApplicationContext,只有register处写入的配置类不同。(SpringMvcConfig.class 与 SpringConfig.class )

可以简化成如下:(但这样子做不方便查看是进行了什么操作。)

在这里插入图片描述

public class ServletContainersInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer{
    protected Class<?>[] getServletConfigClasses(){
        return new Class[]{SpringMvcConfig.class};
    }
    protected Class<?>[] getRootConfigClasses(){
        return new Class[]{SpringConfig.class};
    }
    protected String[] getServletMappings(){
        return new String[]{"/"};
    }
}


请求与响应

请求映射路径

使用的是@RequestMapping注解,不止可以在方法上进行注解,也可以在类注解上。

在类注解上做一个前缀路径,方便不同模块下的相同名字的注解路径进行成功映射。

在这里插入图片描述

请求参数

发送携带参数Get请求

利用Postman发送Get请求,并进行接收

在这里插入图片描述


发送携带参数Post请求

利用Postman发送Post请求,并进行接收

在这里插入图片描述


SpringMVC解决Post请求中文乱码问题

在这里插入图片描述


具体代码中实现如下:

在这里插入图片描述


在这里插入图片描述

此时用Post发送请求时,就可以发送中文了。


请求参数类型

参数类型大致分为如下的五种

(补充知识: POJO Plain Ordinary Java Object 简单java对象,内在含义指的是那些没有从任何类继承、也没有实现任何接口,更没有被其它框架侵入的java对象)

  • 普通参数
  • POJO类型参数
  • 嵌套POJO类型参数
  • 数组类型参数
  • 集合类型参数

传参数过程中我们常用到@RequestParam注解,它能给我们带来很多的便利。

名称:@RequestParam

类型:形参注解

位置:SpringMVC控制器方法形参定义前面

作用:绑定请求参数与处理器方法形参间的关系。

@RequestParam接收的参数是来自HTTP请求体或请求url的QueryString中,该注解用来处理Content-Type为application/x-www-form-urlencoded编码的内容,同时也可以用来处理POST等请求。


范例:

@RequestMapping("/commparamDifferentName")
@ResponseBody
public String commmonParamDifferentName(@RequestParam("name")String userName,int age){
    System.out.println("dddd");
    return "{'module':'common param different name'}";
}

注解的参数:

  • “name” :页面传来的地址参数名。

  • required:是否为必传参数

  • defaultValue:参数默认值


具体对不同请求参数类型,进行如下的分析介绍:

  1. 普通参数

    分为两种,当地址参数名与形参变量名相同与不同。

在这里插入图片描述


在这里插入图片描述


  1. POJO类型参数

在这里插入图片描述


  1. 嵌套POJO类型参数

在这里插入图片描述


在这里插入图片描述


  1. 数组类型参数

在这里插入图片描述


  1. 集合类型参数

在这里插入图片描述

当没有加@RequestParam进行集合类型参数传递的时候 ,由于List集合也是属于一个引用对象,所以和其他引用对象一样,请求参数传递进来的时候,自动装入了引用对象的属性中。比如list的length属性等。

此处只有加了@RequestParam注解后才能和我们预期的一样,装入到list集合中的数据去,作为集合的数据出现。


实战实例:

@Controller
public class UserController{
    
    //普通参数
    @RequestMapping("/commonParam")
    @ResponseBody
    public String commonParam(String name, int age){
        System.out.println("普通参数传递 name ==> " + name);
        System.out.println("普通参数传递 age ==>"+age);
        return "{'moudle':'common param'}";
    }

    //普通参数 : 请求参数名(地址参数名) 与形参名不同
    @RequestMapping("/commonParamDifferentName")
    @ResponseBody
    public String commonParamDifferentName(@RequestParam("name") String userName, int age){
        System.out.println("普通参数传递 userName ==> " + userName);
        System.out.println("普通参数传递 age ==>"+age);
        return "{'moudle':'common param different name'}";
    }
    
    //POJO参数
    @RequestMapping("/pojoParam")
    @ResponseBody
    public String pojoParam(User user){
        System.out.println("pojo参数传递 user ==> "+ user);
        return "{'module':'pojo param'}";
    }
    
    //嵌套POJO参数
    @RequestMapping("/pojoContainPojoParam")
    @ResponseBody
    public String pojoContainPojoParam(User user){
        System.out.println("pojo嵌套pojo参数传递 user ==> "+ user);
        return "{'module':'pojo contain pojo param'}";
    }
    
    //数组参数
    @RequestMapping("/arrayParam")
    @ResponseBody
    public String arrayParam(String[] likes){
        System.out.println("数组参数传递 likes ==>"+Arrays.toString(likes));
        return "{'module':'array param'}";
    }
    
    //集合参数
    @RequestMapping("/listParam")
    @ResponseBody
    public String listParam(@RequestParam List<String> likes){
        System.out.println("集合参数传递 likes ==>" + likes);
        return "{'module':'list param'}";
    }
}

传递JSON数据

  • json数组

  • json对象(POJO)

  • json数组(POJO)

在这里插入图片描述

接收请求中的json数据,主要分为如下四步

  1. 添加json数据转换相关坐标

    <dependency>
    	<groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.9.0</version>
    </dependency>
    

  2. 设置发送json数据(通过postman软件进行模拟发送,在请求body中添加发送json数据)

在这里插入图片描述


  1. 开启自动转换json数据的支持(在SpringMvcConfig配置类中)

    @Configuration
    @ComponentScan("com.catalpa.controller")
    @EnableWebMvc
    public class SpringMvcConfig{
        
    }
    

    @EnableWebMvc注解功能强大,该注解整合了很多功能,此处仅使用其中一部分功能,即能开启json数据进行自动类型转换(还能开启另外的功能,此处不展开讲)


  2. 设置接收json数据

    @RequestMapping("/listParamForJson")
    @ResponseBody
    public String listParamForJson(@RequestBody List<String> likes){
        System.out.println("list common(json)参数传递 list ==>" + likes);
        return "{'module':'list common for json param'}";
    }
    

    此处采用的是@RequestBody注解,来解决Spring/SpringBoot @RequestParam注解无法直接读取application/json格式数据的问题。


实战举例:

//集合参数:json格式
@RequestMapping("/listParamForJson")
@ResponseBody
public String listParamForJson(@RequestBody List<String> likes){
    System.out.println("list common(json)参数传递 list ==>"+likes);
    return "{'module':'list common for json param'}";    
}

//POJO参数:json格式
@RequestMapping("/pojoParamForJson")
@ResponseBody
public String pojoParamForJson(@RequestBody User user){
    System.out.println("pojo(json)参数传递 user ==>"+user);
    return "{'module':' pojo for json param'}";    
}


//集合(POJO)参数:json格式
@RequestMapping("/listPojoParamForJson")
@ResponseBody
public String listPojoParamForJson(@RequestBody List<User> list){
    System.out.println("list pojo(json)参数传递 list ==>"+list );
    return "{'module':'list pojo for json param'}";
}

以上过程中用到的注解,介绍如下

  • @EnableWebMvc

    • 名称:@EnableWebMvc
    • 类型:配置类注解
    • 位置:SpringMvc配置类定义上方
    • 作用:开启SpringMVC多项辅助功能

  • @RequestBody

    • 名称:@RequestBody
    • 类型:形参注解
    • 位置:SpringMVC控制器方法形参定义前面
    • 作用:将请求中请求体所包含的数据传递给请求参数,此注解一个处理方法只能使用一次
      • 该注解一般处理的都是请求体中的数据。requestBody
      • 能补足@RequestParam注解不好处理的json数据
      • 一般用于处理非 Content-Type: application/x-www-form-urlencoded编码格式的数据,比如application/jsonapplication/xml等类型的数据。

@RequestParam与@RequestBody区别

  • 区别
    • @RequestParam用于接收url地址传参,表单传参application/x-www-form-urlencoded
    • @RequestBody用于接收json数据application/json
  • 应用
    • 后期开发中,发送json数据格式为主,@RequestBody应用较多
    • 如果发送非json格式数据,选用@RequestParam接收请求参数


日期类型参数传递

日期类型数据基于系统不同格式也有多种

  • 2022-08-18
  • 2022/08/18
  • 08/18/2022

接收形参时,根据不同的日期格式设置不同的接收方式。使用@DateTimeFormat注解,在该注解的参数pattern中写明我们的日期格式。

@RequestMapping("/dataParam")
@ResponseBody
public String dataParam(Date date,
                       @DateTimeFormat(pattern = "yyyy-MM-dd") Date date1,
                       @DateTimeFormat(pattern = "yyyy/MM/dd HH:mm:ss") Date date2){
    System.out.println("参数传递 date ==>" +date);
    System.out.println("参数传递 date(yyyy-MM-dd) ==>" +date1);
    System.out.println("参数传递 date(yyyy/MM/dd HH:mm:ss) ==>" +date2);
    return "{'module':'data param'}";
}

输出如下:

在这里插入图片描述


以上所用注解如下所示:

  • @DateTimeFormat
    • 名称:@DateTimeFormat
    • 类型:形参注解
    • 位置:SpringMVC控制器方法形参前面
    • 作用:设定日期时间型数据格式
    • 属性:pattern:日期时间格式字符串,如 "yyyy-MM-dd"


类型转换器(Converter)

日期格式的转换,内部利用的是类型转换器,根据Converter接口来实现的,该接口也实现了很多的类型转换问题,这个需要了解一下,后面学习中还会遇到这个接口。

在这里插入图片描述



响应json数据

响应类型:

  • 响应页面

    @RequestMapping("/toPage")
    public String toPage(){
        return "page.jsp";
    }
    

  • 响应数据

    • 文本数据

      @RequestMapping("/toText")
      @ResponseBody
      public String toText(){
          return "response text";
      }
      

      这里返回到页面的,其实是字符串,而并非json!!!(前面所说的只是模拟json,莫慌)


    • json数据

      POJO对象转为json对象

      @RequestMapping("/toJsonPOJO")
      @ResponseBody
      public User toJsonPOJO(){
          System.out.println("返回json对象数据");
          User user = new User();
          user.setName("赵云");
          user.setAge(18);
          return user;
      }
      

      POJO集合对象转为json数组

      @RequestMapping("/toJsonList")
      @ResponseBody
      public List<User> toJsonList(){
          User user1 = new User();
          user1.setName("赵云");
          user1.setAge(41);
          User user2 = new User();
          user2.setName("master 赵云");
          user2.setAge(49);
          List<User> userList = new ArrayList<User>();
          userList.add(user1);
          userList.add(user2);
          return userList;
      }
      

对前面所说的@ResponseBody做一个重审,说明其具体的功能

  • @ResponseBody

名称:@ResponseBody

类型:方法注解

位置:SpringMVC控制器方法定义上方

作用:设置当前控制器返回值作为响应体

比如:如果是String的话,直接作为响应体;如果是对象则转为可识别的数据,再响应出去;对象转json;集合转json等。

举例:

@RequestMapping("/save")
@ResponseBody
public String save(){
    System.out.println("save ...");
    return "{'info':'springmvc'}";
}

类型转换器(HttpMessageConverter)

这一个注解所利用的接口是HttpMessageConverter接口,与Converter接口做的功能是一样的,只不过对应转换的东西不一样,都是用来做类型转换的。(如 数组(POJO)转json,json转数组(POJO))

在这里插入图片描述



REST风格

REST简介

  • 概念

    REST(Representational State Transfer),表现形式状态转换,改变获取资源的形式。

在这里插入图片描述


  • 优点:
    • 隐藏资源你的访问行为,无法通过地址得知对资源是何种操作
    • 书写简化

  • 行为动作

    按照REST风格访问资源时,使用行为动作区分 对资源进行了何种操作?

在这里插入图片描述

在这里插入图片描述


注意事项:上述行为是约定方法,约定不是规范,可以打破不执行,所以称为REST风格,而不是REST规范。

描述模块的名称通常使用复数,也就是加s的格式描述,表示此类资源,而非单个资源,例如:users,books,accounts…


  • RESTful

    根据REST风格对资源进行访问,称为RESTful


REST入门案例

  1. 设定http请求动作(动词)

    //添加用户信息
    @RequestMapping(value = "/users", method = RequestMethod.POST)
    @ResponseBody
    public String save(@RequestBody User user){
        System.out.println("user save..." + user);
        return "{'module':'user save'}";
    }
    
    //修改用户信息
    @RequestMapping(value = "/users", method = RequestMethod.PUT)
    @ResponseBody
    public String update(@RequestBody User user){
        System.our.println("user update..." + user);
        return "{'module':'user update'}";
    }
    

  2. 设定请求参数(路径变量)

    //删除指定用户
    @RequestMapping(value = "/users/{id}",method=RequestMethod.DELETE)
    @ResponseBody
    public String delete(@PathVariable Integer id){
        System.out.println("user delete..." + id);
        return "{'module':'user delete'}";
    }
    

以上主要使用了两个注解@RequestMapping和@PathVariable

  • @RequestMapping

    • 名称:@RequestMapping

    • 类型:方法注解

    • 位置:SpringMVC控制器方法定义上方

    • 作用:设置当前控制器方法请求访问路径

    • 举例:

      @RequestMapping(value = "/users",method = RequestMethod.POST)
      @ResponseBody
      public String save(@RequestBody User user){
          System.out.println("user save ..." + user);
          return "{'module':'user save'}";
      }
      
    • 属性:

      • value(默认有):请求访问路径
      • method:http请求动作,标准动作(GET/POST/PUT/DELETE)

  • @PathVariable

    • 名称:@PathVariable

    • 类型:形参注解

    • 位置:SpringMVC控制器方法形参定义前面

    • 作用:绑定路径参数与处理器方法形参间的关系,要求路径参数名与形参名一一对应

    • 范例:

      @RequestMapping(value = "/users/{id}", method = RequestMethod.DELETE)
      @ResponseBody
      public String delete(@PathVariable Integer id){
          System.out.println("user delete..." + id);
          return "{'module':'user delete'}";
      }
      

目前遇到的注解在方法形参中的注解,有@RequestBody,@RequestParam,@PathVariable三种,他们的作用也相近,都是用来辅助接收数据到形参。下面来做一个区别。

  • 区别
    • @RequestParam用于接收url地址传参或表单传参
    • @RequestBody用于接收json数据
    • @PathVariable用于接收路径参数,使用{参数名称}描述路径参数
  • 应用
    • 后期开发中,发送请求参数超过1个,以json格式为主,@RequestBody应用较广
    • 如果发送非json格式数据,选用@RequestParam接收请求参数
    • 采用RESTful进行开发,当参数数量较少时,例如1个,可以采用@PathVariable接收请求路径变量(通常用于传递id值)

RESTful快速开发

简化代码编写

  • value有统一的路径,可以提前到类前进行注解@RequestMapping(“/books”)

    (常是在公共请求路径后面加s,如books,users)

  • 每个方法都有@ResponseBody,也可以将其提到类前

在这里插入图片描述


  • 用**@RestController**简化合并@Controller和@ResponseBody两个注解

在这里插入图片描述


  • 用@GetMapping、@PostMapping、@PutMapping、@DeleteMapping等标准请求动作映射的注解,来简化method参数

在这里插入图片描述


基于RESTful页面数据交互案例

在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


在这里插入图片描述



SSM整合

基础的整合大致流程如下:

在这里插入图片描述


在这里插入图片描述


SSM整合的过程具体又分为Spring整合Mybatis,和Spring整合SpringMVC


Spring整合Mybatis

  • 大致流程

在这里插入图片描述


  • 配置

    • SpringConfig

在这里插入图片描述


  • JDBCConfig、jdbc.properties

在这里插入图片描述


在这里插入图片描述


  • MybatisConfig

在这里插入图片描述


  • 模型

    • Book

在这里插入图片描述


  • 数据层标准开发

    • BookDao

在这里插入图片描述


  • 业务层标准开发

    • BookService

在这里插入图片描述


  • BookServiceImpl

在这里插入图片描述


  • 测试接口

    • BookServiceTest

在这里插入图片描述


  • 事务处理

在这里插入图片描述



Spring整合SpringMVC

(包括基于RESTful标准控制器开发)

  • web配置类

在这里插入图片描述


  • SpringMvc配置类

在这里插入图片描述


  • RESTful标准控制器开发

在这里插入图片描述


在这里插入图片描述


在这里插入图片描述



代码实践:

具体看gitee仓库

https://gitee.com/CatalpaHao/ssmtest


表现层与前端数据传输数据协议实现

——————表现层数据封装


表现层与前端数据进行传输的过程中,常遇到数据的规定不统一,读取或存取数据的方式不同,容易造成处理时的繁杂等情况。

后续提出统一数据返回结果类,双方按照一定的规范来处理,对表现层的数据进行封装。

  • 设置统一数据返回结果类

    public class Result{
        private Object data;	//存放返回的数据(如查询数据)
        private Integer code;	//编码,表示该段数据的执行情况
        private String msg;		//消息message,情况具体说明(比如查询失败信息)
        
        //提供构造器和setter、getter
    }
    

    (Result类中的字段并不是固定的,可以根据需求自行增减,提供若干个构造方法,方便操作)


  • 设置统一数据返回结果编码(code)

    public class Code{
        public static final Integer SAVE_OK = 20011;
        public static final Integer DELETE_OK = 20021;
        public static final Integer UPDATE_OK = 20031;
        public static final Integer GET_OK = 20041;
        
        public static final Integer SAVE_ERR = 20010;
        public static final Integer DELETE_ERR = 20020;
        public static final Integer UPDATE_ERR = 20030;
        public static final Integer GET_ERR = 20040;
    }
    

    (Code类的常量设计也不是固定的,可以根据需要自行增减,例如将查询再进行细分为GET_OK,GET_ALL_OK,GET_PAGE_OK)


  • 根据情况设定合理的Result

    @RequestMapping("/books")
    public class BookController{
        @Autowired
        private BookService bookService;
        @GetMapping("/{id}")
        public Result getById(@PathVariable Integer id){
            Book book = bookService.getById(id);
            Integer code = book != null ? Code.GET_OK :Code.GET_ERR;
            String msg = book != null ? "" : "数据查询失败,请重试!";
            return new Result(code,book,msg);	//一般习惯会先写code。
        }
    }
    

总的来说,表现层借助Result类和定义好的Code,配合业务将数据整理成统一格式,进行封装,反馈给前端页面,再由前端页面进行解析,将数据渲染到页面上。



异常处理器

程序在开发过程中不可避免的会遇到异常形象

出行异常形象的常见位置与常见诱因如下:

  • 框架内部抛出的异常:因使用不合规导致
  • 数据层抛出的异常:因外部服务器故障导致(例如:服务器访问超时)
  • 业务层抛出的异常:因业务逻辑书写错误导致(例如:遍历业务书写操作,导致索引异常等)
  • 表现层抛出的异常:因数据手机、校验等规则导致(例如:不匹配的数据类型间导致异常)
  • 工具类抛出的异常:因工具类书写不严谨不够健壮导致(例如:必要释放的连连接长期未被释放等)

– 异常要进行分类处理,根据不同种类不同处理;所有的异常均抛出到表现层进行处理;异常要用AOP思想来处理。(----SpringMvc提供了快捷方式——异常处理器)


异常处理器

  • 集中的、统一的处理项目中出现的异常

    // REST风格下用@RestControllerAdvice ,还有另外类似功能的注解@ControllerAdvice
    @RestControllerAdvice
    public class ProjectExceptionAdvice{
        @ExceptionHandler(Exception.class)
        public Result doException(Exception ex){
            return new Result(666,null,"异常报错了,和你说一下");
        }
    }
    

以上所用注解

  • @RestControllerAdvice

    • 名称:@RestControler

    • 类型:类注解

    • 位置:Rest风格开发的控制器增强类定义上方

    • 作用:为Rest风格开发的控制器类做增强,声明这个类是做异常处理的。

    • 范例

      @RestControllerAdvice
      public class ProjectExceptionAdvice{
          
      }
      
    • 说明:

      此注解自带@ResponseBody注解与@Component注解,具备对应的功能

  • @ExceptionHandler

    • 名称:@ExceptionHandler

    • 类型:方法注解

    • 位置:专用于异常处理的控制器方法上方

    • 作用:设置指定异常的处理方案,功能等同于控制器方法,出现异常后终止原始控制器执行,并转入当前方法执行

    • 范例:

      @RestControllerAdvice
      public class ProjectExceptionAdvice{
          @ExceptionHandler(Exception.class)
          public Result doException(Exception ex){
              return new Result(666,null,"异常我来了");
          }
      }
      
    • 说明

      此类方法可以根据处理的异常不同,制作多个方法分别处理对应的异常

在这里插入图片描述


项目异常处理

异常分类:
  • 业务异常
    • 规范的用户行为产生的异常
    • 不规范的用户行为操作产生的异常
  • 系统异常
    • 项目运行过程中可预计且无法避免的异常
  • 其他异常
    • 编程人员未预期到的异常

异常处理方案
  • 业务异常
    • 发送对应消息传递给用户,提醒规范操作
  • 系统异常
    • 发送固定消息传递给用户,安抚用户
    • 发送特定消息给运维人员,提醒维护
    • 记录日志
  • 其他异常
    • 发送固定消息传递给用户,安抚用户
    • 发送特定消息给编程人员,提醒维护(纳入预期范围内)
    • 记录日志

异常处理操作流程
  1. 自定义项目系统级异常

    public class SystemException extends RuntimeException{
        private Integer code;
        public SystemException(Integer code, String message){
            super(message);
            this.code = code;
        }
        public SystemException(Integer code,String message, Throwable cause){
            super(message, cause);
            this.code = code;
        }
        public Integer getCode(){
            return code;
        }
        public void setCode(Integer code){
            this.code = code;
        }
    }
    

  2. 自定义项目业务级异常

    public class  BusinessException extends RuntimeException{
        private Integer code;
        public BusinessException(Integer code,String message){
            super(message);
            this.code = code;
        }
        public BusinessException(Integer code,String message,Throwable cause){
            super(message, cause);
            this.code = code;
        }
        public Integer getCode(){
            return code;
        }
        public void setCode(Integer code){
            this.code = code;
        }
    }
    

  3. 自定义异常编码(只是一部分,可以根据需求添加)

    public class Code{
        public static final Integer SYSTEM_UNKNOW_ERROR = 50001;
        public static final Integer	SYSTEM_TIMOUT_ERROR = 50002;
        
        public static final Integer PROJECT_VALIDATE_ERROR = 60001;
        public static final Integer PROJECT_BUSINESS_ERROR = 60002; 
    }
    

  4. 触发自定义异常

    (只是做一个异常出现情况的模拟,并没有实际含义)

    @Service
    public class BookServiceImpl implements BookService{
        @Autoired
        private BookDao bookDao;
        public Book getById(Integer id){
            if(id < 0){
                throw new BusinessException(Code.PROJECT_BUSINESS_ERROR,"请勿进行非法操作!");
            }
            return BookDao.getById(id);
        }    
    }
    

  5. 拦截并处理异常

    @RestControllerAdvice
    public class ProjectExceptionAdvice{
        @ExceptionHandler(BusinessException.class)
        public Result doBusinessException(BusinessException ex){
            return new Result(ex.getCode(),null,ex.getMessage());
        }
        
        @ExceptionHandler(SystemException.class)
        public Result doSystemException(SystemException ex){
            // 记录日志(错误堆栈)
            // 发送邮件给开发人员
            // 发送短信给运维人员
            return new Result(ex.getCode(), null, ex.getMessage());
        }
        
        @ExceptionHandler(Exception.class)
        public Result doException(Exception ex){
            // 记录日志(错误堆栈)
            // 发送邮件给开发人员
            // 发送短信给运维人员
            return new Result(Code.SYSTEM_UNKNOW_ERROR,null,"系统繁忙,请联系管理员!");
        }
    }
    

  6. 异常处理器效果对比

    成功的数据与异常报错的数据展示

在这里插入图片描述



案例:SSM整合标准开发(包括前端UI)

  • 列表显示
  • 新增
  • 跳转到修改
  • 修改
  • 删除


拦截器

拦截器概念

在这里插入图片描述


  • 拦截器(Interceptor)是一种动态拦截方法调用的机制,在SpringMVC中动态拦截控制器方法的执行

  • 作用

    • 在指定的方法调用前后执行预先设定的代码
    • 阻止原始方法的执行

  • 拦截器与过滤器区别
    • 归属不同:Filter属于Servlet技术,Interceptor属于SpringMVC技术
    • 拦截内容不同(执行的时机不同):Filter对所有访问进行增强(是在Tomcat服务器的阶段进行配置的),Interceptor仅针对SpringMVC的访问进行增强(取决于getServletMappings方法的配置–>“拦截的路径”)。

入门案例

  1. 步骤一:声明拦截器的bean,并实现HandlerInterceptor接口(注意要扫描加载bean)(示例)

    @Component
    public class ProjectInterceptor implements HandlerInterceptor{
        public boolean preHandle(..) throws Exception{
            System.out.println("preHandle...");
            return true;
        }
        public void postHandler(..) throws Exception{
            System.out.println("postHandle...");
        }
        public void afterCompletion(..) throws Exception{
            System.out.println("afterCompletion...");
        }
    }
    

  2. 步骤二:定义配置类,继承WebMvcConfigurationSupport,实现addInterceptor方法(注意加载配置类)(该配置类一定要用SpringMvcConfig来扫描来加载,否则将失效或报错)

    @Configuration
    @ComponentScan({"com.catalpa.controller","com.catalpa.config"})
    @EnableWebMvc
    public class SpringMvcSupport extends WebMvcConfigurationSupport{
        @Override
        public void addInterceptors(InterceptorRegistry registry){
            //...
        }
    }
    

  3. 步骤三:添加拦截器并设定拦截的访问路径,路径可以通过可变参数设置多个

    @Configuration
    public class SpringMvcSupport extends WebMvcConfigurationSupport{
        @Autowired
        private ProjectInterceptor projectInterceptor;
        
        @Override
        public void addInterceptors(InterceptorRegistry registry){
            registry.addInterceptor(projectInterceptor).addPathPatterns("/books");
        }
    }
    

  4. 使用标准接口WebMvcConfigurer简化开发(注意,该简化方法侵入性较强,一般不写在SpringMvcConfig里)

    @Configuration
    @ComponentScan("com.catalpa.controller")
    @EnableWebMvc
    public class SpringMVcConfig implements WebMvcConfigurer{
        @Autowired
        private ProjectInterceptor projectInterceptor;
        
        public void addInterceptors(InterceptorRegistry registry){
            registry.addInterceptor(projectInterceptor).addPathPatterns("/books","/books/*");
        }
    }
    


拦截器执行顺序,如图所示

在这里插入图片描述


拦截器参数

  • 前置处理

    public boolean preHandle(HttpServletRequest request,
                            HttpServletResponse response,
                            Object handler) throws Exception{
        System.out.println("preHandle...");
        return true;
    }
    
    • 参数:
      • request:请求对象
      • response:响应对象
      • handler:被调用的处理器对象,本质上是一个方法对象,对反射技术中的Method对象进行了再包装
    • 返回值
      • 返回值为false,被拦截的处理器将不再执行
      • 返回值为true,拦截的处理器继续执行

  • 后置处理

    public void postHandle(HttpServletRequest request,
                          HttpServletResponse response,
                          Object handler,
                          ModelAndView modeAndView) throws Exception{
        System.out.println("postHandle...");
    }
    
    • 参数
      • modelAndView:如果处理器执行完成具有返回结果,可以读取到对应数据与页面信息,并进行调整。

  • 完成后处理

    public void afterCompletion(HttpServletRequest request,
                               HttpServletResponse response,
                               Object handler,
                               Exception ex) throws Exception{
        System.out.println("afterCompletion...");
    }
    
    • 参数:
      • ex:如果处理器执行过程中出现异常对象,可以针对异常情况进行单独处理


多拦截器执行顺序

拦截器配置:

创建多个拦截器类后,配置一个拦截器,加一条“add”代码。一个个顺序地写上即可配置。(如图的加代码方式)

@Override
public void addInterceptors(InterceptorRegistry registry){
    registry.addInterceptor(projectInterceptor).addPathPatterns("/books","/books/*");
    registry.addInterceptor(projectInterceptor2).addPathPatterns("/books","/books/*");
}

  • 当配置多个拦截器的时候,将会形成拦截器链
  • 拦截器链的运行顺序参照拦截器添加顺序为准
  • 当拦截器中出现对原始处理器的拦截,后面的拦截器均终止运行
  • 当拦截器运行中断,仅运行 配置在前面的拦截器的afterCompletion操作

(如图可以加强理解)

在这里插入图片描述


  • 拦截器链的运行顺序
    • preHandle:与配置顺序相同,必定运行
    • postHandle:与配置顺序相反,可能不运行
    • afterCompletion:与配置顺序相反,可能不运行


总结

以上就是关于在黑马的课程里学习SpringMVC过程的笔记,记录下面,方便今后查看,也做一个交流。
SSM = Spring + SpringMvc + Mybatis。


就这样,老规矩,不秃头 日志,以上为个人笔记,也作为经验分享,大家可以参考使用,有问题也可以提出。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值