SpringMVC基础1

SpringMVC

SpringMvc入门

1.设置SpringMVC配置类

2.创建Controller类

3.配置ResultMapping注解

4.配置ResponseBody注解,不然的话默认return为页面

5.配置ServletWeb配置,替换web.xml,实现AbstractDispatcherServletInitializer接口

6.设置ServletWeb中的方法的返回值,以及拦截路径

注意事项

  • SpringMVC是基于Spring的,在pom.xml只导入了spring-webmvc jar包的原因是它会自动依赖spring相关坐标

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

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

    • createServletApplicationContext方法,创建Servlet容器时,加载SpringMVC对应的bean并放入WebApplicationContext对象范围中,而WebApplicationContext的作用

    • 范围为ServletContext范围,即整个web容器范围

    • getServletMappings方法,设定SpringMVC对应的请求映射路径,即SpringMVC拦截哪些请求

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

    • createServletApplicationContext用来加载SpringMVC环境

    • createRootApplicationContext用来加载Spring

@Controller

名称@Controller
类型类注解
位置SpringMVC控制器类定义上方
作用设定SpringMVC的核心控制器bean

@ResquestMapping

名称@RequestMapping
类型类注解或方法注解
位置SpringMVC控制器类或方法定义上方
作用设置当前控制器方法请求访问路径
相关属性value(默认),请求访问路径

@ResponseBody

名称@ResponseBody
类型类注解或方法注解
位置SpringMVC控制器类或方法定义上方
作用设置当前控制器方法响应内容为当前返回值,无需解析
  • 一次性工作

    • 创建工程,设置服务器,加载工程

    • 导入坐标

    • 创建web容器启动类,加载SpringMVC配置,并设置SpringMVC请求拦截路径

    • SpringMVC核心配置类(设置配置类,扫描controller包,加载Controller控制器bean)

  • 多次工作

    • 定义处理请求的控制器类

    • 定义处理请求的控制器方法,并配置映射路径(@RequestMapping)与返回json数据(@ResponseBody)

服务器初始化流程

1.服务器启动,执行ServletContainersInitConfig类,初始化web容器

  • 功能类似于以前的web.xml

2.执行createServletApplicationContext方法,创建了WebApplicationContext对象

  • 该方法加载SpringMVC的配置类SpringMvcConfig来初始化SpringMVC的容器

3.加载SpringMvcConfig配置类

4.执行@ComponentScan加载对应的bean

  • 扫描指定包其子包下所有类上的注解,如Controller类上的@Controller注解

5.加载UserController,每个@RequestMapping的名称对应一个具体的方法

  • 此时就建立了 /save 和 save方法的对应关系

6.执行getServletMappings方法,设定SpringMVC拦截请求的路径规则

  • 代表所拦截请求的路径规则,只有被拦截后才能交给SpringMVC来处理请求

单次请求过程

1.发送请求http://localhost/save

2.web容器发现该请求满足SpringMVC拦截规则,将请求交给SpringMVC处理

3.解析请求路径/save

4.由/save匹配执行对应的方法save()

  • 上面的第五步已经将请求路径和方法建立了对应关系,通过/save就能找到对应的save方法

5.执行save()

6.检测到有@ResponseBody直接将save()方法的返回值作为响应体返回给请求方

bean加载控制

当前目录结构

  • config配置类

    • ServletContainersInitConfig

    • SpringConfig

    • SpringMvcConfig

    • JdbcConfig

    • MybatisConfig

  • controller目录存放的是SpringMVC的controller类

  • service目录存放的是service接口和实现类

  • dao目录存放的是dao/Mapper接口

