I am running into a wall on how to configure my application. The goal is to be able to have on the same Tomcat server the following:
- A full restful service (ie. Hypermedia layer, thus returning application/hal+json format)
- A rest service service the old fashion way (controller access)
- A classic set of controller for web pages delivery
Environment is:
<spring-framework.version>4.0.1.RELEASE</spring-framework.version>
<spring-framework.version>4.0.1.RELEASE</spring-framework.version>
<spring-test.version>4.0.1.RELEASE</spring-test.version>
<spring-data-rest-webmvc.version>2.0.0.RC1</spring-data-rest-webmvc.version>
<spring-data-jpa.version>1.4.3.RELEASE</spring-data-jpa.version>
<spring-data-commons.version>1.7.0.RC1</spring-data-commons.version>
The repository:
@RepositoryRestResource( path = "u")
public interface IUserRepository extends CrudRepository<Users, Long> {
Users findByName(@Param("name") String name);
}
The rest controller:
@RestController
@RequestMapping (value = "/users", produces=MediaType.APPLICATION_JSON_VALUE)
public class RestUserController {
@Autowired
private IService service;
@RequestMapping (method = RequestMethod.GET)
public @ResponseBody Iterable<DomainModel.User> findAllUsers() {
return service.findAllUsers();
}
}
The "web" controller:
@Controller
@RequestMapping (value = "/web")
public class HomeController {
@RequestMapping(method = RequestMethod.GET, value = "/home")
public String displayHome(Model model) {
return "home"
}
The JPA config (to simplify I just put the declaration for the jpa datasource...)
@Configuration
@PropertySource({ "classpath:persistence-mysql.properties" })
@ComponentScan(basePackages = { "com.xxx.controller.rest", com.xxx.services.rest.impl" })
@EnableJpaRepositories(basePackages = "com.xxx.persistence.repository")
@EnableTransactionManagement
public class ConfigForJpa {
...
}
The config for WebMvc:
@Configuration
@EnableWebMvc
@ComponentScan(basePackages = { "com.xxx.controller.web" })
public class ConfigForWebMvc extends WebMvcConfigurerAdapter {
private static final String VIEW_RESOLVER_PREFIX = "/WEB-INF/views";
private static final String VIEW_RESOLVER_SUFFIX = ".jsp";
...
@Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setViewClass(JstlView.class);
viewResolver.setPrefix(VIEW_RESOLVER_PREFIX);
viewResolver.setSuffix(VIEW_RESOLVER_SUFFIX);
return viewResolver;
}
...
}
The config for repository:
@Configuration
@ComponentScan(basePackages = { "com.xxx.controller.rest" })
public class ConfigForRepositoryRestMvc extends RepositoryRestMvcConfiguration {
}
The initializer config:
public class WebApplicationInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[] { ConfigForJpa.class };
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[] { ConfigForWebMvc.class,
ConfigForRepositoryRestMvc.class };
}
@Override
protected String getServletName() {
return " ServletName";
}
@Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
}
Keep in mind the web root context is set to "sr"
When the tomcat server started I can clearly see the mappings happening.
RequestMappingHandlerMapping - Mapped "{[/web/home],methods=[GET],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public java.lang.String com.xxx.controller.web.HomeController.displayHome
RequestMappingHandlerMapping - Mapped "{[/users/user],methods=[POST],params=[],headers=[],consumes=[],produces=[application/json],custom=[]}" onto public com.xxx.model.DomainModel$User com.xxx.controller.rest.RestUserController
...
SimpleUrlHandlerMapping - Mapped URL path [/resources/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
...
RepositoryRestHandlerMapping - Mapped "{[/{repository}],methods=[GET],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public org.springframework.hateoas.Resources
RepositoryRestHandlerMapping - Mapped "{[/],methods=[GET],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public org.springframework.data.rest.webmvc.RepositoryLinksResource org.springframework.data.rest.webmvc.RepositoryController.listRepositories()
The good:
when I hit the server on xlocalhostx:8080/sr (sr is the root web context), I do get the list of my restful service in hypermedia fashion like so:
{ "_links" : { "userss" : { "href" : "
http://xlocalhostx:8080
/sr/u" } } }when I hit the server on
xlocalhostx:8080/sr/users
I get as expected this:
[{"id":1,"name":"Clark","lastname":"Kent"},{"id":2,"name":"Lois","lastname":"Lane"}]
When I ran the following test, it passes:
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration(classes = { ConfigForWebMvc.class, ConfigForRepositoryRestMvc.class} )
public class HomeControllerTest {
@Autowired
private WebApplicationContext wac;
private MockMvc mockMvc;
@Before
public void setup() {
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
}
@Test
public void getHome() throws Exception {
this.mockMvc.perform(get("/web/home"))
.andDo(print())
.andExpect(status().isOk())
.andExpect(forwardedUrl("/WEB-INF/views/home.jsp"));
}
}
The bad - when I hit the server on xlocalhostx:8080/sr/web/home I get a 404 because the view resolution process is trying to return a view using a wrong path. ( my home.jsp resides of course under the WEB-INF folders under the views folder. I can clearly see my HomeController is being hit because I have log trace.
What I get back from the server is the following:
a 404 saying: /sr/WEB-INF/viewshome.jsp The requested resource is not available. As you can see the path is not correct at all, I have the root web context ("sr") in the front of it, and missing forward slash before the home.jsp file.
Any ideas are welcome.
Thanks.