概述
Controller是Spring MVC为我们提供的基础的控制器接口,和HttpServlet一样,接收request和response参数处理用户请求,并返回ModelAndView,从概念上可以类比Struts的Action。
Controller主要实现的如下功能:
- 接收并处理用户请求
- 调用业务方法
- 返回ModelAndView
基于Controller开发请求处理Handler的特点:
- 需要实现Controller接口
- 请求参数需从请求request中获取
- 请求处理Handler与Spring深度耦合
就目前项目开发,几乎不会使用此方式进行开发,除非维护一些历史项目。目前是基于注解进行开发,从Spring2.5及之后开始支持。编写本章内容主要是基于知识点的全面性来考虑,大家可以了解了解。
本系列文章是基于Spring5.0.5RELEASE。
接口Controller
Spring提供的Controller接口,定义了一个方法,作用就是处理用户请求,源码如下:
package org.springframework.web.servlet.mvc;
public interface Controller {
/**
*接收request和response参数,处理用户请求
*参数从request中获取
*方法返回ModelAndView,Model为模型数据,View为视图
*/
ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception;
}
Spring提供的实现类
Spring提供了如下实现:
AbstractController 控制浏览器缓存、支持的请求方法等等
ServletForwardingController 将Spring Handler接收的请求转发给一个Servlet去执行
ParameterizableViewController 参数化视图控制器,根据参数的逻辑视图名直接选择需要展示的视图
AbstractUrlViewController 根据请求URL路径直接转化为逻辑视图名的支持基类
UrlFilenameViewController 将请求URL路径转换为逻辑视图名并返回的实现类ServletWrappingController Servlet包装控制器
以上是Spring MVC为我们提供Controller接口的默认实现,下面我们接着分析这些实现类。
AbstractController
该抽象类继承WebContentGenerator并实现Controller接口,其中WebContentGenerator类用于浏览器缓存控制、自定义Controller支持的请求方法类型(默认支持:GET/HEAD/POST)等。
WebContentGenerator类的主要属性如下:
/** 支持的请求方法类型,默认支持:GET、HEAD、POST */
@Nullable
private Set<String> supportedMethods;
@Nullable
private String allowHeader;
/** 当前请求是否必须有session */
private boolean requireSession = false;
@Nullable
private CacheControl cacheControl;
/** 缓存过期时间,正数表示需要缓存,负数表示不做任何事情 */
private int cacheSeconds = -1;
@Nullable
private String[] varyByRequestHeaders;
/** 是否使用HTTP1.0协议过期响应头:如果true则会在响应头添加“Expires:”;需要配合cacheSeconds使用 */
private boolean useExpiresHeader = false;
/** 是否使用HTTP1.1协议的缓存控制响应头,如果true则会在响应头添加;需要配合cacheSeconds使用 */
private boolean useCacheControlHeader = true;
/** 是否使用HTTP 1.1协议的缓存控制响应头,如果true则会在响应头添加;需要配合cacheSeconds使用 */
private boolean useCacheControlNoStore = true;
AbstractController类源码如下:
/** 表示该控制器是否在执行时同步session,从而保证该会话的用户串行访问该控制器 */
private boolean synchronizeOnSession = false;
/**
*实现Controller接口的handleRequest方法
*/
@Override
@Nullable
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)
throws Exception {
if (HttpMethod.OPTIONS.matches(request.getMethod())) {
response.setHeader("Allow", getAllowHeader());
return null;
}
// 检查是否支持请求方法以及必须的session
checkRequest(request);
// 根据设置准备response
prepareResponse(response);
// 如果必要顺序执行handleRequestInternal方法
if (this.synchronizeOnSession) {
HttpSession session = request.getSession(false);
if (session != null) {
Object mutex = WebUtils.getSessionMutex(session);
synchronized (mutex) {
return handleRequestInternal(request, response);
}
}
}
return handleRequestInternal(request, response);
}
/**
* 需要子类实现的模板方法
*/
@Nullable
protected abstract ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response)
throws Exception;
实战
本章实战是通过继承AbstractController类编写用户请求handler,测试如下几点:
- 继承AbstractController抽象类,实现handlerRequestInternal方法处理用户请求
通过前几篇及上面的分析,SimpleControllerHandlerAdapter类可以适配实现了Controller接口的类,AbstractController实现了Controller接口的handleRequest方法,并预留了handleRequestInternal模板方法供子类实现,用户处理用户请求,根据这个思路,我们要使用SimpleControllerHandlerAdapter适配Controller时,只需继承AbstractController类并实现handleRequestInternal方法即可,具体源码如下:
自定义Controller源码:
/**
*继承AbstractController并实现handleRequestInternal方法
*/
public class HelloWorldController extends AbstractController {
/**
*通过response直接回写数据,也可通过ModelAndView指定逻辑视图并回写数据
*/
@Override
protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) throws Exception {
Writer writer = response.getWriter();
writer.write("hello AbstractController");
writer.flush();
return null;
}
}
配置文件配置如下:
<!-- 使用BeanNameUrlHandlerMapping映射器
可以不用配置,Spring MVC默认支持:BeanNameUrlHanderMapping、RequestMappingHandlerMapping
-->
<bean id="handlerMapping" class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
<!-- 指定Spring使用SimpleControllerHandlerAdapter适配器
可以不用配置,Spring MVC默认支持:HttpRequestHandlerAdapter、SimpleControllerHandlerAdapter、RequestMappingHandlerAdapter
-->
<bean id="handlerAdapter" class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
<!-- 配置Controller bean -->
<bean name="/helloWorldController" class="com.github.dalianghe.controller.HelloWorldController"/>
验证结果
代码编写完后,启动应用进行测试,AbstractController默认支持GET、HEAD、POST方法类型,我们使用Postman进行测试,GET请求结果如下:
HEAD、POST也能处理,但如果发起PUT请求则返回不支持方法类型,如下图:
- 指定请求方法类型
AbstractController默认支持GET、HEAD、POST三种请求类型,本例通过设置supportedMethods属性来设置支持的请求方法类型,代码如下:
配置文件配置如下:
<!-- 配置Controller bean -->
<bean name="/helloWorldController" class="com.github.dalianghe.controller.HelloWorldController">
<!-- 设置支持的请求方法类型,如下支持PUT、POST -->
<property name="supportedMethods">
<set>
<value>PUT</value>
<value>POST</value>
</set>
</property>
</bean>
验证结果
只需在Controller Bean修改supportMethods属性接口,测试PUT请求,结果如下:
- requireSession前置检查
当把requireSession属性设置为true时,访问Controller需检查有无session,如果没有将跑出HttpSessionRequiredException异常,代码如下:
配置文件配置如下:
<!-- 配置Controller bean -->
<bean name="/helloWorldController" class="com.github.dalianghe.controller.HelloWorldController">
<!-- 设置支持的请求方法类型,如下支持PUT、POST -->
<property name="supportedMethods">
<set>
<value>GET</value>
<value>POST</value>
</set>
</property>
<!-- 访问此处理器前检查session -->
<property name="requireSession" value="true"/>
</bean>
<!-- 增加一个处理器,用于获取session -->
<bean id="/helloWorld2Controller" class="com.github.dalianghe.controller.HelloWorld2Controller"/>
新增的HelloWorld2Controller与HelloWorldController代码基础上增加获取session的代码,如下:
request.getSession(true);
测试验证
首先验证没有session情况下,结果如下:
说明在访问到自定义Controller前检查session没有,抛出HttpSessionRequiredException异常
我们增加了一个新的controller用于设置创建session,此时我们访问一次后,再访问需要验证的session的请求,结果如下:
通过结果可见,测试能正常访问了。
总结
本章主要分析了Controller接口、AbstractController抽象类以及对自定义Controller的几个重要属性进行了测试,希望对大家有帮助,谢谢。
最后创建了qq群方便大家交流,可扫描加入,同时也可加我qq:276420284,共同学习、共同进步,谢谢!
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。