controller、service和dao这些类都需要被容器管理成bean对象,那么到底是该让SpringMVC加载还是让Spring加载呢?

  • SpringMVC加载其相关bean(表现层bean),也就是controller包下的类

  • Spring控制的bean

    • 业务bean(Service)

    • 功能bean(DataSource,SqlSessionFactoryBean,MapperScannerConfigurer等


在SpringMVC的配置中,只需要添加注解 Configuration 和 CompoentScan 并将 scan 扫描范围设置在 controller层即可

但是在Spring配置中,Scan 范围为整个包,所以 Spring 也会将 SpringMVC 扫描进来,但是由于功能不同所以不需要加载SpringMVC的Bean

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

  • 方式二:Spring加载的bean设定扫描范围为com.itheima,排除掉controller包中的bean

  • 方式三:不区分Spring与SpringMVC的环境,加载到同一个环境中[了解即可]

方法一:

直接进行配置精确路径即可

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

因为Dao最终是交给MapperScannerConfigurer对象来进行扫描处理的,我们只需要将其扫描到service包即可

方法二:

@Configuration
@ComponentScan(value = "com.itheima",
excludeFilters = @ComponentScan.Filter(
        type = FilterType.ANNOTATION,
        classes = Controller.class
    )
)
public class SpringConfig {
}
  • excludeFilters属性:设置扫描加载bean时,排除的过滤规则

  • type属性:设置排除规则,当前使用按照bean定义时的注解类型进行排除

    • ANNOTATION:按照注解排除

    • ASSIGNABLE_TYPE:按照指定的类型过滤

    • ASPECTJ:按照Aspectj表达式排除,基本上不会用

    • REGEX:按照正则表达式排除

    • CUSTOM:按照自定义规则排除

  • classes属性:设置排除的具体注解类,当前设置排除@Controller定义的bean

在进行测试是否排除的时候,需要将 SpringMVC 中的 Scan 去掉,因为,Spring 会将 SpringMVC 的配置扫描进来,因此也会将 SpringMVC 的 Scan 扫描进来,会再次加载进 Controller


启动 tomcat 服务器的时候我们需要将 Spring 和 SpringMVC 的配置加载进 tomcat 的服务器中,因此我们需要修改 ServletContainersInitConfig 配置类中的参数

public class ServletContainersInitConfig extends AbstractDispatcherServletInitializer {
    //加载springMVC容器配置
    @Override
    protected WebApplicationContext createServletApplicationContext() {
        AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
        ctx.register(SpringMvcConfig.class);
        return ctx;
    }
    //设置哪些请求归SpringMVC处理
    @Override
    protected String[] getServletMappings() {
        return new String[]{"/"}; // 所有请求
    }
    //加载Spring容器配置
    @Override
    protected WebApplicationContext createRootApplicationContext() {
        AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
        ctx.register(SpringConfig.class);
        return ctx;
    }
}

对于上述的配置方式,Spring还提供了一种更简单的配置方式,可以不用再去创建 AnnotationConfigWebApplicationContex t对象,不用手动register对应的配置类,即继承 AbstractAnnotationConfigDispatcherServletInitializer 类

public class ServletContainersInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
​
​
    protected Class<?>[] getRootConfigClasses() {
        return new Class[]{SpringConfig.class};// Spring
    }
​
    protected Class<?>[] getServletConfigClasses() {
        return new Class[]{SpringMvcConfig.class}; //SpringMve
    }
​
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }
    // 解决乱码问题
    @Override
    protected Filter[] getServletFilters() {
​
        CharacterEncodingFilter filter = new CharacterEncodingFilter();
        filter.setEncoding("UTF-8");
        return new Filter[]{filter};
    }
名称@ComponetScan
类型类注解
位置类定义上方
作用设置spring配置类扫描路径,用于加载使用注解格式定义的bean
相关属excludeFilters:排除扫描路径中加载的bean,includeFilters:加载指定的bean,需要指定类别(type)和具体项(classes)

请求与响应

  • 请求映射路径

  • 请求参数

  • 日期类型参数传递

  • 响应json数据

设置映射路径

如果只通过 ResultMapping 的映射路径来进行设置路径的话,当存在多个模块出现共同方法的时候就会出现找不到路径的问题,因此我们需要解决这种问题的出现

通过观察我们可以发现,我们可以根据模块的名称来设置相应的绝对路径,因此可以设置为这种格式

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

问题是解决了,但是每个方法前面都需要进行修改,写起来比较麻烦而且还有很多重复代码,如果/user后期发生变化,所有的方法都需要改,耦合度太高。因此我们可以将 RequeMapping 配置在 Controller 类的路径上

