SpringMvc初识
1、概述
- Spring MVC 是 Spring 提供的一个基于 MVC 设计模式的轻量级 Web 开发框架,本质上相当于 Servlet。
- 由于 Spring MVC 本身就是 Spring 框架的一部分,所有与 Spring 框架是无缝集成。是当今业界最主流的 Web 开发框架。
2、SpringMvc入门
使用的是maven项目
2.0、导入依赖
<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>
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper</artifactId>
<version>4.1.5</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>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>
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.22</version>
<scope>provided</scope>
</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>
添加为web项目
2.1、基于xml
2.1.1、步骤
- 编写controller
- 编写jsp:显示内容
- 编写配置文件:用于扫描controller路径
- 在web.xml配置前端控制器:加载配置文件
2.1.2、实现
项目结构
-
controller
package com.czxy.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; @Controller //添加到spring容器 @RequestMapping("/user") //设置类的映射路径 public class UserController { @RequestMapping("/first") //设置方法的映射路径 public String first(){ return "/pages/first.jsp"; } }
-
index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <a href="${pageContext.request.contextPath}/user/first.action">点我</a> </body> </html>
-
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.controller"/> </beans>
-
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>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>
运行结果
2.2、基于注解
-
在pom.xml里面进行修改
<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>
-
创建配置类(相当于上面的springmvc.xml)
@Configuration @ComponentScan("com.czxy.controller") //配置 public class MvcConfiguration { }
-
创建核心配置类:(取代web.xml)
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的初始化方法 } }
运行结果与xml一致
3、Spring基础
3.1、@RequestMapping (请求路径)
-
@RequestMapping 注解可用于类或方法上
-
用于类上,表示请求前缀。
-
用于方法上,设置方法的请求路径
-
完整请求:前缀+请求路径
-
@RequestMapping 允许配置多个访问路径
@requestMapping的常用属性
属性 | 描述 |
---|---|
value属性 | 默认属性,类的请求路径,支持通配符匹配,并且可以配置多个路径 |
path属性 | 和value一样,支持通配符匹配,并且可以配置多个路径 |
name属性 | 相当于方法的注解 |
method属性 | 表示方法支持什么请求 不配置默认支持所有的请求方式 |
params属性 | 用于指定请求中的参数 如@ReuqestMapping(value="/find",params=“uid”) 在请求里面必须有uid这个参数才能访问 也可以规定参数的值 如@ReuqestMapping(value="/find",params=“uid=1”) 在请求里面必须有uid这个参数并且值为1才能访问 |
3.1.1、请求方法的限定
-
@RequestMapping 默认支持所有的请求方式
-
可以通过method属性来限制不同的请求
-
可以设置多个请求方式
-
常见的method参数
注解 描述 @RequestMapping(method=RequestMethod.GET) 只有get请求可访问 @RequestMapping(method=RequestMethod.POST) 只有POST请求可访问 @RequestMapping(method={RequestMethod.POST,RequestMehtod.GET}) get和post都可以访问
3.2、请求参数
3.2.1、基本数据类型的绑定
- 在控制器的方法中,只要有对应的参数名,spring mvc就可以自动完成参数封装
- 支持基本数据类型
实例
访问路径
<a href="${pageContext.request.contextPath}/user/id.action?id=10">点我</a>
controller
@Controller //添加到spring容器
@RequestMapping("/user") //设置类的映射路径
public class UserController {
@RequestMapping("/id")
public String findId(String id){
System.out.println("id = "+ id);
return "/index.jsp";
}
}
运行结果
自定义变量名:@RequestParam
- 如果访问路径的参数与方法的形参不匹配可以使用@RequestParam进行赋值
- @RequestParam需要与访问路径的参数名一致
访问路径
<a href="${pageContext.request.contextPath}/user/name.action?name=zhangsan">名称</a>
controller
@Controller //添加到spring容器
@RequestMapping("/user") //设置类的映射路径
public class UserController {
@RequestMapping("/name")
public String findName(@RequestParam("name") String username){
System.out.println("username = "+ username);
return "/index.jsp";
}
}
运行结果
3.2.2、pojo类型的绑定
- 当提交一组数据时,通常我们会提供一个JavaBean用于数据的封装。
- 需要注意,Bean 的属性名称必须与请求参数名称相同
实例
JavaBean
public class User {
private String id;
private String username;
private String password;
//get、set、构造方法、toString自行创建
}
请求路径
<form action="${pageContext.request.contextPath}/user/findUser.action" method="post">
id:<input type="text" name="id" value="u001"><br>
昵称:<input type="text" name="username" value="anc"><br>
密码:<input type="text" name="password" value="123"><br>
<input type="submit">
</form>
controller
@Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping("/findUser")
public String findUser(User user){
System.out.println(user);
return "/index.jsp";
}
}
运行结果
中文乱码
在web启动配置类中,配置字符编码过滤器CharacterEncodingFilter
//2 post中文乱码
FilterRegistration.Dynamic encodingFilter = servletContext.addFilter("encoding", new CharacterEncodingFilter("UTF-8"));
encodingFilter.addMappingForUrlPatterns(null, true, "/*");
3.2.3、复杂POJO
- 在开发中,除了简单POJO类型外,还有复杂POJO(包装POJO)。
- 在一个类里面包含另外一个类
实例
JavaBean
public class Order {
private Double price;
private User user;
//get、set、构造方法、toString自行创建
}
请求路径
<form action="${pageContext.request.contextPath}/user/order.action" method="post">
价格:<input type="text" name="price" value="190.0"><br>
id:<input type="text" name="user.id" value="u001"><br>
昵称:<input type="text" name="user.username" value="anc"><br>
密码:<input type="text" name="user.password" value="123"><br>
<input type="submit">
</form>
controller
@Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping("/order")
public String findOrder(Order order){
System.out.println(order);
return "/index.jsp";
}
}
运行结果
3.2.4、数组、集合类型
JavaBean
public class User {
private String id;
private String username;
private String password;
private String[] hobbies;
//get、set、构造方法、toString自行创建
}
访问路径
<form action="${pageContext.request.contextPath}/user/findUser.action" method="post">
id:<input type="text" name="id" value="u001"><br>
昵称:<input type="text" name="username" value="anc"><br>
密码:<input type="text" name="password" value="123"><br>
兴趣爱好:<input type="checkbox" name="hobbies" value="吃饭" checked="checked">吃饭
<input type="checkbox" name="hobbies" value="睡觉" checked="checked">睡觉
<input type="checkbox" name="hobbies" value="打游戏">打游戏 <br>
<input type="submit">
</form>
controller
@Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping("/findUser")
public String findUser(User user){
System.out.println(user);
return "/index.jsp";
}
}
运行结果
3.2.5、自定义参数绑定:日期
-
SpringMvc 默认支持的日期格式位
yyyy-MM-dd
-
方式1:单独配置
-
给需要的属性单独配置
-
配置类需要添加 @EnableWebMvc,开启自定义配置。
@Configuration @ComponentScan("com.czxy.controller") @EnableWebMvc public class MvcConfiguration { }
-
在目标类的属性上加上@DateTimeFormat ,并配置日期格式
public class User { private String id; private String username; private String password; private String[] hobbies; @DateTimeFormat(pattern = "yyyy-MM-dd") private Date birthday; }
-
缺点是如果有多个日期类型,需要一个一个去配置
-
-
方式2:全局配置
-
修改MvcConfiguration 配置类
-
实现 WebMvcConfigurer 接口,已经有默认方法,所以不需要实现任何方法。
WebMvcConfigurer配置类是Spring内部的一种配置方式,针对框架个性化定制
-
添加 @EnableWebMvc,开启自定义配置。
-
重写addFormatters方法,注册自定义日期格式
@Configuration @ComponentScan("com.czxy.controller") @EnableWebMvc public class MvcConfiguration implements WebMvcConfigurer { @Override public void addFormatters(FormatterRegistry registry) { //org.springframework 包下的 DateFormatter dateFormatter = new DateFormatter(); //默认格式位yyyy-MM-dd registry.addFormatterForFieldType(Date.class,dateFormatter); } }
DateFormatter的默认格式为
也可以在构造中写自定义的转换格式
-
-
3.3、视图解析器
3.3.1、什么是视图解析器
- 视图解析器的作用就是将
逻辑视图
转换为用户可以看到的物理视图 - 在开发中,大部分物理视图都有相同的前缀和后缀。所以将相同的前缀和后缀抽到视图解析器中。
3.3.2、配置WebMvcConfigurer
- 实现 WebMvcConfigurer 接口,已经有默认方法,所以不需要实现任何方法。
- 添加 @EnableWebMvc,开启个性定制。
- 覆盖
configureViewResolvers()
配置视图解析器
配置类
@Configuration
@ComponentScan("com.czxy.controller")
@EnableWebMvc
public class MvcConfiguration implements WebMvcConfigurer {
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
registry.jsp("/pages/",".jsp");
}
}
之前的方法返回值
@RequestMapping("/first")
public String first(){
return "/pages/first.jsp";
}
现在的方法返回值
@RequestMapping("/first")
public String first(){
return "first";
}
3.3.3、绕过视图解析器
-
声明
请求转发
或重定向
,都可以绕过视图解析器如
@RequestMapping("/first") public String first(){ return "redirect:/pages/first.jsp"; }
3.4、方法返回值
3.4.1、ModelAndView
-
ModelAndView可以返回视图名称和数据
-
方法
@RequestMapping("/list") public ModelAndView list(){ ModelAndView modelAndView = new ModelAndView(); modelAndView.addObject("username","zhangsan"); modelAndView.set ViewName("list"); return modelAndView; }
访问路径
<a href="${pageContext.request.contextPath}/user/list.action">点我</a>
3.4.2、返回字符串
-
默认使用请求转发
-
请求转发
return "forward:物理视图"; //jsp路径
-
重定向
return "redirect:物理视图"; //jsp路径
3.5、异常处理器
3.5.1、什么是异常处理器
- 在spring mvc使用过程中,如果出现异常,会将异常抛给浏览器
- SpringMvc可以使用异常处理器对异常进行处理
- 异常处理器
- 对控制器抛出的异常进行拦截,并作出处理的程序
3.5.2、实现方式
-
方式1:实现类,编写实现类实现
HandlerExceptionResolver
接口 -
方式2:增强类
- 使用@ControllerAdvice对Controller进行增强
- 使用@ExceptionHandler用于捕获控制器里面的异常,并进行处理
方式1:
自定义异常
public class MyException extends RuntimeException {
public MyException() {
super();
}
public MyException(String message) {
super(message);
}
public MyException(String message, Throwable cause) {
super(message, cause);
}
public MyException(Throwable cause) {
super(cause);
}
protected MyException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}
异常处理器
- 需要将@ComponentScan扫描的路径更改可以扫描到处理类
@Component
public class ExceptionHandler implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
ModelAndView modelAndView = new ModelAndView();
if (ex instanceof MyException){
MyException exception = (MyException) ex;
modelAndView.addObject("msg",exception.getMessage());
}else {
modelAndView.addObject("msg","系统异常");
}
modelAndView.setViewName("forward:/error.jsp");
return modelAndView;
}
}
controller
@Controller //添加到spring容器
@RequestMapping("/user") //设置类的映射路径
public class UserController {
@RequestMapping("/ex")
public String ex(Integer id){
if (id==0){
int i =1/0;
}else if (id==1){
throw new MyException("自定义异常");
}
return "forward:/index.jsp";
}
}
访问路径
<a href="${pageContext.request.contextPath}/user/ex.action?id=0">点我</a>
error.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
${msg}
</body>
</html>
方式2:
-
编写 GlobalExceptionResolver 类,用于处理所有异常
-
编写 custom() 方法用于处理自定义异常
-
编写 other()方法用于处理,除自定义异常之外的其他异常。
-
@ControllerAdvice
public class GlobalExceptionResolver {
@ExceptionHandler(MyException.class)
public String custom(MyException e, Model model){
model.addAttribute("msg",e.getMessage());
return "forward:/error.jsp";
}
@ExceptionHandler(Exception.class)
public String other(Exception e,Model model){
model.addAttribute("msg","系统错误");
return "forward:/error.jsp";
}
}