系列文章
SSM之SpringMVC 01 —— SpringMVC原理及概念、Hello SpringMVC 注解版和配置版
SSM之SpringMVC 02 —— Controller和RestFul风格、转发和重定向、数据处理和乱码问题、Json
SSM之SpringMVC 03 —— 整合SSM(简单图书系统)
SSM之SpringMVC 04 —— Ajax、拦截器、文件上传和下载
文章目录
1、回顾Servlet
在学习SpringMVC前需要先了解什么是MVC,这部分可以看我另一篇博客 JavaWeb 开发 04 —— JSP(原理、语法、指令、内置对象、JSP标签、JSTP标签)、JavaBean、MVC
同时,需要先回忆起Servlet,这里创建一个简单Servlet。
-
新建一个普通Maven项目,无需导入模板。
-
右键该项目,添加框架支持,并选择JavaWeb。
- 编写Servlet以及注册Servlet
HelloServlet.java
public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1. 获取前端参数
String method = req.getParameter("method");
if (method.equals("method1"))
req.getSession().setAttribute("message", "执行了method1");
else if (method.equals("method2"))
req.getSession().setAttribute("message", "执行了method2");
//2. 调用业务层
//3. 视图转发或重定向
req.getRequestDispatcher("/WEB-INF/jsp/test.jsp").forward(req,resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
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_4_0.xsd"
version="4.0">
<servlet>
<servlet-name>helloServlet</servlet-name>
<servlet-class>com.zcy.servlet.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>helloServlet</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
</web-app>
- 编写jsp
index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>$Title$</title>
</head>
<body>
<form action="/hello" method="post">
<input type="text" name="method">
<input type="submit" value="提交"/>
</form>
</body>
</html>
test.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Test</title>
</head>
<body>
${message}
</body>
</html>
- 配置Tomcat并测试
2、SpringMVC
2.1、什么是SpringMVC
官方文档:https://docs.spring.io/spring-framework/docs/4.3.24.RELEASE/spring-framework-reference/html/mvc.html
SpringMVC是Spring Framework 的一部分,是基于Java实现MVC的轻量级Web架构。
SpringMVC的特点:
- 轻量级,简单易学,简洁灵活
- 高效,基于请求响应的MVC框架
- 与Spring兼容性好,无缝结合
- 约定大于配置
- 功能强大:数据验证、格式化、本地化、主题等
- 最重要的是使用的人多!
2.2 前端控制器
SpringMVC分为两个控制器,DispatcherServlet(前端控制器)和Controller(业务控制器)。由DispatcherServlet接收客户端请求,再根据客户端请求的URL的特点,分发到对应的Controller,比如UserController。
SpringMVC的原理如下图所示:
2.3、SpringMVC执行原理
图为SpringMVC的一个较完整的流程图,实线表示SpringMVC框架提供的技术,不需要开发者实现,虚线表示需要开发者实现 。
简要分析执行流程
DispatcherServlet
表示前端控制器,是整个 SpringMVC 的控制中心。用户发出请求,会先被它接收并拦截。
假设请求的URL为 : http://localhost:8080/HelloCtontroller/hello- http://localhost:8080 表示服务器域名
- HelloCtontroller 表示部署在服务器上的web站点
- hello 表示控制器
该URL表示请求位于服务器localhost:8080上的HelloCtontroller站点的hello控制器。
HandlerMapping
为处理映射器,当DispatcherServlet
调用HandlerMapping
时,HandlerMapping
会根据请求的URL找对应的实际处理器。HandlerExecution
表示具体的处理器,它根据URL查找对应的控制器,如上URL被查找控制器为:hello。HandlerExecution
将解析后的信息传递给DispatcherServlet
,如解析控制器映射等。HandlerAdapter
表示处理器适配器,其按照特定的规则去执行Handler
。Handler
让具体的Controller
执行。Controller
将具体的执行信息返回给HandlerAdapter
,如ModelAndView模型视图
。HandlerAdapter
将视图名称或模型传递给DispatcherServlet
。DispatcherServlet
调用视图解析器(ViewResolver
)来解析HandlerAdapter
传递的逻辑视图名。- 视图解析器将解析的逻辑视图名传给
DispatcherServlet
。 DispatcherServlet
根据视图解析器解析的视图结果,调用具体的视图。- 最终视图呈现给用户。
3、Hello SpringMVC
对于配置版,先不用管具体原理,看看注释,然后照着代码写,正常执行一遍!再回过头去看看上面的原理。配置版主要是用于了解原理的。
可能碰到的问题:
1、运行时出现404:查看Artifacts中该模块是否包含lib目录以及各种包。
2、如果出现下面错误:是由于SpringMVC配置重复
解决方法:只保留一个就行。
3.1、配置版
一般开发不会这么写,比较麻烦,但执行原理是按照配置版来的。
1、新建一个Model
2、导入SpringMVC依赖
3、配置web.xml,注册 DispatcherServlet
(这是依赖自带的)
<?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">
<!-- 1. 注册DispatcherServlet -->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 关联一个springmvc的配置文件:springmvc-servlet.xml -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc-servlet.xml</param-value>
</init-param>
<!-- 启动级别 1 -->
<load-on-startup>1</load-on-startup>
</servlet>
<!-- 匹配所有请求,都用SpringMvc -->
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<!-- 注意/*是包括了.jsp,而/是不包括.jsp -->
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
4、编写SpringMVC的配置文件:springmvc-servlet.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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 添加官方的 处理映射器 -->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
<!-- 添加官方的 处理适配器 -->
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
<!-- 添加官方的 视图解析器 -->
<bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 下面的前后缀用于省略我们使用请求转发或者重定向时填写的路径,以后只需要写文件名 -->
<!-- 前缀 -->
<property name="prefix" value="/WEB-INF/jsp/"/>
<!-- 后缀 -->
<property name="suffix" value=".jsp"/>
</bean>
<!-- 注册HelloController:通过向/hello发送请求,就会跳转到HelloController -->
<bean id="/hello" class="com.zcy.controller.HelloController"/>
</beans>
5、编写Controller类(对比Servlet类)
package com.zcy.controller;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class HelloController implements Controller {
public ModelAndView handleRequest(
HttpServletRequest request, HttpServletResponse response
) throws Exception {
//ModelAndView 代表模型和视图
ModelAndView mv = new ModelAndView();
String method = request.getParameter("method");
//封装视图:把要跳转的新视图放在ModelAndView
mv.setViewName("test");//因为我们在springmvc-servlet.xml配置了前缀和后缀
if (method.equals("method1")){
//封装对象:把数据放在ModelAndView,因为模型用于存放数据
mv.addObject("message", "执行了method1");
}
else if (method.equals("method2")){
mv.addObject("message", "执行了method2");
}else{
mv.addObject("message", "未执行method1和method2");
}
return mv;
}
}
6、编写jsp页面:
index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>$Title$</title>
</head>
<body>
<form action="/hello" method="post">
<input type="text" name="method">
<input type="submit" value="提交"/>
</form>
</body>
</html>
test.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Test</title>
</head>
<body>
${message}
Hello SpringMVC
</body>
</html>
3.1、注解版
1、创建Maven Web项目
2、导入相关包
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.1.9.RELEASE</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.2</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
</dependencies>
<!--在build中配置resources,来防止我们资源导出失败的问题-->
<build>
<resources>
<resource>
<directory>${basedir}/src/main/webapp</directory>
</resource>
<resource>
<directory>${basedir}/src/main/resources</directory>
</resource>
<resource>
<directory>${basedir}/src/main/java</directory>
<includes>
<include>**/*.xml</include>
<include>**/*.properties</include>
</includes>
</resource>
</resources>
</build>
2、编写web.xml,注册DispatcherServlet
<?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">
<!--1.注册servlet-->
<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>
<!-- 启动顺序,数字越小,启动越早 -->
<load-on-startup>1</load-on-startup>
</servlet>
<!--所有请求都会被springmvc拦截 -->
<servlet-mapping>
<servlet-name>SpringMVC</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
3、编写SpringMVC配置文件springmvc-servlet.xml(其实就是Spring配置文件)
<?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
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- 自动扫描包,让指定包下的注解生效,由IOC容器统一管理 -->
<context:component-scan base-package="com.zcy.controller"/>
<!-- 让Spring MVC不处理静态资源 .css、.js等,以便提高效率 -->
<mvc:default-servlet-handler />
<!--
支持mvc注解驱动
在spring中一般采用@RequestMapping注解来完成映射关系
要想使@RequestMapping注解生效
必须向上下文中注册DefaultAnnotationHandlerMapping
和一个AnnotationMethodHandlerAdapter实例
这两个实例分别在类级别和方法级别处理。
而annotation-driven配置帮助我们自动完成上述两个实例的注入。
-->
<mvc:annotation-driven />
<!-- 视图解析器 -->
<bean id="internalResourceViewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver" >
<!-- 前缀 -->
<property name="prefix" value="/WEB-INF/jsp/" />
<!-- 后缀 -->
<property name="suffix" value=".jsp" />
</bean>
</beans>
5、创建对应的控制类
package com.zcy.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@RequestMapping("/HelloController")
@Controller
public class HelloController {
//真实访问地址:项目名/HelloController/hello
@RequestMapping("/hello")
public String hello(Model model) {
//向模型添加msg属性,后面JSP页面通过${msg}读取
model.addAttribute("msg", "Hello SpringMVC Annotation");
//返回视图,由于配置文件写了前缀和后缀,所以只需要视图文件名
return "hello";
}
}
- @Controller 是为了让Spring IOC容器初始化时自动扫描到;
- @RequerstMapping 是为了映射请求路径,这里在类和方法上都有映射,所以是 /HelloController/hello ;
- 方法中声明的Model类型就是模型,用于存储数据,能把数据带到视图去;
- 方法返回的结果是视图的名称hello,就可以转发到hello.jsp
6、创建视图层
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
${msg}
</body>
</html>
8、运行Tomcat
小结
使用SpringMVC 我们通常需要配置三个东西:处理器映射器、处理器适配器、视图解析器,其他就是控制类以及业务。但注解版可以帮我们省去映射器和适配器,极大简化开发过程。