@Controller 
@RequestMapping("/user") 
public class UserController {
    @RequestMapping("/save") 
    @ResponseBody
    public String save(){ 
    System.out.println("user save ...");
    return "{'module':'user save'}"; 
    }
}
  • 当类上和方法上都添加了@RequestMapping注解,前端发送请求的时候,要和两个注解的value值相加匹配才能访问到。

  • @RequestMapping注解value属性前面加不加/都可以

请求参数

请求路径设置好后,只要确保页面发送请求地址和后台Controller类中配置的路径一致,就可以接收到前端的请求,接收到请求后,如何接收页面传递的参数?


对于常见的请求方式主要有两种,分别为

  • Post

  • Get

Get请求

接受单个普通参数:

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

接受多个普通参数:

@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 "{'module':'commonParam'}";
    }
}

Get请求中出现中文乱码:

只需要修改xml配置文件即可

<configuration> 
    <port>80</port><!--tomcat端口号-->
    <path>/</path> <!--虚拟目录-->
    <uriEncoding>UTF-8</uriEncoding><!--访问路径编解码字符集-->
</configuration>

Post请求

与Get请求处理方法一样

Post请求中出现中文乱码:

通过配置过滤器来进行处理中文乱码:也就是初始化 Web 服务器时配置乱码处理的过滤器,并设置编码格式为 utf-8

public class ServletContainersInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
    protected Class<?>[] getRootConfigClasses() {
        return new Class[0];
    }

    protected Class<?>[] getServletConfigClasses() {
        return new Class[]{SpringMvcConfig.class};
    }

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

    //乱码处理
    @Override
    protected Filter[] getServletFilters() {
        CharacterEncodingFilter filter = new CharacterEncodingFilter();
        filter.setEncoding("UTF-8");
        return new Filter[]{filter};
    }
}

CharacterEncodingFilter是在spring-web包中,所以用之前需要导入对应的jar包

五种类型请求参数传递

前面我们已经能够使用GET或POST来发送请求和数据,所携带的数据都是比较简单的数据,接下来在这个基础上,我们来研究一些比较复杂的参数传递,常见的参数种类有:

  • 普通参数

  • POJO类型参数

  • 嵌套POJO类型参数

  • 数组类型参数

  • 集合类型参数


普通参数:url地址传参,地址参数名与形参变量名相同,定义形参即可接收参数。

如果存在参数名不一样的情况下,则需要使用 @RequestParam 注解来解决参数问题

@RequestMapping("/commonParamDifferentName")
@ResponseBody 
public String commonParamDifferentName(@RequestPaam("name") String userName,int age)
{
    System.out.println("普通参数传递 userName ==> "+userName);
    System.out.println("普通参数传递 age ==> "+age);
    return"{'module':'common param different name'}";
}

POJO参数:请求参数名与形参对象属性名相同,定义POJO类型形参即可接收参数

后台接收参数:

//POJO参数:请求参数与形参对象中的属性对应即可完成参数传递
@RequestMapping("/pojoParam") 
@ResponseBody 
public String pojoParam(User user){
    System.out.println("pojo参数传递 user ==> "+user);
    return"{'module':'pojo param'}";
}
  • POJO参数接收,前端GET和POST发送请求数据的方式不变。

  • 请求参数key的名称要和POJO中属性的名称一致,否则无法封装。

嵌套POJO参数:请求参数名与形参对象属性名相同,按照对象层次结构关系即可接收嵌套POJO属性参数

在 pojo 类型中,设置了另外的 pojo 类型:

public class Address {
    private String province;
    private String city; //setter...getter...略 }

    public class User {
        private String name;
        private int age;
        private Address address; //setter...getter...略 
    }
}

后台接收参数:

发送的格式应该为: address.city address.provience

请求参数key的名称要和POJO中属性的名称一致,否则无法封装

//POJO参数:请求参数与形参对象中的属性对应即可完成参数传递
@RequestMapping("/pojoParam")
@ResponseBody 
public String pojoParam(User user){
    System.out.println("pojo参数传递 user ==> "+user);
    return "{'module':'pojo param'}";
}

数组参数:请求参数名与形参对象属性名相同且请求参数为多个,定义数组类型即可接收参数

后台接收参数:

@RequestMapping("/arrayParam") 
@ResponseBody 
public String arrayParam(String[]likes){
    System.out.println("数组参数传递 likes ==> "+Arrays.toString(likes));
    return"{'module':'array param'}";
}

