Spring Boot
中的Controller
是对Java Web
中的Servlet
进行封装处理.等同于Struts 2
中的Action
.
在对Conroller
的处理上,主要分为
- 过滤器(Filter)
- 拦截器(Interceptor)
- 监听器(Listener)
- Spring Boot
提供的其他工具类.
功能上, 过滤器
,拦截器
,监听器
所能做的功能,彼此都能相互替代.而仅仅以设计模式的角度分析:
- 过滤器: 将请求中符合要求的东西挑选出来.
- 拦截器: 干涉流程的进展, 甚至终止它进行
- 监听器: 获得请求中的详细信息,但不干预这个请求.
过滤器(Filter)
基本过滤器
过滤器的顶级接口为:javax.servlet.Filter
, 通过实现这个接口可以创建一个最基本的Filter Bean
.然后通过@WebFilter
将这个Filter Bean
加入过滤器列表. 这是最基本的过滤器的实现.
@Configuration
@WebFilter
public class MyFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("MyFilter init");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("MyFilter doFilter");
}
@Override
public void destroy() {
System.out.println("MyFilter destroy");
}
}
其他过滤器实现类
OncePerRequestFilter
这个过滤器的实现类,可以保证每次请求,只调用一次该过滤器.
为了兼容各种不同的运行环境和版本,Filter
继承OncePerRequestFilter
是一个比较稳妥的选择。
因为Servlet不同版本的表现不同.在servlet-2.3中,Filter会过滤一切请求,包括服务器内部使用forward转发请求.
到了servlet-2.4中Filter默认下只拦截外部提交的请求,forward和include这些内部转发都不会被过滤,但是有时候我们需要 forward的时候也用到Filter.
配置过滤器列表
通过注解配置过滤器
@WebFilter
在Filter Bean
添加@WebFilter
即可将该Filter
加入过滤器列表
属性 | 类型 | 是否必须 | 说明 |
---|---|---|---|
filterName | String | 否 | 过滤器名, 默认为类名 |
urlPatterns | String[] | 否 | 过滤地址匹配式, 默认 /* |
未实际使用过 | |||
asyncSupported | boolean | 否 | 指定Filter是否支持异步模式 默认false |
dispatcherTypes | DispatcherType[] | 否 | 指定Filter对哪种方式的请求进行过滤。 支持的属性:ASYNC、ERROR、FORWARD、INCLUDE、REQUEST; 默认过滤所有方式的请求 |
initParams | WebInitParam[] | 否 | 配置参数 |
displayName | String | 否 | Filter显示名 |
servletNames | String[] | 否 | 指定对哪些Servlet进行过滤 |
- @Order
在Filter Bean
添加@Order
可配置Filter的顺序
属性 | 说明 |
---|---|
value | Filter Bean 顺序,值越小越靠前 |
拦截器(Interceptor)
实现HandlerInterceptor
类,可定义一个拦截器
public class MyInterceptor implements HandlerInterceptor {
/**
* 在实际的handler被执行前调用
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
return true;
}
/**
* 在handler被执行后调用
* @param request
* @param response
* @param handler HandlerMethod实现类
* @param modelAndView
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
}
/**
* 当request处理完成后调用
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
}
}
配置拦截器列表
在Spring Boot 2.0
中,WebMvcConfigurerAdapter
类被标记废弃,可使用WebMvcConfigurationSupport
添加拦截器列表
@Configuration
public class MyWebMvcConfigureAdapter extends WebMvcConfigurationSupport{
@Override
protected void addInterceptors(InterceptorRegistry registry) {
super.addInterceptors(registry);
registry.addInterceptor(new MyInterceptor())
.addPathPatterns("/api/**")
.excludePathPatterns("/api/login")
.order(1);
registry.addInterceptor(new MyInterceptor2())
.addPathPatterns("/api/**")
.excludePathPatterns("/api/login")
.order(10)
}
}
监听器(Listener)
监听器负责监听容器生命周期的创建与销毁,包括ServletContext
,SessionContext
, RequestContext
等.
Context
ServletContextListener
Servlet容器生命周期的监听器.
@Log4j2
@Configuration
@WebListener
public class MyListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
}
@Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
}
}
SessionContextListener
Session生命周期的监听器
@Log4j2
@Configuration
@WebListener
public class MyListener implements SessionListener {
@Override
public void sessionEvent(SessionEvent sessionEvent) {
Session session = sessionEvent.getSession();
}
}
RequestContextListener
Http Request 生命周期的监听器
@Log4j2
@Configuration
@WebListener
public class MyListener extends RequestContextListener {
@Override
public void requestInitialized(ServletRequestEvent requestEvent) {
super.requestInitialized(requestEvent);
}
@Override
public void requestDestroyed(ServletRequestEvent requestEvent) {
super.requestDestroyed(requestEvent);
}
}
配置
@WebListener
Sprring
提供的Controller控制
@ControllerAdvice
Spring 3.2提供的新注解,大体意思为Controller增强器.
可将一个类声明为Controller Advice
.
默认情况下,注解了ControllerAdvice
,作用域是全部声明了@RequestMapper
注解的Controller
类.
属性 | 类型 | 是否必须 | 说明 |
---|---|---|---|
value() | String[] | 否 | 作用域包地址 |
basePackages | String[] | 否 | 同上 |
basePackageClasses | Class[] | 否 | 作用域的类,实际测试为该类所在的包全部有效 |
assignableTypes | Class[] | 否 | |
annotations | Class[] | 否 |
Controller Advice
类可使用以下注解
- @ExceptionHandler
: 该注解声明的方法,将作为@ControllerAdvice
作用域中Controller
抛出异常时的处理方法.
- @ModelAttribute
: 该注解声明的方法返回值,可在@ControllerAdvice
作用域中作为Controller
的参数.
- @InitBinder
:
这三个注解可用于所有
Controller
类,当声明在Controller
类时,则仅对该Controller
方法有效
@ExceptionHandler
声明一个统一处理Controller抛出异常的方法
- 该注解声明一个处理异常的方法
@ExceptionHandler
public void exceptionHandler(HttpServletRequest request, HttpServletResponse response,Exception e) throws IOException {
// 异常处理逻辑
}
- 指明处理何种异常
@ExceptionHandler(value = ServletException.class)
public void exceptionHandler(HttpServletRequest request, HttpServletResponse response,ServletException e) throws IOException {
// 异常处理逻辑
}
参数
@ExceptionHandler
声明的方法,参数可以是以下任意类型
- HttpServletRequest
或ServletRequest
- HttpServletResponse
或ServletResponse
- Exception
: 可以是@ExceptionHandler.value
声明的异常类或其父类(或其公共父类)
返回值
- 空返回值
@ExceptionHandler
声明的方法,返回值可以为void
,由response对象
写入返回值
@ExceptionHandler
public void exceptionHandler(HttpServletRequest request, HttpServletResponse response,Exception e) throws IOException {
response.setStatus(500);
response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
response.getWriter().write(e.getMessage());
}
- 根据注解定义返回值
@ResponseBody
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
@ExceptionHandler(value = Exception.class)
public MyResult exceptionHandler(Exception e) throws IOException {
// 异常处理逻辑
return new MyResult(e.getMessage());
}
- 返回
ResponseEntity<T>
对象
可通过自定义ResponseEntity
对象对返回值进行设置
@ExceptionHandler(Exception.class)
public ResponseEntity<MyError> handlerException(Exception e) {
log.error("发生异常:{}", e);
ResponseEntity<MyError> responseEntity = ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(new MyError("A01",e.getMessage()));
return responseEntity;
}
@ModelAttribute
@ModelAttribute
声明的方法,将为ControllerAdvice
作用于下的所有Controller
添加通用对象.
@ModelAttribute
public MyResult newUser(){
return new MyResult("1111");
}
@GetMapping("/1")
public String say(MyResult myResult){
System.out.println(myResult);
return myResult.getMessage();
}
@InitBinder
自定义参数解析 – HandlerMethodArgumentResolver
类
public interface HandlerMethodArgumentResolver {
/**
* 是否执行resolveArgument
* @param methodParameter
* @return
*/
boolean supportsParameter(MethodParameter var1);
/**
* 读取request并取得参数.
* 返回的参数将会创配到同Class下的Controller方法参数中
*
* @param methodParameter
* @param modelAndViewContainer
* @param nativeWebRequest
* @param webDataBinderFactory
* @return
* @throws Exception
*/
@Nullable
Object resolveArgument(MethodParameter var1, @Nullable ModelAndViewContainer var2, NativeWebRequest var3, @Nullable WebDataBinderFactory var4) throws Exception;
}
HandlerMethodArgumentResolver
的实现类,不是通过Spring Bean
生效,而是要通过WebMvcConfigurationSupport
类进行配置.
@Configuration
public class MyWebMvcConfigurationSupport extends WebMvcConfigurationSupport {
@Override
protected void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
super.addArgumentResolvers(argumentResolvers);
argumentResolvers.add(new MyHandlerMethodArgumentResolver());
}
}
HandlerMethodArgumentResolver
与@ModelAttribute
HandlerMethodArgumentResolver
与@ModelAttribute
都可以对Controller
的请求数据进行装配.而他们两者之间的区别在于:
1. HandlerMethodArgumentResolver
可获得MethodParameter
对象.再加上Request对象
,可对请求进行更加细粒化的判断.所以一般用于特例性的自定义参数装配.
2. @ModelAttribute
方法中只能取得Request对象
,他的作用域是基于ControllerAdvice
或当前Controller
的.所以一般用于全局或通用参数的自定义装配.
自定义返回值处理 – HandlerMethodReturnValueHandler
类
public interface HandlerMethodReturnValueHandler {
/**
* 是否执行handleReturnValue
* @param MethodParameter
* @return
*/
boolean supportsReturnType(MethodParameter var1);
/**
*
*/
void handleReturnValue(@Nullable Object var1, MethodParameter var2, ModelAndViewContainer var3, NativeWebRequest var4) throws Exception;
}
在handleReturnValue方法体中可用的方法:
//该方法执行后不执行后续HandlerMethodReturnValueHandler类方法
modelAndViewContainer.setRequestHandled(true);
//取得Request
HttpServletRequest request = nativeWebRequest.getNativeRequest(HttpServletRequest.class);
//取得Response
HttpServletResponse response = nativeWebRequest.getNativeResponse(HttpServletResponse.class);
- 基本用法同上
- 创建了
HandlerMethodReturnValueHandler
类后,也需要将其注册.可通过WebMvcConfigurationSupport.addReturnValueHandlers
方法注册. - 在
Spring MVC
中,已注册了许多Handler.而自定义返回值处理,与自定义参数装配不同的是:当HandlerMethodReturnValueHandler
列表中已有符合该请求的返回值处理器,处理返回值后将不再查找排在后面的返回值处理器.所以注册HandlerMethodReturnValueHandler
还需要考虑列表顺序. - 处理JSON数据返回值,需要将其加入在
RequestResponseBodyMethodProcessor
返回其之前.