三大框架学习之 - SpringMVC基础

164 阅读14分钟

- SpringMVC概述

  • 在我们之前WEB层使用的是servlet技术,但是每一个servlet都需要进行一个配置,太过于复杂,SpringMVC就能够解决这个问题;
  • SpringMVC是一个基于MVC模式的WEB/表现层框架,它解决WEB开发中常见的问题:参数接收、文件上传/下载、表单验证、国际化等等;
  • SpringMVC作为Spring框架一个非常重要的功能模块,可以与Spring无缝集成,提高开发效率;
  • Spring是一个轻量级的Java 开发框架,为了解决企业应用开发的复杂性而创建。SpringMVC以Spring框架为核心,为应用程序中的Web层(表现层)提出的一套优秀的解决方案;
  • 目前很多公司都使用SpringMVC,90%的招聘单位要求熟悉使用SpringMVC;

注意:SpringMvc的功能就是之前Servlet的功能,可以理解为使用SpringMVC代替了Servlet;

- SpringMVC入门

  • jar包管理

    • SpringMVC是建立在Spring基础上的。所以使用SpringMVC必须先保证你的项目拥有Spring的运行环境;

    • 使用框架的第一步需要框架的官方网站下载框架相关的文件,而SpringMVC无需单独下载,因为SpringMVC是作为Spring中的一个模块存在,所以我们只需要下载Spring即可;

    • SpringMVC需要的jar包:

      • spring-webmvc-4.1.2.RELEASE.jar -- SpringMVC核心包
      • spring-web-4.1.2.RELEASE.jar -- Spring对Web项目项目的支持
    • 加入相关Spring的jar包

         - com.springsource.org.apache.commons.logging-1.1.1.jar
         - spring-beans-4.1.2.RELEASE.jar
         - spring-context-4.1.2.RELEASE.jar
         - spring-core-4.1.2.RELEASE.jar			
         - spring-expression-4.1.2.RELEASE.jar	
         - spring-aop-4.1.2.RELEASE.jar -- Spring测试需要导入此包
         - servlet-api.jar -- SpringMVC底层还是使用了servlet,所以需要servletjar包
         
      复制代码
      

      注意:1. spring orm、jdbc、tx相关jar根据项目使用自行添加; 2. 不要使用spring.3的jar和4.x的jar文件混用;

    • SpringMVC核心控制器

      • 核心控制器:用于Web层核心功能的处理以及在所有控制器执行之前,所有的WebMvc框架都采用了这种方式,在SpringMVC中使用的是DispatcherServlet为核心控制器. DispatcherServlet核心控制器会拦截匹配的请求,把拦截下来的请求,依据相应的规则分发到目标Controller来处理;

image.png

  • 配置核心控制器

    • webmvc框架的心脏就是核心控制器,负责所有请求的公共功能,然后在分发给具体的控制器(我们编写的控制器),完成业务逻辑,响应视图;
    • 核心控制器其实就是一个Servlet,只不过这个Servlet是由SpringMVC框架提供的,不需要自己写,只需要配置,交给容器去管理。在web.xml配置核心控制器(容器启动时就创建sevlet实例对象,并加载classpath下的一个名为spring-mvc.xml文件);
	<servlet>
                <!-- 给核心控制器配置起一个唯一的名称 -->
		<servlet-name>dispatcherServlet</servlet-name>
                <!-- 核心控制器的全限定名 -->
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<!-- init-param标签的位置必须在load-on-startup上面 -->
		<!-- 告诉SpringMVC去哪里找核心配置文件 -->
		<init-param>
		<!-- contextConfigLocation 固定写法,不能改变 -->
		<param-name>contextConfigLocation</param-name>
		<param-value>classpath:spring-MVC.xml</param-value>
		</init-param>
		<!-- 这个的意思是指定核心控制器的加载时机,参数值为 1~10 数字越低加载时机越高 -->
		<load-on-startup>1</load-on-startup>
		
	</servlet>
	<servlet-mapping>
                <!-- 根据名称引入核心控制器 -->
		<servlet-name>dispatcherServlet</servlet-name>
		<!-- url-pattern参数值,有两种写法 
				1./ 拦截所有请求
				2. *.do
					*: 匹配所有的意思
					.do: 以.do结尾的所有请求
                                3./* 拦截所有请求
		-->
		
		<url-pattern>*.do</url-pattern>
	</servlet-mapping>
复制代码
  • 准备SpringMVC核心配置文件

    • SpringMVC是Spring的一个模块,它的配置文件和Spring的配置差不多,复制一份applicationContext.xml修改为spring-mvc.xml;
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd"
>
</beans>
复制代码
  • 编写请求处理器Controller

  • 三种方式:第一种

    • 我们以前使用servlet的时候,我们写的是一个HelloServlet控制器类,然后实现的是Servlet,现在我们使用SpringMVC就实现一个Controller

    • 编写HelloController

      • handleRequest方法的两个参数与我们以前的servlet中service方法一样,request和response对象,我们可以使用这个两个对象完成一次请求的所有工作,比如你可以使用request接受参数,或者使用response重定向等等,注意方法除了返回值以外还有一个返回值ModelAndView;
      • ModelAndView是SpringMVC控制器中特有一个对象,描述一次请求响应的数据(Model)和 视图(View);
package cn.itsource.springmvc_01;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;

// 以前我们写第一个HelloServlet,是实现的Servlet
// 现在我们写第一个HelloController, 我们就实现一个Controller 接口就可以了

// 第一种实现方式
public class HelloController01 implements Controller{

	/**
	 * ModelAndView: 模型和视图
	 * Model:后台封装数据的,方便前端获取
	 * View:定义控制器返回的路径
	 */
	@Override
	public ModelAndView handleRequest(HttpServletRequest req, HttpServletResponse resp) throws Exception {
		// 创建一个ModelAndView
		ModelAndView modelAndView = new ModelAndView();
		// 以前servlet传递参数的写法
//		req.setAttribute("msg", "你好,控制器!!!");
		// 现在的用法, 将参数封装到作用域中
		modelAndView.addObject("msg", "你好,控制器!!!");
		// 告诉控制器,跳转的路径
		modelAndView.setViewName("/WEB-INF/views/index.jsp");
		return modelAndView;
	}

}

