SpringMVC概述

SpringWebMVC是在ServletAPI基础上构建的Web端框架,它用于表现层开发,通过把Model,View,Controller三层分离,把较为复杂的web应用分成逻辑清晰的三个部分,使得web开发更为简易。

1.MVC模型

MVC全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,一种软件设计典范,用业务逻辑、数据、界面三种模式显示分离的方法组织代码,将业务逻辑聚集到一个模型里面,在改进和个性化定制界面及用户交互的同时,不需要重新编写业务逻辑。MVC被独特的发展起来用于映射传统的输入、处理和输出功能在一个逻辑的图形化用户界面的结构中。 —— 来自百度百科


  • 视图是用户看到并和其交互的界面。对老式的Web应用程序来说,视图就是由HTML元素组成的界面,在新式的Web应用程序中,HTML依旧在视图中扮演着重要的角色。

    视图


  • 模型代表一个存取数据的对象或者Java的POJO类,用于封装与应用程序业务逻辑相关的数据以及对数据的处理方法。

    模型


  • 控制器用于接收用户的输入并调用模型和视图去完成用户的需求,当单击Web页面中的超链接和发送html表单时,控制器本身不输出任何东西和做任何处理。它只是负责接收请求并决定调用哪个模型构件去处理请求,然后再确定用哪个视图来显示返回的数据。

    控制器

  1. —— 图片来自谷歌

2.前端控制器思想

前端控制器模式(Front Controller Pattern)是用于提供一个集中的请求处理机制,所有的请求都将由一个单一的处理程序处理。该处理程序可以做认证/授权/记录日志,或者跟踪请求,然后把请求传给相应的处理程序。以下是这种设计模式的实体。

  • 前端控制器(Front Controller) 处理应用程序所有类型请求的单个处理程序,应用程序可以是基于 web 的应用程序,也可以是基于桌面的应用程序。
  • 调度器(Dispatcher) 前端控制器可能使用一个调度器对象来调度请求到相应的具体处理程序,负责页面之间的跳转。
  • 视图(View) 视图是为请求而创建的对象。

3.SpringMVC快速入门

3.1代码实现

下面基于Hello,World程序的一个快速演示工程,通过SpringMVC技术实现简单的网页输出字符串的功能。

3.2 创建maven工程并导入依赖

  1. <dependencies>
  2. <dependency>
  3. <groupId>org.springframework</groupId>
  4. <artifactId>spring-webmvc</artifactId>
  5. <version>5.2.8.RELEASE</version>
  6. </dependency>
  7. <dependency>
  8. <groupId>javax.servlet</groupId>
  9. <artifactId>servlet-api</artifactId>
  10. <version>2.5</version>
  11. <scope>provided</scope>
  12. </dependency>
  13. <dependency>
  14. <groupId>javax.servlet.jsp</groupId>
  15. <artifactId>jsp-api</artifactId>
  16. <version>2.0</version>
  17. <scope>provided</scope>
  18. </dependency>
  19. <dependency>
  20. <groupId>org.projectlombok</groupId>
  21. <artifactId>lombok</artifactId>
  22. <version>1.18.12</version>
  23. </dependency>
  24. </dependencies>

配置web项目需要右击项目,点击Add FrameWork Support,添加webApplication支持

