java.lang.IllegalStateException: Invalid target for Validator [idv.neil.model.ProductValidator@5ddffa]: idv.neil.web.Pager@11ba4a2 at org.springframework.validation.DataBinder.setValidator(DataBinder.java:498) at idv.neil.web.ctrl.ProductController.formBackingObject(ProductController.java:100) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at com.google.appengine.tools.development.agent.runtime.Runtime.invoke(Runtime.java:104)Spring MVC 3 以後可以使用 Annotation 將 MultiActionController 與 SimpleFormController 做在同一隻 controller:
@Controller
@RequestMapping("/product")
@SessionAttributes("cmd")
public class ProductController {
private static final Logger log = LoggerFactory.getLogger(ProductController.class);
private ProductService productService;
@Autowired
public void setProductService(ProductService productService) {
this.productService = productService;
}
@RequestMapping(method = RequestMethod.GET)
public String form(@RequestParam(required = false) Long id, Model model) {
Product cmd;
if (id == null) {
cmd = new Product();
}
else {
cmd = this.productService.getProduct(id);
}
model.addAttribute("cmd", cmd);
return "productForm";
}
@RequestMapping(method = RequestMethod.POST)
public String sync(@Valid @ModelAttribute("cmd") Product cmd,
BindingResult result) {
if (result.hasErrors()) {
return "productForm";
}
if (cmd.getId() == null) {
this.productService.addProduct(cmd);
}
else {
this.productService.updateProduct(cmd);
}
return "redirect:/product/list.do";
}
@RequestMapping("/list")
public ModelAndView list(HttpServletRequest request) {
ModelAndView mav = new ModelAndView("productList");
Pager pager = Pager.createPager(request,
this.productService.countProduct());
List<Product> list = this.productService.listProduct(
pager.getStart(), pager.getPageSize());
mav.addObject("list", list);
mav.addObject(Pager.PAGER, pager);
return mav;
}
@RequestMapping("/delete")
public String delete(@RequestParam("id") Long id) {
this.productService.deleteProduct(id);
return "redirect:/product/list.do";
}
@InitBinder
public void initBinder(WebDataBinder binder) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
dateFormat.setLenient(false);
binder.registerCustomEditor(Date.class, new CustomDateEditor(
dateFormat, false));
binder.registerCustomEditor(Text.class, new TextPropertyEditor());
binder.setValidator(new ProductValidator());
}
}在 @InitBinder 裡加入 binder.setValidator(new ProductValidator()) 之前,運作一切正常,加入後,在進入列表頁時就發生上述的錯誤。最後發現問題出現在 @InitBinder 預設會在該 @Controller 所有 request 進來時執行,此時若設有 Validator,則會針對 Model 裡的所有物件進行驗證,但有一些例外,可以在 ModelFactory.isBindingCandidate(...) 看到例外。
為避免這種情形,@InitBinder 有一個 value 參數供設定,一旦設定後,就只有 command 或 form 的 attribute name 以及 request parameter 裡有符合的名稱時,才會執行該 @InitBinder,就以上的範例來看,應該改為 @InitBinder("cmd") 就沒問題了,除非在 form 以外的 request model 裡放了該死的 cmd 屬性。
沒有留言:
張貼留言