2

我的问题归结为:你如何让 spring mvc@ModelAttribute在它已经被填充后调用?

详细地说,我正在使用 Ashish Sarin 的Portlets in Action 的第 8 章中的 BookCatalog 示例(这真的很好),我遇到了一个问题, @ModelAttribute即使在连续加载时,也只调用一次带有注释的方法。例如:

  1. 显示 BookCatalog Portlet
  2. 单击编辑 Book1。Book1 显示在编辑窗体中
  3. 点击首页
  4. 单击编辑 Book2。Book1仍然显示在编辑表单中

我在每个方法的开头添加了 sysouts,以查看在哪里调用了什么。结果如下:

showBooks 
getBook!
initBinder
showEditBookForm
showBooks
initBinder <- Where is getBook!?
showEditBookForm

我在某处读到,@ModelAttribute只要@ModelAttribute 请求参数,就会调用方法。所以我尝试添加@ModelAttribute("book") Book book到 showEditBookForm 但似乎仍然没有触发该@ModelAttribute方法。

我正在使用 Spring 3.1.3.RELEASE 并使用 maven 部署到 Liferay 6.1.1。

任何援助将不胜感激!

编辑书控制器:

@Controller
@RequestMapping(value="VIEW")
@SessionAttributes({"book"})
public class EditBookController {

    ...

    @RenderMapping(params="myaction=editBookForm")
    public String showEditBookForm(@ModelAttribute("book") Book book) {
       System.out.println("showEditBookForm");
       return "editBookForm"
    }

    @InitBinder("book")
    public void initBinder(WebDataBinder binder) {
       System.out.println("initBinder");
       binder.registerCustomEditor(Long.class, new LongNumberPropertyEditor());
       binder.setDisallowedFields(new String[] {"isbnNumber"});
    }

    @ModelAttribute("book")
    public Book getBook(@RequestParam Long isbnNumber) {
       System.out.println("getBook!");
       return bookService.getBook(isbnNumber);
    }

    ...
}

图书控制器:

@Controller
@RequestMapping(value = "VIEW")
public class BookController {
    ...
    @RenderMapping
    public String showBooks(RenderResponse response,SessionStatus sessionStatus) {
       System.out.println("showBooks");
       return "home";
    }
    ...
}
4

2 回答 2

3

根据这行代码:

@SessionAttributes({"book"})
public class EditBookController {

您将“书”属性用作会话属性。这意味着第一次向门户发出请求时,框架将验证具有该名称的属性是否存在于 Portlet 会话中。如果不是,它会调用相应的@ModelAttribute方法生成一个实例并放入Session中。但是如果 Session 中已经有一个具有该名称的属性,则 Controller 将使用现有对象。

因此,当您第一次调用 Book Catalog Portlet 时,会生成 Book Attribute 的实例并将其存储在 Session 中。但是第二次——因为对象已经在会话中——Portlet 将使用第一次请求中生成的对象。如果您想在渲染或操作请求后清除存储在 Session 中的每个对象,您只需调用SessionStatus.setComplete()以触发 Session 清除。

这就是理论和书中所说的,但是其中存在一些错误的行为,SessionStatus.setComplete()并且书作者对此有一些想法

于 2012-12-01T01:19:17.447 回答
0

只是为了说明我最终登陆的内容:

@RenderMapping(params="myaction=editBookForm")
public String showEditBookForm(
        @ModelAttribute("book") Book book
        , @RequestParam Long isbnNumber
        , SessionStatus sessionStatus) {
        System.out.println("showEditBookForm");

       if(book != null 
          && book.getIsbnNumber() != isbnNumber) {
           sessionStatus.setComplete();
       }

       return "editBookForm";
}
于 2012-12-03T15:50:48.113 回答