Search code examples
htmlcheckboxstruts2struts2-interceptorsstruts-tags

Checkbox value `on` is not submitted to Action class. Shall I get parameter from HttpServletRequest directly?


I want to submit a form to my action class with Struts 2 classic getter/setter way. All other fields get their value, except for a boolean field, which stays being false when I check the checkbox it corresponds.

I have a checkbox like this in my jsp:

<div class="col-md-3">
   <input class="input-md" type="checkbox" id="soloIdaId" name="soloIda" />
</div>

And in my action class I have:

private boolean soloIda;

and its getter/setter. But it stays to be false when I checked it.

I noticed that in the queryString contains:

...&soloIda=on&... (I am testing with FF)

And, if I try to get the parameter of request, I get true:

HttpServletRequest request = ServletActionContext.getRequest();
String soloIdaParam = request.getParameter("soloIda"); //"true" when I debug

Don't know if this matters, but I am using my interceptor. But I always include the defaultStack, and I believe the default interceptor is handling this kind of job(using getter/setter to assign values to fields). So why?

Attaching my struts.xml here:

 <interceptors>
    <interceptor name="authentication"
        class="com.WindThunder.interceptor.LoginInterceptor">
    </interceptor>
    <interceptor name="query"
        class="com.WindThunder.interceptor.QueryInterceptor">
    </interceptor>
    <interceptor-stack name="authStack">
        <interceptor-ref name="authentication"></interceptor-ref>
        <interceptor-ref name="defaultStack"></interceptor-ref> <!-- this
          line is necessary for every stack!!!! -->
    </interceptor-stack>
    <interceptor-stack name="pageStack">
        <interceptor-ref name="query"></interceptor-ref>
        <interceptor-ref name="defaultStack"></interceptor-ref>
    </interceptor-stack>
</interceptors>

<action name="searchCiudad" class="com.WindThunder.action.VueloAction"
      method="searchCiudad">
<interceptor-ref name="pageStack"/>
  <result name="success">/listaCiudads.jsp</result>
  <result name="error">/common/error.jsp</result>
  <result name="vacio">/common/listaVacia.jsp</result>
</action>

And my QueryInterceptor.java:

@Override
public String intercept(ActionInvocation invocation) throws Exception {
    //get previous action name = pagePath. (/searchxxx.action)
    this.session = invocation.getInvocationContext().getSession();
    HttpServletRequest request = ServletActionContext.getRequest();
    String path = request.getRequestURI(); //contaits domain
    String pagePath = path.substring(path.lastIndexOf("/"));

    //get previous query string (param1=xx&param2=xx, or null)
    String queryString = request.getQueryString();
    addParamToSession(queryString, session);
    String prePage = "";
    if (!pagePath.equalsIgnoreCase("/login.action")){
        prePage = pagePath;
    }
    if (prePage != null && !prePage.equals("")){
        session.put("prePage",prePage);
    }
    return invocation.invoke();
}

Now I want to get the parameter "soloIda" directly from request and do some manual assignment, but I think it is Struts 1's way of working. Any idea why it is not working? I must be doing something wrong.


Solution

  • It's not your Interceptor's fault... it's just that checkboxes are an ugly thing.

    Things to know:

    1. What browsers send for checkboxes when a value is not specified is browser-specific;
    2. Browsers don't send anything for unchecked values (this may be irrelevant in case of Booleans because the default is false, but still...)

    Then you could force the value with

    <input class = "input-md"
            type = "checkbox" 
              id = "soloIdaId" 
            name = "soloIda" 
           value = "true" />
    

    and then you'd need to deal with unckecked values.

    To handle this situation, Struts2 provides you the <s:checkbox /> (and the <s:checkboxlist />) tag, with its value and fieldValue attributes, and the hidden parameter (__checkbox_something) that the tag generates to send something even when the checkbox is not checked. This parameter is then read by the Checkbox Interceptor.

    Eg. from the docs:

    <s:checkbox cssClass = "input-md"
                      id = "soloIdaId"
                    name = "soloIda" 
              fieldValue = "true"
                   value = "aBoolean" 
    />
    

    will translate to the following HTML (with Simple Theme and Boolean aBoolean = true;):

    <input type = "checkbox" 
          class = "input-md"
             id = "soloIdaId"
           name = "soloIda" 
          value = "true" 
        checked = "checked"
    />
    <input type = "hidden"  
             id = "__checkbox_soloIdaId" 
          value = "true" 
           name = "__checkbox_soloIda" 
    />
    

    Read the Mkyong example on <s:checkbox /> and also this SO answer to better understand where to start.

    Always consider using the framework specific tags (at least at first), that already handles many problems for you transparently.