3.3 配置web.xml

  1. <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
  2. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
  4. version="4.0">
  5. <display-name>Archetype Created Web Application</display-name>
  6. <servlet>
  7. <!-- 配置前端控制器Servlet -->
  8. <servlet-name>dispatcherServlet</servlet-name>
  9. <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  10. <!-- 映射resources路径下的spring配置文件 -->
  11. <init-param>
  12. <param-name>contextConfigLocation</param-name>
  13. <param-value>classpath:springmvc.xml</param-value>
  14. </init-param>
  15. <!-- 配置 servlet 的对象的创建时间点:应用加载时创建。
  16. 取值只能是非0正整数,表示启动顺序 -->
  17. <load-on-startup>1</load-on-startup>
  18. </servlet>
  19. <!-- servlet-name需要对应上面配置前端控制器的名称,
  20. /表示匹配所有的请求(不包括.jsp文件)
  21. /*表示匹配所有的请求(包括.jsp文件)
  22. -->
  23. <servlet-mapping>
  24. <servlet-name>dispatcherServlet</servlet-name>
  25. <url-pattern>/</url-pattern>
  26. </servlet-mapping>
  27. </web-app>

配置web.xml文件时需要注意首先导入头文件,配置前端控制器DispatcherServlet时需要对应一个映射的名称和匹配的路径,也就是<srvlet-mapping/> 中的内容,<init-param/>参数表示映射spring配置文件的内容。

3.4新建Controller控制器

在web阶段通常使用servlet来做网页的控制器,但到了SpringMVC中,只需要编写简单的Java类,利用几个简单的注解或配置就可完成请求与转发的功能。

  1. public class IndexController implements Controller {
  2. public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
  3. //创建模型和视图对象,并在构造方法中添加名为hello的视图
  4. ModelAndView mv = new ModelAndView("hello");
  5. //添加属性值,通过键取值
  6. mv.addObject("message","Hello,World");
  7. return mv;
  8. }
  9. }

上面通过实现Controller 接口重写handleRequest 方法的方式去对网页做一个交互,使用ModelAndView 对象设置转发的视图和属性值,并返回此对象。

3.5 配置spring文件

要想真正的使用SpringMVC 技术实现对网页的操作还需要springIOC技术的支持,将SpringMVC 中的组件注册到spring bean容器中,而InternalResourceViewResolver 对象则是支持实现页面跳转的功能。

  1. <beans xmlns="http://www.springframework.org/schema/beans"
  2. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. xsi:schemaLocation="http://www.springframework.org/schema/beans
  4. http://www.springframework.org/schema/beans/spring-beans.xsd">
  5. <!-- 注册视图解析器对象的bean,必须有视图解析器的支撑才能跳转页面 -->
  6. <bean id="ViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
  7. <!-- prefix代表映射包前缀名 -->
  8. <property name="prefix" value="/WEB-INF/pages/"/>
  9. <!-- suffix代表映射后缀名,配置.jsp文件 -->
  10. <property name="suffix" value=".jsp"/>
  11. </bean>
  12. <!-- 注册IndexController类到容器中,id为页面访问的hello路径 -->
  13. <bean id="/hello" class="com.springmvc.controller.IndexController"/>
  14. </beans>

3.6 创建jsp视图页面

由于上面在spring配置文件中指定视图文件的路径,所以需要在WEB-INF下创建pages 包,在里面创建jsp视图文件才可被视图解析器解析到。创建hello.jsp文件

  1. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
  2. <html>
  3. <head>
  4. <title>Title</title>
  5. </head>
  6. <body>
  7. <!-- 输出模型视图对象中设置的键,根据键获取对象的值。 -->
  8. ${message}
  9. </body>
  10. </html>

3.7 配置Tomcat启动项目测试

点击Edit Configurations 进入配置界面,然后在点击+Tomcat Server —> Local —>Application server 指定本机Tomcat路径,然后点击Depolyment 添加Artifacts 模块。

运行Tomcat访问http://localhost:8080/hello查看结果

以上快速入门代码是通过ModelAndView 进行视图和属性值的设置,并在spring容器当中注册bean 的组件,这样的方式相较注解来说要麻烦一些,因为每次都要实现Controller 接口,并且在spring容器中为每一个方法注册一个bean 的组件。下面通过注解的方式来改善这种现象。

3.7.1 修改spring配置文件

使用注解的方式需要导入额外的XML 头文件支持,下面加入mvc,context属性。

  1. <beans xmlns="http://www.springframework.org/schema/beans"
  2. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. xmlns:mvc="http://www.springframework.org/schema/mvc"
  4. xmlns:context="http://www.springframework.org/schema/context"
  5. xsi:schemaLocation="http://www.springframework.org/schema/beans
  6. http://www.springframework.org/schema/beans/spring-beans.xsd
  7. http://www.springframework.org/schema/mvc
  8. http://www.springframework.org/schema/mvc/spring-mvc.xsd
  9. http://www.springframework.org/schema/context
  10. http://www.springframework.org/schema/context/spring-context.xsd">
  11. <!-- 开启对注解的支持 -->
  12. <mvc:annotation-driven/>
  13. <!-- 自动扫描Controller的包 -->
  14. <context:component-scan base-package="com.springmvc.controller"/>
  15. <!-- 注册视图解析器对象的bean -->
  16. <bean id="InternalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
  17. <!-- prefix代表包前缀名 -->
  18. <property name="prefix" value="/WEB-INF/pages/"/>
  19. <!-- suffix代表后缀名,配置.jsp文件 -->
  20. <property name="suffix" value=".jsp"/>
  21. </bean>
  22. </beans>

3.7.2 新建Controller类

HelloController分别使用@Controller表示这是一个控制层的组件,并且注入到spring容器当中,和@RequestMapping 注解设置访问的路径,将这两个注解分别注释到类和方法中,即可实现网页之间的请求转发和属性的设置。

  1. @Controller
  2. public class HelloController {
  3. @RequestMapping("/hello") //设置访问路径为/hello
  4. public String hello(Model model) {
  5. model.addAttribute("hello","Hello,World");
  6. return "hello"; //返回到hello.jsp视图中
  7. }
  8. }

3.7.3 输出hello.jsp文件测试

使用EL表达式输出Controller层设置的属性键,即可得到设置的属性值。

  1. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
  2. <html>
  3. <head>
  4. <title>Title</title>
  5. </head>
  6. <body>
  7. ${hello}
  8. </body>
  9. </html>

启动Tomcat 服务器访问http://localhost:8080/hello

测试结果:

@RequestMapping注解

上面第二种方式配置的请求路径是通过@RequestMapping注解来实现的,可以使用此注解将请求的路径映射到控制器方法上,同样也可以作用于类上方。

源码:

  1. @Target({ElementType.TYPE, ElementType.METHOD})
  2. @Retention(RetentionPolicy.RUNTIME)
  3. @Documented
  4. @Mapping
  5. public @interface RequestMapping {
  6. /**
  7. 为该映射路径分配名称
  8. */
  9. String name() default "";
  10. /**
  11. 映射url路径,可以批量填写,功能和path相同
  12. */
  13. @AliasFor("path")
  14. String[] value() default {};
  15. /**
  16. 映射url路径,可以批量填写,功能和value相同
  17. */
  18. @AliasFor("value")
  19. String[] path() default {};
  20. /**
  21. 指定http请求方法,默认有8中
  22. */
  23. RequestMethod[] method() default {};
  24. /**
  25. 映射请求的参数
  26. */
  27. String[] params() default {};
  28. /**
  29. 映射请求的头部
  30. */
  31. String[] headers() default {};
  32. /**
  33. 缩小映射的范围
  34. */
  35. String[] consumes() default {};
  36. /**
  37. 缩小请求映射范围
  38. */
  39. String[] produces() default {};
  40. }

