Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring MVC form not backed by a model object

I am pretty new to Spring MVC so please be easy on me.

I am having difficulties to understand how to achieve the following requirements in Spring MVC:

  • JSP list form, to list users from the database (service, repository thing are working properly).
  • Form is not backed by a model attribute object. This is a list/find form!
  • I need to list users matching some criteria taken from several "filter" fields like:
    • Region (dropdown list)
    • Is user archived? (yes/no dropdown list)

userList.jsp

<spring:url value="strFormAction" var="/rest/security/user/list" />
<form:form id="userListForm" method="GET" action="${strFormAction}" modelAttribute="user">

<form:select id="strRegionId" path="${strRegionId}" cssClass="form-control" onchange="updateUsersList('1');">
    <spring:message var="strSelectRegionLabel" code="select.region" />                          
    <form:option value="0" label="${strSelectRegionLabel}" />
    <form:options items="${regions}" itemValue="intId" itemLabel="strNameFr" />
</form:select>

<form:select id="strArchived" path="${strArchived}" cssClass="form-control">
    <spring:message var="strYesLabel" code="yes" />
    <form:option value="true" label="${strYesLabel}"/>

    <spring:message var="strNoLabel" code="no" />
    <form:option value="false" label="${strNoLabel}"/>
</form:select>

<table>

...

<c:forEach items="${users}" var="user">
...rows generated here...
</c:forEach>
 ...
</table>

</form:form>

UserController.java

@RequestMapping(value = "/list", method = RequestMethod.GET)
public String processUserList(  @ModelAttribute("user") User user, 
                                @RequestParam(value = "strRegionId", required = false) String strRegionId,
                                @RequestParam(value = "strArchived", required = false) String strArchived,
                                @RequestParam(value = "strSortBy", required = false) String strSortBy,
                                Model model) {

    int intRegionId = strRegionId != null && strRegionId.equals("0") == false ? Integer.valueOf(strRegionId) : 0;
    boolean booArchived = strArchived != null && strArchived.length() > 0 ? Boolean.valueOf(strArchived) : false;       
    int intSortBy = strSortBy != null && strSortBy.length() > 0 ? Integer.valueOf(strSortBy) : 1;

    List<Region> regions = this.locationService.lstRegions();
    model.addAttribute("strRegionId", String.valueOf(intRegionId));
    model.addAttribute("strArchived", String.valueOf(booArchived));
    model.addAttribute("strSortBy", String.valueOf(intSortBy));

    List<User> users = this.securityService.listUsersByRegionAndArchiveState(intRegionId, booArchived, intSortBy);

    model.addAttribute("user", new User());
    model.addAttribute("users", users);
    model.addAttribute("regions", regions);

    return "user/userList";
}

It seems like I can't use the Spring form taglib at all without providing a modelAttribute in the form. I have then placed a dummy modelAttribute from my controller, but now I get:

javax.servlet.ServletException: javax.servlet.jsp.JspException: org.springframework.beans.NotReadablePropertyException: Invalid property '0' of bean class [spring4base.model.security.User]: Bean property '0' is not readable or has an invalid getter method: Does the return type of the getter match the parameter type of the setter?

As I said earlier, that page is not meant to be backed by any specific POJO. This is a search page, that must return a list of users (User entity bean) based on filters selected previously (region, archived state). Form must submit on itself every time a dropdown is changed (user chooses a region, submit is done on the same mapping, and then the users list reloads with only users from that specific region).

I'm coming from Struts 1 in which we needed to create ActionForm for every single page. From what I read from the documentation, forms are not necessary these days so I am really looking forward into fixing that issue.

Any help would be greatly appreciated.

like image 562
Charles Morin Avatar asked Nov 10 '14 20:11

Charles Morin


1 Answers

I would just create helper class containing your search criteria, for instance:

public class UserSearchCriteria {
    private String regionId;
    private Boolean archived;
    private String sortBy;

    // Getters and setters
}

Then I would modify your controller method like so (some code is missing, but this should give you the idea).

@RequestMapping(value = "/list", method = RequestMethod.GET)
public String processUserList(@ModelAttribute("searchCriteria") UserSearchCriteria userSearchCriteria, Model model) {
    // Retrieve users and perform filtering based on search criteria
    List<User> users = this.securityService.listUsers(searchCriteria);

    model.addAttribute("users", users);
    model.addAttribute("regions", regions);

    return "user/userList";
}

And then you would use your filtering form like this:

<spring:url value="/rest/security/user/list" var="formAction" />
<form:form id="userListForm" method="GET" action="${formAction}" modelAttribute="searchCriteria">

<form:select path="regionId" cssClass="form-control" onchange="updateUsersList('1');">
    <spring:message var="strSelectRegionLabel" code="select.region" />                          
    <form:option value="0" label="${strSelectRegionLabel}" />
    <form:options items="${regions}" itemValue="intId" itemLabel="strNameFr" />
</form:select>

<form:select path="archived" cssClass="form-control">
    <spring:message var="strYesLabel" code="yes" />
    <form:option value="true" label="${strYesLabel}"/>

    <spring:message var="strNoLabel" code="no" />
    <form:option value="false" label="${strNoLabel}"/>
</form:select>

You had several errors in the form in your snippet. For example the path attribute takes String containing name (or path) of the property to bind to, you were passing it some variable. Also you had value and var switched in your <spring:url> I think.

Try it, it's not complete solution but hopefully it will give you some directions on how to implement this. If you run into any problems, leave a comment and I'll update the answer.

like image 123
Bohuslav Burghardt Avatar answered Oct 12 '22 18:10

Bohuslav Burghardt