1

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?

Alireza Fattahi
  • 42,517
  • 14
  • 123
  • 173
  • Do you have a problem to configure this url or what? Did you initially use back slashes in url or it's a typo? – Roman C Mar 17 '23 at 14:44
  • Dear @RomanC no there is no typo in the URL. The URL which needs to be maped to an action is 'my.action/param1/value1' these slashes after the action makes struts not map it to action – Alireza Fattahi Mar 17 '23 at 21:11
  • In this question is not clear how did you map actions to the URLs. – Roman C Mar 18 '23 at 12:42
  • 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. But I don't know how. I tried to do this in the interceptors, but `callinf my.action/param1/value1` dose not execute any interceptor – Alireza Fattahi Mar 19 '23 at 08:36
  • That will be awful. You'll likely need a catch-all action that does the mapping and transformation manually, although you could build an interceptor that does this and puts the fake params into the params. – Dave Newton Mar 19 '23 at 15:38

2 Answers2

1

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>

Roman C
  • 49,761
  • 33
  • 66
  • 176
  • Refer to https://stackoverflow.com/questions/75920856/urlrewrite-is-not-working-in-struts-2-and-the-actions-are-not-found/75927718#75927718 if there is a problem for config struts and url wrtie – Alireza Fattahi Apr 05 '23 at 05:30
0

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>
Roman C
  • 49,761
  • 33
  • 66
  • 176
Alireza Fattahi
  • 42,517
  • 14
  • 123
  • 173