@RequestMapping中有一个核心的枚举类,RequestMethod 里面定义了8种http的请求,分别为:GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE 。可以通过此类注明要发送的请求为哪种类型。

4.SpringMVC组件

4.1 DisPatcherServlet:前端控制器

DispatcherServlet 是一个Java 类,此类是SpringMVC 围绕着前端控制器设计实现的类,其功能主要是使用Spring配置来进行web开发之间的流程控制,例如请求映射、视图解析、异常处理等等…
主要功能共有以下几种:

  1. multipartResolver :文件解析,用于处理文件上传服务
  2. localeResolver :区域解析,处理应用的国际化问题
  3. themeResolver:主题解析,定义Web应用程序可以使用的主题-例如,提供个性化的布局
  4. handlerMapping :用于处理程序的请求与映射的关系
  5. handlerAdapter :处理适配器,定义DispatcherServlet 的请求处理规则
  6. handlerExceptionResolver : 解决异常的策略,将错误输出到日志当中
  7. viewNameTranslator :将指定的视图名按照定义的RequestToViewNameTranslators替换成指定的格式。
  8. viewResolver :视图解析,解析逻辑String-从处理程序返回到实际视图名的基于视图的名称View用来呈现给响应的
  9. 存储和检索FlashMap它可以用于将属性从一个请求传递到另一个请求,通常跨重定向。

5. 请求数据绑定

在原生的servlet 中获取对象请求参数的时候需要用到request.getParameter(); 方法,而在SpringMVC 当中只需要定义一个方法,并且指定方法形式参数的名称要与请求的参数名称一致即可。

5.1 支持绑定的数据类型

5.1.1 基本参数类型

基本数据类型对应着Java中的八大数据类型,byteshortintlongfloatdoubleboolean。这几种都可作为参数进行网页之间的数据绑定,只是传入的参数名称必须和方法中的形参名一致,否则会为null。

下面新建一个RequestController进行演示。

