2014-01-30 61 views
0

我試圖在我的Spring MVC應用程序中實現P/R/G(POST/Redirect/GET)模式,以避免重複的表單提交,而不是顯示一些成功的觀點(GET),我重定向到另一個URL(redirect:/essays/main/student/{studentId}/activity/add/existing),我需要通過完整的模型。對於org.springframework.web.servlet.view.RedirectView春天文檔說:Spring MVC和重定向(P/R/G)

「查看重定向到一個絕對的,上下文相關,或當前請求相對URL,暴露所有的模型屬性作爲HTTP查詢參數。」

,所以我可以從請求檢索序列化對象,它正常工作與字符串,但如果我想在我的情況下,通過更復雜的對象,就像它不工作,夫婦(activityListcourseList對象列表,中,teacherList )。

這是它是如何想的工作: 首先我告訴我的searchActivity視圖,這工作得很好:

@RequestMapping(value="/{studentId}/activity/search", method = RequestMethod.GET) 
public String getSearchActivity(@PathVariable Integer studentId, Model model) { 

    StudentActivityDTO studentActivityDTO = new StudentActivityDTO(); 
    Student student = studentService.get(studentId); 
    studentActivityDTO.setStudent(student); 
    model.addAttribute("studentActivityDTO", studentActivityDTO); 

    return "searchActivity"; 
} 

這是我searchActivity觀的重要組成部分:

<c:url var="studentUrl" value="/essays/main/student/${studentActivityDTO.student.studentId}/activity/search" /> 
<form:form modelAttribute="studentActivityDTO" id="myForm" method="POST" action="${studentUrl}"> 
... 
<label for="activityDescription">Eneter search string:</label> 
<input type="text" id="activityDescription" name="activityDescription"> 
<input type="submit" value="Submit" id="submit"/> 
... 
</form:form> 

然後我輸入一個搜索字符串(activityDescription)並提交我的表單以進行實際搜索(POST),除了最後一行代碼(重定向部分)之外,其也可以正常工作:

@RequestMapping(value="/{studentId}/activity/search", method = RequestMethod.POST) 
public String postSearchActivity(@PathVariable Integer studentId, 
     @RequestParam(value="activityDescription") String activityDescription, 
     @ModelAttribute("studentActivityDTO") StudentActivityDTO studentActivityDTO, 
     Model model) { 

    List<Activity> activityList = activityService.search(activityDescription); 
    model.addAttribute("activityList", activityList); 

    Student student = studentService.get(studentId); 
    studentActivityDTO.setStudent(student); 
    model.addAttribute("studentActivityDTO", studentActivityDTO); 
    model.addAttribute("activityDescription", activityDescription); 
    model.addAttribute("courseList", courseService.getAll()); 
    model.addAttribute("teacherList", teacherService.getAll()); 

    return "redirect:/essays/main/student/{studentId}/activity/add/existing"; 
    // return "addExistingActivity"; <-- If I use this it works fine! 
} 

現在我需要通過模型的一些控制器GET方法:

@RequestMapping(value="/{studentId}/activity/add/existing", method = RequestMethod.GET) 
public String getAddExistingActivity(@PathVariable Integer studentId, Model model) { 
    // some stuff 
    return "addExistingActivity"; 
} 

addExistingActivity觀的重要組成部分:

<c:url var="studentUrl" value="/essays/main/student/${studentActivityDTO.student.studentId}/activity/add/existing" /> 
<form:form modelAttribute="studentActivityDTO" id="myForm" method="POST" action="${studentUrl}"> 
... 
<label for="activityId">Activity Id:</label> 
<input type="text" id="activityId" name="activityId"> 
<input type="submit" id="submit" value="Submit"/> 

<c:if test="${!empty activityList}"> 
... 
</c:if> 
<c:if test="${empty activityList}"> 
    <div style="color: #ff0000">No results!</div> 
</c:if> 
... 
</form:form> 

但我的列表(activityListcourseListteacherList)是不存在,我總是收到「沒有結果!」的信息。我只在我的堆棧跟蹤得到這樣的:

[DEBUG] [http-bio-8080-exec-7 08:32:44] (AbstractView.java:exposeModelAsRequestAttributes:373) Added model object 'studentId' of type [java.lang.Integer] to request in view with name 'addExistingActivity' 
[DEBUG] [http-bio-8080-exec-7 08:32:44] (AbstractView.java:exposeModelAsRequestAttributes:373) Added model object 'studentActivityDTO' of type [rs.ac.uns.tfzr.zpupin.dto.StudentActivityDTO] to request in view with name 'addExistingActivity' 
[DEBUG] [http-bio-8080-exec-7 08:32:44] (AbstractView.java:exposeModelAsRequestAttributes:373) Added model object 'org.springframework.validation.BindingResult.studentActivityDTO' of type [org.springframework.validation.BeanPropertyBindingResult] to request in view with name 'addExistingActivity' 

但是,如果使用的return "addExistingActivity"代替redirect:...一切工作正常,我有這個在我的堆棧跟蹤:

