[英]Spring MVC @Controller to intercept own requests
想象我們有一個像這樣的控制器:
@RestController
@RequestMapping("/{parameter}")
public class MyController {
@ExceptionHandler(SomeException.class)
public Object handleSomeException() { /* handle */ }
@RequestMapping("/something")
public Object handleSomething(@PathVariable("parameter") String parameter) {
/* handle */
}
@RequestMapping("/somethingElse")
public Object handleSomethingElse(@PathVariable("parameter") String parameter) {
/* handle */
}
}
問題是,如何以類似於@ExceptionHandler
工作的方式為此特定控制器實現一些常見的pre \\\\ post-handling處理? 例如,我想在控制器中有一個方法,該方法先接收處理程序方法的請求,但僅接收對此特定控制器的請求。
我知道RequestBodyAdvice
和ResponseBodyAdvice
接口,但是想要控制器本地的東西。
作為使用示例-我想在每個處理程序之前對公用parameter
變量進行一些驗證。
上面所有遺漏的內容回答了如何為特定控制器注冊攔截器,可以通過以下方式完成:
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LocaleChangeInterceptor());
registry.addInterceptor(new ThemeChangeInterceptor()).addPathPatterns("/**").excludePathPatterns("/admin/**");
registry.addInterceptor(new SecurityInterceptor()).addPathPatterns("/secure/*");
}
}
在XML中,相同:
<mvc:interceptors>
<bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor"/>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<mvc:exclude-mapping path="/admin/**"/>
<bean class="org.springframework.web.servlet.theme.ThemeChangeInterceptor"/>
</mvc:interceptor>
<mvc:interceptor>
<mvc:mapping path="/secure/*"/>
<bean class="org.example.SecurityInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
您將需要編寫自己的HandlerInterceptor
。 您可以通過擴展HandlerInterceptorAdapter
輕松地做到這一點。 然后,您可以覆蓋preHandle()
和/或postHandle()
。
在
HandlerMapping
確定適當的處理程序對象之后,但在HandlerAdapter
調用處理程序之前,將調用preHandle()
。在
HandlerAdapter
實際調用處理程序之后,但在DispatcherServlet
呈現視圖之前,將調用postHandle()
。
您可以使用HttpServletRequest
的getRequestURI()
方法為preHandle()
不同處理程序添加邏輯。
例:
public class ValidationInterceptor extends HandlerInterceptorAdapter {
public static final String FOO_URL = "foo";
public static final String BAR_URL = "bar";
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
String uri = request.getRequestURI();
if (FOO_URL.equals(uri)) {
// for example - validation failed
response.sendRedirect("/to/some/url");
return false;
} else if (BAR_URL.equals(uri)) {
// for example - validation successful
}
return true;
}
}
然后在您的dispatcher-servlet.xml
注冊這個HandlerInterceptor
。
<mvc:interceptors>
<bean class="your.package.ValidationInterceptor"/>
</mvc:interceptors>
您可以將其配置為更多特定於URL。 參見Spring Reference的22.16.5攔截器部分。
盡管HandlerInterceptorAdapter
似乎是“正確”的解決方案,但它似乎並不是您想要的解決方案。
下面的代碼可能是您想要的解決方案(或者至少是您在問題中要求的解決方案)。
摘要:編寫您自己的preBlam
和postBlam
方法。
一些代碼:
@RestController
@RequestMapping("/{parameter}")
public class MyController
{
@ExceptionHandler(SomeException.class)
public Object handleSomeException()
{
/* handle */
}
@RequestMapping("/something")
public Object handleSomething(@PathVariable("parameter") String parameter)
{
preBlam(desired params here);
/* handle */
postBlam(desired params here);
}
@RequestMapping("/somethingElse")
public Object handleSomethingElse(@PathVariable("parameter") String parameter)
{
preBlam(desired params here);
/* handle */
postBlam(desired params here);
}
private blam preBlam(parameters)
{
// do initial blamish work
}
private blam postBlam(parameters)
{
// do post blamish work here
}
}
另一個選擇:使用AOP為受影響的方法設置前置和后置處理程序。 我不是AOP的大用戶,所以我不能只是舉個例子。
使用HandlerInterceptorAdapter
截獲控制器執行之前和之后,記錄執行時間的開始和結束,並將其保存到現有截獲的控制器的modelAndView中,以供以后顯示。
public class ExecuteTimeInterceptor extends HandlerInterceptorAdapter{
private static final Logger logger = Logger.getLogger(ExecuteTimeInterceptor.class);
//before the actual handler will be executed
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler)
throws Exception {
long startTime = System.currentTimeMillis();
request.setAttribute("startTime", startTime);
return true;
}
//after the handler is executed
public void postHandle(
HttpServletRequest request, HttpServletResponse response,
Object handler, ModelAndView modelAndView)
throws Exception {
long startTime = (Long)request.getAttribute("startTime");
long endTime = System.currentTimeMillis();
long executeTime = endTime - startTime;
//modified the exisitng modelAndView
modelAndView.addObject("executeTime",executeTime);
//log it
if(logger.isDebugEnabled()){
logger.debug("[" + handler + "] executeTime : " + executeTime + "ms");
}
}
其他一些示例-http: //www.mkyong.com/spring-mvc/spring-mvc-handler-interceptors-example/
當您想以通用方式處理path變量時,請考慮引入模型對象。 有了它,您可以驗證屬性(java bean驗證),還可以混合路徑變量和查詢參數(這里是一個非常簡單的示例,您甚至可以創建自定義驗證):
@Data
class SomeModel {
@NotEmpty
private String parameter;
}
在控制器中,您只需要將模型添加為參數:
@RequestMapping("/something")
public Object handleSomething(@Valid SomeModel model) {
/* handle using model.getParameter() */
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.