复制代码
  • 编写页面,展示数据

    • 在WEB-INF下创建views文件夹,然后创建index.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>

${msg}

</body>
</html>
复制代码
  • 配置控制器

    • SpringMVC是基于Spring,Spring中的核心就是Ioc容器,而Ioc容器中最重要的成员就是bean,SpringMVC中的控制器也是一个一个bean;
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd"
>
<!-- id在以前学习spring的时候是我们全局唯一的名称,在引入SpringMVC之后,id就是我们往外面暴露的请求路径 -->
<!-- class 就是控制器的全限定名 -->
<bean id="/hello1.do" class="cn.itsource.springmvc_01.HelloController01"></bean>

</beans>
复制代码
  • 访问控制器

    注意:因为我们设置的拦截是*.do,并且暴露的连接请求是hello1.do,所以我们访问hello1.do

    • 查看效果,展示我们在ModelAndView中设置的值

image.png

  • 三种方式:第二种

    • 实现HttpRequestHandler接口
    • 除了实现Controller接口的这种方式,我们还可以使用第二种
package cn.itsource.springmvc_01;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.HttpRequestHandler;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;

// 第二种实现方式
public class HelloController02 implements HttpRequestHandler{

	@Override
	public void handleRequest(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		req.setAttribute("msg", "第二种方式!!!");
		req.getRequestDispatcher("/WEB-INF/views/index.jsp").forward(req, resp);
	}


}

复制代码
  • 配置spring-mvc.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd"
>
<!-- id在以前学习spring的时候是我们全局唯一的名称,在引入SpringMVC之后,id就是我们往外面暴露的请求路径 -->
<!-- class 就是控制器的全限定名 -->
<bean id="/hello2.do" class="cn.itsource.springmvc_01.HelloWordController02"></bean>

</beans>
复制代码

image.png

  • 三种方式:第三种

    • 前面两种方式,都与我们的Servlet方式十分的相似,并没有改变我们的配置复杂的问题,如果SpringMVC只能达到这种程度,我们完全没必要学习他,所以我们来看SpringMVC推荐的方式,也是我们最常用的方式!
    • 创建控制器
package cn.itsource.springmvc_01;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

// 第三种实现方式 在类上加上controller注解
// 标识这个类是一个控制器
@Controller
public class HelloController03 {

	// 就是对外暴露的资源路径
	@RequestMapping("/hello3")
	public ModelAndView hello3() {
		ModelAndView modelAndView = new ModelAndView();
		modelAndView.addObject("msg", "第三种实现方式!!!");
		modelAndView.setViewName("/WEB-INF/views/index.jsp");
		return modelAndView;
	}

}

