2016-06-13 127 views
1

對於同一個問題,我有兩種解決方案,但我不確定哪種解決方案最適合長期使用。@RequestBody與Spring中的HandlerMethodArgumentResolver

溶液1:

控制器是:

@RequestMapping(value = "/skill/leatherworking/curing/start", method = RequestMethod.POST) 
public Response startCuring(final UserEntity userEntity, @RequestBody @Valid final CuringCreateRequest curingCreateRequest) { 
    final CuringResult result = curingService.cure(userEntity, recipeDefinitionCache.getDefinition(curingCreateRequest.getRecipeId())); 
    ... 
} 

和域目的是:

public class CuringCreateRequest { 

    @Min(1) 
    private int recipeId; 

    ... 
} 

溶液2:

控制器是:

@RequestMapping(value = "/skill/leatherworking/curing/start", method = RequestMethod.POST) 
public Response startCuring(final UserEntity userEntity, @Valid final CuringCreateRequest curingCreateRequest) { 
    final CuringResult result = curingService.cure(userEntity, curingCreateRequest.getRecipe()); 
    ... 
} 

在這裏,我們也有一個HandlerMethodArgumentResolver:

public class RequestContextHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver { 

    /** 
    * {@inheritDoc} 
    */ 
    @Override 
    public boolean supportsParameter(final MethodParameter parameter) { 
     return parameter.getParameterType().equals(CuringCreateRequest.class); 
    } 

    /** 
    * {@inheritDoc} 
    */ 
    @Override 
    public Object resolveArgument(final MethodParameter parameter, final ModelAndViewContainer mavContainer, final NativeWebRequest webRequest, 
     final WebDataBinderFactory binderFactory) throws Exception { 
     ... //Manually resolve the argument via JsonMapper and RecipeDefinitionCache. This way we can create an immutable class and that's a bonus too. 
    } 
} 

和域對象是:

public class CuringCreateRequest { 

    @NotNull 
    private RecipeDefinition recipe; 

    ... 
} 

哪種方案更好地在長期使用?特別是在一箇中型或大型項目中?我更喜歡解決方案2,因爲它的清潔度和控制器的響應性較低,但並不完全確定它的優點足以滿足爲每個不同參數創建另一個類的麻煩。特別是@RequestBody可以在2秒內解決問題。

+1

爲什麼你不能用解決方案1創建一個不可變的對象。使用直接字段訪問而不是屬性訪問和presto。您不希望爲您需要綁定的每個類都推出自己的實現,請使用該框架來獲得您的優勢。 –

+0

@ M.Deinum主要原因爲什麼我會使用HandlerMethodArgumentResolver,因爲我可以解析解析器中的配方而不是控制器中的配方。這樣控制器甚至不應該知道recipeDefinitionCache。 (我儘量避免使用控制器。) –

+0

使用來自Jackson的自定義(De)串行器(假設您使用該串行器)來應用該功能。此外,爲什麼控制器應該知道,您可以隨時將該行移至服務器(應該放在第一位的地方)以執行查找。 –

回答

1

我會推薦使用選項2.您可以增強此功能的一種方法是在您的對象的setter方法中添加編程驗證方法,並在實現的HandlerMethodArgumentResolver中調用setter方法。

例如像

public class Foo { 
    private String bar; 
    ... 
    public void setBar (String bar) { 
     //disallow special characters 
     if (!StringUtils.isAlphanumeric(bar) 
      this.bar = null; 
     else 
      this.bar = bar; 
    } 
} 

然後在您的自定義HandlerMethodArgumentResolver使用說setter方法:

public class CustomFooHandlerMethodArgumentResolver extends HandlerMethodArgumentResolver { 
    @Override 
    public boolean supportsParameter (MethodParameter methodParameter) { 
     return methodParameter.getParameterType().equals(Foo.class); 
    } 

    @Override 
    public Object resolveArgument (MethodParameter methodParam, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) { 

     Foo myFoo = new Foo(); 
     myFoo.setBar(webRequest.getParameter("bar")); 
     ... 
     return myFoo; 
    } 
} 

有了這種實現的,你只需要驗證(setter方法)的一箇中心點,並可以防止非法值在端點和整個程序中設置字段。

另一個想法是,你可以在二傳手不是您可以與註釋,其中包括製造額外的方法添加更加複雜的驗證邏輯調用來處理不允許值(或額外的方法調用來獲取默認值等)

底線,沒有正確的方式,取決於項目的範圍,但您可能可以像選擇2一樣嚴格,而選擇1則略有限制(但運行速度更快)。

+0

謝謝,我有同樣的想法。 –

相關問題