2013-10-05 65 views
2

我對Spring MVC有一個問題,如下所示:我使用JSR 303驗證以確保bean的屬性(請參閱PasswordInfo下面)既不爲空也不爲空在使用JSR 303處理空值的Spring MVC控制器中驗證問題

我是還檢查業務邏輯規則,即兩個密碼相同

問題是如果其中一個字符串字段(currentPassword和newPassword)爲空,它仍然被控制器傳遞給服務層以檢查業務邏輯規則,當然還會引發IllegalArgumentException!

這裏是PasswordInfo豆:

@RooEquals 
@RooJavaBean 
public class PasswordInfo { 

    @NotNull(groups = { ValidationGroups.PasswordModification.class }) 
    @NotEmpty(groups = { ValidationGroups.PasswordModification.class }) 
    private String currentPassword; 

    @NotNull(groups = { ValidationGroups.PasswordModification.class, ValidationGroups.PasswordReset.class }) 
    @NotEmpty(groups = { ValidationGroups.PasswordModification.class, ValidationGroups.PasswordReset.class })  
    @Size(min = 6, groups = { ValidationGroups.PasswordModification.class, ValidationGroups.PasswordReset.class }) 
    private String newPassword; 
... 

下面是相關控制方法:

@RequestMapping(value = "/preference/password", method = RequestMethod.POST, produces = "text/html") 
    public String modifyPassword(@ModelAttribute @Validated({ ValidationGroups.PasswordModification.class }) PasswordInfo passwordInfo, 
      BindingResult bindingResult, Model model, @CurrentMember Member member) { 
     if (!preferenceService.passwordsMatch(member.getPassword(), passwordInfo.getCurrentPassword())) { 
      bindingResult.rejectValue("currentPassword", "controller.preference.wrong_current_password"); 
     } 

     if (bindingResult.hasErrors()) { 
      model.addAttribute("passwordInfo", passwordInfo); 
      return "preference/password"; 
     } 

     preferenceService.modifyPassword(member, passwordInfo.getNewPassword()); 
     return "redirect:/preference/password"; 
    } 

下面是相關的服務層方法:

@Override 
    public boolean passwordsMatch(String encrypted, String plain) { 
     if (encrypted == null || encrypted.isEmpty() || plain == null || plain.isEmpty()) { 
      throw new IllegalArgumentException("One argument is null or empty"); 
     } 
     return passwordEncoder.matches(plain, encrypted); 
    } 

我的關注是要避免放置另一個綁定爲了避免重複自己

if (bindingResult.hasErrors()) { 
     model.addAttribute("passwordInfo", passwordInfo); 
     return "preference/password"; 
    } 

...業務邏輯校驗前...

任何人都可以請建議一個乾淨的解決了這個問題:Results.hasErrors阻止如?

回答

0

我不會按照你整個例子,說實話,我不完全理解你的問題,但我想知道的事情之一就是你爲什麼不使用Bean驗證,以及輸入密碼匹配約束?你可以寫一個自定義的類約束PasswordInfo

+0

哈代您好!實際上,這個問題與Spring MVC相比,更多地與JSR 303相關 - 儘管我在文章中添加了「bean-validation」標籤。基本上,我正在尋找一種乾淨的方式,以避免在自定義驗證與JSR 303驗證混合時重複'if(bindingResult.hasErrors())'塊。你看到了這個觀點嗎? – balteo

2

這裏的問題是,由於您提供了一個BindingResult作爲參數,Spring MVC期待您處理控制器方法中的驗證問題。它不會完全拒絕請求(即阻止呼叫您的控制器方法並拋出異常)。您可能只需重構您的方法即可獲得期望的結果:

@RequestMapping(value = "/preference/password", method = RequestMethod.POST, produces = "text/html") 
public String modifyPassword(@ModelAttribute @Validated({ ValidationGroups.PasswordModification.class }) PasswordInfo passwordInfo, 
          BindingResult bindingResult, Model model, @CurrentMember Member member) { 
    String view = "preference/password"; 
    if (!bindingResult.hasErrors()) { 
     if (preferenceService.passwordsMatch(member.getPassword(), passwordInfo.getCurrentPassword())) { 
      preferenceService.modifyPassword(member, passwordInfo.getNewPassword()); 
      view = "redirect:/preference/password"; 
     } else { 
      bindingResult.rejectValue("currentPassword", "controller.preference.wrong_current_password"); 
     } 
    } 
    // NOTE: I have removed the call to model.addAttribute("passwordInfo", passwordInfo) because it should already exist in the model, no? 
    return view; 
} 
+0

謝謝。你提供的代碼實際上是一個不錯的主意。儘管如此,我真的很想知道Spring MVC最好的(和已經建立的)做法:使用與你的代碼類似的代碼(它工作的很好,但是更難讀取和測試 - 嵌套的ifs),或者繼續放鬆服務層檢查:保留「空」檢查,但刪除「isEmpty」檢查... – balteo

+0

您對我最後一條評論的看法是什麼? – balteo

+0

我不認爲真的有一個「最好」或「建立」的方式來構建你的邏輯......至少不是從Spring MVC的角度來看。我會保持你的驗證,當然,因爲這就是它的目的:驗證。 – MattSenter