复制代码
  • 因为我们使用了注解,所以我们需要在配置文件中添加注解扫描
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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"
>
<!-- id在以前学习spring的时候是我们全局唯一的名称,在引入SpringMVC之后,id就是我们往外面暴露的请求路径 -->
<!-- class 就是控制器的全限定名 -->
<bean id="/hello1.do" class="cn.itsource.springmvc_01.HelloWordController01"></bean>
<bean id="/hello2.do" class="cn.itsource.springmvc_01.HelloWordController02"></bean>

<!-- 这个就是配置哪个包下面的注解需要去扫描 -->
<context:component-scan base-package="cn.itsource"/>

</beans>
复制代码

image.png

- 前端控制器 url-pattern 配置

  • url-pattern就是设置我们拦截方式的,他有三种拦截方式

    • 第一种:*.do 不推荐使用

      • 拦截所有以.do结尾的请求
      • 问题:这种请求方式要求你的请求路径必须以.do的方式才能访问我的核心控制器
    • 第二种:/* 不推荐使用

      • 拦截所有请求
      • 问题:这种请求方式会在我们跳转jsp页面的时候也拦截,会导致我们在访问控制器之后跳转页面时404
    • 第三种:/ 推荐使用

      • 拦截所有请求,并且不会拦截页面资源,还支持restful风格

      • 问题:如果拦截路径是 / ,他会把tomcat自带的servlet给覆盖掉,被覆盖的servlet就是别人专门处理静态资源的servlet,所以就会导致我们无法访问静态资源

      • 解决方案:springMVC给我们提供了解决访问,所以我们需要在springMVC核心控制器中加入以下配置

        • 引入mvc命名空间
        • 加入 <mvc:default-servlet-handler /> 表示静态资源放行
        • 加入静态资源放行,会导致springMVC的注解失效,也就是@RequestMapping("/hello3"),所以需要开启springMVC注解支持
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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"
>
<!-- id在以前学习spring的时候是我们全局唯一的名称,在引入SpringMVC之后,id就是我们往外面暴露的请求路径 -->
<!-- class 就是控制器的全限定名 -->
<bean id="/hello1.do" class="cn.itsource.springmvc_01.HelloWordController01"></bean>
<bean id="/hello2.do" class="cn.itsource.springmvc_01.HelloWordController02"></bean>

<!-- 这个就是配置哪个包下面的注解需要去扫描 -->
<context:component-scan base-package="cn.itsource"/>

<!-- 静态资源放行 -->
<mvc:default-servlet-handler/>

<!-- 开启对springMVC注解的支持 -->
<mvc:annotation-driven/>

</beans>
复制代码

注意:虽然配置 / 也会有一些问题,但是springMVC已经给我们提供了解决方案,所以我们推荐使用 / 方式配置拦截,这也是现在最流行的使用方式

- restful风格

  • REST(英文:Representational State Transfer,简称REST)Rest是web服务的一种架构风格,一种设计风格,是一种思想;同时Rest不是针对某一种编程语言的。
  • 以往我们写接口访问路径,我们会以路径区别我们具体访问的那个方法

http://localhost:8080/admin/getUser (查询用户)

http://localhost:8080/admin/addUser (新增用户)

http://localhost:8080/admin/updateUser (更新用户)

http://localhost:8080/admin/deleteUser (删除用户)

  • Rest架构:一个请求路径对应多个方法,以请求方式区分此请求到底进那个方法

GET http://localhost:8080/admin/user (查询用户)

POST http://localhost:8080/admin/user (新增用户)

PUT http://localhost:8080/admin/user (更新用户)

DELETE http://localhost:8080/admin/user (删除用户)

- 接收参数的五种方式

  • 以前我们在使用Servlet的时候,我们接收参数的方式是通过HttpServletRequest获取,在SpringMVC中有五种方式获取
  • 第一种:

/**
	 * SpringMVC 接收参数方式一,通过HttpServletRequest获取(不推荐)
	 * @param username
	 * @param age
	 */
	@RequestMapping("/param/03")
	public void param03(HttpServletRequest request) {
		System.out.println(request.getParameter("username"));
		System.out.println(request.getParameter("password"));
	}
复制代码
  • 第二种:通过形参直接接收,SpringMVC可以自动将值给我们注入到形参中,但是前后端的形参类型,形参名称要一致
/**
	 * SpringMVC 接收参数方式二(推荐使用)
	 * @param username
	 * @param age
	 */
	@RequestMapping("/param/01")
	public void param01(String username, Integer age) {
		System.out.println("username = " + username);
		System.out.println("age = " + age);
	}