这种情况下会有错误的出现,SpringMVC 会将 List 当作一个POJO 的对象来处理,所以会报错,因此我们可以使用 @RequestParam注解

@RequestMapping("/listParam")
@ResponseBody
public String listParam(@RequestParam List<String> likes){
    System.out.println("集合参数传递 likes ==> "+likes);
    return"{'module':'list param'}";
}
  • 集合保存普通参数:请求参数名与形参集合对象名相同且请求参数为多个,@RequestParam绑定参数关系

  • 对于简单数据类型使用数组会比集合更简单些

名称@RequestParam
类型类注解或方法注解
位置SpringMVC控制器类或方法定义上方
作用设置当前控制器方法请求访问路径
相关参数value(默认),请求访问路径

JSON数据传输

对于JSON数据类型,我们常见的有三种:

  • json普通数组(["value1","value2","value3",...])

  • json对象({key1:value1,key2:value2,...})

  • json对象数组([{key1:value1,...},{key2:value2,...}])

JSON普通数组:

在SpringMVC的配置类中开启SpringMVC的注解支持,这里面就包含了将JSON转换成对象的功能

@Configuration 
@ComponentScan("com.itheima.controller")
//开启json数据类型自动转换
@EnableWebMvc 
public class SpringMvcConfig {   
}
//使用@RequestBody注解将外部传递的json数组数据映射到形参的集合对象中作为数据
@RequestMapping("/pojoParamForJson")
@ResponseBody 
public String pojoParamForJson(@RequestBody User user){ 
    System.out.println("pojo(json)参数传递 user ==> "+user);
    return "{'module':'pojo for json param'}";
}

SpringMVC接收JSON数据的实现步骤为:

  • (1)导入jackson包

  • (2)使用PostMan发送JSON数据

  • (3)开启SpringMVC注解驱动,在配置类上添加@EnableWebMvc注解

  • (4)Controller方法的参数前添加@RequestBody注解

名称@EnableWebMvc
类型配置类注解
位置SpringMVC控制器类或方法定义上方
作用开启SpringMVC多项辅助功能

@RequestBody

名称@ResponseBody
类型类注解或方法注解
位置SpringMVC控制器类或方法定义上方
作用设置当前控制器方法响应内容为当前返回值,无需解析

@RequestBody与@RequestParam区别

  • 区别

    • @RequestParam用于接收url地址传参,表单传参【application/x-www-formurlencoded】

    • @RequestBody用于接收json数据【application/json】

  • 应用

  • 后期开发中,发送json格式数据为主,@RequestBody应用较广如果发送非json格式数据,选用@RequestParam接收请求参数

日期类型参数传递

SpringMVC默认支持的字符串转日期的格式为yyyy/MM/dd,如果想传入别的值则可以使用 @DateTimeFormat 注解

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

@DateTimeFormat

名称@DateTimeFormat
类型形参注解
位置SpringMVC控制器方法形参前面
作用设定日期时间型数据格式
相关属性pattern:指定日期时间格式字符串

内部实现原理

讲解内部原理之前,我们需要先思考个问题:

  • 前端传递字符串,后端使用日期Date接收

  • 前端传递JSON数据,后端使用对象接收

  • 前端传递字符串,后端使用Integer接收

  • 后台需要的数据类型有很多中

  • 在数据的传递过程中存在很多类型的转换

问:谁来做这个类型转换?

答:SpringMVC

问:SpringMVC是如何实现类型转换的?

答:SpringMVC中提供了很多类型转换接口和实现类

  1. Converter接口,Converter所属的包为org.springframework.core.convert.converter,

请求参数年龄数据(String→Integer)

日期格式转换(String → Date)

  1. HttpMessageConverter接口,该接口是实现对象与JSON之间的转换工作

注意:SpringMVC的配置类把@EnableWebMvc当做标配配置上去,不要省略


响应

SpringMVC接收到请求和数据后,进行一些了的处理,当然这个处理可以是转发给Service,Service层再调用Dao层完成的,不管怎样,处理完以后,都需要将结果告知给用户

对于响应,主要就包含两部分内容:

  • 响应页面

  • 响应数据

    • 文本数据

    • json数据

因为异步调用是目前常用的主流方式,所以我们需要更关注的就是如何返回JSON数据


