alejo
alejo

Reputation: 307

Using Spring controllers inside Struts 2 to create a REST API

I have an application that uses Struts (version 2.3.16.1 GA) and Spring (version 3.2.4 GA) to inject objects into Actions, etc.

Now, I need to create a REST API for my app, and I can't use Struts' REST plugin for that, so I thought that since Spring was around already, I could just create Spring Controllers and then serve the API with Spring.

Say my current app runs in the app context on the server, so I will access it like this:

http://www.myserver.com:8080/app/some/path/anAction.action

And then that's how the whole flow of my current app works. Now what I'm intending to do, is to create a specific path which will be used exclusively by my REST API, so I tried making it work like this for example:

http://www.myserver.com:8080/app/api/users

I want to map /api/* to Spring, so all my controllers will live there.

Here are the relevant bits of my config that I did in order to accomplish this.

web.xml:

<filter>
    <filter-name>struts-prepare</filter-name>
    <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareFilter</filter-class>
</filter>
<filter>
    <filter-name>struts-execute</filter-name>
    <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsExecuteFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>struts-prepare</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>REQUEST</dispatcher>
    <dispatcher>FORWARD</dispatcher>
</filter-mapping>
<filter-mapping>
    <filter-name>struts-execute</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>REQUEST</dispatcher>
    <dispatcher>FORWARD</dispatcher>
</filter-mapping>

<servlet>
    <servlet-name>rest-api</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
    <init-param>
        <param-name>contextClass</param-name>
        <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
    </init-param>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>com.myapp.spring.SpringApplicationConfiguration</param-value>
    </init-param>
</servlet>
<servlet-mapping>
     <servlet-name>rest-api</servlet-name>
    <url-pattern>/api/*</url-pattern>
</servlet-mapping>

struts.xml:

<constant name="struts.action.excludePattern" value="/api/*"/>

SpringApplicationConfiguration.java:

@Configuration
@EnableWebMvc
@ComponentScan( basePackages = {"com.myapp.controller"})
@Import( {BaseConfig.class, DataBaseConfiguration.class})
public class SpringApplicationConfiguration {}

UserController.java:

@Controller
public class UserController {

    @Autowired
    private UserService service;

    @RequestMapping(value="/users", method=GET)
    @ResponseBody public List<User> list(@RequestParam(defaultValue = "25") int limit, @RequestParam(defaultValue = "1") int offset,  @RequestParam String filter ) {
        return service.list(limit, offset, filter);
    }
}

That's all the configuration I think I should have. Now, I start the server, login into the app (so check that Struts keep working fine), then try to send a GET request into my REST endpoint, and here are the logs:

Logs:

INFO  [org.springframework.web.servlet.DispatcherServlet] (MSC service thread 1-2) FrameworkServlet 'rest-api': initialization completed in 8939 ms
INFO  [org.jboss.web] (MSC service thread 1-2) JBAS018210: Registering web context: /app
INFO  [org.jboss.as.server] (DeploymentScanner-threads - 1) JBAS018559: Deployed "app.ear"
INFO  [com.app.web.filter.SignOnFilter] (http--0.0.0.0-8443-5) Redirecting to signon: /signon.action?redirectUri=index.action
WARN  [org.springframework.web.servlet.PageNotFound] (http--0.0.0.0-8443-3) No mapping found for HTTP request with URI [/app/api/users] in DispatcherServlet with name 'rest-api'

Upvotes: 5

Views: 4029

Answers (2)

Abolfazl Hashemi
Abolfazl Hashemi

Reputation: 764

The problem is in defining your pattern in struts.xml. change

<constant name="struts.action.excludePattern" value="/api/*"/>

to

<constant name="struts.action.excludePattern" value="/api/.*"/>

Upvotes: 0

Roman C
Roman C

Reputation: 1

No mapping is because you didn't map it correctly

@RequestMapping(value="/api/users", method=GET)

Upvotes: 0

Related Questions