复制代码
  • 第三种:如果形参过多,那么我们可以封装一个实体类,通过实体类接收
/**
	 * SpringMVC 接收参数方式三(推荐使用)
	 * @param username
	 * @param age
	 */
	@RequestMapping("/param/02")
	public void param02(User user) {
		System.out.println("user = " + user);
	}
复制代码
  • 第四种:Restful风格,参数作为访问路径的时候
/**
	 * SpringMVC 接收参数方式四(推荐使用 Restful风格,将参数作为路径,这时候就要加上注解 @PathVariable(路径的参数对应的形参))
	 * @param username
	 * @param age
	 */
	@RequestMapping("/param/04/{username}/{password}")
	public void param04(@PathVariable("username")String username,@PathVariable("password")Integer password) {
		System.out.println(username);
		System.out.println(password);
	}
复制代码
  • 第五种:其实跟第二种很相似,但是区别在于如果前后端的参数名称不一致的时候如何处理
/**
	 * SpringMVC 接收参数方式五(在前后端参数不一致时,可以使用@RequestParam("name") 指定前端的参数名称注入到后端那个参数里面)
	 * @param username
	 * @param age
	 */
	@RequestMapping("/param/05")
	public void param05(@RequestParam("name")String username,@RequestParam("pword") Integer password) {
		System.out.println(username);
		System.out.println(password);
	}
复制代码

- URL地址的抽取

  • 在刚才我们学习五种参数类型时,大家可以发现我们每个请求前面都有一个param,那么既然我每个请求路径都需要一个param,我能不能抽取出来呢?

    • 解决方案:在SrpringMVC中,我们在方法上是可以加上 @RequestMapping(/公共路径) 设置我们该控制器的公共地址的
package cn.itsource.springmvc_01;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
// 一级路径可以抽取出来,放在方法上面,还是使用@RequestMapping("") 指定该类的公共路径
@RequestMapping("/param2")
public class ParamController {
	
	/**
	 * SpringMVC 接收参数方式一(推荐使用)
	 * @param username
	 * @param age
	 */
	@RequestMapping("/01")
	public void param01(String username, Integer age) {
		System.out.println("username = " + username);
		System.out.println("age = " + age);
	}
	
	/**
	 * SpringMVC 接收参数方式二(推荐使用)
	 * @param username
	 * @param age
	 */
	@RequestMapping("/02")
	public void param02(User user) {
		System.out.println("user = " + user);
	}
	
	
	/**
	 * SpringMVC 接收参数方式三(不推荐)
	 * @param username
	 * @param age
	 */
	@RequestMapping("/03")
	public void param03(HttpServletRequest request) {
		System.out.println(request.getParameter("username"));
		System.out.println(request.getParameter("password"));
	}
	
	/**
	 * SpringMVC 接收参数方式四(推荐使用 Restful风格,将参数作为路径,这时候就要加上注解 @PathVariable(路径的参数对应的形参))
	 * @param username
	 * @param age
	 */
	@RequestMapping("/04/{username}/{password}")
	public void param04(@PathVariable("username")String username,@PathVariable("password")Integer password) {
		System.out.println(username);
		System.out.println(password);
	}
	
	/**
	 * SpringMVC 接收参数方式五(在前后端参数不一致时,可以使用@RequestParam("name") 指定前端的参数名称注入到后端那个参数里面)
	 * @param username
	 * @param age
	 */
	@RequestMapping("/05")
	public void param05(@RequestParam("name")String username,@RequestParam("pword") Integer password) {
		System.out.println(username);
		System.out.println(password);
	}
	

}

复制代码

注意:路径的前面的 / 可写可不写,因为SpringMVC会自动帮我们加上。但是规范写法我们还是写上

- 向页面传值的三种方式

  • 我们以前在Servlet时期,传递值到前端是通过我们的HttpServletRequest,SpringMVC可以有三种传递值得方式
  • 第一种
/**
	 * 方式一:就是以前我们servlet的那种方式
	 * @return
	 */
	@RequestMapping("/transfer03")
	public String transfer03(HttpServletRequest request) {
		request.setAttribute("msg", "hello word 第三种方式!!!");
		// 指定跳转路径
		return "/WEB-INF/views/index.jsp";
	}
复制代码
  • 第二种
/**
	 * 方式二:使用Model进行数据的封装
	 * @return
	 */
	@RequestMapping("/transfer02")
	public String transfer02(Model model) {
		// 将数据封装到Model中
		model.addAttribute("msg", "hello word 第二种方式!!!");
		// 指定跳转路径
		return "/WEB-INF/views/index.jsp";
	}
