一、Spring MVC 概述
- Spring MVC 是 Spring 提供的一个基于MVC设计模式的轻量级Web开发框架,本质上相当于Servlet。
- 因为Spring MVC 本身就是Spring 框架的一部分,所以和Spring框架是无缝集成。是现在业界最主流的Web开发框架。
二、SpringMVC 执行流程
1. 用户点击某个请求路径,发起一个 HTTP request 请求,该请求会被提交到 DispatcherServlet(前端控制器);
2. 由 DispatcherServlet 请求一个或多个 HandlerMapping(处理器映射器),并返回一个执行链(HandlerExecutionChain)。
3. DispatcherServlet 将执行链返回的 Handler 信息发送给 HandlerAdapter(处理器适配器);
4. HandlerAdapter 根据 Handler 信息找到并执行相应的 Handler(常称为 Controller);
5. Handler 执行完毕后会返回给 HandlerAdapter 一个 ModelAndView 对象(Spring MVC的底层对象,包括 Model 数据模型和 View 视图信息);
6. HandlerAdapter 接收到 ModelAndView 对象后,将其返回给 DispatcherServlet ;
7. DispatcherServlet 接收到 ModelAndView 对象后,会请求 ViewResolver(视图解析器)对视图进行解析;
8. ViewResolver 根据 View 信息匹配到相应的视图结果,并返回给 DispatcherServlet;
9. DispatcherServlet 接收到具体的 View 视图后,进行视图渲染,将 Model 中的模型数据填充到 View 视图中的 request 域,生成最终的 View(视图);
10. 视图负责将结果显示到浏览器(客户端)。
三、Spring MVC 入门
3.1入门案例:基于xml配置文件
3.1.1需求:
- 基于XML配置文件的入门案例
3.1.2 搭建环境
- 导入坐标
<packaging>war</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<!--声明不需要web.xml文件-->
<failOnMissingWebXml>false</failOnMissingWebXml>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.2.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.2.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.4.RELEASE</version>
</dependency>
<!-- 事务 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.4.RELEASE</version>
</dependency>
<!-- mysql驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.24</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.4</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.7</version>
</dependency>
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper</artifactId>
<version>3.5.2</version>
</dependency>
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>3.7.5</version>
</dependency>
<!--整合-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.5</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<!-- mvc json -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.10.2</version>
</dependency>
<!--swagger2-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.7.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.7.0</version>
</dependency>
<!--文件上传-->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
<!--jsp相关-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.10</version>
</dependency>
</dependencies>
3.1.3项目结构
3.1.4 实现
1.编写UserController:业务处理入口
package com.czxy.mvc.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* @Author: 小新
* @Date: 2021-12-06 17:55
*/
@Controller //将当前类添加到spring容器中
@RequestMapping("/user")//给当前类中所有功能,设置一个路径访问前缀
public class UserController {
//最终访问路径:/user/selectAll.action
@RequestMapping("/selectAll")//当前功能方法,设置一个访问路径。
public String selectAll(){
return "/list.jsp"; //jsp页面在web下
}
}
2.编写jsp页面
- list.jsp:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
列表页面
</body>
</html>
3. 编写核心配置文件,用于扫描controller
- springmvc.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"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
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/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 扫描注解包 -->
<context:component-scan base-package="com.czxy.mvc.controller" />
</beans>
4.在web.xml中配置前端控制器:加载核心配置文件
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<!--设置前端控制器-->
<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>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>*.action</url-pattern>
</servlet-mapping>
</web-app>
5.编写首页
- index.jsp:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<a href="${pageContext.request.contextPath}/user/selectAll.action">入门案例</a>
</body>
</html>
3.2 入门案例:基于注解配置类
3.2.1 搭建环境
<packaging>war</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<!--声明不需要web.xml文件-->
<failOnMissingWebXml>false</failOnMissingWebXml>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.2.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.2.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.4.RELEASE</version>
</dependency>
<!-- 事务 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.4.RELEASE</version>
</dependency>
<!-- mysql驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.24</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.4</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.7</version>
</dependency>
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper</artifactId>
<version>3.5.2</version>
</dependency>
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>3.7.5</version>
</dependency>
<!--整合-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.5</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<!-- mvc json -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.10.2</version>
</dependency>
<!--swagger2-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.7.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.7.0</version>
</dependency>
<!--文件上传-->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
<!--jsp相关-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.10</version>
</dependency>
</dependencies>
3.2.2 项目结构
3.2.3 实现
1. 编写UserController :业务处理入口
package com.czxy.mvc.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* @Author: 小新
* @Date: 2021-12-07 16:48
*/
@Controller //将当前类添加到Spring容器中
@RequestMapping("/user") //给当前类中所有功能,设置一个路径访问前缀
public class UserController {
/**
* 最终访问路径 / user /selectAll.action
* @return
*/
@RequestMapping("/selectAll")//当前功能方法,设置一个访问路径
public String selectAll(){
return "/pages/list.jsp";
}
}
2.编写jsp展示页面
- list.jsp:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
列表
</body>
</html>
3.拷贝核心配置类MvcConfiguration:取代spring.xml
package com.czxy.mvc.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.format.FormatterRegistry;
import org.springframework.format.datetime.DateFormatter;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.Date;
/**
* @Author: 小新
* @Date: 2021-12-07 16:48
*/
@Configuration
@ComponentScan(basePackages = {"com.czxy.mvc.controller","com.czxy.mvc.resolver"})
public class MvcConfiguration {
}
4.拷贝核心配置文件WebInitializer:取代web.xml
package com.czxy.mvc.config;
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.filter.CharacterEncodingFilter;
import org.springframework.web.servlet.DispatcherServlet;
import javax.servlet.FilterRegistration;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;
/**
* @Author: 小新
* @Date: 2021-12-07 16:49
*/
public class WebInitializer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
//1 配置spring工厂
AnnotationConfigWebApplicationContext application = new AnnotationConfigWebApplicationContext();
// 注册所有的配置类
application.register(MvcConfiguration.class);
//2 post中文乱码
FilterRegistration.Dynamic encodingFilter = servletContext.addFilter("encoding", new CharacterEncodingFilter("UTF-8"));
encodingFilter.addMappingForUrlPatterns(null, true, "/*");
//3 核心控制器
ServletRegistration.Dynamic mvcServlet = servletContext.addServlet("springmvc", new DispatcherServlet(application));
mvcServlet.addMapping("*.action");
mvcServlet.setLoadOnStartup(2); //tomcat启动时,执行servlet的初始化方法
}
}
5.编写首页
- index.jsp:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<a href="${pageContext.request.contextPath}/user/selectAll.action">入门案例</a><br/>
四、Spring MVC 基础
4.1 窄化请求路径
- @RequestMapping 放在类名上边 : 设置类请求路径。
- @RequestMapping 放在方法名上边 : 设置方法请求路径。
- 需求:使用/demo01/index.action 访问首页
- 编写controller:
package com.czxy.mvc.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
/**
* @Author: 小新
* @Date: 2021-12-07 17:03
*/
@Controller
@RequestMapping("/demo01")
public class Demo01IndexController {
@RequestMapping({"/index"})
public String index(){
return "/index.jsp";
}
}
- 访问路径:
<a href="${pageContext.request.contextPath}/demo01/index.action">基础-窄化</a><br/>
4.2 多路径映射
- @RequestMapping 允许配置多个访问路径
- 编写 controller:
package com.czxy.mvc.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
/**
* @Author: 小新
* @Date: 2021-12-07 17:03
*/
@Controller
@RequestMapping("/demo01")
public class Demo01IndexController {
/**
* 多路径
* @return
*/
@RequestMapping({"/index","/index2"})
public String index(){
return "/index.jsp";
}
- 访问路径:
<a href="${pageContext.request.contextPath}/demo01/index2.action">基础-多路径</a><br/>
4.3 请求方法限定
- @RequestMapping 默认支持各种请求方式的访问,可以通过 method属性限制不同的请求方式。
注解 | 描述 |
---|---|
@RequestMapping(method = RequestMethod.GET) | 只有get请求方式可访问 |
@RequestMapping(method = RequestMethod.POST) | 只有post请求方式可访问 |
@RequestMapping(method={RequestMethod.GET,RequestMethod.POST}) | get和post都可访问 |
- 需求: 使用不同请求方式访问首页
- GET请求抛出异常
- POST允许访问
- 编写 controller :
/**
* get请求抛异常 RequestMethod.GET,
* post允许访问 RequestMethod.POST
* @return
*/
@RequestMapping(value = "/post",method={RequestMethod.GET,RequestMethod.POST})
public String get(){
return "/index.jsp";
}
- 访问路径:
<a href="${pageContext.request.contextPath}/demo01/post.action">基础-get请求访问</a><br/>
<form action="${pageContext.request.contextPath}/demo01/post.action" method="post">
<input type="submit" value="基础-post请求访问"/>
</form><br/>
4.4 参数绑定
4.4.1 简单数据类型
- 在控制器的方法中,只要有对应的参数名,spring mvc就可以自动完成参数封装
1.基本操作:
- 需求:访问
/demo02/findById.action?id=10
,设置参数id - controller:
package com.czxy.mvc.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* @Author: 小新
* @Date: 2021-12-07 17:03
*/
@Controller
@RequestMapping("/demo02")
public class Demo02ParamController {
/**
* 限定:参数名和变量名必须保持一致。
* @param id
* @return
*/
@RequestMapping({"/findById"})
public String findById(String id){
System.out.println("id: " + id);
return "/index.jsp";
}
}
- 访问路径
<a href="${pageContext.request.contextPath}/demo02/findById.action?id=10">参数-简单数据</a> <br/>
2.自定义变量名:@RequestParam
- 如果请求参数名和方法参数名不一致时,需要使用@RequestParam标记对应关系。
- controller:
package com.czxy.mvc.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
/**
* @Author: 小新
* @Date: 2021-12-07 17:03
*/
@Controller
@RequestMapping("/demo02")
public class Demo02ParamController {
@RequestMapping({"/findById2"})
public String findById2(@RequestParam("id") String name){
System.out.println("name: " + name);
return "/index.jsp";
}
}
- 访问路径:
<a href="${pageContext.request.contextPath}/demo02/findById2.action?id=10">参数-简单数据name-自定义</a> <br/>
4.4.2.绑定POJO类型
- 当提交一组数据时,通常我们会提供一个JavaBean用于数据的封装。
- User 类:
package com.czxy.mvc.domain;
import org.springframework.format.annotation.DateTimeFormat;
import java.util.Date;
import java.util.List;
/**
* @Author: 小新
* @Date: 2021-12-07 17:25
*/
public class User {
private Integer id;
private String username;
private String password;
private List<String> hobbies;
private Date birthday;
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
", hobbies=" + hobbies +
", birthday=" + birthday.toLocaleString()+
'}';
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public List<String> getHobbies() {
return hobbies;
}
public void setHobbies(List<String> hobbies) {
this.hobbies = hobbies;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
}
- controller :
package com.czxy.mvc.controller;
import com.czxy.mvc.domain.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* @Author: 小新
* @Date: 2021-12-07 17:03
*/
@Controller
@RequestMapping("/demo02")
public class Demo02ParamController {
/**
*路径多参数
*需求:请求多个参数`/demo02/add.action?id=10&username=jack&password=1234`
* @param user
* @return
*/
@RequestMapping({"/add"})
public String add(User user){
System.out.println(user);
return "/index.jsp";
}
}
- 访问路径:
<a href="${pageContext.request.contextPath}/demo02/add.action?id=10&username=jack&password=1234">参数-POJO-路径</a> <br/>
<!--表单参数-->
<form action="${pageContext.request.contextPath}/demo02/add.action" method="post">
<input type="text" name="id" placeholder="id"/> <br/>
<input type="text" name="username" placeholder="用户名"/> <br/>
<input type="password" name="password" placeholder="密码"/> <br/>
<input type="submit" value="参数-POJO-表单"/>
</form>
4.4.3复杂POJO
- Order:
package com.czxy.mvc.domain;
/**
* @Author: 小新
* @Date: 2021-12-07 17:32
*/
public class Order {
private Double price;
private User user ;
@Override
public String toString() {
return "Order{" +
"price=" + price +
", user=" + user +
'}';
}
public Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
- controller:
package com.czxy.mvc.controller;
import com.czxy.mvc.domain.Order;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* @Author: 小新
* @Date: 2021-12-07 17:03
*/
@Controller
@RequestMapping("/demo02")
public class Demo02ParamController {
/**
* 复杂POJO(包装(POJO))
* @param order
* @return
*/
@RequestMapping({"/addOrder"})
public String addOrder(Order order){
System.out.println(order);
return "/index.jsp";
}
}
- 访问路径:
<!--提交订单以及用户数据-->
<form action="${pageContext.request.contextPath}/demo02/addOrder.action" method="post">
<input type="text" name="price" placeholder="价格" /> <br/>
<input type="text" name="user.id" placeholder="用户id" /> <br/>
<input type="text" name="user.username" placeholder="用户名" /> <br/>
<input type="password" name="user.password" placeholder="密码"/> <br/>
<input type="submit" value="复杂-POJO-表单"/> <br/>
</form>
4.4.4 绑定数组/集合
- controller:
package com.czxy.mvc.controller;
import com.czxy.mvc.domain.Order;
import com.czxy.mvc.domain.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
/**
* @Author: 小新
* @Date: 2021-12-07 17:03
*/
@Controller
@RequestMapping("/demo02")
public class Demo02ParamController {
/**
* 绑定数组/集合
* @param user
* @return
*/
@RequestMapping({"/add"})
public String add(User user){
System.out.println(user);
return "/index.jsp";
}
}
- 访问路径:
<!--绑定数组/集合-->
<form action="${pageContext.request.contextPath}/demo02/add.action" method="post">
<input type="text" name="id" placeholder="id"/> <br/>
<input type="text" name="username" placeholder="用户名"/> <br/>
<input type="password" name="password" placeholder="密码"/> <br/>
<input type="checkbox" name="hobbies" value="抽烟" />抽烟
<input type="checkbox" name="hobbies" value="喝酒" />喝酒
<input type="checkbox" name="hobbies" value="烫头" />烫头 <br/>
<input type="text" name="birthday" value="2021-12-09"/><br/>
<input type="submit" value="参数-POJO-表单-绑定数组(集合)"/>
</form>
自定义参数绑定: 日期
- Spring MVC 默认支持的日期格式
yyyy/MM/dd
方式一:全局配置
- MvcConfiguration 配置类:
package com.czxy.mvc.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.format.FormatterRegistry;
import org.springframework.format.datetime.DateFormatter;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.Date;
/**
* @Author: 小新
* @Date: 2021-12-07 16:48
*/
@Configuration
@ComponentScan(basePackages = {"com.czxy.mvc.controller"})
@EnableWebMvc
public class MvcConfiguration implements WebMvcConfigurer {
/**
* 设置日期转换
* @param registry
*/
public void addFormatters(FormatterRegistry registry) {
DateFormatter dateFormatter = new DateFormatter();
dateFormatter.setPattern("yyyy-MM-dd");
registry.addFormatterForFieldType(Date.class,dateFormatter);
}
}
方式二:单独设置
- User 类
//方式2:单独设置
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date birthday;
4.5 视图解析器
4.5.1 什么是视图解析器
- Spring MVC 中的视图解析器的主要作用就是将
逻辑视图
转换成用户可以看到的物理视图
- 返回jsp的具体位置 如:
return "/pages/list.jsp";
我们称为物理视图
。 - 在开发中,我们发现
物理视图
都有相同的前缀和后缀。所以将相同的前缀和后缀抽取到视图解析器中。
4.5.2 配置MvcConfiguration
package com.czxy.mvc.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.format.FormatterRegistry;
import org.springframework.format.datetime.DateFormatter;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.Date;
/**
* @Author: 小新
* @Date: 2021-12-07 16:48
*/
@Configuration
@ComponentScan(basePackages = {"com.czxy.mvc.controller","com.czxy.mvc.resolver"})
@EnableWebMvc
public class MvcConfiguration implements WebMvcConfigurer {
/**
* 设置日期转换
* @param registry
*/
public void addFormatters(FormatterRegistry registry) {
DateFormatter dateFormatter = new DateFormatter();
dateFormatter.setPattern("yyyy-MM-dd");
registry.addFormatterForFieldType(Date.class,dateFormatter);
}
/**
* 配置视图解析器
* @param registry
*/
public void configureViewResolvers(ViewResolverRegistry registry) {
//前缀 : pages 后缀 : .jsp
registry.jsp("/pages/",".jsp");
}
}
4.5.3使用controller
package com.czxy.mvc.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* @Author: 小新
* @Date: 2021-12-07 16:48
*/
@Controller //将当前类添加到Spring容器中
@RequestMapping("/user") //给当前类中所有功能,设置一个路径访问前缀
public class UserController {
/**
* 返回逻辑视图名
* @return
*
@RequestMapping("/selectAll2")//当前功能方法,设置一个访问路径
public String selectAll2(){
return "list";
}
- 访问路径:
<a href="${pageContext.request.contextPath}/user/selectAll2.action">视图解析器</a><br/>
4.5.4 绕过视图解析器
- 声明式
请求转发
或重定向
, 都可以绕过视图解析器。 - controller:
package com.czxy.mvc.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* @Author: 小新
* @Date: 2021-12-07 16:48
*/
@Controller //将当前类添加到Spring容器中
@RequestMapping("/user") //给当前类中所有功能,设置一个路径访问前缀
public class UserController {
/**
* 绕过视图解析器
* redirect & forward 都可以绕过视图解析器
* @return
*/
@RequestMapping("/selectAll2")//当前功能方法,设置一个访问路径
public String selectAll2(){
return "forward:/pages/list.jsp";
}
}
- 访问路径:
<a href="${pageContext.request.contextPath}/user/selectAll2.action">绕过视图解析器</a><br/>
4.6 方法返回值
4.6.1 默认返回值:ModelAndView
- 编写controller:
package com.czxy.mvc.controller;
import com.czxy.mvc.domain.Person;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
/**
* @Author: 小新
* @Date: 2021-12-07 18:15
*/
@Controller
@RequestMapping("/demo03")
public class Demo03BookeController {
/**
* 默认返回值 ModelAndView
* @return
*/
@RequestMapping("/list")
public ModelAndView list(){
//1、创建对象
ModelAndView modelAndView = new ModelAndView();
//2、设置视图
modelAndView.setViewName("book");
//3、设置模型数据
modelAndView.addObject("username","jack");
return modelAndView;
}
}
- 编写视图页面
book.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
${username}
</body>
</html>
- 访问路径:
<a href="${pageContext.request.contextPath}/demo03/list.action">返回值-ModelAndView</a><br/>
4.6.2 返回字符串
1)请求转发(默认)
- 编写controller
package com.czxy.mvc.controller;
import com.czxy.mvc.domain.Person;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
/**
* @Author: 小新
* @Date: 2021-12-07 18:15
*/
@Controller
@RequestMapping("/demo03")
public class Demo03BookeController {
/**
* 默认 请求转发
* @param model
* @return
*/
@RequestMapping("/list2")
public String list2(Model model){
//设置数据
model.addAttribute("username","jack2");
return "book";
}
}
- 访问路径:
<a href="${pageContext.request.contextPath}/demo03/list2.action">返回值-请求转发(默认)</a><br/>
2)重定向
- 编写 controller
package com.czxy.mvc.controller;
import com.czxy.mvc.domain.Person;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
/**
* @Author: 小新
* @Date: 2021-12-07 18:15
*/
@Controller
@RequestMapping("/demo03")
public class Demo03BookeController {
/**
* 重定向
* @return
*/
@RequestMapping("/list4")
public String list4(Model model){
model.addAttribute("username","jack3");
return "redirect:/pages/book.jsp";
}
}
- 访问路径:
<a href="${pageContext.request.contextPath}/demo03/list4.action">返回值-重定向</a><br/>
4.6.3 返回值 void
1) 返回void
- 需求:controller 返回 void
- 编写 controller:
package com.czxy.mvc.controller;
import com.czxy.mvc.domain.Person;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
/**
* @Author: 小新
* @Date: 2021-12-07 18:15
*/
@Controller
@RequestMapping("/demo03")
public class Demo03BookeController {
* 返回值void
* 根据访问路径显示对应的视图路径,该视图不存在,所以提示404。
*/
@RequestMapping("/void1")
public void void1(){
System.out.println("void1 执行了!");
}
}
- 访问路径:
<a href="${pageContext.request.contextPath}/demo03/void1.action">返回值-void1</a><br/>
2)请求调度器
- 需求:使用servlet 请求调度器完成
请求转发
/请求包含
操作。 - 编写 controller :
package com.czxy.mvc.controller;
import com.czxy.mvc.domain.Person;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
/**
* @Author: 小新
* @Date: 2021-12-07 18:15
*/
@Controller
@RequestMapping("/demo03")
public class Demo03BookeController {
//方式一: 获得request对象
//@Resource
//private HttpServletRequest request;
/**
* 请求调度器
* 使用servlet 请求调度器完成`请求转发`/`请求包含`操作。
* @param response
* @param request
* @throws ServletException
* @throws IOException
*/
@RequestMapping("/void2")
public void void2(/*方式二:*/HttpServletResponse response , HttpServletRequest request) throws Exception {
//设置数据
request.setAttribute("username","void2");
//请求转发
request.getRequestDispatcher("/pages/book.jsp").forward(request,response);
//请求包含
//request.getRequestDispatcher("/pages/book.jsp").include(request,response);
}
}
- 访问路径:
<a href="${pageContext.request.contextPath}/demo03/void2.action">请求调度器-void2</a><br/>
3)response 响应数据
- 编写 controller
package com.czxy.mvc.controller;
import com.czxy.mvc.domain.Person;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
/**
* @Author: 小新
* @Date: 2021-12-07 18:15
*/
@Controller
@RequestMapping("/demo03")
public class Demo03BookeController {
/**
* response 响应数据
* @param request
* @param response
* @throws IOException
*/
@RequestMapping("/void3")
public void void3(HttpServletRequest request , HttpServletResponse response) throws IOException {
response.setContentType("text/html;charset=UTF-8");//解决乱码问题
response.getWriter().print("<font color='pink' size='28px'>void3</font>");
}
}
- 访问路径:
<a href="${pageContext.request.contextPath}/demo03/void3.action">response 响应数据-void3</a><br/>
4)响应JSON
- 编写 controller:
package com.czxy.mvc.controller;
import com.czxy.mvc.domain.Person;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
/**
* @Author: 小新
* @Date: 2021-12-07 18:15
*/
@Controller
@RequestMapping("/demo03")
public class Demo03BookeController {
/**
* 响应JSON
*/
@RequestMapping("/void4")
@ResponseBody
public void void4(){
System.out.println("void4");
}
}
- 访问路径:
<a href="${pageContext.request.contextPath}/demo03/void4.action">响应JSON 响应数据-void4</a><br/>
4.7 异常处理器
4.7.1 什么是异常处理器
-
对控制器抛出的异常进行拦截,并做出友好处理的程序。
-
在spring mvc使用过程中,如果程序出现异常,默认情况将抛向浏览器。
-
spring mvc 需要使用异常处理器对异常进行处理。
4.7.2 异常处理器执行流程
4.7.3 基本功能
1)需求
- 访问
/demo04/item.action?id=1
- id =1 系统异常
- id =2 自定义异常
- id =3 正常
2) 实现
- 运行时异常:RuntimeException 【推荐】,并重新构造方法。
- 编译时异常:Exception
- 步骤一:编写自定义异常
package com.czxy.mvc.exception;
/**
* @Author: 小新
* @Date: 2021-12-09 16:38
*/
public class CustomException extends RuntimeException {
public CustomException() {
super();
}
public CustomException(String message) {
super(message);
}
public CustomException(String message, Throwable cause) {
super(message, cause);
}
public CustomException(Throwable cause) {
super(cause);
}
protected CustomException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}
- 步骤二:编写Controller,一个参数,控制逻辑代码(正常、系统异常、自定义异常)
package com.czxy.mvc.controller;
import com.czxy.mvc.exception.CustomException;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* @Author: 小新
* @Date: 2021-12-09 16:39
*/
@Controller
@RequestMapping("/demo04")
public class Demo4ItemController {
/**
* 异常处理器
* id =1 系统异常
* id =2 自定义异常
* id =3 正常
* 一个参数,控制逻辑代码(正常、系统异常、自定义异常)
* @param id
* @return
*/
@RequestMapping("/item")
public String item(Integer id){
if (id == 1){
//系统异常
int i = 1 / 0 ;
}else if (id == 2){
//自定义异常
CustomException exception = new CustomException("自定义异常");
throw exception;
}
//正常 id == 3
return "forward:/index.jsp";
}
}
- 访问路径:
<a href="${pageContext.request.contextPath}/demo04/item.action?id=1">异常处理 id =1 系统异常</a> <br/>
<a href="${pageContext.request.contextPath}/demo04/item.action?id=2">异常处理 id =2 自定义异常 </a> <br/>
<a href="${pageContext.request.contextPath}/demo04/item.action?id=3">异常处理正常</a> <br/>
4.7.4 异常处理器:
1)方式一:实现接口
- 编写
HandlerExceptionResolver
接口的实现类 - 并根据参数
Exception e
对捕获的异常进行处理:自定义异常、系统异常。
package com.czxy.mvc.resolver;
import com.czxy.mvc.exception.CustomException;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @Author: 小新
* @Date: 2021-12-10 11:04
*/
//@Component
public class CustomExceptionResolver implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {
//1、统一异常
ModelAndView modelAndView = new ModelAndView();
if (e instanceof CustomException){
//自定义异常
CustomException customException = (CustomException) e;
modelAndView.addObject("error",customException.getMessage());
}else{
//系统异常
modelAndView.addObject("sorry! 系统失联了~");
}
modelAndView.setViewName("forward:/error.jsp");
return modelAndView;
}
}
2)方式二:通知类
- 编写 GlobalExceptionResolver 类,用于处理所有异常
package com.czxy.mvc.resolver;
import com.czxy.mvc.exception.CustomException;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
/**
* @Author: 小新
* @Date: 2021-12-10 11:13
*/
@ControllerAdvice
public class GlobalExceptionResolver {
/**
* 自定义异常处理器
* @param ce
* @param model
* @return
*/
@ExceptionHandler(CustomException.class)
public String custom(CustomException ce , Model model){
model.addAttribute("error",ce.getMessage());
return "forward:/error.jsp";
}
/**
* 其他异常处理器
* @param e
* @param model
* @return
*/
@ExceptionHandler(Exception.class)
public String other(Exception e , Model model){
model.addAttribute("系统繁忙,请稍后再试哦~");
return "forward:/error.jsp";
}
}
3) 错误信息展示
- error.jsp:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>错误页面</title>
</head>
<body>
${error}
</body>
</html>