2014-01-14 15 views
3

給定一個彈簧MVC的控制器方法:如何在Spring MVC控制器方法中檢查未綁定的請求參數?

@RequestMapping(value = "/method") 
public void method(ParamModel params) { /*...*/ } 

與模型類:

public class ParamModel { public int param1; } 

以下兩個結果如預期的/所需的:

  • 請求與param1=1method完成成功。
  • 請求與param1=blahJBWEB000120: The request sent by the client was syntactically incorrect.

然而...

  • 如果請求與一個附加的參數(例如nonexistentparam=1)製成,沒有錯誤

如果包含任何不屬於此API的參數,是否有方法確保請求被驗證並被拒絕?

+0

我還沒有看到自己需要這樣做,我找不到任何直接解決它的文檔,但似乎您可能需要配置(或子類)容器的'RequestMappingHandlerAdapter'。 – chrylis

+2

如何區分無效的請求參數?請求參數未映射到控制器參數的事實並不意味着它是無效的請求參數,因爲可能有其他組件使用它,例如, servlet過濾器,或者它只是簡單地通過並在一個隱藏的領域再次呈現。 –

+0

@chrylis需要這樣做是由分離的客戶端/服務器開發驅動的。我正在研究可能會發生變化的服務器端API,如果例如參數被重命名或棄用(而不是默默忽略它們),客戶端請求會中斷。 –

回答

0

一個好的做法是Bean-Validation(JSR-303)。這裏是Document

保持簡單,你需要有這個在你的Spring配置:

<mvc:annotation-driven /> 

,你可以在你的代碼有這樣的:

@RequestMapping(value = "/method") 
public void method(@Valid ParamModel params, BindingResult result) { 
    if(result.hasErrors()) {...} 
    else {...} 
} 

public class ParamModel { 
    @SomeAnnotation // details see document 
    private int param1; 
} 
+2

雖然Bean Validation很有用,但它並不回答這個問題,這是如何讓額外HTTP參數引發Spring錯誤發送。將Bean驗證設置到模型對象後發生。 – chrylis

0

您可以使用過濾器來檢查對於無效參數爲

web.xml

<filter> 
    <filter-name>MyFilter</filter-name> 
    <filter-class>com.mypackage.filter.MyFilter</filter-class> 
</filter> 
<filter-mapping> 
    <filter-name>MyFilter</filter-name> 
    <url-pattern>/*</url-pattern> 
</filter-mapping> 

MyFilter類

import javax.servlet.Filter; 
public class MyFilter implements Filter { 

    public void destroy() { 
    } 

    public void doFilter(ServletRequest request, ServletResponse response, 
      FilterChain chain) throws IOException, ServletException { 
     String requestUrl = request.getParameter("param1"); 
    //here I am considering 'param1=1' as valid request rest of all are invalid 
      if(!requestUrl.equals("1")) { 
     logger.info("Invalid Request"); 
     //for invalid request redirect to error or login page 
     response.sendRedirect("/error"");   
    } else { 
     logger.info("Valid Request"); 
    } 
    } 

    public void init(FilterConfig filterConfig) throws ServletException { 
    }  

} 

希望這將解決您的問題

+2

這是一個通用的「做某事」的答案,完全沒有解決如何配置Spring以提高錯誤,如果有額外的參數沒有在模型類中定義。 – chrylis

+0

@chrylis請檢查我的更新 –

+0

重點是檢測是否有*額外*參數。 – chrylis

0

Spring的@RequestMapping採用 「PARAMS」 參數。

文檔:

映射請求的參數,縮小主映射。用於任何環境

相同格式:「myParam = myvalue的」風格 表達式序列,與請求僅當每個這樣的參數是 發現具有所述給定值進行映射。使用 「!=」運算符可以取消表達式,如在「myParam!= myValue」中所述。 「myParam」風格表達式 也被支持,這些參數必須存在於 請求中(允許有任何值)。最後,「!myParam」風格 表達式指示指定的參數是不應該 存在於該請求。

另一種可能是使用PathVariable(總是必需)或RequestParam與需要=真。

參數

更新:

你可以通過繼承RequestMappingHandlerMapping和壓倒一切的getCustomMethodCondition創建您自己的請求映射條件/ getCustomTypeCondition。

但是XML配置<mvc:annotation-driven/>無法使用,因爲它也會聲明此Bean,並且最終會生成2個處理程序映射。 詳情請看Adding custom RequestCondition's in Spring mvc 3.1

+1

他想拒絕*所有*不匹配的參數。映射條件允許您指定阻止匹配的參數。 – chrylis

0

最明顯的,枯燥和非Springish選項是使用:

@RequestParam Map<String,String> allRequestParams 

...,並檢查自己的參數列表。當然,它需要您解析(以整數等)並手動驗證值,而不是使用DTO和/或javax.validation註釋。

完整的示例(需要映射InvalidParamsException到一個狀態碼):

@GetMapping("/my_strict_api") 
public void myStrictApi(@RequestParam Map<String,String> allRequestParams) { 
    Set<String> allowed = new HashSet<>(Arrays.asList("cat", "dog")); 
    if (!allowed.containsAll(allRequestParams.keySet())) { 
    throw new InvalidParamsException("We only accept: " + allowed.toString()); 
    } 
    // You should also validate the parameter values before using them 
} 
0

有重寫控制器請求方法的調用的方式:

@Bean 
public WebMvcRegistrations mvcRegistrations() { 
    return new WebMvcRegistrationsAdapter() { 
    @Override 
    public RequestMappingHandlerAdapter getRequestMappingHandlerAdapter() { 
     return new RequestMappingHandlerAdapter() { 
     private ParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer(); 

     @Override 
     protected ServletInvocableHandlerMethod createInvocableHandlerMethod(HandlerMethod handlerMethod) { 
      return new ServletInvocableHandlerMethod(handlerMethod) { 
      Set<String> boundParametersNames = Stream.of(getMethodParameters()) 
       .map(methodParameter -> { 
        methodParameter.initParameterNameDiscovery(parameterNameDiscoverer); 
        return methodParameter.getParameterName(); 
       }) 
       .collect(Collectors.toSet()); 

      @Override 
      public Object invokeForRequest(NativeWebRequest request, 
              ModelAndViewContainer mavContainer, 
              Object... providedArgs) throws Exception { 
       for (Iterator<String> iterator = request.getParameterNames(); iterator.hasNext();) { 
       String parameterName = iterator.next(); 
       if (!boundParametersNames.contains(parameterName)) { 
        return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(null); 
       } 
       } 
       return super.invokeForRequest(request, mavContainer, providedArgs); 
      } 
      }; 
     } 
     }; 
    } 
    }; 
} 

在InvocableHandlerMethod兩個請求參數和方法參數可以很容易地訪問和驗證。

相關問題