复制代码
  • 第三种
/**
	 * 方式三:使用ModelAndView进行数据的封装,路径的跳转
	 * @return
	 */
	@RequestMapping("/transfer01")
	public ModelAndView transfer01() {
		// 初始化一个ModelAndView
		ModelAndView modelAndView = new ModelAndView();
		// 封装数据到ModelAndView
		modelAndView.addObject("msg", "hello word 第一种方式!!!");
		// 指定跳转的路径
		modelAndView.setViewName("/WEB-INF/views/index.jsp");
		// 返回ModelAndView
		return modelAndView;
	}
复制代码

注意:三种方式没有好坏之分,都可以使用

- SpringMVC视图解析器

  • 通过刚才的代码我们发现,在返回页面时,页面的路径前面都是相同的,并且我们的页面类型也都是jsp,那么我们能否抽取公共的页面路径,并且自动给我们加上.jsp后缀呢?

    • SpringMvc提供了InternalResourceViewResolver,用于统一管理响应视图的匹配;
    • 使用之后,响应的数据就会交给这个视图解析器进行解析,然后转向响应的页面,控制器中响应视图写法就比较简单了;
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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"
>
<!-- id在以前学习spring的时候是我们全局唯一的名称,在引入SpringMVC之后,id就是我们往外面暴露的请求路径 -->
<!-- class 就是控制器的全限定名 -->
<bean id="/hello1.do" class="cn.itsource.springmvc_01.HelloWordController01"></bean>
<bean id="/hello2.do" class="cn.itsource.springmvc_01.HelloWordController02"></bean>

<!-- 这个就是配置哪个包下面的注解需要去扫描 -->
<context:component-scan base-package="cn.itsource"/>

<!-- 静态资源放行 -->
<mvc:default-servlet-handler/>

<!-- 开启对springMVC注解的支持 -->
<mvc:annotation-driven/>

<!-- 配置视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 在我的访问页面的路径前加上我的公共路径 -->
<property name="Prefix" value="/WEB-INF/views/"></property>
<!-- 在我的访问页面名称后面加上.jsp -->
<property name="Suffix" value = ".jsp"></property>
</bean>

</beans>
复制代码

- SpringMVC跳转页面的四种方式

  • 刚才我们配置了视图解析器,以后我们的页面返回路径就会自动给我们加上前缀和后缀,那么如果我的前缀和后缀不是配置的视图解析器,我应该如何跳转呢?
package cn.itsource.springmvc_01;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class JumpController {
	
	/**
	 * SpringMVC跳转的方式一:如果公共的路径下面还有路径,那么我们在跳转的时候加上前面的路径即可
	 * @return
	 */
	@RequestMapping("/list")
	public String list() {
		return "/student/list";
	}
	
	/**
	 * SpringMVC跳转的方式二:如果跳转的页面后缀不是你指定的公共后缀类型,那么就不能直接返回路径
	 * 就必须全路径并且要加上 forward 或者redirect 
	 * forward:请求转发,访问路径不会发生变化
	 * redirect:重定向,访问路径会发生变化
	 * @return
	 */
	@RequestMapping("/01")
	public String list01() {
		return "forward:/WEB-INF/views/student/student.html";
	}
	
	/**
	 * SpringMVC跳转的方式三:如果返回值类型是ModelAndView,那么在返回页面的时候,
	 * 也要必须全路径并且要加上 forward 或者redirect 
	 * forward:请求转发,访问路径不会发生变化
	 * redirect:重定向,访问路径会发生变化
	 * @return
	 */
	@RequestMapping("/02")
	public ModelAndView list02() {
		ModelAndView modelAndView = new ModelAndView();
		modelAndView.setViewName("forward:/WEB-INF/views/student/student.html");
		return modelAndView;
	}
	
	/**
	 * SpringMVC跳转的方式四:如果是在webapp下面的静态资源,
	 * 那么就直接使用forward或者redirect去访问页面即可
	 * forward:请求转发,访问路径不会发生变化
	 * redirect:重定向,访问路径会发生变化
	 * @return
	 */
	@RequestMapping("/03")
	public String list03() {
		return "forward:/student.html";
	}
	

}

复制代码