[DEBUG] [http-bio-8080-exec-6 07:42:25] (AbstractView.java:exposeModelAsRequestAttributes:373) Added model object 'studentId' of type [java.lang.Integer] to request in view with name 'addExistingActivity' 
[DEBUG] [http-bio-8080-exec-6 07:42:25] (AbstractView.java:exposeModelAsRequestAttributes:373) Added model object 'studentActivityDTO' of type [rs.ac.uns.tfzr.zpupin.dto.StudentActivityDTO] to request in view with name 'addExistingActivity' 
[DEBUG] [http-bio-8080-exec-6 07:42:25] (AbstractView.java:exposeModelAsRequestAttributes:373) Added model object 'org.springframework.validation.BindingResult.studentActivityDTO' of type [org.springframework.validation.BeanPropertyBindingResult] to request in view with name 'addExistingActivity' 
[DEBUG] [http-bio-8080-exec-6 07:42:25] (AbstractView.java:exposeModelAsRequestAttributes:373) Added model object 'activityList' of type [java.util.Collections$CheckedRandomAccessList] to request in view with name 'addExistingActivity' 
[DEBUG] [http-bio-8080-exec-6 07:42:25] (AbstractView.java:exposeModelAsRequestAttributes:373) Added model object 'activityDescription' of type [java.lang.String] to request in view with name 'addExistingActivity' 
[DEBUG] [http-bio-8080-exec-6 07:42:25] (AbstractView.java:exposeModelAsRequestAttributes:373) Added model object 'courseList' of type [java.util.Collections$CheckedRandomAccessList] to request in view with name 'addExistingActivity' 
[DEBUG] [http-bio-8080-exec-6 07:42:25] (AbstractView.java:exposeModelAsRequestAttributes:373) Added model object 'teacherList' of type [java.util.Collections$CheckedRandomAccessList] to request in view with name 'addExistingActivity' 

全部列出目前,佔!

我需要什麼樣的自定義實現才能使其工作?任何幫助都感激不盡!

此外,我知道我可以使用Flash屬性爲此,但不會消失後擊中F5?

+0

如果我沒有記錯,您必須在Spring MVC中添加任何模型屬性作爲「flash屬性」,以使用重定向在控制器之間傳遞模型屬性。這可能會幫助你:http://stackoverflow.com/questions/7429649/how-to-pass-model-attributes-from-one-spring-mvc-controller-to-another-controlle – CodeChimp

+0

@CodeChimp是的,但點擊後F5在頁面上,閃光屬性消失了,不是?我不希望發生這種情況...... –

+0

如果您正在重定向到另一個未與重定向的人共享會話數據的控制器或應用程序服務器,那麼除了將數據放在某處之外,實際上沒有任何其他方式「共同點」。例如,您可以修改重定向的收件人以查找某個ID,將數據寫入具有該ID的文件共享/數據庫,然後重定向傳入ID。現在另一端知道去哪裏看。不過,這需要能夠修改兩端的代碼。 – CodeChimp

回答

1

RedirectView默認情況下將所有包含基元的原始模型屬性或集合公開爲HTTP查詢參數。這就是爲什麼,當你添加一個字符串作爲模型屬性時,它會被暴露,並且當你添加一個對象時 - 它不會。事實上,這就是RedirectView文檔當前所說的(Spring 4.0.1):

...默認情況下,所有原始模型屬性(或其集合)都作爲HTTP查詢參數公開(假設它們尚未用作URI模板變量)...

所以其實下面的方法:

@RequestMapping(value = "post", method = RequestMethod.POST) 
public String post(@ModelAttribute PrgForm form, Model model) { 
    model.addAttribute("testString", "Some string"); 
    model.addAttribute("testCollection", Lists.newArrayList("Element 1", "Element 2")); 
    model.addAttribute("testObject", form); 
    return "redirect:/demo/get"; 
} 

將導致重定向到:demo/get?testString=Some+string&testCollection=Element+1&testCollection=Element+2

正如你所看到的,testObject不在查詢參數。

如果仔細查看RedirectView源代碼,您會發現有一種方法isEligibleProperty(String, Object)可確定給定的模型元素是否應作爲查詢屬性公開。

此方法的行爲可能會改變。所以,事實上,你可以實現自己的RedirectView如下:

private class CustomRedirectView extends RedirectView { 

    public CustomRedirectView(String url) { 
     super(url); 
    } 

    @Override 
    protected boolean isEligibleProperty(String key, Object value) { 
     if ("testObject".equals(key)) { 
      return true; 
     } else { 
      return super.isEligibleProperty(key, value); 
     } 
    } 

    @Override 
    protected void appendQueryProperties(StringBuilder targetUrl, Map<String, Object> model, String encodingScheme) throws UnsupportedEncodingException { 
     // do some stuff 
    } 
} 

而且從@Controller's方法返回它:

@RequestMapping(value = "post", method = RequestMethod.POST) 
public View post(@ModelAttribute PrgForm form, Model model) { 
    model.addAttribute("testString", "Some string"); 
    model.addAttribute("testCollection", Lists.newArrayList("Element 1", "Element 2")); 
    model.addAttribute("testObject", form); 
    return new CustomRedirectView("/demo/get"); 
} 

我以前從未做過這種實現的,所以我不知道如何它可以完全實現你需要支持的場景。我認爲儘管利用Flash屬性會更好。

我希望它有幫助。

+0

謝謝@RafalBorowiec,我需要思考這一段時間。只是一個簡單的問題:擊中F5後不會閃爍屬性消失? –

+0

是的,刷新後它們將不可用。 –