Hidden field becomes null when binding it in strip

2019-07-21 04:05发布

问题:

I have a stripes action page. and When the page loads, I want to save an originalAssignee by assigning it from an object (i.e setOriginalAssignee (userAction.getAssignee())) so that in case if the object's field assignee is changed i will do some computing. Here is my action bean:

@UrlBinding("/action/view-details.page")
public class ActionListViewPage extends CustomAction {
.
.
.
private static final String ACTION_LIST_VIEW = "/action/view-details.jsp";
private static final String ACTION_HOME_PAGE="/action/dashboard.page";
private SecurityPerson originalAssignee;
private UserAction userAction;

    public UserAction getUserAction() {
        return userAction;
    }

    public void setUserAction(UserAction userAction) {
        this.userAction = userAction;
    }

    public SecurityPerson getOriginalAssignee() {
        return originalAssignee;
    }

    public void setOriginalAssignee(SecurityPerson originalAssignee) {
        this.originalAssignee = originalAssignee;
    }

@DefaultHandler
    public Resolution showUserAction() {


        if(userAction==null){
            flash("error", "Can't find the the specified User action." );
           return new RedirectResolution(ACTION_HOME_PAGE);
        }

        setOriginalAssignee(userAction.getAssignee());// This one works fine and assigns the the assignee to originalAssignee for future reference 
        return new ForwardResolution(ACTION_LIST_VIEW);
    }
 public Resolution saveUserAction() {

        try {

            if(!originalAssignee.equals(userAction.getAssignee())){
                userAction.setStatusEnum(StatusEnum.RE_ASSIGNED);
                userAction.setAssignedBy(getCurrentUser(getRequest()));
                userAction.setAssignedTimestamp(new Date());
            }

            if (userAction.getStatusEnum() == null) {
                userAction.setStatusEnum(FinAidActionStatusEnum.UNASSIGNED);
            }


            userAction.save();
            flash("ok", "User Action change has been saved to the database. ");

        }
        catch (Exception e) {

            flash("error", "Error saving UserAction./n " + e.getMessage());
        }
        return new RedirectResolution(ACTION_HOME_PAGE);
    }


}

part of the view-details.jsp page looks like this

<stripes:form beanclass="${actionBean.class}" name="actionListForm" id="actionListForm" method="POST"
                              action="view-details.page?saveUserAction=1"
                              style="padding-left:20px;">
                   **<stripes:hidden name="originalAssignee"/>**

                    <tr>
                        <td align="left"> Assign to:</td>

                        <td align="right">
                            <stripes:select name="userAction.assignee" value="${actionBean.userAction.assignee}"
                                            onchange="$('actionListForm').submit();">
                                <stripes:option value=""> </stripes:option>
                                <stripes:options-collection collection="${actionBean.assigneeList}"
                                                            label="person.name"/>
                            </stripes:select>
                        </td>
                        </br> </br>
                    </tr>
                    <tr>
                        <td>
                            Status:
                        </td>
                        <td>
                            <stripes:select name="userAction.statusEnum" onchange="$('actionListForm').submit();"
                                            value="${actionBean.userAction.statusEnum}">
                                <stripes:option value=""> </stripes:option>
                                <stripes:options-enumeration enum="uiowa.maui.biz.finaid.enums.FinAidActionStatusEnum"/>
                            </stripes:select>
                        </td>

                    </tr>

                    <stripes:hidden name="userAction"/>


                </stripes:form>

As you can see from my code i used hidden variable to keep originalAssignee ... but when the saveUserAction method is called, it says the originalAssignee is null. I shouldn't figure out the reason. Is there a change i should make on the Forward or Redirect resolution?

FYI: userAction is a hibernate persistent object. Thank you.

回答1:

This is what I have when i see the source

<input type="hidden" value="" name="originalAssignee">

However, when I add " value="${actionBean.originalAssignee}" " to the hidden var .. and it worked fine. I don't know why the original code is not working but, for now at least it solved the problem.

FYI: If you can provide why the previous one is not working and your solution is better than mine, I will make your's the solution. So, feel free to add your answer.



回答2:

Your problem is with type conversion / formatting.

Within the HTTP protocol data can only be represented as Strings. So all HTML form values need to be formatted as String values and when the setter on the action bean is called type conversion is needed. Out of the box Stripes has type converters / formatters for int, long, date etc.

But logically Stripes can not know how to format/convert your own self made classes, thus you either need to use getters and setters with String values (or any other already known type) and do the mapping to your own types your self. Or you need to extend the type conversion/formatting system of Stripes by providing custom Formatter/TypeConverters and use the @Validate(converter=UserTypeConverter.class)

See also: http://www.stripesframework.org/display/stripes/Binding+Into+Domain+Models and http://www.stripesframework.org/display/stripes/Validation+Reference

BTW Stripersist packages also contains a EntityTypeConverter / EntityFormatter that will map your JPA entities.



回答3:

The reasons is because Stripes default input tag population strategy first looks at request parameters and then at the ActionBean values:

Check out https://stripesframework.atlassian.net/wiki/display/STRIPES/Tag+Library+Doc section Input Tag Population and Repopulation"

The DefaultPopulationStrategy searches in the following order for the first non-null value(s) when populating a given input tag:

  1. The HttpServletRequest parameter map for values matching the name of the input tag
  2. The ActionBean for a property or nested property
    matching the name of the input tag
  3. The value specified by the tag
    itself (varies by tag; usually as a value attribute, or as the body of the tag)

You can change this behaviour system-wide by using the BeanFirstPopulationStrategy. There are also ways to limit this behaviour to a specific bean: https://stripesframework.atlassian.net/wiki/display/STRIPES/Overriding+PopulationStrategy+per+ActionBean