一 Spring Web介绍
1 MVC 思想
2 Spring MVC
Servlet:Web 服务的模块,包含对 MVC 与 REST 的实现,Spring MVC。
Web:提供与 Web 的集成,基于 Web 应用程序上下文。
WebSocket:实现客户端与服务端主动通信。
Portlet:提供了在 Portlet 环境中实现 MVC。
Spring MVC 是 Spring 对 MVC 思想的实现,它解决 Web 开发中常见的问题(参数接收、文件上传、表单验证、国际化等),而且使用简单,与 Spring 无缝集成。支持 RESTful 风格的 URL 请求 ,采用了松散耦合可插拔组件结构,比其他 MVC 框架更具扩展性和灵活性,易与其他视图技术集成。
二 前端控制器
1 介绍
前端控制器(Front Controller)是一种设计模式,常用于Web应用程序开发中。它主要负责集中处理所有的请求,并根据这些请求的类型和性质,将其分派给相应的处理程序或控制器。通过这种方式,前端控制器实现了应用程序的中心化管理和控制。做一个共同的处理,如权限检查,授权,日志记录等。因为前端控制的集中处理请求的能力,因此提高了可重用性和可拓展性。
2 Spring MVC 的前端控制器
Spring MVC 提供了一个 DispatcherServlet 类作为前端控制器,使用 Spring MVC 必须在 web.xml 中配置前端控制器。处理请求的对象称之为处理器或后端控制器,Spring MVC 中称之为 Controller,如处理学生请求即 StudentController
三 简单Demo
1 Demo构建
2 导入依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cn.tj</groupId>
<artifactId>spring-mvc</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
<spring.version>5.0.8.RELEASE</spring.version>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<!--所需依赖 统一管理 于properties中定义-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.0.1</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.1</version>
<configuration>
<port>8080</port>
<path>/</path>
<uriEncoding>UTF-8</uriEncoding>
</configuration>
</plugin>
</plugins>
</build>
</project>
3 配置前端控制器 web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<!--前端控制器配置-->
<servlet>
<servlet-name>DispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--加载mvc配置文件-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-mvc.xml</param-value>
</init-param>
<!--当<load-on-startup>标签值为正整数时,表示容器在应用启动时就加载这个servlet-->
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>DispatcherServlet</servlet-name>
<!--设置请求拦截规则 拦截所有请求进入前端控制器-->
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
4 创建处理器 HelloController
@Controller
@RequestMapping("hello")
public class HelloController {
/*后台方法*/
@RequestMapping("hello")
public ModelAndView hello(){
System.out.println("spring mvc 入门示例....");
// 该对象有作用域和转发等功能(不是重定向)
ModelAndView mav =new ModelAndView();
// 跳转携带的参数 底层存入request的作用域
mav.addObject("msg","hello spring mvc!");
// 设置跳转的页面路径
mav.setViewName("/WEB-INF/views/ok.jsp");
// 跳转路径
return mav;
}
}
5 创建spring容器 spring-mvc.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
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/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
">
<!--开启springmvc注解扫描-->
<context:component-scan base-package="cn.tj.controller"></context:component-scan>
<!--开启springmvc注解驱动(解析器)-->
<mvc:annotation-driven></mvc:annotation-driven>
<!--配置注解解析器之后以下bean就自动注入到spring容器中-->
<!-- <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"></bean>-->
<!-- <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"></bean>-->
<!-- <bean class="org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver"></bean>-->
<!-- -->
</beans>
6 创建跳转页面 ok.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>ok</title>
</head>
<body>
<h3>此处一个EL表达式</h3>
${msg}
</body>
</html>
四 前端控制器的映射路径
1 映射路径的配置
- 配置如 .do、.htm 是最传统方式,可以访问静态文件(图片、 JS、 CSS 等),但不支持 RESTful 风格。
- 配置成 /,可以支持流行的 RESTful 风格,但会导致静态文件(图片、 JS、 CSS 等)被拦截后不能访问。
- 配置成 /*,是错误的方式,可以请求到 Controller 中,但跳转到调转到 JSP 时被拦截,不能渲染 JSP 视图,也会导致静资源访问不了。
2 访问静态资源和 JSP 被拦截
Tomcat 容器处理静态资源是交由内置 DefaultServlet 来处理的(拦截路径是 /),处理 JSP 资源是交由内置的 JspServlet 处理的(拦截路径是*.jsp | .jspx)。
启动项目时,先加载容器的 web.xml,而后加载项目中的 web.xml。当拦截路径在两者文件中配置的一样,后面会覆盖掉前者。
所以前端控制器配置拦截路径是 / 的所有静态资源都会交由前端控制器处理,而拦截路径配置 /,所有静态资源和 JSP 都会交由前端控制器处理。
3 静态资源访问
① 方式一 web.xml 中修改前端控制器的映射路径,但访问控制器里的处理方法时,请求路径须携带 .do。
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
② 方式二 mvc.xml中进行配置,该配置会在 Spring MVC 上下文中创建存入一个 DefaultServletHttpRequestHandler 的 bean,它会对进入 DispatcherServlet 的请求进行筛查,若不是映射的请求,就将该请求交由容器默认的 Servlet 处理。
<mvc:default-servlet-handler/>
五 处理响应
编写控制器里面的处理方法接受请求做响应,找视图文件和往作用域中存入数据。要处理方法要做响应,一般处理方法返回的类型为 ModelAndView 和 String。响应 HTML 格式数据
1 返回 ModelAndView
① 编写处理方法
// 方法中返回 ModelAndView 对象,此对象中设置模型数据并指定视图。
@Controller
public class ResponseController {
// 提供方法处理请求,localhost/resp
@RequestMapping("/resp")
public ModelAndView resp() {
// 通过类对象,让Spring MVC找对应视图文件, 向作用域或者往模型中存入数据
ModelAndView mv = new ModelAndView();
// 向作用域或者模型中存入数据
mv.addObject("msg", "方法返回类型是 ModelAndView");
// 找视图
mv.setViewName("/WEB-INF/views/resp.jsp");
return mv;
}
//addObject(String key, Object value):设置共享数据的 key 和 value。
//addObject(Object value):设置共享数据的 value,key 为该 value 类型首字母小写。
② 编写 JSP
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<%--对应路径下新建 resp.jsp--%>
<title>响应</title>
</head>
<body>
${msg}
</body>
</html>
2 返回 String
String 类型共享数据,需要同Model 参数组合使用,用其往作用域或模型中存入数据
@Controller
public class ResponseController {
// 提供方法处理请求,localhost/resp
@RequestMapping("/resp")
public String resp(Model model) {
// 往作用域或者模型中存入数据
model.addAttribute("msg", "方法返回类型是 String");
// 返回视图名
return "/WEB-INF/views/resp.jsp";
}
}
3 消除视图前缀后缀
视图位置固定且统一选用一种视图技术,故视图后缀名也是一样的,那么处理方法设置的视图路径代码随着项目增长,会有大量重复。Spring MVC 提供配置方法消除视图路径重复,需在 mvc.xml进行配置
<!--
配置视图解析器,配置后 Spring MVC 找视图的路径为:前缀+文件名(视图名)+后缀=后台返回的跳转路径
-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 视图前缀 -->
<property name="prefix" value="/WEB-INF/views/"/>
<!-- 视图后缀 -->
<property name="suffix" value=".jsp"/>
</bean>
<!--
原方法中返回如下
return "/WEB-INF/views/ok.jsp";
配置后返回如下
return "ok";
-->
六 请求转发及 URL 重定向
1 请求转发和 URL 重定向对比
地址栏 | WEB-INF | 共享请求数据 | 表达重复提交 | |
---|---|---|---|---|
请求转发 | 不变 | 可以访问 | 共享 | 有 |
URL 重定向 | 变 | 不可访问 | 不共享 | 无 |
2 请求转发
forward 前缀为请求转发,相当于 request.getRequestDispatcher().forward(request,response),转发后浏览器地址栏不变,共享之前请求中的数据。(默认转发,可以省略)
@Controller
public class ResponseController {
@RequestMapping("/forward")
public String forward() {
return "forward:/WEB-INF/views/ok.jsp";
}
}
3 URL 重定向
redirect 前缀为重定向,相当于 response.sendRedirect(),重定向后浏览器地址栏变为重定向后的地址,不共享之前请求的数据。(重定向可访问WEB-INF目录下文件)
@Controller
public class ResponseController {
@RequestMapping("/redirect")
public String redirect() {
return "redirect:/static/demo.html";
}
}
4 路径问题
请求转发或者 URL 重定向时,路径有无 / 的区别
// 加 /,使用是绝对路径(推荐使用),从项目根路径(webapp)下找;
// 没加 /,使用是相对路径,相对于上一次访问上下文路径的上一级找。
/response/test ---> "redirect:/hello.html" ---> localhost:/hello.html
/response/test ---> "redirect:hello.html" ---> localhost:/response/hello.html