跳过上面配置的web.xmlspring配置文件的步骤。

  1. @Controller
  2. public class RequestController {
  3. //发送get请求,路径设置为user
  4. @GetMapping("/user")
  5. public void request(String name, int age, double money,boolean boo) {
  6. System.out.println(name);
  7. System.out.println(age);
  8. System.out.println(money);
  9. System.out.println(boo);
  10. }
  11. }

上面只创建了一个普通的无返回值方法,括号里传入四种不同数据类型的参数,并且发送Get请求设置访问路径为/user,只需要在浏览器地址栏以键值对的方式输出参数对应的参数名即可获取到绑定的值,并且在控制台输出。

测试:启动项目访问http://localhost:8080/user?name=Trump&age=3&money=1.2&boo=false ,路径后面加问号,键为属性名称,值根据数据类型添加,多个键值对之间用&符号分隔

404的原因是因为方法控制器是无返回值的类型,而且并没有指定要返回的视图,只是在控制台打印输出。

5.1.2 POJO类型参数

根据一个具体的对象实体类作为方法的参数,只需要在括号中传入一个对象类即可,但需要根据对象中的字段名指定其属性的名称并且赋值,否则为null。

创建User 类↓

  1. @Data
  2. public class User {
  3. private Long userId;
  4. private String username;
  5. private String password;
  6. }

RequestController 中新建一个方法并传入User 对象

  1. @Controller
  2. public class RequestController {
  3. @GetMapping("/user")
  4. public void requestUser(User user) { //传入User对象
  5. System.out.println(user);
  6. }
  7. }

打开浏览器在地址栏中访问测试http://localhost:8080/user?userId=1&username=Bear&password=123456

测试结果

5.1.3 数组&集合类型参数

通过数组[]和集合类型进行参数的传递,而这两个类型要放在对象中才可使用。

修改User

  1. @Data
  2. public class User {
  3. private Long userId;
  4. private String username;
  5. private String password;
  6. private String arr[];
  7. List<String> list;
  8. }

User类中分别添加一个数组类型和一个List集合类型,传值的时候通过变量名称。

Controller测试方法不变

  1. @GetMapping("/user")
  2. public void requestUser(User user) {
  3. System.out.println(user);
  4. }

测试:

启动项目设置参数并访问http://localhost:8080/user?list=list1,list2&arr=arr1,arr2 ,集合和数组的多个参数值设置均用逗号分隔为多个值。

控制台打印结果

5.1.4 @RequestParam 注解

使用此注解可以将方法中的参数进行绑定,也就是指定一个新的名称作为参数的名字,并且该注解是能注释到方法参数中。

示例:新建一个Get 请求方法,对两个参数进行绑定

  1. @GetMapping("/binding") //请求路径为/binding
  2. public void binding(@RequestParam(value = "name") String username,
  3. @RequestParam("age") Integer age) {
  4. System.out.println(username); //在控制台打印输出
  5. System.out.println(age);
  6. }

此时启动项目访问:http://localhost:8080/binding?name=Bear&age=18 路径即可看到结果

再使用了@RequestParam 注解进行指定名称绑定的时候,路径必须跟绑定的名称一致,否则会报以下错误。