响应页面:

@Controller
public class UserController {
    @RequestMapping("/toJumpPage")
    //注意 //1.此处不能添加@ResponseBody,如果加了该注入,会直接将page.jsp当字符串返回前端
          //2.方法需要返回
     String public String toJumpPage(){
        System.out.println("跳转页面");
        return "page.jsp";
    }
}

返回文本数据:

@Controller
public class UserController {
    @RequestMapping("/toText") 
    //注意此处该注解就不能省略,如果省略了,会把response text当前页面名称去查找,如果没有 回报404错误 
    @ResponseBody 
    public String toText(){ 
        System.out.println("返回纯文本数据"); 
        return "response text";
    } 
}

响应JSON数据:

响应Pojo对象:

@Controller
public class UserController {
    @RequestMapping("/toJsonPOJO")
    @ResponseBody
    public User toJsonPOJO() {
        System.out.println("返回json对象数据");
        User user = new User();
        user.setName("itcast");
        user.setAge(15);
        return user;
    }
}

返回值为实体类对象,设置返回值为实体类类型,即可实现返回对应对象的json数据,需要依赖@ResponseBody注解和@EnableWebMvc注解

响应POJO集合对象:

@Controller
public class UserController {
    @RequestMapping("/toJsonList")
    @ResponseBody
    public List<User> toJsonList() {
        System.out.println("返回json集合数据");
        
        User user1 = new User();
        user1.setName("传智播客");
        user1.setAge(15);
        
        User user2 = new User();
        user2.setName("黑马程序员");
        user2.setAge(12);
        
        List<User> userList = new ArrayList<User>();
        userList.add(user1);
        userList.add(user2);
        return userList;
    }
}

@ResponseBody

名称@ResponseBody
类型方法\类注解
位置SpringMVC控制器方法定义上方和控制类上
作用设置当前控制器返回值作为响应体,写在类上,该类的所有方法都有该注解功能

说明:

  • 该注解可以写在类上或者方法上

  • 写在类上就是该类下的所有方法都有@ReponseBody功能

  • 当方法上有@ReponseBody注解后

    • 方法的返回值为字符串,会将其作为文本内容直接响应给前端

    • 方法的返回值为对象,会将对象转换成JSON响应给前端

此处又使用到了类型转换,内部还是通过Converter接口的实现类完成的,所以Converter除了前面所说的功能外,它还可以实现:

  • 对象转Json数据(POJO -> json)

  • 集合转Json数据(Collection -> json)

Rest风格

对于Rest风格,我们需要学习的内容包括:

  • REST简介

  • REST入门案例

  • REST快速开发

  • 案例:基于RESTful页面数据交互

Rest简介

传统方式一般是一个请求url对应一种操作,这样做不仅麻烦,也不安全,因为会程序的人读取了你的请求url地址,就大概知道该url实现的是一个什么样的操作,查看REST风格的描述,你会发现请求地址变的简单了,并且光看请求URL并不是很能猜出来该URL的具体功能

所以REST的优点有:

  • 隐藏资源的访问行为,无法通过地址得知对资源是何种操作

  • 书写简化

一个相同的url地址即可以是新增也可以是修改或者查询,那么到底我们该如何区分该请求到底是什么操作?

请求的方式比较多,但是比较常用的就4种,分别是GET , POST , PUT , DELETE,按照不同的请求方式代表不同的操作类型

  • 发送GET请求是用来做查询

  • 发送POST请求是用来做新增

  • 发送PUT请求是用来做修改

  • 发送DELETE请求是用来做删除

但是注意:

  • 上述行为是约定方式,约定不是规范,可以打破,所以称REST风格,而不是REST规范

    • REST提供了对应的架构方式,按照这种架构设计项目可以降低开发的复杂性,提高系统的可伸缩性

    • REST中规定GET/POST/PUT/DELETE针对的是查询/新增/修改/删除,但是我们如果非要用GET请求做删除,这点在程序上运行是可以实现的

    • 但是如果绝大多数人都遵循这种风格,你写的代码让别人读起来就有点莫名其妙了。

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

清楚了什么是REST风格后,我们后期会经常提到一个概念叫RESTful,那什么又是RESTful呢?

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

