Spring MVC 注解开发

SpringMVC 可以通过注解配置的方式进行开发。

一、使用注解开发的好处

  • 一个 Controller 类中可以编写多个处理方法,从而可以与多个 url 建立映射关系,处理多个请求
  • 开发更加简单,减少代码

二、开发流程

1. 前置工作

(1) 导入依赖

在 pom.xml 文件中添加信息如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!--Spring-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>版本号</version>
</dependency>

<!--Servlet-->
<dependency>
<groupId>javax.servlet</groupId>
<!--3.0版本前是servlet-api-->
<!--3.0版本后是javax.servlet-api-->
<artifactId>javax.servlet-api</artifactId>
<version>版本号</version>
</dependency>

(2) 接管所有请求

DispatcherServlet 是整个 SpringMVC 的核心,它会接管所有请求,并将请求分配给对应的 controller 。

为拦截所有请求,需要在 web.xml 中配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">

<!--注册DispatcherServlet-->
<servlet>
<servlet-name>SpringMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--关联SpringMVC配置文件-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:SpringMVC-servlet.xml</param-value>
</init-param>
<!--表示容器再启动时立即加载servlet-->
<load-on-startup>1</load-on-startup>
</servlet>

<!--匹配所有请求-->
<servlet-mapping>
<servlet-name>SpringMVC</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>

</web-app>

(3) 创建 SpringMVC 配置文件并开启注解功能

创建 SpringMVC-servlet.xml,填写如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">

<!--开启注解功能,扫描包中的类,根据注解注册对应的Bean-->
<context:component-scan base-package="全限定包名"/>

<!--使SpringMVC不处理静态资源-->
<mvc:default-servlet-handler/>

<!--为了使SpringMVC支持注解,还需要配置两个实例-->
<!--* DefaultAnnotationHandlerMapping-->
<!--* AnnotationMethodHandlerAdapter-->
<!--可以通过 <mvc:annotation-driven/> 标签完成上述实例的注入-->
<mvc:annotation-driven/>

</beans>

2. 编写 Controller

  • 创建类,使用 @Controller 注解

  • 在类中编写方法

    • 为方法添加注解,与路径建立映射关系

      1
      @RequestMapping("/访问路径")
    • 为方法添加类型为 Model 的形参,通过该对象的 addAttribute() 等方法传递数据

    • 方法的返回类型应为 String,将希望跳转的视图的视图路径以字符串的形式 return

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Controller
public class Controller{

@RequestMapping("/访问路径1")
public String 方法名1(Model model) {
// 传递模型
model.addAttribute(键, 值);

// 跳转视图
return "视图路径";
}

@RequestMapping("/访问路径2")
public String 方法名2(Model model) {
// 传递数据
model.addAttribute(键, 值);

// 跳转视图
return "视图路径";
}

}

3. 启动项目

使用 Tomcat 启动,通过 https://域名:端口/项目路径/访问路径,即可访问到对应的方法。

三、@Controller 注解

@Controller 注解用于声明类为 Controller,并且被 Spring 接管。

四、@RequestMapping 注解

1. 作用

@RequestMapping 注解用于将类或方法与路径建立映射关系。

2. 属性

  • value 和 path:即映射的路径

  • name:别名,相当于注释

  • method:用于指定 HTTP 请求方法

    例如:

    method 为 RequestMethod.GET,则只有 HTTP 请求方法为 get 的请求才能访问到该方法

  • params:用于指定请求中的参数,只有请求中包含指定参数时才能访问到该方法

  • header:用于指定请求头,仅当包含指定请求头时才能访问到该方法

  • consumers:用于指定处理请求的提交内容类型

  • produces:用于指定返回的内容类型

3. 类路径

Controller 类上也可以使用 @RequestMapping("/访问路径") 进行注解

1
2
3
4
5
6
7
8
9
10
@Controller
@RequestMapping("/类上路径")
public class Controller{

@RequestMapping("/方法上路径")
public String 方法名1(Model model) {
···
}

}

