Spring MVC 面试题
Spring MVC 面试题
- Spring MVC 面试题
- 简单介绍一下 Spring MVC 框架
- Spring MVC 有什么优点?
- 描述一下 Spring MVC 的工作流程
- 简单介绍 Spring MVC 的核心组件
- @Controller 注解有什么用?
- @RequestMapping 注解有什么用?
- @RestController 和 @Controller 有什么区别?
- @RequestMapping 和 @GetMapping 注解的不同之处在哪里?
- @RequestParam 和 @PathVariable 两个注解的区别
- 返回 JSON 格式使用什么注解?
- 介绍一下 Spring MVC 中的 WebApplicationContext ?
- Spring MVC 和 Struts2 的异同?
- 介绍下 Spring MVC 拦截器?
- Spring MVC 的拦截器和 Filter 过滤器有什么差别?
- REST 面试题
简单介绍一下 Spring MVC 框架
在早期 Java Web 的开发中,统一把显示层、控制层、显示层的操作全部交给 JSP 或者 Java Bean 来进行处理,存在一定的弊端,例如:JSP 和 Java Bean 之间严重耦合、开发效率低等弊端。
Spring MVC 是 Spring 体系中的一员,提供“模型-视图-控制器”(Model-View-Controller)架构和随时可用的组件,用于开发灵活且松散耦合的 Web 应用程序。
MVC 模式有助于分离应用程序的不同方面,如输入逻辑,业务逻辑和 UI 逻辑,同时在所有这些元素之间提供松散耦合。
Spring MVC 有什么优点?
- 使用真的非常方便,无论是添加 HTTP 请求方法映射的方法,还是不同数据格式的响应。
- 提供拦截器机制,可以方便的对请求进行拦截处理。
- 提供异常机制,可以方便的对异常做统一处理。
- 可以任意使用各种视图技术,而不仅仅局限于 JSP ,例如 Freemarker、Thymeleaf 等等。
描述一下 Spring MVC 的工作流程
Spring MVC 也是基于 Servlet 来处理请求的,主要通过 DispatcherServlet 这个 Servlet 来处理请求,处理过程需要通过九大组件来完成,先看到下面这个流程图:
Spring MVC 处理请求的流程大致如上图所示
- 用户的浏览器发送一个请求,这个请求经过互联网到达了我们的服务器。Servlet 容器首先接待了这个请求,并将该请求委托给
DispatcherServlet
进行处理。 DispatcherServlet
将该请求传给了处理器映射组件HandlerMapping
,并获取到适合该请求的 HandlerExecutionChain 拦截器和处理器对象。- 在获取到处理器后,
DispatcherServlet
还不能直接调用处理器的逻辑,需要进行对处理器进行适配。处理器适配成功后,DispatcherServlet
通过处理器适配器HandlerAdapter
调用处理器的逻辑,并获取返回值ModelAndView
对象。 - 之后,
DispatcherServlet
需要根据 ModelAndView 解析视图。解析视图的工作由ViewResolver
完成,若能解析成功,ViewResolver
会返回相应的 View 视图对象。 - 在获取到具体的 View 对象后,最后一步要做的事情就是由 View 渲染视图,并将渲染结果返回给用户。
以上就是 Spring MVC 处理请求的全过程,上面的流程进行了一定的简化,主要涉及到最核心的组件,还有许多其他组件没有表现出来,不过这并不影响大家对主过程的理解。
总结:客户端发起请求后,最终会交由 DispatcherServlet 来处理,它会通过你的 URI 找到对应的方法,从请求中解析参数,然后通过反射机制调用该方法,将方法的执行结果设置到响应中,如果存在对应的 View 对象,则进行页面渲染,实际上就是将请求转发到指定的 URL
简单介绍 Spring MVC 的核心组件
那么接下来就简单介绍一下 DispatcherServlet
和九大组件(按使用顺序排序的):
组件 | 说明 |
---|---|
DispatcherServlet | Spring MVC 的核心组件,是请求的入口,负责协调各个组件工作 |
MultipartResolver | 内容类型( Content-Type )为 multipart/* 的请求的解析器,例如解析处理文件上传的请求,便于获取参数信息以及上传的文件 |
HandlerMapping | 请求的处理器匹配器,负责为请求找到合适的 HandlerExecutionChain 处理器执行链,包含处理器(handler )和拦截器们(interceptors ) |
HandlerAdapter | 处理器的适配器。因为处理器 handler 的类型是 Object 类型,需要有一个调用者来实现 handler 是怎么被执行。Spring 中的处理器的实现多变,比如用户处理器可以实现 Controller 接口、HttpRequestHandler 接口,也可以用 @RequestMapping 注解将方法作为一个处理器等,这就导致 Spring MVC 无法直接执行这个处理器。所以这里需要一个处理器适配器,由它去执行处理器 |
HandlerExceptionResolver | 处理器异常解析器,将处理器( handler )执行时发生的异常,解析( 转换 )成对应的 ModelAndView 结果 |
RequestToViewNameTranslator | 视图名称转换器,用于解析出请求的默认视图名 |
LocaleResolver | 本地化(国际化)解析器,提供国际化支持 |
ThemeResolver | 主题解析器,提供可设置应用整体样式风格的支持 |
ViewResolver | 视图解析器,根据视图名和国际化,获得最终的视图 View 对象 |
FlashMapManager | FlashMap 管理器,负责重定向时,保存参数至临时存储(默认 Session) |
Spring MVC 对各个组件的职责划分的比较清晰。DispatcherServlet
负责协调,其他组件则各自做分内之事,互不干扰。
@Controller 注解有什么用?
@Controller
注解标记一个类为 Spring Web MVC 控制器 Controller。Spring MVC 会将扫描到该注解的类,然后扫描这个类下面带有 @RequestMapping
注解的方法,根据注解信息,为这个方法生成一个对应的处理器对象,在上面的 HandlerMapping 和 HandlerAdapter组件中讲到过。
当然,除了添加 @Controller
注解这种方式以外,你还可以实现 Spring MVC 提供的 Controller
或者 HttpRequestHandler
接口,对应的实现类也会被作为一个处理器对象
@RequestMapping 注解有什么用?
@RequestMapping
注解,在上面已经讲过了,配置处理器的 HTTP 请求方法,URI等信息,这样才能将请求和方法进行映射。这个注解可以作用于类上面,也可以作用于方法上面,在类上面一般是配置这个控制器的 URI 前缀
@RestController 和 @Controller 有什么区别?
@RestController
注解,在 @Controller
基础上,增加了 @ResponseBody
注解,更加适合目前前后端分离的架构下,提供 Restful API ,返回例如 JSON 数据格式。当然,返回什么样的数据格式,根据客户端的 ACCEPT
请求头来决定。
@RequestMapping 和 @GetMapping 注解的不同之处在哪里?
-
@RequestMapping
:可注解在类和方法上;@GetMapping
仅可注册在方法上 -
@RequestMapping
:可进行 GET、POST、PUT、DELETE 等请求方法;@GetMapping
是@RequestMapping
的 GET 请求方法的特例,目的是为了提高清晰度。
@RequestParam 和 @PathVariable 两个注解的区别
两个注解都用于方法参数,获取参数值的方式不同,@RequestParam
注解的参数从请求携带的参数中获取,而 @PathVariable
注解从请求的 URI 中获取
返回 JSON 格式使用什么注解?
可以使用 @ResponseBody
注解,或者使用包含 @ResponseBody
注解的 @RestController
注解。
当然,还是需要配合相应的支持 JSON 格式化的 HttpMessageConverter 实现类。例如,Spring MVC 默认使用 MappingJackson2HttpMessageConverter
介绍一下 Spring MVC 中的 WebApplicationContext ?
WebApplicationContext 是实现 ApplicationContext 接口的子类,专门为 WEB 应用准备的
- 它允许从相对于 Web 根目录的路径中加载配置文件,完成初始化 Spring MVC 组件的工作。
- 从 WebApplicationContext 中,可以获取 ServletContext 引用,整个 Web 应用上下文对象将作为属性放置在 ServletContext 中,以便 Web 应用环境可以访问 Spring 上下文。
Spring MVC 和 Struts2 的异同?
入口不同
- Spring MVC 的入门是一个 Servlet 控制器。
- Struts2 入门是一个 Filter 过滤器。
配置映射不同,
- Spring MVC 是基于方法开发,传递参数是通过方法形参,一般设置为单例。
- Struts2 是基于类开发,传递参数是通过类的属性,只能设计为多例。
视图不同
- Spring MVC 通过参数解析器是将 Request 对象内容进行解析成方法形参,将响应数据和页面封装成 ModelAndView 对象,最后又将模型数据通过 Request 对象传输到页面。其中,如果视图使用 JSP 时,默认使用 JSTL 。
- Struts2 采用值栈存储请求和响应的数据,通过 OGNL 存取数据。
介绍下 Spring MVC 拦截器?
Spring MVC 拦截器有三个增强处理的地方:
- 前置处理:在执行方法前执行,全部成功执行才会往下执行方法
- 后置处理:在成功执行方法后执行,倒序
- 已完成处理:不管方法是否成功执行都会执行,不过只会执行前置处理成功的拦截器,倒序
可以通过拦截器进行权限检验,参数校验,记录日志等操作
Spring MVC 的拦截器和 Filter 过滤器有什么差别?
有以下几点:
- 功能相同:拦截器和 Filter 都能实现相应的功能,谁也不比谁强
- 容器不同:拦截器构建在 Spring MVC 体系中;Filter 构建在 Servlet 容器之上
- 使用便利性不同:拦截器提供了三个方法,分别在不同的时机执行;过滤器仅提供一个方法,当然也能实现拦截器的执行时机的效果,就是麻烦一些
一般拓展性好的框架,都会提供相应的拦截器或过滤器机制,方便的开发人员做一些拓展
REST 面试题
REST 代表着什么?
REST 代表着抽象状态转移,它是根据 HTTP 协议从客户端发送数据到服务端,例如:服务端的一本书可以以 XML 或 JSON 格式传递到客户端
然而,假如你不熟悉REST,我建议你先看看 REST API design and development 这篇文章来更好的了解它。也可以阅读知乎上的 《怎样用通俗的语言解释 REST,以及 RESTful?》 讨论
资源是什么?
资源是指数据在 REST 架构中如何显示的。将实体作为资源公开 ,它允许客户端通过 HTTP 方法如:GET, POST,PUT, DELETE 等读,写,修改和创建资源
什么是安全的 REST 操作?
REST 接口是通过 HTTP 方法完成操作
- 一些 HTTP 操作是安全的,如 GET 和 HEAD ,它不能在服务端修改资源
- 换句话说,PUT、POST 和 DELETE 是不安全的,因为他们能修改服务端的资源
所以,是否安全的界限,在于是否修改服务端的资源
什么是幂等操作? 为什么幂等操作如此重要?
有一些 HTTP 方法,如:GET,不管你使用多少次它都能产生相同的结果,在没有任何一边影响的情况下,发送多个 GET 请求到相同的URI 将会产生相同的响应结果。因此,这就是所谓幂等操作
换句话说,POST方法不是幂等操作 ,因为如果发送多个 POST 请求,它将在服务端创建不同的资源。但是,假如你用 PUT 更新资源,它将是幂等操作。
甚至多个 PUT 请求被用来更新服务端资源,将得到相同的结果
REST 是可扩展的或说是协同的吗?
是的,REST 是可扩展的和可协作的。它既不托管一种特定的技术选择,也不定在客户端或者服务端。你可以用 Java, C++, Python, 或 JavaScript 来创建 RESTful Web 服务,也可以在客户端使用它们。
我建议你读一本关于REST接口的书来了解更多,如:RESTful Web Services 。
所以这里的“可拓展”、“协同”对应到我们平时常说的,“跨语言”、“语言无关”
REST 用哪种 HTTP 方法呢?
REST 能用任何的 HTTP 方法,但是,最受欢迎的是:
- 用 GET 来检索服务端资源
- 用 POST 来创建服务端资源
- 用 PUT 来更新服务端资源
- 用 DELETE 来删除服务端资源
恰好,这四个操作,对上我们日常逻辑的 CRUD 操作
删除的 HTTP 状态返回码是什么 ?
在删除成功之后,您的 REST API 应该返回什么状态代码,并没有严格的规则。它可以返回 200 或 204 没有内容
- 一般来说,如果删除操作成功,响应主体为空,返回 204
- 如果删除请求成功且响应体不是空的,则返回 200
REST API 是无状态的吗?
是的,REST API 应该是无状态的,因为它是基于 HTTP 的,它也是无状态的
REST API 中的请求应该包含处理它所需的所有细节。它不应该依赖于以前或下一个请求或服务器端维护的一些数据,例如会话
REST 规范为使其无状态设置了一个约束,在设计 REST API 时,你应该记住这一点
REST安全吗? 你能做什么来保护它?
安全是一个宽泛的术语。它可能意味着消息的安全性,这是通过认证和授权提供的加密或访问限制提供的
REST 通常不是安全的,需要开发人员自己实现安全机制
参考文章:芋道源码《精尽 Spring MVC 源码分析》