如果想指定其中一个对应的参数可以使用required = false 参数,表示路径中不必须包含此参数。

  1. @GetMapping("/binding")
  2. public void binding(@RequestParam(value = "name",required = false)
  3. String username,
  4. @RequestParam("age") Integer age) {

此时可以访问http://localhost:8080/binding?age=12 路径,缺少一个String类型的参数但也可以成功输出结果,不过username 会为空

5.2 消息头注解

5.2.1 RequestHeader

此注解用于将请求头部分的信息映射到方法中处理的参数中。

获取可选的参数有以下几种:

  1. Host localhost:8080
  2. Accept text/html,application/xhtml+xml,application/xml;q=0.9
  3. Accept-Language fr,en-gb;q=0.7,en;q=0.3
  4. Accept-Encoding gzip,deflate
  5. Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7
  6. Keep-Alive 300

示例:创建一个方法,指定两个String类型的参数,并且绑定指定的http信息参数。

  1. @GetMapping("/header")
  2. public void RequestHeader(@RequestHeader(value = "host") String host,
  3. @RequestHeader(value = "Accept") String accept) {
  4. System.out.println(host);
  5. System.out.println(accept);
  6. }

测试:启动项目访问 http://localhost:8080/header?host&accept 分别获取本机地址端口号和浏览器接受的数据类型信息

5.2.2 CookieValue

HTTPcookie的值绑定到控制器中的方法参数。

  1. @GetMapping("/requestCookie")
  2. public void handle(@CookieValue("JSESSIONID") String cookie) {
  3. System.out.println(cookie);
  4. }

访问 http://localhost:8080/requestCookie?cookie 地址查看输出的Cookie 值。

JSESSIONID 属性是根据浏览器中Cookie名称获取的,具体可在浏览器按F12 查看浏览器中的所有Cookies

5.3 ModelAttribute

@ModelAttribute 注解可以注释在方法或者方法的参数内,用于访问其它的属性,用在方法上则是在控制器执行之前执行,在参数上则是调用指定方法中的内容。

修饰方法

示例:创建两个方法,一个用@ModelAttribute 修饰,作为数据提供方,一个为普通GET请求的方法。

  1. @ModelAttribute
  2. public void model(String param){
  3. System.out.println(param);
  4. }
  5. @GetMapping(value = "/requestAttr")
  6. public void attribute() {}

测试访问http://localhost:8080/requestAttr?param=hello,world 地址即可成功给model方法中的参数param赋值,其就是因为经过@ModelAttribute 注解修饰,在控制器执行之前调用了此方法。

修饰参数

通过在两个方法中使用@ModelAttribute 注解修饰并且指定其名称让修饰在参数内的注解调用

  1. @ModelAttribute(name = "attr")
  2. public void model() {
  3. System.out.println("hello,world");
  4. }
  5. @GetMapping(value = "/requestAttr") //此时的注解指定了上面方法修饰的注解名称
  6. public void attribute(@ModelAttribute(name = "addr") String param) {}

接下来通过访问 http://localhost:8080/requestAttr?param 地址,则会调用到被@ModelAttribute注解修饰方法中的内容。

5.4 SessionAttribute

@SessionAttribute 注解只能作用于方法参数中,作用是给指定某个参数绑定存储到session 域当中,并且可以通过输出原参数可以获得存入的session值。

示例:创建一个方法,使用@SessionAttribute 注解指定参数的名称,并用HttpSession存储值到参数中

  1. @GetMapping("/session")
  2. public void session(@SessionAttribute("name") String session, HttpSession httpSession) {
  3. httpSession.setAttribute("name","hello,world");
  4. System.out.println(session); //打印绑定session值后的参数
  5. }

测试访问: http://localhost:8080/session?name 地址

以上首先使用了@SessionAttribute 绑定了session 字符串类型的变量,并制定其名称为name,然后再用HttpSession 接口向name 属性中添加一个session值,并最终打印其字符串类型变量输出绑定的session值。

5.5 Restful请求

5.5.1 Restful概述

表现层状态转换(Representational State Transfer)简称REST。是一种软件设计架构风格,目的是便于不同软件、程序在网络(例如互联网)中互相传递信息。

5.5.2 Restful 设计标准

REST是设计风格而不是标准。REST通常基于HTTPURIXML以及HTML这些现有的广泛流行的协议和标准。

  • 资源是由URI来指定。
  • 对资源的操作包括获取、创建修改和删除,这些分别对应HTTP协议的GET、POST、PUT和DELETE方法。
  • 通过操作资源的表现形式来操作资源。
  • 资源的表现形式则是XML或者HTML,取决于读者是机器还是人、是消费Web服务的客户软件还是Web浏览器。当然也可以是任何其他的格式,例如JSON。 —— 来自维基百科

5.5.3 @PathVaribale

一个满足RESTful的程序或设计应满足以下条件和约束:

  • 请求的URL需要进行规范,确保URL地址中不会出现动词,例如:getadd,而是使用名词代替
  • 充分利用HTTP协议中的方法,HTTP方法名包括:GET、POST、PUT、PATCH、DELETE

@PathVaribaleSpringMVC提供的注解,可以通过此注解来进行参数的绑定,并实现Restful请求

下面根据模拟用户参数查询,实现restful风格的请求、

Controller 中添加一个方法,并添加@PathVariable注解,和路径中{}的参数互相映射

  1. @GetMapping("/users/{userId}")
  2. public void requestQuery(@PathVariable(value = "userId") String uid) {
  3. System.out.println("查询了" + uid + "号用户");
  4. }

模拟测试访问http://localhost:8080/users/3 路径,表示访问users路径下的3号用户

查看控制台结果:

5.6 @ResponseBody

@ResponseBody 注解的作用是将数据以JSON 字符串形式展示到网页上。此注解可以添加到类型和方法上

示例:

  1. @GetMapping("/get")
  2. @ResponseBody
  3. public String response() {
  4. return "Hello,World";
  5. }

访问http://localhost:8080/get 查看结果

6. 响应数据

因为数据需要和网页之间进行交互,所以需要存取数据到某个容器中,然后再返回响应到网页上进行数据的显示。在SpringMVC中回显数据有以下几种方式。

  1. 使用Map集合
  2. Model接口对象
  3. ModelMap接口对象
  4. ModelAndView对象
  5. session&request

6.1 返回值类型

不同的返回值类型对应着不同的作用,以下三种类型分别是对控制器不同的操作方法。

6.1.1 字符串

字符串类型可以表示返回一个视图,也可以是json 字符串类型,通过业务的需求进行更改。

下面通过返回视图的方式,并利用五种数据回显对象进行演示。

在控制器类中添加一个方法。

  1. @GetMapping("/data")
  2. public String map(Map<String,String> map, Model model, ModelMap modelMap, HttpServletRequest request,HttpSession session) {
  3. map.put("map","hello,world");
  4. model.addAttribute("model","hello,fuckerTrump");
  5. modelMap.addAttribute("modelMap","hello,teddy");
  6. request.setAttribute("request","hello,bear");
  7. session.setAttribute("session","hello,ted");
  8. return "hello";
  9. }

创建一个hello.jsp,并通过$符号取值,进行网页上的数据渲染

  1. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
  2. <html>
  3. <head>
  4. <title>Title</title>
  5. </head>
  6. <body>
  7. Map接口渲染数据:${map}
  8. Model接口渲染数据: ${model}
  9. ModelMap对象渲染数据:${modelMap}
  10. request对象渲染数据:${requestScope.request} <!-- 使用request域调用键 -->
  11. session对象渲染数据:${sessionScope.session} <!-- 使用session域调用键 -->
  12. </body>
  13. </html>

启动项目访问:http://localhost:8080/data

需要注意的是ModelModelMap两个对象,这两个对象的功能基本一致,不同的是ModelMap对象继承了LinkedHashMap 所以拥有其所有的方法使用权,比Model对象拥有更多的操作空间。

6.1.2 void关键字

使用void类型则没有任何的返回值,也不能返回视图和JSON 字符串。

  1. @GetMapping("/void")
  2. public void result() {
  3. System.out.println("this is void method");
  4. }

访问 http://localhost:8080/void 即可看到在控制台打印的效果。

6.1.3 ModelAndView

ModelAndViewSpringMVC提供的一个对象,用于设置属性值和视图。

  1. @GetMapping("/model")
  2. public ModelAndView modelAndView() {
  3. ModelAndView mv = new ModelAndView(); //创建对象
  4. mv.setViewName("hello"); //设置返回视图为hello的名称
  5. mv.addObject("msg","ModelAndView"); //设置属性值
  6. return mv;
  7. }

使用键将值渲染到hello.jsp页面中显示。

  1. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
  2. <html>
  3. <head>
  4. <title>Title</title>
  5. </head>
  6. <body>
  7. 使用ModelAndView对象:${msg}
  8. </body>
  9. </html>

6.2 转发和重定向

请求转发是浏览器向服务端发送一次请求就获取一次响应,也称为本服务器内跳转,并且只能请求转发到当前web应用的内部资源,不可以转发到其它连接,例如www.baidu.com

重定向则是向服务器发出几次请求就获取几次请求,被称为服务器的外部跳转,也就是页面之间的跳转,并且不可跳转携带资源的页面。

使用Model 对象绑定一个参数并转发到指定页面回显数据。

  1. @GetMapping("/request")
  2. public String request2(Model model) {
  3. model.addAttribute("message","request2");
  4. return "hello";
  5. }

jsp页面

  1. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
  2. <html>
  3. <head>
  4. <title>Title</title>
  5. </head>
  6. <body>
  7. ${message}
  8. </body>
  9. </html>

而使用重定向的方式则是将当前页面资源定向到其它URL 资源中,例如请求重定向到http://www.baidu.com地址中。

  1. @GetMapping("/redirect")
  2. public String redirect() {
  3. return "redirect:http://www.baidu.com";
  4. }

此时访问http://localhost:8080/redirect 路径则会调转到百度页面

7. 文件上传

  1. 使用`SpringMVC框架` 实现文件的上传功能。

7.1 代码实现

新建项目导入依赖

  1. <dependencies>
  2. <dependency>
  3. <groupId>org.springframework</groupId>
  4. <artifactId>spring-webmvc</artifactId>
  5. <version>5.2.9.RELEASE</version>
  6. </dependency>
  7. <dependency>
  8. <groupId>javax.servlet</groupId>
  9. <artifactId>servlet-api</artifactId>
  10. <version>2.5</version>
  11. <scope>provided</scope>
  12. </dependency>
  13. <dependency>
  14. <groupId>commons-fileupload</groupId>
  15. <artifactId>commons-fileupload</artifactId>
  16. <version>1.3.3</version>
  17. </dependency>
  18. <dependency>
  19. <groupId>javax.servlet.jsp</groupId>
  20. <artifactId>jsp-api</artifactId>
  21. <version>2.0</version>
  22. <scope>provided</scope>
  23. </dependency>
  24. </dependencies>

配置web和spring的xml文件

  1. <beans xmlns="http://www.springframework.org/schema/beans"
  2. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. xmlns:mvc="http://www.springframework.org/schema/mvc"
  4. xmlns:context="http://www.springframework.org/schema/context"
  5. xsi:schemaLocation="http://www.springframework.org/schema/beans
  6. http://www.springframework.org/schema/beans/spring-beans.xsd
  7. http://www.springframework.org/schema/mvc
  8. http://www.springframework.org/schema/mvc/spring-mvc.xsd
  9. http://www.springframework.org/schema/context
  10. http://www.springframework.org/schema/context/spring-context.xsd">
  11. <!-- 开启注解的支持 -->
  12. <mvc:annotation-driven/>
  13. <context:component-scan base-package="com.springmvc.controller"/>
  14. <!-- 注册视图解析器对象的bean -->
  15. <bean id="InternalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
  16. <!-- prefix代表包前缀名 -->
  17. <property name="prefix" value="/WEB-INF/pages/"/>
  18. <!-- suffix代表后缀名,配置.jsp文件 -->
  19. <property name="suffix" value=".jsp"/>
  20. </bean>
  21. <!-- 文件上传配置 -->
  22. <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
  23. <!-- 设置编码格式 -->
  24. <property name="defaultEncoding" value="UTF-8"/>
  25. <!-- 上传的文件大小限制,10485760=10MB -->
  26. <property name="maxUploadSize" value="10485760"/>
  27. <property name="maxInMemorySize" value="40960"/>
  28. </bean>
  29. </beans>
  30. <!-- web.xml配置 -->
  31. <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
  32. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  33. xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
  34. version="4.0">
  35. <display-name>Archetype Created Web Application</display-name>
  36. <servlet>
  37. <!-- 配置前端控制器Servlet -->
  38. <servlet-name>dispatcherServlet</servlet-name>
  39. <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  40. <init-param>
  41. <param-name>contextConfigLocation</param-name>
  42. <param-value>classpath:springmvc.xml</param-value>
  43. </init-param>
  44. <load-on-startup>1</load-on-startup>
  45. </servlet>
  46. <servlet-mapping>
  47. <servlet-name>dispatcherServlet</servlet-name>
  48. <url-pattern>/</url-pattern>
  49. </servlet-mapping>
  50. </web-app>

编写Controller文件上传功能

  1. @RestController
  2. public class FileController {
  3. @PostMapping("/upload")
  4. public String upload(@RequestParam(value = "file")CommonsMultipartFile file) throws IOException {
  5. String path = "D:\\upload"; //定义上传文件的目录,D盘下面
  6. File realPath = new File(path);
  7. if(!realPath.exists()) { //如果不存在文件
  8. // 创建文件夹
  9. realPath.mkdirs();
  10. }
  11. System.out.println(realPath); //打印上传的路径
  12. //通过CommonsMultipartFile类直接写入文件
  13. file.transferTo(new File(realPath + "/" + file.getOriginalFilename()));
  14. return "上传成功";
  15. }
  16. }

上传表单页面。

  1. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
  2. <html>
  3. <head>
  4. <title>fileUpload</title>
  5. </head>
  6. <body>
  7. <form action="${pageContext.request.contextPath}/upload" enctype="multipart/form-data" method="post">
  8. <input type="file" name="file">
  9. <input type="submit" value="upload">
  10. </form>
  11. </body>
  12. </html>

multipart/form-data 会以二进制流的方式来处理表单数据,这种编码方式会把文件域指定文件的内容封装到请求参数中,不对字符进行编码。

启动项目点击上传文件按钮即可上传文件,但需要根据spring 中配置的参数大小选择文件。

8. 拦截器

SpringMVC 中的拦截器类似于Servlet中的Filter过滤器,其思想是基于SpringAOP实现的,主要用于对某些路径和资源进行预处理和后处理,相当于请求只有在通过了拦截器之后才可执行真正的功能。

实现拦截器功能

新建web项目导入依赖

  1. <dependencies>
  2. <dependency>
  3. <groupId>org.springframework</groupId>
  4. <artifactId>spring-webmvc</artifactId>
  5. <version>5.2.9.RELEASE</version>
  6. </dependency>
  7. <dependency>
  8. <groupId>javax.servlet</groupId>
  9. <artifactId>servlet-api</artifactId>
  10. <version>2.5</version>
  11. <scope>provided</scope>
  12. </dependency>
  13. <dependency>
  14. <groupId>javax.servlet.jsp</groupId>
  15. <artifactId>jsp-api</artifactId>
  16. <version>2.0</version>
  17. <scope>provided</scope>
  18. </dependency>
  19. </dependencies>

web.xmlspring配置文件

  1. <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
  2. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
  4. version="4.0">
  5. <display-name>Archetype Created Web Application</display-name>
  6. <servlet>
  7. <!-- 配置前端控制器Servlet -->
  8. <servlet-name>dispatcherServlet</servlet-name>
  9. <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  10. <init-param>
  11. <param-name>contextConfigLocation</param-name>
  12. <param-value>classpath:springmvc.xml</param-value>
  13. </init-param>
  14. <load-on-startup>1</load-on-startup>
  15. </servlet>
  16. <servlet-mapping>
  17. <servlet-name>dispatcherServlet</servlet-name>
  18. <url-pattern>/</url-pattern>
  19. </servlet-mapping>
  20. </web-app>
  21. <!-- spring配置文件 -->
  22. <beans xmlns="http://www.springframework.org/schema/beans"
  23. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  24. xmlns:mvc="http://www.springframework.org/schema/mvc"
  25. xmlns:context="http://www.springframework.org/schema/context"
  26. xsi:schemaLocation="http://www.springframework.org/schema/beans
  27. http://www.springframework.org/schema/beans/spring-beans.xsd
  28. http://www.springframework.org/schema/mvc
  29. http://www.springframework.org/schema/mvc/spring-mvc.xsd
  30. http://www.springframework.org/schema/context
  31. http://www.springframework.org/schema/context/spring-context.xsd">
  32. <!-- 开启注解的支持 -->
  33. <mvc:annotation-driven/>
  34. <context:component-scan base-package="com.springmvc.controller"/>
  35. <!-- 注册视图解析器的bean -->
  36. <bean id="InternalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
  37. <!-- prefix代表包前缀名 -->
  38. <property name="prefix" value="/WEB-INF/pages/"/>
  39. <!-- suffix代表后缀名,配置.jsp文件 -->
  40. <property name="suffix" value=".jsp"/>
  41. </bean>
  42. <!-- 拦截器配置 -->
  43. <mvc:interceptors>
  44. <mvc:interceptor>
  45. <!-- /**表示拦截所有请求 -->
  46. <mvc:mapping path="/**"/>
  47. <!-- 注入拦截器类到bean容器中 -->
  48. <bean class="com.springmvc.config.MyInterceptor"/>
  49. </mvc:interceptor>
  50. </mvc:interceptors>
  51. </beans>

编写拦截器的类,实现HandlerInterceptor 接口

  1. @Configuration
  2. public class MyInterceptor implements HandlerInterceptor {
  3. //return true; 放行,执行下一个拦截器
  4. public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
  5. System.out.println("preHandle方法执行前");
  6. return true;
  7. }
  8. public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
  9. System.out.println("postHandle方法处理后");
  10. }
  11. public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
  12. System.out.println("afterCompletion方法处理完成后");
  13. }
  14. }

编写一个测试的Controller

  1. @RestController
  2. public class TestController {
  3. @GetMapping("/test")
  4. public String interceptor() {
  5. System.out.println("测试拦截器方法执行了...");
  6. return "ok";
  7. }
  8. }

以上实现了自定义拦截器的方法并且注入到了spring中,在执行请求路径的时候会先执行拦截器中对应的方法,然后再执行其请求。

启动项目访问http://localhost:8080/test路径。