通过 https://域名:端口/项目路径/类上路径/方法上路径 来访问到对应的方法

五、参数获取

1. 获取请求参数

可以在 Controller 类的方法上添加形参来获取请求中的参数,当请求中的参数的名称与类型和形参相对应时,参数值将会被传递到形参之中

Controller 类如下:

1
2
3
4
5
6
7
8
9
@Controller
public class Controller{

@RequestMapping("/访问路径")
public String add(Model model, int a) {
···
}

}

客户端访问路径,并传入参数 https://域名:端口/项目路径/访问路径?a=4

此时便可以在方法中通过形参 a 来获取到客户端传入的值。

2. @RequestParam 注解

还可以为形参增加 @RequestParam 注解,其作用有:

  • 用于表明形参是从请求中获取的参数
  • 可以显式指定请求中应包含的参数
  • 当形参中的参数名与请求中的参数名不相同时,可以通过它修改
1
2
3
4
5
6
7
8
9
@Controller
public class Controller{

@RequestMapping("/访问路径")
public String 方法名(Model model, @RequestParam("请求中参数名") 参数类型 形参名) {
···
}

}

3. RestFul 风格参数获取

(1) RestFul 风格

具体请看:

面试官:你连RESTful都不知道我怎么敢要你? - 知乎

(2) RestFul 风格的 url

  • 传统做法的 url:

    1
    2
    获取标识为1用户信息
    https://example.com/api/getuser?id=1
  • RestFul 风格的 url:

    1
    2
    获取标识为1用户信息
    https://example.com/api/users/1

参数在路径中,而不是在请求参数中。

(3) 获取RestFul 风格路径中的参数

  • 用 @RequestMapping 注解方法,并在访问路径中要填入参数的位置用 {参数名} 占位
  • 在方法的形参中增加形参,并用 @PathVariable 注解
1
2
3
4
5
6
7
8
9
10
@Controller
public class Controller{

@RequestMapping("/···/{参数1}/{参数2}/···")
public String 方法名(@PathVariable 参数类型 参数1, @PathVariable 参数类型 参数2, Model model) {

···
}

}

SpringMVC 会将方法映射到用任意字符替代 {参数名} 的路径,并将其值赋给形参。

4. 获取 request 和 response

可以在 Controller 类的方法上添加 类型为 HttpServletRequest 和 HttpServletResponse 的形参,从而获取到 request 和 response 对象。

不推荐

六、传递数据

1. 普通传递

为方法添加类型为 Model 的形参,通过该对象的 addAttribute() 等方法传递数据。

2. @ModelAttribute 注解

(1) 说明

@ModelAttribute 注解可以有以下几种应用方式:

  • 应用在方法上
  • 应用在参数上
  • 和 @RequestMapping 共同应用在方法上

@ModelAttribute 注解用于将请求参数添加到 Model 对象上。

(2) 应用在方法上

被 @ModelAttribute 注解的方法会在 Controller 每个方法执行之前都执行,可以通过它为 Controller 的每一个方法的 model 添加数据。