- 过滤器

  • 在以前我们使用Servlet的时候,我们解决Post乱码的方式就是通过在每个Servlet中配置字符集编码 req.setCharacterEncoding("UTF-8"),在SpringMVC中使用此方法就无法解决我们的Post乱码问题了,所以我们需要使用过滤器来帮助我们解决乱码问题

    • Filter过滤器是一个对访问的请求和响应进行拦截的web组件;
    • Filter过滤器可以实现web容器对某资源的访问前截获进行相关的处理,还可以在某资源向web容器返回响应前进行截获进行处理;

image.png

  • 过滤器编写

    • 写一个类去实现Filter接口,并实现接口中的所有方法;
    • 在web.xml中配置或者使用注解配置【@WebFilter("/")】
package cn.itsource.springmvc_01;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;

// 与配置二选一,使用了注解就不用配置过滤路径
@WebFilter("/*")
public class AFilter implements Filter{
	
	/**
	 * 在tomcat启动的时候执行
	 */
	@Override
	public void init(FilterConfig arg0) throws ServletException {
		System.out.println("tomcat启动执行了过滤器的init方法。。。");
		
	}
	
	/**
	 * 过滤器的核心方法
	 */
	@Override
	public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
			throws IOException, ServletException {
		System.out.println("放行前。。。");
		// 设置字符集编码
		req.setCharacterEncoding("UTF-8");
		// 对拦截放行
		chain.doFilter(req, resp);
		System.out.println("放行后。。。");
		
	}

	/**
	 * 在tomcat正常关闭的时候执行,不推荐在里面写代码
	 */
	@Override
	public void destroy() {
		
	}

}
复制代码
<!-- WEB.xml配置拦截路径,如果使用注解方式就不用配置,二选一 -->
  <filter>
  	<filter-name>first</filter-name>
  	<filter-class>cn.itsource.filter.FirstFilter</filter-class>
  </filter>
  <filter-mapping>
  	<filter-name>first</filter-name>
  	<url-pattern>/*</url-pattern>	
  </filter-mapping>
复制代码
  • 配置字符编码过滤器

    • springmvc框架本身没有处理请求编码,但是spring框架为我们提供了一个编码过滤器。开发者只需要配置一个spring内置请求编码过滤器即可。在web.xml配置一个请求编码过滤器:
<?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_3_1.xsd"
  version="3.1"
  metadata-complete="false">

	<servlet>
		<!-- 给核心控制器配置起一个唯一的名称 -->
		<servlet-name>dispatcherServlet</servlet-name>
		<!-- 核心控制器的全限定名 -->
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<!-- init-param标签的位置必须在load-on-startup上面 -->
		<!-- 告诉DispatcherServlet核心控制器去哪里找核心配置文件 -->
		<init-param>
		<!-- contextConfigLocation 固定写法,不能改变 -->
		<param-name>contextConfigLocation</param-name>
		<param-value>classpath:spring-MVC.xml</param-value>
		</init-param>
		<!-- 这个的意思是指定核心控制器的加载时机,参数值为 1~10 数字越低加载时机越高 -->
		<load-on-startup>1</load-on-startup>
		
	</servlet>
	<servlet-mapping>
		<servlet-name>dispatcherServlet</servlet-name>
		<!-- url-pattern参数值,有两种写法
				1./ 拦截所有请求(推荐使用,问题有解决方案),但是他不会拦截页面资源,并且支持restful风格
					问题:如果路径是/,他会把tomcat自带的servlet给覆盖掉
							被覆盖的servlet就是别人专门处理静态资源的servlet
				2. *.do:你的请求路径必须以.do结尾,才能访问我的核心控制器
					*: 匹配所有的意思
					.do: 以.do结尾的所有请求
				3./* : 也是拦截所有请求,但是他会把jsp跳转也拦截(这个方式不推荐使用)
		-->
		
		<url-pattern>/</url-pattern>
	</servlet-mapping>
	
	<!-- 解决SpringMVC post 提交乱码问题 -->
	<filter>
	<filter-name>characterEncodingFilter</filter-name>
	<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
	<!-- 指定字符编码集 -->
	<init-param>
	<param-name>encoding</param-name>
	<param-value>UTF-8</param-value>
	</init-param>
	<!-- 强制指定字符编码,即使request或response设置了字符编码,
	也会强制使用当前设置的,任何情况下强制使用此编码 -->
	<init-param>
	<param-name>forceEncoding</param-name>
	<param-value>true</param-value>
	</init-param>
	</filter>
	<filter-mapping>
	<filter-name>characterEncodingFilter</filter-name>
	<url-pattern>/*</url-pattern>
	</filter-mapping>
	
</web-app>

复制代码

SpringMVC的基础学习就到此结束了