后期我们在进行开发的过程中,大多是都是遵从REST风格来访问我们的后台服务,所以可以说咱们以后都是基于RESTful来进行开发的。


Restful开发

需求:将之前的增删改查替换成RESTful的开发方式。

1.之前不同的请求有不同的路径,现在要将其修改为统一的请求路径

修改前: 新增: /save ,修改: /update,删除 /delete...

修改后: 增删改查: /users

2.根据GET查询、POST新增、PUT修改、DELETE删除对方法的请求方式进行限定

3.发送请求的过程中如何设置请求参数?

新增:

@Controller
public class UserController {
    //设置当前请求方法为POST,表示REST风格中的添加操作 
    @RequestMapping(value = "/users", method = RequestMethod.POST)
    @ResponseBody
    public String save() {
        System.out.println("user save...");
        return "{'module':'user save'}";
    }
}
  • 将请求路径更改为/users

  • 使用method属性限定该方法的访问方式为POST

    • 如果发送的不是POST请求,比如发送GET请求,则会报错

删除:

@Controller
public class UserController {
    //设置当前请求方法为DELETE,表示REST风格中的删除操作 
    @RequestMapping(value = "/users", method = RequestMethod.DELETE)
    @ResponseBody
    public String delete(Integer id) {
        System.out.println("user delete..." + id);
        return "{'module':'user delete'}";
    }
}

访问成功,但是删除方法没有携带所要删除数据的id,所以针对RESTful的开发,如何携带数据参数?

前端发送请求的时候使用: http://localhost/users/1 ,路径中的1就是我们想要传递的参数

后端获取参数,需要做如下修改:

  • 修改@RequestMapping的value属性,将其中修改为/users/{id},目的是和路径匹配

  • 在方法的形参前添加@PathVariable注解

@Controller
public class UserController {
    //设置当前请求方法为DELETE,表示REST风格中的删除操作
    @RequestMapping(value = "/users/{id}", method = RequestMethod.DELETE)
    @ResponseBody
    public String delete(@PathVariable("id") Integer id) {
        System.out.println("user delete..." + id);
        return "{'module':'user delete'}";
    }
}
}

当形参与 value 中参数一样时,可以忽略 PathVariable 中的属性

前端发送请求的时候使用: http://localhost/users/1/tom ,路径中的1和tom就是我们想要传递的两个参数

@Controller
public class UserController {
    //设置当前请求方法为DELETE,表示REST风格中的删除操作 
    @RequestMapping(value = "/users/{id}/{name}", method = RequestMethod.DELETE)
    @ResponseBody
    public String delete(@PathVariable Integer id, @PathVariable String name) {
        System.out.println("user delete..." + id + "," + name);
        return "{'module':'user delete'}";
    }
}

修改:

@Controller
public class UserController {
    //设置当前请求方法为PUT,表示REST风格中的修改操作
    @RequestMapping(value = "/users", method = RequestMethod.PUT)
    @ResponseBody
    public String update(@RequestBody User user) {
        System.out.println("user update..." + user);
        return "{'module':'user update'}";
    }
}
  • 将请求路径更改为/users

  • 访问并携带参数: 使用 json 的形式传入参数

根据ID查询

@Controller
public class UserController {
    //设置当前请求方法为GET,表示REST风格中的查询操作 
    @RequestMapping(value = "/users/{id}", method = RequestMethod.GET)
    @ResponseBody
    public String getById(@PathVariable Integer id) {
        System.out.println("user getById..." + id);
        return "{'module':'user getById'}";
    }
}
}

将请求路径更改为/users

查询所有:

@Controller
public class UserController {
    //设置当前请求方法为GET,表示REST风格中的查询操作
    @RequestMapping(value = "/users", method = RequestMethod.GET)
    @ResponseBody
    public String getAll() {
        System.out.println("user getAll...");
        return "{'module':'user getAll'}";
    }
}
}

将请求路径更改为/users

小结

(1)设定Http请求动作(动词)

@RequestMapping(value="",method = RequestMethod.POST|GET|PUT|DELETE)

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

@RequestMapping(value="/users/{id}",method = RequestMethod.DELETE)

@ReponseBody

public String delete(@PathVariable Integer id){

}

@PathVariable

