笔记输出来源:拉勾教育Java就业急训营
如有侵权,私信立删
修改时间:2020年2月24日
作者:pp_x
邮箱:[email protected]
SpringMVC简介
MVC模式
- MVC是软件工程中的一种软件架构模式,它是一种分离业务逻辑与显示界面的开发思想
- M(model)模型:处理业务逻辑,封装实体
- V(view) 视图:展示内容
- C(controller)控制器:负责调度分发(1.接收请求、2.调用模型、3.转发到视图)
SpringMVC概述
- SpringMVC 是一种基于 Java 的实现 MVC 设计模式的轻量级 Web 框架,属于
SpringFrameWork
的后续产品,已经融合在 Spring Web Flow 中
- SpringMVC的框架就是封装了原来Servlet中的共有行为;例如:参数封装,视图转发
Spring快速入门
步骤分析
- 创建web项目,导入SpringMVC相关坐标
- 配置SpringMVC前端控制器
DispathcerServlet
- 编写
Controller
类和视图页面 - 使用注解配置Controller类中业务方法的映射地址
- 配置SpringMVC核心文件
spring-mvc.xml
代码实现
- pom.xml
<packaging>war</packaging>
<dependencies>
<!--springMVC坐标-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<!--servlet坐标-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<!--jsp坐标-->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.2</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.8</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.8</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.3</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>compile</scope>
</dependency>
</dependencies>
- web.xml(需要配置DispatcherServlet初始化参数,用来加载spring-mvc.xml并且使应用启动时就完成servlet实例化操作)
<!-- Springmvc的前端控制器:DispatcherServlet -->
<servlet>
<servlet-name>DispatcherServlet</servlet-name>
<!--原本servlet需要请求来到以后实例化-->
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--设置初始化参数-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-mvc.xml</param-value>
</init-param>
<!--在应用启动的时候就完成servlet的实例化及初始化操作-->
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>DispatcherServlet</servlet-name>
<!-- /会匹配到所有不带后缀的访问路径 例如 /a.jsp -->
<!--/*会匹配到所有的访问路径-->
<url-pattern>/</url-pattern>
</servlet-mapping>
- 控制层
@Controller//存在springmvc的ioc容器中
@RequestMapping("/user")//一级访问目录
public class UserController {
//http://localhost:8080/springmvc_quickstart/user/quick
/*
* path:作用等同于value 同样是设置方法映射的地址
* method:用来限定请求的方式 RequestMethod:post 只能以post请求方式访问
* */
@RequestMapping(value = "/quick",method = RequestMethod.GET)//二级访问目录
public String quick(){
//业务逻辑
System.out.println("springmvc入门");
//视图跳转 逻辑视图名
return "success";//采用请求转发实现跳转 地址栏不会发生改变
}
}
- spring-mvc.xml
<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">
<!--注解扫描-->
<context:component-scan base-package="com.lagou.controller"/>
<!--处理器映射器 - 处理器适配器 进行功能的增强 支持json的读写-->
<mvc:annotation-driven conversion-service="conversionService"/>
<!--视图解析器 ViewResolver-->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!--WEB-INF属于安全目录 不能通过地址栏输入路径访问 只能通过内部转发-->
<property name="prefix" value="/WEB-INF/page/"/>
<property name="suffix" value=".jsp"/>
</bean>
</beans>
web工程执行流程
SpringMVC组件概述
SpringMVC的执行流程
- 用户发送请求至前端控制器
DispatcherServlet
DispatcherServlet
收到请求调用HandlerMapping
处理器映射器- 处理器映射器找到具体的处理器(可以根据xml配置、注解进行查找),生成处理器对象及处理器拦截器(如果有则生成)一并返回给
DispatcherServlet
DispatcherServlet
调用HandlerAdapter
处理器适配器HandlerAdapter
经过适配调用具体的处理器(Controller,也叫后端控制器)Controller
执行完成返回ModelAndView
HandlerAdapter
将controller
执行结果ModelAndView
返回给DispatcherServlet
DispatcherServlet
将ModelAndView
传给ViewReslover
视图解析器ViewReslover
解析后返回具体ViewDispatcherServlet
根据View进行渲染视图(即将模型数据填充至视图中)DispatcherServlet
将渲染后的视图响应响应用户
SpringMVC组件解析
- 前端控制器:DispatcherServlet
- 用户请求到达前端控制器,它就相当于 MVC 模式中的 C,DispatcherServlet 是整个流程控制的中心,由它调用其它组件处理用户的请求,DispatcherServlet 的存在降低了组件之间的耦合性
- 处理器映射器:HandlerMapping
HandlerMapping
负责根据用户请求找到 Handler 即处理器,SpringMVC 提供了不同的映射器实现不同的映射方式,例如:配置文件方式,实现接口方式,注解方式等
- 处理器适配器:HandlerAdapter
- 通过
HandlerAdapter
对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理器进行执行
- 通过
- 处理器:Handler【开发者编写】
- 它就是我们开发中要编写的具体业务控制器。由
DispatcherServlet
把用户请求转发到 Handler。由Handler 对具体的用户请求进行处理
- 它就是我们开发中要编写的具体业务控制器。由
- 视图解析器:ViewResolver
View Resolver
负责将处理结果生成 View 视图,View Resolver
首先根据逻辑视图名解析成物理视图名,即具体的页面地址,再生成 View 视图对象,最后对 View 进行渲染将处理结果通过页面展示给用户
- 视图:View 【开发者编写】
- SpringMVC 框架提供了很多的 View 视图类型的支持,包括:
jstlView
、freemarkerView
、pdfView
等。最常用的视图就是 jsp。一般情况下需要通过页面标签或页面模版技术将模型数据通过页面展示给用户,需要由程序员根据业务需求开发具体的页面
- SpringMVC 框架提供了很多的 View 视图类型的支持,包括:
SpringMVC注解解析
@Controller
- SpringMVC基于Spring容器,所以在进行SpringMVC操作时,需要将Controller存储到Spring容器
中,如果使用@Controller注解标注的话,就需要使用注解扫描 - SpringMVC的配置文件扫描web层包
- Spring配置文件扫描其他包
<!--配置注解扫描-->
<context:component-scan base-package="com.lagou.controller"/>
@RequestMapping
- 作用:用于建立请求 URL 和处理请求方法之间的对应关系
- 位置:
- 类上:请求URL的第一级访问目录。此处不写的话,就相当于应用的根目录。写的话需要以/开头
- 方便我们使用URL可以按照模块化管理
- 方法上:请求URL的第二级访问目录,和一级目录组成一个完整的 URL 路径
- 类上:请求URL的第一级访问目录。此处不写的话,就相当于应用的根目录。写的话需要以/开头
- 属性:
value
:用于指定请求的URL。它和path属性的作用是一样的method
:用来限定请求的方式params
:用来限定请求参数的条件
总结
- SpringMVC的三大组件
- 处理器映射器:HandlerMapping
- 处理器适配器:HandlerAdapter
- 视图解析器:View Resolver
- 开发者编写
- 处理器:Handler
- 视图:View
SpringMVC的请求
请求参数类型介绍
- 格式:
name=value&name=value……
- SpringMVC可以接收如下类型的参数:
- 基本类型参数
- 对象类型参数
- 数组类型参数
- 集合类型参数
获取基本类型参数
- Controller中的业务方法的参数名称要与请求参数的name一致,参数值会自动映射匹配。并且能自动做类型转换;自动的类型转换是指从String向其他类型的转换
- jsp页面
<%-- a标签的请求方式是get请求 pageContext.request.contextPath动态的获取项目路径 tomcat8.5内部解决了get存在的中文乱码问题--%>
<a href="${pageContext.request.contextPath}/user/simpleParam?id=1&username=杰克">基本类型参数</a>
- 控制层
/*
* 获取基本类型参数 形参名要与传递过来的参数相同
* */
@RequestMapping("/simpleParam")
public String simpleParam(Integer id,String username){
System.out.println(id);
System.out.println(username);
return "success";
}
获取对象类型参数
- Controller中的业务方法参数的POJO属性名与请求参数的name一致,参数值会自动映射匹配
- jsp页面
<%--form表单 post请求 会产生中文乱码 需要设置过滤器--%>
<form action="${pageContext.request.contextPath}/user/pojoParam" method="post">
编号:<input type="text" name="id"><br>
用户名:<input type="text" name="name"><br>
<input type="submit" value="对象类型参数">
</form>
- 控制器
/*
* 获取对象类型参数
* */
@RequestMapping("/pojoParam")
public String pojoParam(User user){
System.out.println(user);
return "success";
}
过滤post的中文乱码
- 当post请求时,数据会出现乱码,我们可以设置一个过滤器来进行编码的过滤
- web.xml中设置全局过滤器
<!--中文乱码过滤器-->
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
获取数组类型参数
- Controller中的业务方法数组名称与请求参数的name一致,参数值会自动映射匹配
- jsp页面
<%--form表单 数组类型参数--%>
<form action="${pageContext.request.contextPath}/user/arrayParam"method="post">
<input type="checkbox" name="ids" value="1">1<br>
<input type="checkbox" name="ids" value="2">2<br>
<input type="checkbox" name="ids" value="3">3<br>
<input type="checkbox" name="ids" value="4">4<br>
<input type="submit" value="数组类型参数">
</form>
- 控制器
/*
* 获取数组类型参数
* */
@RequestMapping("/arrayParam")
public String pojoParam(Integer[] ids){
System.out.println(Arrays.toString(ids));
return "success";
}
获取集合(复杂)类型参数
- 获得集合参数时,要将集合参数包装到一个POJO中才可以
- jsp页面
<%--演示获取集合类型请求参数--%>
<form action="${pageContext.request.contextPath}/user/queryParam" method="post">
搜索关键字:
<input type="text" name="keyword"><br>
user对象:
<input type="text" name="user.id" placeholder="编号">
<input type="text" name="user.username" placeholder="姓名"><br>
list集合:
第一个元素:
<input type="text" name="userList[0].id" placeholder="编号">
<input type="text" name="userList[0].username" placeholder="姓名"><br>
第二个元素:
<input type="text" name="userList[1].id" placeholder="编号">
<input type="text" name="userList[1].username" placeholder="姓名"><br>
Map集合:
第一个元素:
<input type="text" name="userMap['u1'].id" placeholder="编号">
<input type="text" name="userMap['u1'].username" placeholder="姓名"><br>
第二个元素:
<input type="text" name="userMap['u2'].id" placeholder="编号">
<input type="text" name="userMap['u2'].username" placeholder="姓名"><br>
<input type="submit" value="复杂类型">
</form>
- QuertyVo实体类
public class QueryVo {
private String keyword;
private User user;
private List<User> userList;
private Map<String,User> userMap;
public String getKeyword() {
return keyword;
}
public void setKeyword(String keyword) {
this.keyword = keyword;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public List<User> getUserList() {
return userList;
}
public void setUserList(List<User> userList) {
this.userList = userList;
}
public Map<String, User> getUserMap() {
return userMap;
}
public void setUserMap(Map<String, User> userMap) {
this.userMap = userMap;
}
@Override
public String toString() {
return "QueryVo{" +
"keyword='" + keyword + '\'' +
", user=" + user +
", userList=" + userList +
", userMap=" + userMap +
'}';
}
}
- 控制器
/*
* 获取集合类型的请求参数
* */
@RequestMapping("/queryParam")
public String queryParam(QueryVo queryVo){
System.out.println(queryVo);
return "success";
}
自定义类型转换器
- SpringMVC 默认已经提供了一些常用的类型转换器;例如:客户端提交的字符串转换成int型进行参数设置,日期格式类型要求为:yyyy/MM/dd 不然的话会报错,对于特有的行为,SpringMVC提供了自定义类型转换器方便开发者自定义处理
- 自定义转换类
public class DateConverter implements Converter<String,Date> {
// s就是表单传递过来的请求参数 2012-12-12
@Override
public Date convert(String s) {
// 将日期字符串转换成日期对象,进行返回
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
Date date = null;
try {
date = simpleDateFormat.parse(s);
} catch (ParseException e) {
e.printStackTrace();
}
return date;
}
}
- spring-mvc.xml配置
<!--处理器映射器 - 处理器适配器 进行功能的增强 支持json的读写 配置类型转换器-->
<mvc:annotation-driven conversion-service="conversionService"/>
<!--自定义类型转换器配置-->
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="com.lagou.converter.DateConverter"/>
</set>
</property>
</bean>
- 控制层
/**
* 获取日期类型参数 自定义类型转换器
*/
@RequestMapping("/converterParam")
public String converterParam(Date birthday){
System.out.println(birthday);
return "success";
}
请求相关注解
@RequestParam
- 当请求的参数name名称与Controller的业务方法参数名称不一致时,就需要通过
@RequestParam
注解显示的绑定 name
:匹配页面传递参数的名称defaultValue
:设置参数的默认值required
:设置是否必须传递该参数,默认值为true,如果设置了defaultValue,会默认为false
/**
* @requestParam
* name:匹配页面传递参数的名称
* defaultValue:设置参数的默认值
* required:设置是否必须传递该参数 默认值为true 如果设置了defaultValue,会默认为false
*/
@RequestMapping("/findByPage")
public String findByPage(@RequestParam(name = "pageNo",defaultValue = "1",required = false) Integer pageNum, @RequestParam(defaultValue = "5") Integer pageSize){
System.out.println(pageNum);
System.out.println(pageSize);
return "success";
}
@RequestHeader
- 获取请求头参数
/**
* 演示RequestHeader注解的使用
* 表示获取请求头中cookie的值 并赋值给cookie
*/
@RequestMapping("/RequestHeader")
public String requesHeader(@RequestHeader("cookie")String cookie){
System.out.println(cookie);
return "success";
}
@CookieValue
- 获取cookie中的数据。
/**
* @CookieValue的使用
*/
@RequestMapping("/CookieValue")
//获取cookie中key为JSESSIONID的值并赋值给jsessionId
public String cookieValue(@CookieValue("JSESSIONID") String jsessionId){
System.out.println(jsessionId);
return "success";
}
SpringMVC的响应
SpringMVC响应方式介绍
- 页面跳转
- 返回字符串逻辑视图
- void原始ServletAPI
- ModelAndView
- 返回数据
- 直接返回字符串数据
- 将对象或集合转为json返回
返回字符串逻辑视图
- 直接返回字符串:此种方式会将返回的字符串与视图解析器的前后缀拼接后跳转到指定页面
void原始ServletAPI
/**
* 原始servletApi进行页面跳转
*
*/
@RequestMapping("/returnVoid")
public void returnVoid(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException {
/*直接返回数据*/
response.setContentType("text/html;charset=UTF-8");
response.getWriter().write("ppx12138");
//借助request对象完成请求转发 一次请求
//request.getRequestDispatcher("/WEB-INF/page/success.jsp").forward(request,response);
//借助response对象完成重定向 相当于两次请求 不允许外部请求直接访问该目录资源 只可以进行服务器内部转发
//response.sendRedirect(request.getContextPath()+"/index.jsp");
}
SpringMVC的转发和重定向
请求转发
- 使用
forward:
- 使用此方法路径必须写成实际视图url,不能写逻辑视图
- 可以转发到其他控制器方法 写对应的目录及对应的映射地址
/**
* 演示forward关键字进行显示请求转发
* 当写了forward关键字或者redirect关键字 此请求不会通过视图解析器(不会通过前缀后缀拼接)
*/
@RequestMapping("/forward")
public String forward(Model model){
//想在视图模型中设置一些值
model.addAttribute("username","ppx");
//使用请求转发 既可以转发到jsp
return "forward:/WEB-INF/page/success.jsp";
//也可以转发到其他控制器方法 写对应的目录及对应的映射地址
// return "forward:/product/findAll";
}
重定向
- 我们可以不写虚拟目录,springMVC框架会自动拼接,并且将Model中的数据拼接到url地址上
/**
* 演示Redirect关键字进行重定向
*
*/
@RequestMapping("/redirect")
public String redirect(Model model){
//底层使用的是request.setAttribute 域范围是:一次请求 重定向是两次请求 所以此方法页面取不到值
model.addAttribute("username","ppx");
return "redirect:/index.jsp";
}
ModelAndView
方式一
- 在Controller中方法创建并返回ModelAndView对象,并且设置视图名称
/**
* modelAndView进行页面跳转 使用方式一
*/
@RequestMapping("returnModelAndView")
public ModelAndView returnModelAndView(){
/**
* model:模型 :封装存放数据
* view: 视图: 用来展示数据
*/
ModelAndView modelAndView = new ModelAndView();
//设置模型数据
modelAndView.addObject("username","使用方式一");
//设置视图名称 视图解析器解析此对象
modelAndView.setViewName("success");
return modelAndView;
}
方式二
- 在Controller中方法形参上直接声明ModelAndView,无需在方法中自己创建,在方法中直接使用该对象设置视图,同样可以跳转页面
/**
* modelAndView进行页面跳转 使用方式二
*/
@RequestMapping("returnModelAndView2")
public ModelAndView returnModelAndView2(ModelAndView modelAndView){
/**
* model:模型 :封装存放数据
* view: 视图: 用来展示数据
*/
//设置模型数据
modelAndView.addObject("username","使用方式二");
//设置视图名称 视图解析器解析此对象
modelAndView.setViewName("success");
return modelAndView;
}
@SessionAttributes
- 如果需要在多个请求中共享数据,可以在控制器类上加一个此注解,加上此注解后,在model中存放的数据也会暂存到session中
- 此注解只能加载到类上
@Controller
@SessionAttributes("username") //向request域存入的key为username时,同步到session域中 public class UserController {
@RequestMapping("/forward")
public String forward(Model model) {
model.addAttribute("username", "子慕");
return "forward:/WEB-INF/pages/success.jsp";
}
@RequestMapping("/returnString")
public String returnString() {
return "success";
}
}
SpringMVC静态资源访问的开启
- 因为SpringMVC的前端控制器DispatcherServlet的url-pattern配置的是 /(缺省),代表对所有的
静态资源都进行处理操作(会当作controller方法拦截),这样就不会执行Tomcat内置的DefaultServlet处理
解决方式
- 方式一
<!-- 方式一:放行指定的静态资源
mapping:放行映射路径 /js/**代表js后不论多少层级都放行
location:静态资源所在的目录-->
<mvc:resources mapping="/js/**" location="/js/"/>
<mvc:resources mapping="/css/**" location="/css/"/>
<mvc:resources mapping="/img/**" location="/img/"/>
- 方式二
<!--在springmvc配置文件中开启DefaultServlet处理静态资源-->
<mvc:default-servlet-handler/>