一、SpringMVC介绍
1. 什么是SpringMVC
- SpringMVC是一个基于Java实现了MVC设计模式的请求驱动类型的轻量级Web框架
- 把模型-视图-控制器分离,将web层进行职责解耦,简化开发,减少出错,方便开发人员配合
- Model-View-Controller
- Model:提供需要展示的数据
- View:展示的模型
- Controller:接收请求,委托处理,返回结果(调度器)
2. SpringMVC的优点
- 可以支持各种视图技术,不仅局限于JSP
- 与Spring框架集成
- 角色清晰分配
- 支持各种请求资源的映射策略
二、SpringMVC的核心组件
-
前端控制器(DispatcherServlet)
- 作用:接收请求,相应结果,相当于转发调度器
-
处理器映射器(HandlerMapping)
- 作用:根据请求的URL来查找Handler
-
处理器适配器(HanderAdaptor)
-
处理器(Handler)
- 需要程序员开发
-
视图解析器(ViewResolver)
- 作用:进行视图解析,将视图的逻辑名解析成为真正的视图
-
视图(View)
- 需要程序员开发
- 作用:是一个接口,它的实现类支持不同的视图类型
三、SpringMVC工作原理
- 用户发送请求至前端控制器(DispatcherServlet)
- DispatcherServlet收到请求后,调用处理器映射器(HandlerMapping),请求获取Handle
- HandlerMapping根据请求URL找到具体的处理器,生成处理器对象(Handler)及处理器拦截器**(如果有拦截器则生成),将生成结果返回给DispatcherServlet
- DispatcherServlet调用处理器适配器(HandlerAdaptor)
- HandlerAdaptor经过适配,调用具体的Handler
- Handler执行完毕,给HandlerAdaptor返回ModelAndView
- HandlerAdaptor将Handler执行结果(ModelAndView)返回给DispatcherServlet
- DispatcherServlet将ModelAndView传给视图解析器(ViewResolver)进行解析
- ViewResolver解析后返回具体的View视图
- DispatcherServlet对View进行渲染(将模型数据填充至视图中)
- DispatcherServlet相应用户
四、SpringMVC常用注解
-
@RequestMapping
- 用于处理请求URL映射
- 类上:类中所有响应请求的方法都以该地址作为父路径
- 方法上:该方法以该地址作为路径
- 六个属性值:
- value:请求指定实际地址(可以是URI Template)
- method:请求指定方法
- consumes:请求提交的内容类型(如html/text、application/josn)
- produces:返回内容类型,仅当Request请求头中包含指定类型时才返回
- params:指定Request请求中必须包含某些参数值,否则不处理
- headers:指定Request请求中必须包含某些指定的header值,否则不处理
- 用于处理请求URL映射
-
@ResquestBody
- 作用:主要用来接收前端传递给后端的json字符串中的数据的(请求体中的数据的)
- 原理:josn数据会在Request的请求体中,所以前端不能使用GET方式提交数据,必须使用POST方式提交
- 使用场景:前端给后端传输的是批量数据(List、Map)等结构时,转换成json再传输
-
@ResponseBody
- 作用:将Conreoller方法返回对象转化为json对象响应给客户
- 原理:通过适当的HttpMessageConverter转换为指定格式后,写入到Response对象的body数据区
-
@Controller
- 作用:注解在类上,表示该类为一个控制器对象
- 控制器Controller负责处理由DispatcherServlet 分发的请求,它把用户请求的数据经过业务处理层处理之后封装成一个Model,然后再把该Model返回给对应的View进行展示
- Spring MVC中提供了一个非常简便的定义Controller的方法,你无需继承特定的类或实现特定的接口,只需使用@Controller标记一个类是Controller,然后使用@RequestMapping和@RequestParam 等一些注解用以定义URL请求和Controller方法之间的映射,这样的Controller就能被外界访问到
- Controller 不会直接依赖于HttpServletRequest 和HttpServletResponse 等HttpServlet 对象,它们可以通过Controller 的方法参数灵活的获取到
-
@PathVariable
- 作用:映射URL中的占位符{xxx}到目标方法的参数中(名字不一样时可以进行指定)
- 主要用于接收Restful风格的请求中的参数
// 前端请求为: .../getUserById/tom
@RequestMapping("/getUserById/{name}")
public User getUser(@PathVariable("name") String userName){
return userService.selectUser(userName);
}
- @RequestParam
- 作用:将请求参数绑定到你控制器的方法参数上
- 主要用于接收普通请求中的参数
// 前端请求为: .../getUserById?name=tom
@RequestMapping("/getUserById/{name}")
public User getUser(@RequestParam("name") String userName){
return userService.selectUser(userName);
}
五、 SpringMVC拦截器
-
拦截器作用:
- 拦截器用于对处理器进行预处理和后处理的技术。
- 可以定义拦截器链,连接器链就是将拦截器按着顺序结成一条链,在访问被拦截的方法时,拦截器链中的拦截器会按着定义的顺序执行。
- 依赖于web框架,在SpringMVC中就是依赖于SpringMVC框架。在实现上基于Java的反射机制,属于面向切面编程(AOP)的一种运用。
- 一个拦截器实例在一个controller生命周期之内可以多次调用。但是缺点是只能对controller请求进行拦截,对其他的一些比如直接访问静态资源的请求则没办法进行拦截处理
-
自定义拦截器
- 方法:实现HandlerInterceptor 接口,然后在springmvc.xml中配置拦截器/使用注解将拦截器托管(SpringBoot)
- 如果定义了多个拦截器,会按照加入的顺序进行拦截
-
用例:
- 自定义拦截器内容:
public class MyInterceptor implements HandlerInterceptor {
/**
* 预处理,controller 方法执行前
* 应用:用于身份认证、身份授权
* return true 放行,执行下一个拦截器,如果没有,执行 controller 中的方法
* return false 不放行,即不向下执行
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle");
return true;
}
/**
* 后处理方法,controller 方法执行后,方法跳转 success.jsp 执行之前
* 应用:从modelAndView出发:将公用的模型数据(比如菜单导航)在这里传到视图,也可以在这里统一指定视图
*/
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle");
}
/**
* success.jsp 页面执行后,该方法会执行
* 应用:统一异常处理,统一日志处理
*/
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion");
}
}
- 配置文件配置:
<!--配置拦截器-->
<mvc:interceptors>
<!--配置拦截器,多个拦截器时,顺序执行-->
<mvc:interceptor>
<!--要拦截的具体的方法-->
<mvc:mapping path="/user/*"/>
<!--不去拦截的方法
<mvc:exclude-mapping path=""/>
-->
<!--配置拦截器对象-->
<bean class="com.qf.interceptor.MyInterceptor" />
</mvc:interceptor>
</mvc:interceptors>
- 注解配置:
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
/**
* 在这里添加自己定义的拦截器
* @param registry
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyInterceptor())
// 只拦截test路径
.addPathPatterns("/test/**")
// 不拦截pass路径
.excludePathPatterns("/pass/**");
}
}
六、 Servlet过滤器
-
过滤器作用:
- 使用过滤器的目的是用来做一些过滤操作,获取我们想要获取的数据;(比如:在过滤器中修改字符编码;在过滤器中修改HttpServletRequest的一些参数,包括:过滤低俗文字、危险字符等)
- 依赖于servlet容器。在实现上基于函数回调,可以对几乎所有请求进行过滤,但是缺点是一个过滤器实例只能在容器初始化时调用一次
- 详解:过滤器详解
-
实现方法:
- 实现Filter接口,定义过滤器功能
- 配置过滤器(xml配置/注解配置)
Filter的主要的作用就是用户在访问某个目标资源之前,对访问的请求和响应进行拦截,做一些处理,然后再调用目标程序,这样做的好处是可以对一些公共的操作进行抽象,就拿设置字符集来说,如果不使用这种方式,我们每个页面都要写设置字符集的语句。不但麻烦而且维护困难,但是如果使用Filter的话,只需要添加一个类,在xml中配置一下,如果不想使用了,将配置文件中的内容去除即可。Filter基于回调函数,我们需要实现的Filter接口中doFilter方法就是回调函数。
- 用例:
- 过滤器功能:
public class EncodingFilter implements Filter {
private String encoding = null;
public void destroy() {
encoding = null;
}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
String encoding = getEncoding();
if (encoding == null){
encoding = ”gb2312”;
}
request.setCharacterEncoding(encoding);//在请求里设置指定的编码
chain.doFilter(request, response);
//通过控制对chain.doFilter的方法的调用,来决定是否需要访问目标资源
}
public void init(FilterConfig FilterConfig) throws ServletException {
this.encoding = FilterConfig.getInitParameter(“encoding”);
}
private String getEncoding() {
return this.encoding;
}
}
- xml文件配置:
<Filter>
<Filter-name>EncodingFilter</Filter-name>
<Filter-class>com.logcd.Filter.EncodingFilter</Filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>gb2312</param-value>
</init-param>
</Filter>
<Filter-mapping>
<Filter-name>EncodingFilter</Filter-name>
<url-pattern>/*</url-pattern>
</Filter-mapping>
- 注解配置:
- 使用注解配置需要在实现Filter类上加@WebFilter,还要再启动类上加@ServletComponentScan
@Configuration
public class WebComponent2Config {
@Bean
public FilterRegistrationBean someFilterRegistration1() {
//新建过滤器注册类
FilterRegistrationBean registration = new FilterRegistrationBean();
// 添加我们写好的过滤器
registration.setFilter(new EncodingFilter());
// 设置过滤器的URL模式
registration.addUrlPatterns("/*");
return registration;
}
}
七、问题
1. 什么是DispatcherServlet
- SpringMVC框架是围绕着DispatcherServlet来设计的,DispatcherServlet用来处理所有的HTTP请求和相应
2. 什么是SpringMVC的控制器
- 控制器提供一个访问应用程序的行为,此行为通常通过服务接口实现。控制器解析用户输入并将其转换为一个由视图呈现给用户的模型。Spring用一个非常抽象的方式实现了一个控制层,允许用户创建多种用途的控制器。
3. 控制器是不是单例模式
- 控制器是单例模式
- 问题:多线程访问时产生线程安全问题
- 解决:保证控制器是无状态的(控制器中不能有字段)
4. SpringMVC怎么设置转发和重定向
- 转发:返回值前加forward
- 重定向:返回值前加redirect
5. SpringMVC中函数的返回值
- 返回String:
- 进行视图跳转(视图名称)
- json字符串传输给前端(@ResponseBody)
- 返回ModelAndView:
- 返回模型视图对象(若要返回 ModelAndView,则处理器方法中需要定义 ModelAndView 对象)
- 使用场景:需要跳转到其它资源,且又要在跳转的资源间传递数据
6. 拦截器和过滤器异同
-
区别:
- 实现机制不同:拦截器是基于Java的反射机制的,而过滤器是基于函数回调
- 依赖对象不同:拦截器依赖于Spring/SpringMVC框架,过滤器依赖于servlet容器
- 拦截范围不同:拦截器只能对action请求起作用,而过滤器则可以对几乎所有的请求起作用
- 使用资源不同:拦截器也是Spring中的一个组件,因此能够使用Spring中的任何资源、对象,通过IoC注入拦截器即可;而Filter则不能
- 作用范围不同:Filter只在Servlet前后起作用,而拦截器能深入到方法前后/异常抛出前后等(优先使用拦截器)
- 生命周期不同:在action的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次
-
相同:
- 都是AOP思想的体现
- 都能实现权限检查、日志记录等功能