名称@PathVariable
类型形参注解
位置SpringMVC控制器方法形参定义前面
作用绑定路径参数与处理器方法形参间的关系,要求路径参数名与形参名一一对应

关于接收参数,我们学过三个注解@RequestBody、@RequestParam、@PathVariable ,这三个注解之间的区别和应用分别是什么?

  • 区别

    • @RequestParam用于接收url地址传参或表单传参

    • @RequestBody用于接收json数据

    • @PathVariable用于接收路径参数,使用{参数名称}描述路径参数

  • 应用

    • 后期开发中,发送请求参数超过1个时,以json格式为主,@RequestBody应用较广

    • 如果发送非json格式数据,选用@RequestParam接收请求参数

    • 采用RESTful进行开发,当参数数量较少时,例如1个,可以采用@PathVariable接收请求路径变量,通常用于传递id值


RESTful快速开发

做完了RESTful的开发,你会发现好麻烦,麻烦在哪?

问题1:每个方法的@RequestMapping注解中都定义了访问路径/books,重复性太高

将@RequestMapping提到类上面,用来定义所有方法共同的访问路径。

问题2:每个方法的@RequestMapping注解中都要使用method属性定义请求方式,重复性太高

使用@GetMapping @PostMapping @PutMapping @DeleteMapping代替

问题3:每个方法响应json都需要加上@ResponseBody注解,重复性太高

1.将ResponseBody提到类上面,让所有的方法都有@ResponseBody的功能 
2.使用@RestController注解替换@Controller与@ResponseBody注解,简化书写

所以我们可以这样:

@RestController//@Controller + ReponseBody
@RequestMapping("/books")
public class BookController {
    //@RequestMapping(method = RequestMethod.POST)
    @PostMapping
    public String save(@RequestBody Book book) {
        System.out.println("book save..." + book);
        return "{'module':'book save'}";
    }

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

    //@RequestMapping(method = RequestMethod.PUT)
    @PutMapping
    public String update(@RequestBody Book book) {
        System.out.println("book update..." + book);
        return "{'module':'book update'}";
    }

    //@RequestMapping(value = "/{id}",method = RequestMethod.GET)
    @GetMapping("/{id}")
    public String getById(@PathVariable Integer id) {
        System.out.println("book getById..." + id);
        return "{'module':'book getById'}";
    }

    //@RequestMapping(method = RequestMethod.GET)
    @GetMapping
    public String getAll() {
        System.out.println("book getAll...");
        return "{'module':'book getAll'}";
    }
}

@RestController

名称@RestController
类型类注解
位置基于SpringMVC的RESTful开发控制器类定义上方
作用设置当前控制器类为RESTful风格,等同于@Controller与@ResponseBody两个注解组合功能

@GetMapping @PostMapping @PutMapping @DeleteMapping

名称@GetMapping @PostMapping @PutMapping @DeleteMapping
类型方法注解
位置基于SpringMVC的RESTful开发控制器方法定义上方
作用设置当前控制器方法请求访问路径与请求动作,每种对应一个请求动作,例如@GetMapping对应GET请求
相关属性value(默认):请求访问路径

SpringMVC拦截静态资源

SpringMVC之所以拦截静态资源是因为配置ServletContainerInitConfig的时候设置拦截路径为 “ / ” 所以会拦截所有的路径,解决方案为:

  • SpringMVC需要将静态资源进行放行。

@Configuration
public class SpringMvcSupport extends WebMvcConfigurationSupport {
    @Override
    protected void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/pages/**").addResourceLocations("/pages/");
        registry.addResourceHandler("/js/**").addResourceLocations("/js/");
        registry.addResourceHandler("/css/**").addResourceLocations("/css/");
        registry.addResourceHandler("/plugins/**").addResourceLocations("/plugins/");
    }
}
  • 该配置类是在config目录下,SpringMVC扫描的是controller包,所以该配置类还未生效,要想生效需要将SpringMvcConfig配置类进行修改

@Configuration
@ComponentScan({"com.itheima.controller", "com.itheima.config"})
@EnableWebMvc
public class SpringMvcConfig {
}
//或者
@Configuration
@ComponentScan("com.itheima")
@EnableWebMvc
public class SpringMvcConfig {
}
  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

赵英英俊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值