@ModelAttribute 注解在方法上有两种使用方式:

  • 方法无返回值

    1
    2
    3
    4
    5
    6
    7
    8
    9
    @Controller
    public class Controller{

    @ModelAttribute
    public void 方法名(Model model) {
    model.addAttribute(键, 值);
    }

    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    @Controller
    public class Controller{

    @ModelAttribute
    public void 方法名(Model model) {
    model.addAttribute(键, 值);
    }

    @RequestMapping("/访问路径1")
    public String 方法名1(Model model) {
    return "视图路径";
    }

    @RequestMapping("/访问路径2")
    public String 方法名2(Model model) {
    return "视图路径";
    }

    }

    被 @ModelAttribute 注解的方法将会在 Controller 的每个方法执行前执行。

    因此,上面这段代码等效于:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    @Controller
    public class Controller{

    @RequestMapping("/访问路径1")
    public String 方法名1(Model model) {
    model.addAttribute(键, 值);
    return "视图路径";
    }

    @RequestMapping("/访问路径2")
    public String 方法名2(Model model) {
    model.addAttribute(键, 值);
    return "视图路径";
    }

    }
  • 方法带返回值

    1
    2
    3
    4
    5
    6
    7
    8
    9
    @Controller
    public class Controller{

    @ModelAttribute(键)
    public void 方法名(Model model) {
    return 值;
    }

    }

    这段代码等效于:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    @Controller
    public class Controller{

    @ModelAttribute
    public void 方法名(Model model) {
    model.addAttribute(键, 值);
    }

    }

(3) 应用在参数上

@ModelAttribute 注解也可以应用在参数之上,被它注解的参数将会被添加至 model 之中。

  • 不指定键

    1
    2
    3
    4
    5
    6
    7
    8
    9
    @Controller
    public class Controller{

    @RequestMapping("/访问路径")
    public String 方法名1(Model model, @ModelAttribute 形参类型 形参名) {
    return "视图路径";
    }

    }

    等效于:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    @Controller
    public class Controller{

    @RequestMapping("/访问路径")
    public String 方法名1(Model model, 形参类型 形参名) {
    model.addAttribute(形参类型, 形参值);
    return "视图路径";
    }

    }
  • 指定键

    1
    2
    3
    4
    5
    6
    7
    8
    9
    @Controller
    public class Controller{

    @RequestMapping("/访问路径")
    public String 方法名1(Model model, @ModelAttribute(键) 形参类型 形参名) {
    return "视图路径";
    }

    }

    等效于:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    @Controller
    public class Controller{

    @RequestMapping("/访问路径")
    public String 方法名1(Model model, 形参类型 形参名) {
    model.addAttribute(键, 形参值);
    return "视图路径";
    }

    }

(4) 和 @RequestMapping 共同应用在方法上

1
2
3
4
5
6
7
8
9
10
11
@Controller
public class Controller{

@RequestMapping("/访问路径")
@ModelAttribute(键)
public String 方法名1(Model model) {

return 值;
}

}
  • 方法的返回值将会被存入 model 之中,并以 @ModelAttribute 的属性作为键
  • 方法将跳转至路径为 “/访问路径” 的视图

等效于:

1
2
3
4
5
6
7
8
9
10
@Controller
public class Controller{

@RequestMapping("/访问路径")
public String 方法名1(Model model, 形参类型 形参名) {
model.addAttribute(键, 形参值);
return "/访问路径";
}

}

3. 传递 JSON

(1) 前后端分离开发模式

在前后端分离的开发模式中,后端需要做的不再是向客户端发送视图,而是向客户端发送 JSON 格式的数据,由前端进行解析并展示。

为了向后端返回 JSON ,常用的做法有两种:

  • 在类上加 @RestController 注解
  • 在方法上加 @ResponseBody 注解

(2) @RestController 注解

被 @RestController 注解的类中的方法将不会再跳转视图,而是会将方法返回的结果写入 HTTP 响应正文中。

相当于给类中的每一个方法都加了 @ResponseBody 注解

1
2
3
4
5
6
7
8
9
@RestController
public class Controller{

@RequestMapping("/访问路径")
public String 方法名1(Model model) {
return "Hello";
}

}

(3) @ResponseBody 注解

被 @ResponseBody 注解的方法将不会再跳转视图,而是会将方法返回的结果写入 HTTP 响应正文中。

1
2
3
4
5
6
7
8
9
10
@Controller
public class Controller{

@RequestMapping("/访问路径")
@ResponseBody
public String 方法名1(Model model) {
return "Hello";
}

}

七、转发和重定向

  • 可以获取 request 和 response 后使用原生的方式

    不推荐

    具体请看:

    Java Web 请求转发与重定向

  • 使用 SpringMVC 的方式:

    • 默认情况下,直接 return "/访问路径" 即是转发

      因此,访问 Controller 中的处理方法时,虽然跳转到了视图,但地址栏的 url 并没有发生改变。

    • 显式地 return "forward:/访问路径" 进行转发

    • 显式地 return "redirect:/访问路径" 进行重定向

参考