簡體   English   中英

Spring-MVC @ModelAttribute和@Autowired

[英]Spring-MVC @ModelAttribute and @Autowired

我正在嘗試使用方法上的@ModelAttribute Annontation初始化對象。 當調用URL“ / p / PPP / scope”時,會發生奇怪的事情。 調用@ModelAttribute方法時,似乎未實例化ProjectService,但是調用show()方法時,ProjectService在那里。 有誰知道這有什么問題嗎?

以下是日志語句:

12:32:19 [DEBUG] ScopeController - getProject() - loading project for 'PPP'
12:32:19 [DEBUG] ScopeController - getProject() - projectService initialized? null
12:32:21 [DEBUG] ScopeController - show() - projectService initialized? ...project.ProjectService@20f2442e

以及來源:

@Controller
@RequestMapping("/p/{abbr}/scope")
@SessionAttributes("project")
public class ScopeController {

    public static final String SHOW_PROJECT_PAGE = "/projects/scope/show";

    private static final Logger log = LoggerFactory.getLogger(ScopeController.class);

    @Autowired
    private ProjectService projectService;

    @ModelAttribute("project")
    private Project getProject(@PathVariable(value = "abbr") String abbr) {
        log.debug("getProject() - loading project for '{}'", abbr);
        log.debug("getProject() - projectService initialized? {}", projectService);
        // should call this method:
        // return projectService.find(abbr);
        return new Project();
    }

    @RequestMapping(method = RequestMethod.GET)
    @Transactional
    public String show() throws BindException {
        log.debug("show() - projectService initialized? {}", projectService);
        return SHOW_PROJECT_PAGE;
    }
}

具有ModelAttibute批注的所有方法必須是公共的。

因此,當方法getProject為公共方法時,它將可以正常工作:

 @ModelAttribute("project")
 public Project getProject( ...

也許嘗試一些事情。

  1. 更改以下項的簽名:
    • 私人專案getProject to
    • 公共@ResponseBody項目
  2. 從控制器中刪除@Transactional並將其移動到需要它們的任何服務方法。 (可以說是更好的設計實踐-懷疑它是否會導致您描述的問題)
  3. 將@ModelAttribute(“ Project”)批注移動到Project類

    • @ModelAttribute(“ Project”)public Project get Project(){return new Project(); }

因此,它看起來像:

@Controller
@RequestMapping("/p/{abbr}/scope")
@SessionAttributes("project")
public class ScopeController {

public static final String SHOW_PROJECT_PAGE = "/projects/scope/show";

private static final Logger log = LoggerFactory.getLogger(ScopeController.class);

@Autowired
private ProjectService projectService;

@RequestMapping(value = "/<yourUri for getProject>", method = RequestMethod.GET)
public @ResponseBody Project get(@PathVariable(value = "abbr") String abbr) {
    return getProject(abbr);
}

private Project getProject(String abbr) {
    log.debug("getProject() - loading project for '{}'", abbr);
    log.debug("getProject() - projectService initialized? {}", projectService);
    // should call this method:
    // return projectService.find(abbr);
    return new Project();
}

@RequestMapping(method = RequestMethod.GET)
@Transactional
public String show() throws BindException {
    log.debug("show() - projectService initialized? {}", projectService);
    return SHOW_PROJECT_PAGE;
}

}

//In your Project class 
@ModelAttribute("project")
public class Project {
//your class stuff
}

一方面,我將@Transactional批注放在存儲庫/數據訪問層中,因為這是基於Spring MVC批注的分層應用程序的規范。 另外,您的@PathVariable批注用於檢索在控制器的基本URI之后在URI中傳遞的值。 因此,在不攔截URI模式的私有幫助器方法中使用此注釋幾乎沒有任何意義。

因此,在玩耍之后,我找到了解決方案。 問題是@ModelAttribute中的名稱。 刪除“項目”后,該方法將按預期方式工作。 由於對“ getProject()”方法的困惑,我做了一些重構以使該方法的意圖更加清楚。 這是帶有附加注釋的完整課程:

@Controller
@RequestMapping("/p/{abbr}/scope")
public class ScopeController {

    private static final String SHOW_PROJECT_PAGE = "/projects/scope/show";

    private static final Logger log = LoggerFactory.getLogger(ScopeController.class);

    @Autowired
    private ProjectService projectService;

    // method is called before show() and update()
    @ModelAttribute
    private void initProject(@PathVariable(value = "abbr") String abbr, Model model) {
        log.debug("loading project for '{}'", abbr);
        // load the project JPA entity from the database, will be merged with the  
        // updated form values in the POST request. By doing this, I can asure
        // that the primary key (the ID) and the related objects are present as 
        // needed for the em.saveOrUpdate() in the projectService.save() method.
        model.addAttribute("project", projectService.find(abbr));
    }

    @RequestMapping(method = RequestMethod.GET)
    public String show() throws BindException {
        // shows the project scope form with the project 
        // added in 'initProject()'
        return SHOW_PROJECT_PAGE;
    }

    @RequestMapping(method = RequestMethod.POST)
    public String update(
            // the project with the updated form values and the JPA ID and JPA 
            // relations as loaded in the initProject()
            @Valid @ModelAttribute Project project, BindingResult result, 
            RedirectAttributes redirectAttrs)
            throws MethodArgumentNotValidException {

        redirectAttrs.addFlashAttribute(project);

        try {
            if (!result.hasErrors()) {
                projectService.save(project);
            }
        }
        catch (Exception e) {
            log.error(e.toString());
            throw new MethodArgumentNotValidException(null, result);
        }

        log.debug("project '{}' updated", project.getAbbreviation());
        return SHOW_PROJECT_PAGE;
    }
}

謝謝大家的回答。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM