3

I have an <s:form> that is present on all pages of my web application.

<s:form action="search" method="post">
    <s:textfield name="query" placeholder="Enter movie title..." cssClass="searchbox" />
    <s:submit type="image" src="images/btn_search.gif" />
</s:form>

Currently, it is redirecting to index.jsp when the validate() method of SearchAction class results to input.

<action name="search" class="com.mypackage.action.SearchAction">
    <result>/search-result.jsp</result>
    <result name="input">/index.jsp</result>
</action>

SearchAction:

public class SearchAction extends ActionSupport implements RequestAware, Message {
    private static final long serialVersionUID = 1L;

    private Map<String, Object> request;
    
    private String query;

    @Override
    public String execute() throws Exception {
        // business logic
        request.put("searchResults", searchResults);
        
        return SUCCESS;
    }
    
    @Override
    public void validate() {
        if(getQuery().length() == 0) {
            addFieldError("query", BLANK_SEARCH);
        }
    }

    @Override
    public void setRequest(Map<String, Object> request) {
        this.request = request;         
    }

    public String getQuery() {
        return query;
    }
    
    public void setQuery(String query) {
        this.query = query;
    }
}

Output:

enter image description here

It works, but it seems unnatural for the user to return to index.jsp every time the parameter is invalid (i.e. blank).

My goal is to keep the user on the current page when the Please enter... message appears.

Questions:

  1. How do I get the current page, where the action was called?
    (For example, a visitor used the search while at the Log In page, how do I get login.jsp from the address bar?)
  2. How do I make this current page the location at
    <result name="input">/currentpage</result>?
Roman C
  • 49,761
  • 33
  • 66
  • 176
k_rollo
  • 5,304
  • 16
  • 63
  • 95

3 Answers3

2

You can get the current page name using following code:

String actionName = ServletActionContext.getRequest().getHeader("Referer");

In Struts.xml, use a dynamic result such as:

<result name="input" type="redirect">${url}</result>

In the action, use getter method for url. By default set the value of url as "index.jsp". If you want to change it, set appropriate value for url. Like login.jsp etc.

Jigar Mistry
  • 352
  • 2
  • 12
  • `getName()` returns the `search` action name, not the actual page the user was on when he performed the search. Is it possible to get that value? – k_rollo Nov 24 '14 at 05:51
  • 1
    Use request.getHeader("Referer") to get the name of the page from where the action being called. – Jigar Mistry Nov 24 '14 at 06:12
  • 1
    What I did is `ServletActionContext.getRequest().getHeader("Referer")` and it worked, thanks! Can you kindly edit your answer to also include the `SearchAction` class? – k_rollo Nov 24 '14 at 06:27
2

The current page you can get via servlet request. Create interceptor for intercepting a current page

public class CurrentPageInterceptor extends AbstractInterceptor {

  @Override
  public String intercept(ActionInvocation actionInvocation) throws Exception {
    HttpServletRequest request = ServletActionContext.getRequest();
    Map<String, Object> session = actionInvocation.getInvocationContext().getSession();
    String queryString = request.getQueryString();
    String savedUrl = request.getRequestURI()+(queryString==null?"":("?"+queryString));
    String currentPage = (String) session.get("savedUrl");
    if(currentPage == null) currentPage = savedUrl;
    session.put("currentPage", currentPage); 
    session.put("savedUrl", savedUrl);
    return actionInvocation.invoke();
  }
}

Registering interceptor in the parent package

<interceptors>
  <interceptor name="currentPage" class="com.company.interceptor.CurrentPageInterceptor"/>
  <interceptor-stack name="curentPageStack">
    <interceptor-ref name="currentPage"/>
    <interceptor-ref name="defaultStack"/>
  </interceptor-stack>
</interceptors>

<default-interceptor-ref name="curentPageStack"/>

Add a result to return a dynamic parameter

@Results({
  @Result(name = "input", type = "redirect", location = "${currentPage}"),
  @Result(location= "/search-result.jsp")
})
public class SearchAction extends ActionSupport implements RequestAware, SessionAware, Message {

private String currentPage;
//getter

   @Override
    public String execute() throws Exception {
        if (hasErrors()){
          currentPage = (String) session.get("currentPage");
          return "input";
        }


        // business logic
        request.put("searchResults", searchResults);

        return SUCCESS;
    }

    ...
}
Roman C
  • 49,761
  • 33
  • 66
  • 176
  • Hi, it's my first encounter with an Interceptor class, (1) does it have to be in the same package as the `SearchAction` class? and (2) what will be the configuration in the `struts.xml`? – k_rollo Nov 23 '14 at 14:41
  • Hi, I've edited my web application based on your recommendations, but it's resulting to some errors. I've edited the above post to reflect the changes. Your assistance is much welcome. – k_rollo Nov 24 '14 at 03:48
  • Hi, thank you for continuing your assistance. The errors encountered were posted in the edit (i.e. `No result defined for action X and result success/input`). – k_rollo Nov 27 '14 at 07:48
  • I have added those results. If you find other errors, kindly inform me, so I can update the code. – Roman C Nov 27 '14 at 11:28
  • Changed the name, I've used it before but after update it should have different name. – Roman C Nov 27 '14 at 14:31
2

This is just to show how I went about the solution with Jigar's approach which I marked as accepted answer.

struts.xml:

<action name="search" class="com.mypackage.action.SearchAction">
    <result>/search-result.jsp</result>
    <result name="input">${url}</result>
</action>

I removed the type="redirect" because the fielderror message disappeared. I believe that is the expected behavior as documented in Apache docs:

Redirect Result

The response is told to redirect the browser to the specified location (a new request from the client). The consequence of doing this means that the action (action instance, action errors, field errors, etc) that was just executed is lost and no longer available.

Source: http://struts.apache.org/release/2.1.x/docs/redirect-result.html

SearchAction:

public class SearchAction extends ActionSupport implements RequestAware, Message {

    private String url;

    public String getUrl() {
        return url;
    }

    @Override
    public String execute() throws Exception {
        // business logic
        request.put("searchResults", searchResults);

        return SUCCESS;
    }

    @Override
    public void validate() {
        url = ServletActionContext.getRequest().getHeader("referer")
            .replace("http://localhost:8080/mysite/", ""); // get resource name only

        if(!url.contains(".jsp")) {
            url = "index.jsp"; // default page
        }           

        if(searchWord.length() == 0) {
            addFieldError("searchWord", BLANK_SEARCH);
        }
    }
}

Output:

enter image description here

It now stays on the current page on error.

k_rollo
  • 5,304
  • 16
  • 63
  • 95