How to map a path parameters in URL to the action in Struts 2

582 Views Asked by At

We are using Struts 6.2 on Tomcat 9, and map all .action extensions to actions, for example save-user.action maps to an action correctly.

The web application needs to handle this path parameters ( path variables) ex: save-user.action/name/joe/age/20. As you can see the parameters are send via URL path. The caller is not a browser.

Is there any way that I can configure Struts to handle this URL and map it to correct action?

2

There are 2 best solutions below

1
Roman C On BEST ANSWER

we are using convention-plugin, it seems that we should get the /my.action/param1/value1 url before struts filter. change it to valid url/my.action?param1=value1 and then let struts do the rest of jobs.

It's not easy to do it yourself, fortunately there's a solution to use urlrewrite filter in front of struts filter. See Why URL rewriting is not working in Struts 2:

You can rewrite any URL if you place Tuckey URL rewrite filter before the Struts2 filter in the web application deployment descriptor. Use this guide: Tuckey URLRewrite How-To.


Then you add a rule to rewrite URL similar like this:

<rule match-type="regex">  
  <from>/my.action/param1/(\w+)</from>
  <to>/my.action?param1=$1</to>
</rule>

0
Alireza Fattahi On

I prefer the @RomanC solution as it will needs no code :)

Just if you want to develop it yourself here is another solution.

The idea is to use HttpServletRequestWrapper and change getRequestURI and getServletPath to make url a valid struts action. Also implement getParameterMap to make valid query string

@WebFilter(filterName = "UrlToActionMapperFilter")
public class UrlToActionMapperFilter implements Filter {

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
        throws IOException, ServletException {
    
    HttpServletRequest httpRequest = (HttpServletRequest) request;
    ChangedURIRequestWarpper warpperdRequest = new ChangedURIRequestWarpper(httpRequest);
    chain.doFilter(warpperdRequest, response);

}

public class ChangedURIRequestWarpper extends HttpServletRequestWrapper {

    private final Logger LOG = LoggerFactory.getLogger(ChangedURIRequestWarpper.class);
    private static final String CALLBACKURI = "foo/bar.action";
    private static final String URL_PARAMETERS_REGEX = "(\\w+\\/\\w+)";
    private final Pattern URL_PARAMETERS_PATTERN = Pattern.compile(URL_PARAMETERS_REGEX);

    public ChangedURIRequestWarpper(HttpServletRequest request) {       
        // So that other request method behave just like before
        super(request);
    }

    /**
     * read the parameters from url which is defined as /param1/value1/param2/value2
     * and set them to parameter map
     *  
     */
    @Override
    public Map<String, String[]> getParameterMap() {
        LOG.debug("get the parameters from {}, and set them in parameters map", super.getRequestURI());
        Map<String, String[]> parameters = new HashMap<>();

        //The queryString is /param1/value1/param2/value2
        String queryString = StringUtils.substringAfter(super.getRequestURI(), CALLBACKURI);

        Matcher matcher = URL_PARAMETERS_PATTERN.matcher(queryString);

        while (matcher.find()) {
            String[] keyValue = matcher.group(1).split("/");
            LOG.debug("Set {} in parameters map " , (Object)keyValue);          
            parameters.put( keyValue[0], new String[] {  keyValue[1] });
        }

        return parameters;
    }
    
    /**
     * struts use getRequestURI and getServletPath to determine if it should handle request ot not
     * As this url is fixed we can hardcode it.
     */
    @Override
    public String getRequestURI() {
        return "/"+CALLBACKURI;
    }

    @Override
    public String getServletPath() {
        return "/"+CALLBACKURI;
    }


}

}

in web.xml:

<filter-mapping>
    <filter-name>UrlToActionMapperFilter</filter-name>
    <!-- if you want to change it remember to change ChangedURIRequestWarpper  -->
    <url-pattern>/foo/bar.action/*</url-pattern>
</filter-mapping>