文章目录
SpringMVC简介
什么是MVC
Model 数据模型
View 视图
Controller 控制器
MVC是一种Web应用架构,是一种代码设计思想
思想:将所有客户端请求全部交由控制器,由控制器将其分发并将结果响应给客户端。
常见MVC框架
- 使用原生Servlet实现MVC。
- 配置比较复杂
- 数据处理麻烦
- 实际开发中一般都会使用MVC框架,如Struts1、Struts2、SpringMVC等
对比- 效率方面:Struts1>SpringMVC>Struts2
- Struts2是多例的,效率低;Struts和SpringMVC是单例的,两者效率基本差不多。
- 配置方面:SpringMVC>Struts2>Struts1
- 为什么要使用SpringMVC
- 使用注解配置替代xml配置,更简单
- 效率高,单例的
- 扩展性好,用户自定义
- SpringMVC和Spring无缝衔接
SpringMVC实现原理
- 流程图
- 执行过程
分为六步:
- DispatcherServlet
SpringMVC核心控制器:前端控制器,主要作用是用来分发 - HandlerMapping
映射处理器:根据请求url映射到具体的处理Handler
Handler就是Controller层的实现类,也称为Action或Controller - HandlerAdapter
适配器:用来适配不同的处理器Handler
处理器有两种实现方式:实现接口、基于注解,所以执行之前需要先适配 - Handler
处理器:执行处理具体业务,并产生数据模型Model和视图名View
Handler会将数据模型Model和视图名View封装成ModelAndView对象并返回 - ViewResolver
视图解析器:根据视图名解析为具体的视图,一般多为jsp页面,然后封装为View对象 - View
视图:使用具体的视图技术进行渲染,结合Model展示数据
视图有很多种形式:jsp、freemarker、velocity、excel、pdf等
第一个SpringMVC程序
- 添加jar包
<?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>com.mlj.tshop</groupId>
<artifactId>tshop_parent</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
<modules>
<module>tshop_common</module>
<module>tshop_pojo</module>
<module>tshop_dao</module>
<module>tshop_service</module>
<module>tshop_front_web</module>
<module>tshop_backend_web</module>
</modules>
<name>tshop_parent</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<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>
<junit.version>4.12</junit.version>
<spring.version>5.1.1.RELEASE</spring.version>
<javax.servlet-api.version>3.1.0</javax.servlet-api.version>
<jsp-api.version>2.1</jsp-api.version>
<jstl.version>1.2</jstl.version>
<mybatis.version>3.4.6</mybatis.version>
<mybatis-spring.version>1.3.2</mybatis-spring.version>
<mysql-connector-java.version>8.0.11</mysql-connector-java.version>
<commons-fileupload.version>1.3.3</commons-fileupload.version>
<fastjson.version>1.2.47</fastjson.version>
<druid.version>1.1.10</druid.version>
<tomcat7-maven-plugin.version>2.2</tomcat7-maven-plugin.version>
<log4j.version>1.2.17</log4j.version>
<hibernate-validator.version>5.4.1.Final</hibernate-validator.version>
</properties>
<dependencyManagement>
<dependencies>
<!-- junit -->
<!-- https://mvnrepository.com/artifact/junit/junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<!--java-ee-->
<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>${javax.servlet-api.version}</version>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.servlet.jsp/jsp-api -->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>${jsp-api.version}</version>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/jstl/jstl -->
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>${jstl.version}</version>
</dependency>
<!-- spring -->
<!--spring-ioc-->
<!-- https://mvnrepository.com/artifact/org.springframework/spring-core -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-beans -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-expression -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>${spring.version}</version>
</dependency>
<!--spring-aop-->
<!-- https://mvnrepository.com/artifact/org.springframework/spring-aop -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-aspects -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- spring-jdbc -->
<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-tx -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency>
<!--spring-webmvc-->
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- mybatis -->
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>${mybatis.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>${mybatis-spring.version}</version>
</dependency>
<!-- 分页插件 -->
<!-- https://mvnrepository.com/artifact/com.github.pagehelper/pagehelper -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.1.2</version>
</dependency>
<!-- mysql -->
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql-connector-java.version}</version>
</dependency>
<!-- datasource -->
<!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>${druid.version}</version>
</dependency>
<!-- 其它工具 -->
<!-- commons-fileupload -->
<!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>${commons-fileupload.version}</version>
</dependency>
<!-- fastjson -->
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
<!-- log4j -->
<!-- https://mvnrepository.com/artifact/log4j/log4j -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
<!-- hibernate-validator -->
<!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-validator -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>${hibernate-validator.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>${tomcat7-maven-plugin.version}</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
- 配置核心控制器
<?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">
<!--1.配置DispatcherServlet,核心控制器-->
<servlet>
<servlet-name>springMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springMVC</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
- 核心配置文件
两种定义方式:
- 使用默认位置,默认在WEBINF/目录下,名称为: 核心Servlet名称-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 http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--2.配置HandlerMappring-->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
<!--3.配置HandlerAdapter-->
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
<!--4.配置Handler-->
<bean name="/hello" class="controller.HelloController"/>
<!--5.配置ViewResolver-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/view/"/>
<property name="suffix" value=".jsp"/>
<!--6.配置View,使用jsp视图技术渲染页面-->
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
</bean>
</beans>
- 自定义位置,名称自定义
在web.xml中加入参数
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<?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">
<!--2.配置HandlerMapping-->
<!--<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>-->
<!--3.配置HandlerAdapter-->
<!--<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>-->
<!--mvc的注解驱动,用来简化配置,就是它替代了2,3,注意你需要选择mvc的-->
<mvc:annotation-driven/>
<!--4.配置Handler-->
<context:component-scan base-package="controller"/>
<!--5.配置ViewResolver-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/view/"/>
<property name="suffix" value=".jsp"/>
<!--6.配置View,如果使用的是jsp视图技术,可以省略不写-->
<!--<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>-->
</bean>
<!--使用tomcat提供的默认Servlet处理静态资源-->
<!--<mvc:default-servlet-handler/>-->
<mvc:resources mapping="/img/**" location="/WEB-INF/img/"/>
<mvc:resources mapping="/css/**" location="/WEB-INF/css/"/>
<mvc:resources mapping="/js/**" location="/WEB-INF/js/"/>
<mvc:resources mapping="/images/**" location="/images/"/>
<!--直接访问jsp页面-->
<mvc:view-controller path="/userLogin" view-name="login"/>
</beans>
根据Controller实现方式的不同,配置方式也有所不同,有两种方式定义Controller:
- 实现接口
package controller;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @Description
* @Author Matthew
* @Date 2019/3/25 9:33
**/
public class HelloController implements Controller {
@Override
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
String name = request.getParameter("name");
ModelAndView mav = new ModelAndView();
mav.addObject("msg", "Hello" + name);
mav.setViewName("hello");
return mav;
}
}
- 基于注解
package controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
/**
* @ClassName HelloAnnotationController
* @Description TODO
* @Author Matthew
* @Date 2019/3/25 18:57
* @Version 1.0
**/
@Controller
public class HelloAnnotationController {
@RequestMapping("/hello")
public ModelAndView sayHello(String name){
ModelAndView mav = new ModelAndView();
mav.addObject("msg", "你好 " + name);
mav.setViewName("hello");
return mav;
}
@RequestMapping("/hello2")
public ModelAndView sayHi(String name){
ModelAndView mav = new ModelAndView();
mav.addObject("msg", "您好 " + name);
mav.setViewName("hello");
return mav;
}
}
<%--
Created by IntelliJ IDEA.
User: Matthew
Date: 2019/3/25
Time: 9:38
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>HELLO</title>
</head>
<body>
<h1>HELLO WORLD</h1>
msg:${msg}
</body>
</html>
案例
- 用户登陆
<%--
Created by IntelliJ IDEA.
User: Matthew
Date: 2019/3/25
Time: 19:16
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
<link rel="stylesheet" href="${pageContext.request.contextPath}/css/style.css">
<script src="${pageContext.request.contextPath}/js/hello.js"></script>
</head>
<body>
<h2>用户登录</h2>
<span style="color:red">${loginError}</span>
<form action="${pageContext.request.contextPath}/login2" method="post">
用户名:<input type="text" name="username"> <br>
密码:<input type="password" name="password"><br>
<input type="submit" value="提交">
</form>
<img src="${pageContext.request.contextPath}/img/springMVC.JPG">
</body>
</html>
- 静态资源处理
当配置DispatcherServlet为 <urlpattern>/</urlpattern> 时,会拦截所有请求(包括静态资源),导致所有静态资源都无法访问
两种处理方式:- 使用tomcat提供的默认Servletomcat提供了默认的Servlet来处理静态资源
在springMVC.xml中配置
- 使用tomcat提供的默认Servletomcat提供了默认的Servlet来处理静态资源
<!--使用tomcat提供的默认Servlet处理静态资源-->
<mvc:default-servlet-handler/>
缺点:1. 如果使用的不是tomcat,则可能不生效,与tomcat耦合
2. 只能读取webapp下的资源,无法读取/WEBINF/下的资源
2. 使用SpringMVC提供的处理方式
<mvc:resources mapping="/img/**" location="/WEB-INF/img/"/>
<mvc:resources mapping="/css/**" location="/WEB-INF/css/"/>
<mvc:resources mapping="/js/**" location="/WEB-INF/js/"/>
<mvc:resources mapping="/images/**" location="/images/"/>
3. 直接访问jsp页面
默认不能直接访问WEBINF目录下的jsp页面,一般都是在Controller中做转发映射
<!--直接访问jsp页面-->
<mvc:view-controller path="/userLogin" view-name="login"/>
Controller详解
方法的返回值
有四种类型:
1. ModelAndView 表示返回的为数据模型和视图
2. String 表示返回的是视图
三种写法(形式):
普通字符串——>表示视图名称
@RequestMapping("/login2")
public String login(String username, String password, Model model){//将数据存储到Model对象中
if ("admin".equals(username) && "123".equals(password)){
model.addAttribute("username", username);
return "success";
} else {
model.addAttribute("loginError", "username or password error");
}
return "login";//表示视图名称
}
"forward:"+url——>转发
@RequestMapping("/login2")
public String login(String username, String password, Model model){//将数据存储到Model对象中
if ("admin".equals(username) && "123".equals(password)){
model.addAttribute("username", username);
return "success";
} else {
model.addAttribute("loginError", "username or password error");
}
return "forward:/showLogin2";//转发
}
"redirect:"+url——>重定向
@RequestMapping("/login2")
public String login(String username, String password, Model model){//将数据存储到Model对象中
if ("admin".equals(username) && "123".equals(password)){
model.addAttribute("username", username);
return "success";
} else {
model.addAttribute("loginError", "username or password error");
}
return "redirect:/showLogin2";//重定向
}
3. void 将请求的url作为视图名称,很少使用
@RequestMapping("/test1")
public void test1(){
System.out.println("ReturnController.test1");
}
return的两种返回路径方式(绝对路径和相对路径)
@RequestMapping("/showLogin")
public String showLogin(){
System.out.println("PathController.showLogin");
return "login";
}
@RequestMapping("/forwardLogin")
public String forwardLogin(){
System.out.println("PathController.forwardLogin");
return "forward:/showLogin";
// return "forward:showLogin";不加/为相对路径:PathController.showLogin
// return "forward:/path/showLogin";和return "forward:showLogin";一样
}
ReturnController.test1
4. Object 表示返回的是数据模型(一般返回的是json数据)
SpringMVC注解
注解 | 解释 |
---|---|
@Controller | 将类映射为Controller层,添加到IoC容器中 |
@RequestMapping | 配置请求映射路径,即URL |
@RequestParam | 表示参数来源于请求参数 |
@PathVariable | 表示参数来源于URL |
@RequestHeader | 表示参数来源于请求头 |
@CookieValue | 表示参数来源于Cookie |
@RequestBody | 表示参数来源于请求体 |
@ModelAttribute | 将请求数据转换为对象 |
@Valid | 后台校验 |
@InitBinder | 类型转换,注册属性编辑器 |
@ControllerAdvice | 统一异常处理,处理全局异常 |
@ExceptionHander | 异常处理器,处理特定异常的方法 |
@ResponseBody | 结合返回值为Object的方法使用,用来返回JSON数据 |
@RestController | 将类映射为Controller层,默认为所有方法添加@ResponseBody注解 |
@RequestMapping
基本用法
该注解可以定义在方法上,也可以定义在类上,表示层级关系
配置URL时以/开头和不以/开头的区别:
添加时表示从项目根路径开始查找
不添加时表示从当前方法所在层级开始查找
URL的多种写法
请求映射路径有三种写法:
Ant风格(较少使用)
* 表示单层目录,匹配任意字符,可以没有字符,但正斜杠必须有
@Controller
@RequestMapping("/path")
public class PathController {
/**
* @Description Ant风格
* *表示一层
* **表示多层
* ?表示单个字符,三者可以组合
* @Author Matthew
* @Date 2019/3/26 20:21
* @Param
* @Return
**/
@RequestMapping("/test1/*")
public String test1(){
return "hello";
}
}
** 表示多层或单层目录,可以没有字符,正斜杠也可以没有
@RequestMapping("/test2/**")
public String test2(){
return "hello";
}
? 表示单个字符,必须有一个字符
@RequestMapping("/test3/?")
public String test3(){
return "hello";
}
混合使用
@RequestMapping("/test4/?/aa/*/b?c/**/d")
public String test4(){
return "hello";
}
Rest风格
{变量}表示URL中的占位符,可以结合@PathVariable获取值
{变量:正则}表示使用正则表达式来限定值的格式
/**
* @Description Rest风格
* @Author Matthew
* @Date 2019/3/26 20:30
* @Param
* @Return
**/
@RequestMapping("/test5/{id:\\d+}/{name}")
public String test5(@PathVariable String id, @PathVariable("name") String username){
System.out.println("PathController.test5,id=" + id + " username=" + username);
return "hello";
}
PathController.test5,id=2 username=matthew
固定写法
value和path互为别名,值为数组,可以指定多个值
method来限制请求方式
也有@GetMapping来代替 @RequestMapping(method = RequestMethod.GET)
和@PostMapping来代替@RequestMapping( method = RequestMethod.POST)
@RequestMapping(value = {"/test6", "/t6"})
public String test6(){
return "hello";
}
@RequestMapping(value = "/test7", method = RequestMethod.POST)
public String test7(){
return "hello";
}
// @RequestMapping(path = "/user/{id}", method = RequestMethod.GET)
@GetMapping("/user/{id}")
public String deleteUser(@PathVariable Integer id) {
System.out.println("PathController.deleteUser,id = " + id);
return "hello";
}
// @RequestMapping(path = "/user/{id}", method = RequestMethod.POST)
@PostMapping("/user/{id}")
public String selectUser(@PathVariable Integer id) {
System.out.println("PathController.selectUser,id = " + id);
return "hello";
}
其他属性
/**
* @Description 其他属性
* @Author Matthew
* @Date 2019/3/27 10:36
* @Param
* @Return
*/
//请求参数中必须包含id,且username等于admin,且password不等于123
@RequestMapping(path = "/test8", params = {"id", "username=admin", "password!=123"})
public String test8(){
return "hello";
}
@RequestMapping(path = "/test9", headers = {"Cookie","Accept-Language=zh-CN,zh;q=0.9"})
public String test9(){
return "hello";
}