Spring MVC高级框架
Spring MVC应用
Spring MVC介绍
MVC体系结构
三层架构
在B/S架构中,系统标准的三层架构包括:表现层、业务层、控制层。
- 表现层
表现层包括展现层和控制层:控制层负责接收请求,展示层负责结果的展示。 - 业务层
业务层负责具体的业务逻辑处理。
表现层依赖业务层,业务层不依赖表现层。
业务层可能依赖持久层。 - 持久层
负责数据的持久化。
MVC设计模式(Model View Controller)
MVC分为三个部分:Model、View、Controller,他们各司其职:
- Model(模型):分业务模型和数据模型,业务模型处理业务,数据模型负责封装数据。
- View(视图):负责前端数据展示,如Jsp、html。
- Controller(控制器):处理用户交互,处理程序逻辑。
MVC提倡:每一层只编写自己的东西,不编写其他任何代码;分层是为了解耦,解耦是为了维护方便和分工协作。
Spring MVC是什么
SpringMVC 全名叫 Spring Web MVC,是⼀种基于 Java 的实现 MVC 设计模型的请求驱动类型的轻量级Web 框架,属于 SpringFrameWork 的后续产品。
Spring架构:
image.png
Spring MVC 本质可以认为是对servlet的封装,简化了我们serlvet的开发
image.png
Spring MVC的工作流程:
image.png
Spring Web MVC 工作流程
Spring MVC开发流程:
- 配置DispatchorServlet前端控制器
- 开发处理业务的@Controller,配置请求路径@RequestMapping,返回ModelAndView
- xml配置⽂件配置controller扫描,配置springmvc三⼤件
- 处理器映射器
- 处理器适配器
- 视图解析器
-
将xml⽂件路径告诉springmvc(DispatcherServlet)
image.png
流程说明
第⼀步:⽤户发送请求⾄前端控制器DispatcherServlet
第⼆步:DispatcherServlet收到请求调⽤HandlerMapping处理器映射器
第三步:处理器映射器根据请求Url找到具体的Handler(后端控制器),⽣成处理器对象及处理器拦截
器(如果 有则⽣成)⼀并返回DispatcherServlet
第四步:DispatcherServlet调⽤HandlerAdapter处理器适配器去调⽤Handler
第五步:处理器适配器执⾏Handler
第六步:Handler执⾏完成给处理器适配器返回ModelAndView
第七步:处理器适配器向前端控制器返回 ModelAndView,ModelAndView 是SpringMVC 框架的⼀个底层对 象,包括 Model 和 View
第⼋步:前端控制器请求视图解析器去进⾏视图解析,根据逻辑视图名来解析真正的视图。
第九步:视图解析器向前端控制器返回View
第⼗步:前端控制器进⾏视图渲染,就是将模型数据(在 ModelAndView 对象中)填充到 request 域
第⼗⼀步:前端控制器向⽤户响应结果
Spring MVC九大组件
- HandlerMapping(处理器映射器)
管理请求到handler和Intercepor的映射关系
- HandlerAdapter(处理器适配器)
因为 Spring MVC 中 Handler 可以是任意形式的,只要能处理请求即可。但是把请求交给 Servlet 的时候,由于 Servlet 的⽅法结构都是 doService(HttpServletRequest req,HttpServletResponse resp)形式的,要让固定的 Servlet 处理⽅法调⽤ Handler 来进⾏处理,便是 HandlerAdapter 的职责。
- HandlerExceptionResolver(处理器异常解析器)
根据异常设置ModelAndView,之后交给渲染⽅法进⾏渲染,渲染⽅法会将 ModelAndView 渲染成⻚⾯。
- ViewResoulver(视图解析器)
ViewResolver即视图解析器,⽤于将String类型的视图名和Locale解析为View类型的视图,只有⼀ 个resolveViewName()⽅法。从⽅法的定义可以看出,Controller层返回的String类型视图名 viewName 最终会在这⾥被解析成为View。View是⽤来渲染⻚⾯的,也就是说,它会将程序返回 的参数和数据填⼊模板中,⽣成html⽂件。ViewResolver 在这个过程主要完成两件事情: ViewResolver 找到渲染所⽤的模板(第⼀件⼤事)和所⽤的技术(第⼆件⼤事,其实也就是找到 视图的类型,如JSP)并填⼊参数。默认情况下,Spring MVC会⾃动为我们配置⼀个 InternalResourceViewResolver,是针对 JSP 类型视图的。
- RequestToViewNameTranslator(请求视图名转换器)
是从请求中获取 ViewName.
RequestToViewNameTranslator 组件的作⽤是从请求中获取 ViewName.因为 ViewResolver 根据
ViewName 查找 View,但有的 Handler 处理完成之后,没有设置 View,也没有设置 ViewName,
便要通过这个组件从请求中查找 ViewName。
- LocaleResovler(国际化解析器)
做国际化支持
ViewResolver 组件的 resolveViewName ⽅法需要两个参数,⼀个是视图名,⼀个是 Locale。
LocaleResolver ⽤于从请求中解析出 Locale,⽐如中国 Locale 是 zh-CN,⽤来表示⼀个区域。这
个组件也是 i18n 的基础。
- ThemeResovler(主题解析器)
多套样式主题配置管理。
ThemeResolver 组件是⽤来解析主题的。主题是样式、图⽚及它们所形成的显示效果的集合。
Spring MVC 中⼀套主题对应⼀个 properties⽂件,⾥⾯存放着与当前主题相关的所有资源,如图
⽚、CSS样式等。创建主题⾮常简单,只需准备好资源,然后新建⼀个“主题名.properties”并将资
源设置进去,放在classpath下,之后便可以在⻚⾯中使⽤了。SpringMVC中与主题相关的类有
ThemeResolver、ThemeSource和Theme。ThemeResolver负责从请求中解析出主题名,
ThemeSource根据主题名找到具体的主题,其抽象也就是Theme,可以通过Theme来获取主题和
具体的资源。
- MutipartResovler(多元素解析器)
文件上传
MultipartResolver ⽤于上传请求,通过将普通的请求包装成 MultipartHttpServletRequest 来实
现。MultipartHttpServletRequest 可以通过 getFile() ⽅法 直接获得⽂件。如果上传多个⽂件,还
可以调⽤ getFileMap()⽅法得到Map<FileName,File>这样的结构,MultipartResolver 的作⽤就
是封装普通的请求,使其拥有⽂件上传的功能。
- FlashMapManager
重定向参数传递
FlashMap ⽤于重定向时的参数传递,⽐如在处理⽤户订单时候,为了避免重复提交,可以处理完
post请求之后重定向到⼀个get请求,这个get请求可以⽤来显示订单详情之类的信息。这样做虽然
可以规避⽤户重新提交订单的问题,但是在这个⻚⾯上要显示订单的信息,这些数据从哪⾥来获得
呢?因为重定向时么有传递参数这⼀功能的,如果不想把参数写进URL(不推荐),那么就可以通
过FlashMap来传递。只需要在重定向之前将要传递的数据写⼊请求(可以通过ServletRequestAttributes.getRequest()⽅法获得)的属性OUTPUT_FLASH_MAP_ATTRIBUTE
中,这样在重定向之后的Handler中Spring就会⾃动将其设置到Model中,在显示订单信息的⻚⾯
上就可以直接从Model中获取数据。FlashMapManager 就是⽤来管理 FalshMap 的。
url-pattern配置:
- /*.subfix,后缀方式
- / 拦截除.jsp外的请求,包括静态资源。
- /* 拦截所有,包括.jsp
为什么/不拦截jsp?
因为在web.xml的父配置文件中配置了一个jsp的Servlet用于处理jsp请求。
怎么解决/拦截静态资源?
- 1、在springmvc.xml中配置<mvc:default-servlet-handler/>。
DefaultServletHandler会解析请求,如果发现是静态资源就还给web容器处理,如果不是今天资源就由springmvc继续处理。
但是这个配置只对webapp更目录下的静态资源有效。
- 2、在springmvc.xml中配置<mvc:resources mapping="/resource/**" location="classpath:/" />
由Spring mvc自己管理静态资源。
请求参数绑定
参数绑定的几种方式(见代码):
/**
* @author xdf
* @version 1.0
* @date Create in 17:12 2021/6/17
* @description springmvc 示例的Controller
* @modifiedBy
*/
@Controller
@RequestMapping("/demo")
public class DemoController {
/**
* 1、ModelAndView方式
*/
@RequestMapping("/handle01")
public ModelAndView handle01() {
Date date = new Date();
// 返回服务器时间
// 封装了数据和页面信息的ModelAndView
ModelAndView modelAndView = new ModelAndView();
// 向请求域中设置 request.setAttribute("date",date)
modelAndView.addObject("date",date);
modelAndView.setViewName("success");
return modelAndView;
}
/**
* 2、ModelMap 方式
*
* /
@RequestMapping("/handle02")
public String handle02(ModelMap map) {
System.out.println(map.getClass());
Date date = new Date();
// 返回服务器时间
// 封装了数据和页面信息的ModelAndView
// 向请求域中设置 request.setAttribute("date",date)
map.addAttribute("date",date);
return "success";
}
/**
* 3、Map模式
*/
@RequestMapping("/handle03")
public String handle03(Map<String,Object> map) {
System.out.println(map.getClass());
Date date = new Date();
// 返回服务器时间
// 封装了数据和页面信息的ModelAndView
// 向请求域中设置 request.setAttribute("date",date)
map.put("date",date);
return "success";
}
/**
* 4、Model模式
*/
@RequestMapping("/handle04")
public String handle04(Model map) {
System.out.println(map.getClass());
Date date = new Date();
// 返回服务器时间
// 封装了数据和页面信息的ModelAndView
// 向请求域中设置 request.setAttribute("date",date)
map.addAttribute("date",date);
return "success";
}
}
这四种方式都能将数据绑定到请求参数,然后传递到jsp中去。
为什么不管是用Model
、ModelMap
还是Map
都能实现,参数的绑定?
我们分别打印这三个对象,返现都是
class org.springframework.validation.support.BindingAwareModelMap
类的实例。
查看这个类的类图:
发现Model、Map都是BindingAwareModeMap的接口,ModelMap是它的父类。这里使用的其实都是BindingAwareModeMap的实例,只是用了不同方式来引用它。
image.png请求参数绑定:说⽩了SpringMVC如何接收请求参数
http协议(超⽂本传输协议)
原⽣servlet接收⼀个整型参数:
(1)String ageStr = request.getParameter("age");
(2) Integer age = Integer.parseInt(ageStr);
SpringMVC框架对Servlet的封装,简化了servlet的很多操作
SpringMVC在接收整型参数的时候,直接在Handler⽅法中声明形参即可
@RequestMapping("xxx")
public String handle(Integer age) {
System.out.println(age);
}
参数绑定:取出参数值绑定到handler⽅法的形参上
- 默认⽀持 Servlet API 作为⽅法参数
当需要使⽤HttpServletRequest、HttpServletResponse、HttpSession等原⽣servlet对象时,直接在handler⽅法中形参声明使⽤即可。
/**
*
* SpringMVC 对原⽣servlet api的⽀持 url:/demo/handle02?id=1
*
* 如果要在SpringMVC中使⽤servlet原⽣对象,⽐如
HttpServletRequest\HttpServletResponse\HttpSession,直接在Handler⽅法形参中声
明使⽤即可
*
*/
@RequestMapping("/handle02")
public ModelAndView handle02(HttpServletRequest request,
HttpServletResponse response,HttpSession session) {
String id = request.getParameter("id");
Date date = new Date();
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("date",date);
modelAndView.setViewName("success");
return modelAndView;
}
- 绑定简单类型参数
简单数据类型:⼋种基本数据类型及其包装类型
参数类型推荐使⽤包装数据类型,因为基础数据类型不可以为null
整型:Integer、int
字符串:String
单精度:Float、flfloat
双精度:Double、double
布尔型:Boolean、boolean
说明:对于布尔类型的参数,**请求的参数值为true或false。或者1或0 **
注意:绑定简单数据类型参数,只需要直接声明形参即可(形参参数名和传递的参数名要保持⼀
致,建议 使⽤包装类型,当形参参数名和传递参数名不⼀致时可以使⽤@RequestParam注解进⾏
⼿动映射)
/*
* SpringMVC 接收简单数据类型参数 url:/demo/handle03?id=1
*
* 注意:接收简单数据类型参数,直接在handler⽅法的形参中声明即可,框架会取出参数值
然后绑定到对应参数上
* 要求:传递的参数名和声明的形参名称保持⼀致
*/
@RequestMapping("/handle03")
public ModelAndView handle03(@RequestParam("ids") Integer id,Boolean
flag) {
Date date = new Date();
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("date",date);
modelAndView.setViewName("success");
return modelAndView;
}
- 绑定Pojo类型参数
/*
* SpringMVC接收pojo类型参数 url:/demo/handle04?id=1&username=zhangsan
*
* 接收pojo类型参数,直接形参声明即可,类型就是Pojo的类型,形参名⽆所谓
* 但是要求传递的参数名必须和Pojo的属性名保持⼀致
*/
@RequestMapping("/handle04")
public ModelAndView handle04(User user) {
Date date = new Date();
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("date",date);
modelAndView.setViewName("success");
return modelAndView;
}
- 绑定Pojo包装对象参数
包装类型 QueryVo
package com.lagou.edu.pojo;
public class QueryVo {
private String mail;
private String phone;
// 嵌套了另外的Pojo对象
private User user;
public String getMail() {
return mail;
}
public void setMail(String mail) {
this.mail = mail;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
Handler⽅法
/*
* SpringMVC接收pojo包装类型参数 url:/demo/handle05?
user.id=1&user.username=zhangsan
* 不管包装Pojo与否,它⾸先是⼀个pojo,那么就可以按照上述pojo的要求来
* 1、绑定时候直接形参声明即可
* 2、传参参数名和pojo属性保持⼀致,如果不能够定位数据项,那么通过属性名 + "." 的
⽅式进⼀步锁定数据
*
*/
@RequestMapping("/handle05")
public ModelAndView handle05(QueryVo queryVo) {
Date date = new Date();
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("date",date);
modelAndView.setViewName("success");
return modelAndView;
}
- 绑定⽇期类型参数(需要配置⾃定义类型转换器)
- 前端jsp
<fieldset>
<p>测试⽤例:SpringMVC接收⽇期类型参数</p>
<a href="/demo/handle06?birthday=2019-10-08">点击测试</a>
</fieldset>
- 后台Handler⽅法
/**
* 绑定⽇期类型参数
* 定义⼀个SpringMVC的类型转换器 接⼝,扩展实现接⼝接⼝,注册你的实现
* @param birthday
* @return
*/
@RequestMapping("/handle06")
public ModelAndView handle06(Date birthday) {
Date date = new Date();ModelAndView modelAndView = new
ModelAndView();
modelAndView.addObject("date",date);
modelAndView.setViewName("success");
return modelAndView;
}
- ⾃定义类型转换器
import org.springframework.core.convert.converter.Converter;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* @author 应癫
* ⾃定义类型转换器
* S:source,源类型
* T:target:⽬标类型
*/
public class DateConverter implements Converter<String, Date> {
@Override
public Date convert(String source) {
// 完成字符串向⽇期的转换
SimpleDateFormat simpleDateFormat = new
SimpleDateFormat("yyyy-MM-dd");
try {
Date parse = simpleDateFormat.parse(source);
return parse;
} catch (ParseException e) {
e.printStackTrace();
}
return null;
}
}
- 注册⾃定义类型转换器
<!--
⾃动注册最合适的处理器映射器,处理器适配器(调⽤handler⽅法)
-->
<mvc:annotation-driven conversion�
service="conversionServiceBean"/>
<!--注册⾃定义类型转换器-->
<bean id="conversionServiceBean"
class="org.springframework.format.support.FormattingConversionServiceF
actoryBean">
<property name="converters">
<set>
<bean class="com.lagou.edu.converter.DateConverter">
</bean>
</set>
</property>
</bean>
Restful风格请求支持
什么是Restful
REST(Representational State Transfer),资源表现层状态转移。他是一种网络接口风格。
Restful优点
- 结构清晰
- 符合标准
- 易于理解
- 扩展方便
Restful特性
资源:网络上的一个实体。
表现层:把资源呈现出来的形式。(txt、html、xml、json...)
状态转换:就是 HTTP 协议⾥⾯,四个表示操作⽅式的动词:
GET 、POST 、PUT 、DELETE 。它们分别对应四种基本操作:GET ⽤来获取资源,POST ⽤来新建资源,PUT ⽤来更新资源,DELETE ⽤来删除资源。
RESTful风格的URL:互联网上的所有事物都是资源,URL中只有表示资源的名称,没有操作的动词。
RESTful风格资源操作:使用HTTP请求中的method方法get、post、update、delete来操作资源。put 和 delete⼏乎不使⽤。
RESTful风格资源表述:可以有多种返回数据类型:json、xml等。
Spring MVC对Restful的支持
Restful代码示例:
- 前端代码
<h2>SpringMVC对Restful⻛格url的⽀持</h2>
<fieldset>
<p>测试⽤例:SpringMVC对Restful⻛格url的⽀持</p>
<a href="/demo/handle/15">rest_get测试</a>
<form method="post" action="/demo/handle">
<input type="text" name="username"/>
<input type="submit" value="提交rest_post请求"/>
</form>
<form method="post" action="/demo/handle/15/lisi">
<input type="hidden" name="_method" value="put"/>
<input type="submit" value="提交rest_put请求"/>
</form>
<form method="post" action="/demo/handle/15">
<input type="hidden" name="_method" value="delete"/>
<input type="submit" value="提交rest_delete请求"/>
</form>
</fieldset>
- 后台handler
@RequestMapping(value = "/handle/{id}", method = RequestMethod.GET)
public ModelAndView handleGet(@PathVariable("id") String id) {
System.out.println(id);
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("data", id);
modelAndView.setViewName("success");
return modelAndView;
}
@RequestMapping(value = "/handle/{id}/{name}", method = RequestMethod.POST)
public ModelAndView handlePost(@PathVariable("id") String id, @PathVariable("name") String name) {
System.out.println(id);
String data = "id:" + id + ",name:" + name;
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("data", data);
modelAndView.setViewName("success");
return modelAndView;
}
@RequestMapping(value = "/handle/{id}/{name}", method = RequestMethod.PUT)
public ModelAndView handlePut(@PathVariable("id") String id, @PathVariable("name") String name) {
System.out.println(id);
String data = "id:" + id + ",name:" + name;
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("data", data);
modelAndView.setViewName("success");
return modelAndView;
}
@RequestMapping(value = "/handle/{id}", method = RequestMethod.DELETE)
public ModelAndView handleDelete(@PathVariable("id") String id) {
System.out.println(id);
String data = "id:" + id;
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("data", data);
modelAndView.setViewName("success");
return modelAndView;
}
- web配置文件
<!--配置springmvc请求⽅式转换过滤器,会检查请求参数中是否有_method参数,如果有就
按照指定的请求⽅式进⾏转换-->
<filter>
<filter-name>hiddenHttpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>hiddenHttpMethodFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Ajax JSON交互
什么是JSON
略
@ResponseBody注解
将Controller的返回值转换为指定的格式写入到Response的body区,一般是Json 格式。
分析Spring MVC使用Json交互
- 引入json支持
<!--json数据交互所需jar,start-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.9.0</version>
</dependency>
<!--json数据交互所需jar,end-->
- handler方法返回值用@ResponseBody标注
@RequestMapping("/handle07")
// 添加@ResponseBody之后,不再⾛视图解析器那个流程,⽽是等同于response直接输出数据
public @ResponseBody User handle07(@RequestBody User user) {
// 业务逻辑处理,修改name为张三丰
user.setName("张三丰");
return user;
}
Spring MVC高级技术
拦截器(Interceptor)使用
监听器、过滤器和拦截器对比
- Servlet:处理Request请求和Response响应
- 过滤器(Filter):对Request请求起到过滤作用,作用在Servlet之前。实现Filter接口,配置在web.xml文件中,有web容器调用,不归springmvc管。
- 监听器(Listener):实现了javax.servlet.ServletContextListener 接⼝的服务器端组件,它随 Web应⽤的启动⽽启动,只初始化⼀次,然后会⼀直运⾏监视,随Web应⽤的停⽌⽽销毁。
- 作用一:做一些初始化工作,web应用中spring容器启动ContextLoaderListener。
- 作用二:监听web中的特定事件,比如HttpSession,ServletRequest的创建和销毁;变量的创建、销毁和修改等。
- 拦截器(Interceptor):是SpringMVC、Struts等表现层框架自己的,只会拦截控制器。
- 在Handler执行业务之前拦截一次
- 在Handler逻辑执行完毕但为跳转到页面之前拦截一次
- 在跳转页面之后调用一次
过滤器解决乱码:
- post乱码,配置web.xml
<!-- 解决post乱码问题 -->
<filter>
<filter-name>encoding</filter-name>
<filter-class>
org.springframework.web.filter.CharacterEncodingFilter
</filter-class>
<!-- 设置编码参是UTF8 -->
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
- Get请求乱码,修改server.xml
<Connector URIEncoding="utf-8" connectionTimeout="20000" port="8080"
protocol="HTTP/1.1" redirectPort="8443"/>
拦截器的执行流程
单个拦截器的执行流程 源码解析1)程序先执⾏preHandle()⽅法,如果该⽅法的返回值为true,则程序会继续向下执⾏处理器中的⽅ 法,否则将不再向下执⾏。
2)在业务处理器(即控制器Controller类)处理完请求后,会执⾏postHandle()⽅法,然后会通过
DispatcherServlet向客户端返回响应。
3)在DispatcherServlet处理完请求后,才会执⾏afterCompletion()⽅法。
多个拦截器执行流程
执行流程 image.png示例代码:
实现三个拦截器:
- GlobalInterceptor:全局拦截器
package com.xdf.mvcdemo.interceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @author xdf
* @version 1.0
* @date Create in 14:18 2021/6/21
* @description 自定义拦截器1
* @modifiedBy
*/
public class GlobalInterceptor implements HandlerInterceptor {
/**
* 前置拦截
* @param request 请求
* @param response 响应
* @param handler 控制器
* @return true 继续执行,false拦截请求
* @throws Exception 异常信息
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("GlobalInterceptor preHandle");
return true;
}
/**
* 后置拦截
* @param request 请求
* @param response 响应
* @param handler 控制器
* @param modelAndView 数据和视图
* @throws Exception 异常
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("GlobalInterceptor postHandle");
}
/**
* 视图渲染完拦截器
* @param request 请求
* @param response 响应
* @param handler 控制器
* @param ex 异常,可以在这个方法中处理异常
* @throws Exception 异常
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("GlobalInterceptor afterCompletion");
}
}
- MyInterceptor1:普通拦截器
package com.xdf.mvcdemo.interceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @author xdf
* @version 1.0
* @date Create in 14:18 2021/6/21
* @description 自定义拦截器1
* @modifiedBy
*/
public class MyInterceptor1 implements HandlerInterceptor {
/**
* 前置拦截
* @param request 请求
* @param response 响应
* @param handler 控制器
* @return true 继续执行,false拦截请求
* @throws Exception 异常信息
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("interceptor1 preHandle");
return true;
}
/**
* 后置拦截
* @param request 请求
* @param response 响应
* @param handler 控制器
* @param modelAndView 数据和视图
* @throws Exception 异常
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("interceptor1 postHandle");
}
/**
* 视图渲染完拦截器
* @param request 请求
* @param response 响应
* @param handler 控制器
* @param ex 异常,可以在这个方法中处理异常
* @throws Exception 异常
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("interceptor1 afterCompletion");
}
}
- MyInterceptor2:普通拦截器
package com.xdf.mvcdemo.interceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @author xdf
* @version 1.0
* @date Create in 14:18 2021/6/21
* @description 自定义拦截器1
* @modifiedBy
*/
public class MyInterceptor2 implements HandlerInterceptor {
/**
* 前置拦截
* @param request 请求
* @param response 响应
* @param handler 控制器
* @return true 继续执行,false拦截请求
* @throws Exception 异常信息
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("interceptor2 preHandle");
return true;
}
/**
* 后置拦截
* @param request 请求
* @param response 响应
* @param handler 控制器
* @param modelAndView 数据和视图
* @throws Exception 异常
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("interceptor2 postHandle");
}
/**
* 视图渲染完拦截器
* @param request 请求
* @param response 响应
* @param handler 控制器
* @param ex 异常,可以在这个方法中处理异常
* @throws Exception 异常
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("interceptor2 afterCompletion");
}
}
在springmvc.xml配置拦截器
<mvc:interceptors>
<bean class="com.xdf.mvcdemo.interceptor.GlobalInterceptor"/>
<mvc:interceptor>
<!-- 拦截所有请求 -->
<mvc:mapping path="/**"/>
<bean class="com.xdf.mvcdemo.interceptor.MyInterceptor1"/>
</mvc:interceptor>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.xdf.mvcdemo.interceptor.MyInterceptor2"/>
</mvc:interceptor>
</mvc:interceptors>
随便请求一个接口,输出
GlobalInterceptor preHandle
interceptor1 preHandle
interceptor2 preHandle
15
interceptor2 postHandle
interceptor1 postHandle
GlobalInterceptor postHandle
interceptor2 afterCompletion
interceptor1 afterCompletion
GlobalInterceptor afterCompletion
因此:请求到控制器之间的拦截器执行顺序是配置顺序,控制器到响应返回拦截器执行顺序是配置顺序的反序。
处理multipart形式的数据
文件上传
原⽣servlet处理上传的⽂件数据的,springmvc⼜是对serlvet的封装
需要的依赖:
<!--⽂件上传所需jar坐标-->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
配置⽂件上传解析器
<!--配置⽂件上传解析器,id是固定的multipartResolver-->
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!--设置上传⼤⼩,单位字节-->
<property name="maxUploadSize" value="1000000000"/>
</bean>
前端:
<%--
1 method="post"
2 enctype="multipart/form-data"
3 type="file"
--%>
<form method="post" enctype="multipart/form-data" action="/demo/upload">
<input type="file" name="uploadFile"/>
<input type="submit" value="上传"/>
</form>
后台接收Handler
@RequestMapping("upload")
public String upload(MultipartFile uploadFile, HttpServletRequest request)
throws IOException {
// ⽂件原名,如xxx.jpg
String originalFilename = uploadFile.getOriginalFilename();
// 获取⽂件的扩展名,如jpg
String extendName =
originalFilename.substring(originalFilename.lastIndexOf(".") + 1,
originalFilename.length());
String uuid = UUID.randomUUID().toString();
// 新的⽂件名字
String newName = uuid + "." + extendName;
String realPath =
request.getSession().getServletContext().getRealPath("/uploads");
// 解决⽂件夹存放⽂件数量限制,按⽇期存放
String datePath = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
File floder = new File(realPath + "/" + datePath);
if(!floder.exists()) {
floder.mkdirs();
}
uploadFile.transferTo(new File(floder,newName));
return "success";
}
在控制器处理异常
// 可以让我们优雅的捕获所有Controller对象handler⽅法抛出的异常
@ControllerAdvice
public class GlobalExceptionResolver {
@ExceptionHandler(ArithmeticException.class)
public ModelAndView handleException(ArithmeticException exception,
HttpServletResponse response) {
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("msg",exception.getMessage());
modelAndView.setViewName("error");
return modelAndView;
}
}
基于Flash属性的跨重定向请求数据传递
重定向时请求参数会丢失,我们往往需要重新携带请求参数,我们可以进⾏⼿动参数拼接如下:
return "redirect:handle01?name=" + name;
但是上述拼接参数的⽅法属于get请求,携带参数⻓度有限制,参数安全性也不⾼,此时,我们可以使
⽤SpringMVC提供的flash属性机制,向上下⽂中添加flash属性,框架会在session中记录该属性值,当跳转到⻚⾯之后框架会⾃动删除flflash属性,不需要我们⼿动删除,通过这种⽅式进⾏重定向参数传递,参数长度和安全性都得到了保障,如下:
/**
* SpringMVC 重定向时参数传递的问题
* 转发:A 找 B 借钱400,B没有钱但是悄悄的找到C借了400块钱给A
* url不会变,参数也不会丢失,⼀个请求
* 重定向:A 找 B 借钱400,B 说我没有钱,你找别⼈借去,那么A ⼜带着400块的借钱需求找到
C
* url会变,参数会丢失需要重新携带参数,两个请求
*/
@RequestMapping("/handleRedirect")
public String handleRedirect(String name,RedirectAttributes
redirectAttributes) {
//return "redirect:handle01?name=" + name; // 拼接参数安全性、参数⻓度都有 局限
// addFlashAttribute⽅法设置了⼀个flash类型属性,该属性会被暂存到session中,在 跳转到⻚⾯之后该属性销毁
redirectAttributes.addFlashAttribute("name",name);
return "redirect:handle01";
}
手写MVC框架
自定义MVC框架核心流程:
image.png
代码仓库:https://gitee.com/xdf-lg/custom-springmvc/tree/master
Spring MVC源码深度剖析
前端控制器DispatcherServlet继承结构
image.pngDispatcherServlet实现了Servlet接口(是一个Servlet),关键方法调用结构:
image.png
- doGet/doPost被FrameworkServlet类重写。
- 在FrameworkServlet的doGet/doPost方法中调用processRequest方法处理请求
- 在processRequest方法中调用DispatcherServel中的doService
- doService方法中调用doDispatch方法做请求分发。
重要时机点分析
1)handler方法执行时机
打断点观察:
image.png
调用栈:
image.png
image.png
2)页面渲染时机
image.png
image.png
SpringMVC处理请求的流程图 image.png
SpringMVC处理请求的流程(doDispatch流程):
- 调用getHandler方法获取能处理请求的执行连HandlerExecutionChain
- 调用getHandlerAdapter获取执行器适配器。
- 适配器调用Handler执行ha.handle方法返回一个ModelAndView
- 调用processDispatchResult方法完成视图渲染跳转。
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
ModelAndView mv = null;
Object dispatchException = null;
try {
// 1 检查是否是⽂件上传的请求
processedRequest = this.checkMultipart(request);
multipartRequestParsed = processedRequest != request;
/*
2 取得处理当前请求的Controller,这⾥也称为Handler,即处理器
这⾥并不是直接返回 Controller,⽽是返回 HandlerExecutionChain 请求处
理链对象
该对象封装了Handler和Inteceptor
*/
mappedHandler = this.getHandler(processedRequest);
if (mappedHandler == null) {
// 如果 handler 为空,则返回404
this.noHandlerFound(processedRequest, response);
return;
}
// 3 获取处理请求的处理器适配器 HandlerAdapter
HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
// 处理 last-modified 请求头
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if ((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) {
return;
}
}
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// Actually invoke the handler.
// 4 实际处理器处理请求,返回结果视图对象
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
// 结果视图对象的处理
this.applyDefaultViewName(processedRequest, mv);
mappedHandler.applyPostHandle(processedRequest, response, mv);
} catch (Exception var20) {
dispatchException = var20;
} catch (Throwable var21) {
dispatchException = new NestedServletException("Handler dispatch failed", var21);
}
// 5 跳转⻚⾯,渲染视图
this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);
} catch (Exception var22) {
//最终会调⽤HandlerInterceptor的afterCompletion ⽅法
this.triggerAfterCompletion(processedRequest, response, mappedHandler, var22);
} catch (Throwable var23) {
this.triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", var23));
} finally {
if (asyncManager.isConcurrentHandlingStarted()) {
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
} else if (multipartRequestParsed) {
this.cleanupMultipart(processedRequest);
}
}
}
核心步骤getHandler方法剖析
遍历两个HandlerMapping,试图获取能够处理当前请求的执⾏链
image.png
核心步骤getHandlerAdapter方法剖析
遍历各个HandlerAdapter,看哪个Adapter⽀持处理当前Handler
image.png
核心步骤ha.handle方法剖析
image.png image.pngimage.png
image.png
image.png
核心步骤processDispatchResult方法剖析
render⽅法完成渲染
image.png
视图解析器解析出View视图对象
image.png
在解析出View视图对象的过程中会判断是否重定向、是否转发等,不同的情况封装的是不同的View实现
image.png
解析出View视图对象的过程中,要将逻辑视图名解析为物理视图名
image.png
封装View视图对象之后,调⽤了view对象的render⽅法 image.png
渲染数据
image.png
把modelMap中的数据暴露到request域中,这也是为什么后台model.add之后在jsp中可以从请求域取出来的根本原因
image.png
将数据设置到请求域中
image.png
Spring MVC九大组件初始化
九大组件初始化时机:DispatcherServlet中有一个内部类ContextRefreshListener实现了ApplicationListener,监听了IOC容器的onRefresh方法。当IOC容器执行onRefresh方法时,执行九大组件初始化。如图:
无法复制加载中的内容
在DispatcherServlet中定义了九个属性,每⼀个属性都对应⼀种组件
/** MultipartResolver used by this servlet. */
// 多部件解析器
@Nullable
private MultipartResolver multipartResolver;
/** LocaleResolver used by this servlet. */
// 区域化 国际化解析器
@Nullable
private LocaleResolver localeResolver;
/** ThemeResolver used by this servlet. */
// 主题解析器
@Nullable
private ThemeResolver themeResolver;
/** List of HandlerMappings used by this servlet. */
// 处理器映射器组件
@Nullable
private List<HandlerMapping> handlerMappings;
/** List of HandlerAdapters used by this servlet. */
// 处理器适配器组件
@Nullable
private List<HandlerAdapter> handlerAdapters;
/** List of HandlerExceptionResolvers used by this servlet. */
// 异常解析器组件
@Nullable
private List<HandlerExceptionResolver> handlerExceptionResolvers;
/** RequestToViewNameTranslator used by this servlet. */
// 默认视图名转换器组件
@Nullable
private RequestToViewNameTranslator viewNameTranslator;
/** FlashMapManager used by this servlet. */
// flash属性管理组件
@Nullable
private FlashMapManager flashMapManager;
/** List of ViewResolvers used by this servlet. */
// 视图解析器
@Nullable
private List<ViewResolver> viewResolvers;
九⼤组件都是定义了接⼝,接⼝其实就是定义了该组件的规范,⽐如ViewResolver、HandlerAdapter等都是接⼝
九⼤组件的初始化时机
DispatcherServlet中的onRefresh(),该⽅法中初始化了九⼤组件
initStrategies⽅法
观察其中的⼀个组件initHandlerMappings(context)
image.png
如果按照类型和按照固定id从ioc容器中找不到对应组件,则会按照默认策略进⾏注册初始化,默认策略在DispatcherServlet.properties⽂件中配置
image.pngDispatcherServlet.properties
image.png
注意:多部件解析器的初始化必须按照id注册对象(multipartResolver)
image.png
SSM整合
整合策略
SSM = Spring + SpringMVC + Mybatis = (Spring + Mybatis)+ SpringMVC
先整合 Spring + Mybatis
然后再整合 SpringMVC
基于的需求:查询 Account 表的全部数据显示到⻚⾯
MyBatis整合Spring
- 整合⽬标
- 数据库连接池以及事务管理都交给Spring容器来完成
- SqlSessionFactory对象应该放到Spring容器中作为单例对象管理
- Mapper动态代理对象交给Spring管理,我们从Spring容器中直接获得Mapper的代理对象
- 整合所需 Jar 分析
- Junit测试jar(4.12版本)
- Mybatis的jar(3.4.5)
- Spring相关jar(spring-context、spring-test、spring-jdbc、spring-tx、spring-aop、 aspectjweaver)
- Mybatis/Spring整合包jar(mybatis-spring-xx.jar)
- Mysql数据库驱动jar
- Druid数据库连接池的jar
- 整合后的 Pom 坐标
<!--junit-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!--mybatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.5</version>
</dependency>
<!--spring相关-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.12.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.1.12.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.1.12.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.1.12.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.1.12.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.9</version>
</dependency>
<!--mybatis与spring的整合包-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.3</version>
</dependency>
<!--数据库驱动jar-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.46</version>
</dependency>
<!--druid连接池-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.21</version>
</dependency>
- jdbc.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/bank
jdbc.username=root
jdbc.password=123456
- Spring 配置⽂件
- applicationContext-dao.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
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/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
">
<!--包扫描-->
<context:component-scan base-package="com.lagou.edu.mapper"/>
<!--数据库连接池以及事务管理都交给Spring容器来完成-->
<!--引⼊外部资源⽂件-->
<context:property-placeholder
location="classpath:jdbc.properties"/>
<!--第三⽅jar中的bean定义在xml中-->
<bean id="dataSource"
class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!--SqlSessionFactory对象应该放到Spring容器中作为单例对象管理
原来mybaits中sqlSessionFactory的构建是需要素材的:SqlMapConfig.xml中的内
容
-->
<bean id="sqlSessionFactory"
class="org.mybatis.spring.SqlSessionFactoryBean">
<!--别名映射扫描-->
<property name="typeAliasesPackage" value="com.lagou.edu.pojo"/>
<!--数据源dataSource-->
<property name="dataSource" ref="dataSource"/>
</bean>
<!--Mapper动态代理对象交给Spring管理,我们从Spring容器中直接获得Mapper的代理对
象-->
<!--扫描mapper接⼝,⽣成代理对象,⽣成的代理对象会存储在ioc容器中-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!--mapper接⼝包路径配置-->
<property name="basePackage" value="com.lagou.edu.mapper"/>
<property name="sqlSessionFactoryBeanName"
value="sqlSessionFactory"/>
</bean>
</beans>
- applicationContext-service.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:lgContext="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
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/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
">
<!--包扫描-->
<lgContext:component-scan base-package="com.lagou.edu.service"/>
<!--事务管理-->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--事务管理注解驱动-->
<tx:annotation-driven transaction-manager="transactionManager"/>
</beans>
- AccountMapper接⼝
package com.lagou.edu.mapper;
import com.lagou.edu.pojo.Account;
import java.util.List;
public interface AccountMapper {
// 定义dao层接⼝⽅法--> 查询account表所有数据
List<Account> queryAccountList() throws Exception;
}
- AccountMapper.xml
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.lagou.edu.mapper.AccountMapper">
<select id="queryAccountList" resultType="com.lagou.edu.pojo.Account">
select * from account
</select>
</mapper>
- 测试程序
import com.lagou.edu.pojo.Account;
import com.lagou.edu.service.AccountService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.util.List;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath*:application*.xml"})
public class MybatisSpringTest {
// 希望测试ioc容器中的哪个对象你注⼊即可。
@Autowired
private AccountService accountService;
@Test
public void testMybatisSpring() throws Exception {
List<Account> accounts = accountService.queryAccountList();
for (int i = 0; i < accounts.size(); i++) {
Account account = accounts.get(i);
System.out.println(account);
}
}
}
整合Spring MVC
- 整合思路
把SpringMVC的⼊⻔案例整合进来即可(在已有⼯程基础之上开发⼀个SpringMVC⼊⻔案例) - 引⼊pom坐标
<!--SpringMVC-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.1.12.RELEASE</version>
</dependency>
<!--jsp-api&servlet-api-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jsp-api</artifactId>
<version>2.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<!--⻚⾯使⽤jstl表达式-->
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.2</version>
</dependency>
<!--json数据交互所需jar,start-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.9.0</version>
</dependency>
<!--json数据交互所需jar,end-->
- 添加SpringMVC ⼊⻔案例
- springmvc.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
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/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
">
<!--扫描controller-->
<context:component-scan base-package="com.lagou.edu.controller"/>
<mvc:annotation-driven/>
</beans>
- Controller类
package com.lagou.edu.controller;
import com.lagou.edu.pojo.Account;
import com.lagou.edu.service.AccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.List;
@Controller
@RequestMapping("/account")
public class AccountController {
/**
* Spring容器和SpringMVC容器是有层次的(⽗⼦容器)
* Spring容器:service对象+dao对象
* SpringMVC容器:controller对象,,,,可以引⽤到Spring容器中的对象
*/
@Autowired
private AccountService accountService;
@RequestMapping("/queryAll")
@ResponseBody
public List<Account> queryAll() throws Exception {
return accountService.queryAccountList();
}
}
- web.xml
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:applicationContext*.xml</param-value>
</context-param>
<!--spring框架启动-->
<listener>
<listener�
class>org.springframework.web.context.ContextLoaderListener</listener�
class>
</listener>
<!--springmvc启动-->
<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>