Restful App with Spring MVC - Ambiguous handler methods error - java

I'm trying to build a Restful webapp using Spring MVC 4.
But I'm got this error "Ambiguous handler methods mapped for HTTP".
In my controller I have this endpoints:
GET /people/
GET /people/{id}
POST /people/
DELETE /peope/{id}
PUT /people/{id}
I think this error occurs because I have something wrong in my configuration.
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = { "com.myapp.rest.controller" })
public class MVCConfig extends WebMvcConfigurerAdapter {
#Override
public void addResourceHandlers(final ResourceHandlerRegistry registry) {
registry.addResourceHandler("/site/**").addResourceLocations("/WEB-INF/site/**");
}
}
And this
public class WebAppInitializer implements WebApplicationInitializer {
#Override
public void onStartup(ServletContext servletContext)
throws ServletException {
WebApplicationContext context = getContext();
servletContext.addListener(new ContextLoaderListener(context));
ServletRegistration.Dynamic dispatcher = servletContext.addServlet(
"DispatcherServlet", new DispatcherServlet(context));
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("/*");
}
private AnnotationConfigWebApplicationContext getContext() {
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.setConfigLocation("com.myapp.config");
return context;
}
}
Thank you all

Related

How to enforce Tomcat to accept DispatcherServlet url mapping, configured programmaticaly?

I'm running a hello-world Spring WebMVC sample of 3 classes: WebApplicationInitializer, WebMvcConfigurer and simple controller with a single request handler method.
Inside WebApplicationInitializer 'onStartup(ctxt)' the DispatcherServlet instance is mapped to '/app/*' URL pattern and reflected in ctxt.context.context.servletMapping value as {*.jspx=jsp, /app/*=dispatcher, *.jsp=jsp, /=default} in runtime.
But for unknown reason GET e.g. 'http://localhost:8080/app/sht' is dispatched to Tomcat's DefaultServlet! In runtime the request's context servlet mapping(request.request.applicationMapping.mappingData.context.servletMapping) value states that onStartup() configuration is lost: {*.jspx=jsp, *.jsp=jsp, /=default}
Could you please assist in configuring Spring properly? Thanks!
Spring 5.2.2; Tomcat 9.0.30, running under Eclipse.
public class WebbAppInitializer implements WebApplicationInitializer{
#Override
public void onStartup(ServletContext context) throws ServletException{
// Create the dispatcher servlet's Spring application context
AnnotationConfigWebApplicationContext dispatcherContext = new AnnotationConfigWebApplicationContext();
dispatcherContext.setServletContext(context);
dispatcherContext.register(SpringWebConfig.class);
// Register and map the dispatcher servlet
ServletRegistration.Dynamic dispatcher = context.addServlet("dispatcher", new DispatcherServlet(dispatcherContext));
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("/app/*");
}
}
#EnableWebMvc
#Configuration
#ComponentScan(basePackages = { "cool.videoservice.controller" })
public class SpringWebConfig implements WebMvcConfigurer{
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("index");
}
#Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver bean = new InternalResourceViewResolver();
bean.setViewClass(JstlView.class);
bean.setPrefix("/WEB-INF/view/");
bean.setSuffix(".jsp");
return bean;
}
}
#Controller
public class IndexController{
#GetMapping("/sht")
public String greeting(#RequestParam(name="name", required=false, defaultValue="World") String name, Model model) {
model.addAttribute("name", name);
System.out.println("Oh, yeah!!!!!!");
return "index";
}
}

Spring MVC application deploying multiple times in tomcat

I have application with spring mvc annotation configuration. In my local environment(IDE) it is working perfectly. When i deployed in prod(tomcat 8.5) my application listener calling multiple times. Because of this my executor tasks, schedulers calling multiple times.
AppWebAppInitializer.java
package com.app.config;
public class AppWebAppInitializer implements WebApplicationInitializer {
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(AppMvcConfig.class);
servletContext.addListener(new ContextLoaderListener(ctx));
ServletRegistration.Dynamic dispatcher = servletContext.addServlet("appServlet",new DispatcherServlet(ctx));
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("/*");
dispatcher.setAsyncSupported(true);
servletContext.setSessionTrackingModes(EnumSet.of(SessionTrackingMode.COOKIE)); //uses cookies instead of jsessionId in the url.
}
}
AppMvcConfig.java
package com.app.config;
#Configuration
#EnableWebMvc
#EnableScheduling
#EnableCaching
#ComponentScan("com.app")
#Import({
AppPropertyInitConfig.class,
AppSecurityConfig.class,
WebSocketConfig.class
})
public class AppMvcConfig extends WebMvcConfigurerAdapter implements ApplicationContextAware{
private ApplicationContext applicationContext;
#Value("${app.upload.dir}")
private String uploadDir;
public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
#Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
}
ApplicationStartupListener.java
package com.app.listener;
#Component
public class ApplicationStartupListener {
private final Logger logger = LoggerFactory.getLogger(ApplicationStartupListener.class);
#Autowired
private LookupHolder lookupHolder;
#EventListener
public void handleContextRefreshEvent(ContextRefreshedEvent event) {
logger.info("ApplicationStartupListener initializing lookups");
Runnable lookupInitRunnable = () -> lookupHolder.init(); //initialize the lookups
new Thread(lookupInitRunnable).start();
}
}
In above code ApplicationStartupListener.java --> handleContextRefreshEvent() calling multiple times. As well as my spring default schedules also calling multiple times
In my application i don't have web.xml

Programmatic integration of Spring 4 and jersey [duplicate]

This question already has an answer here:
Combining Spring project and Jersey
(1 answer)
Closed 6 years ago.
How do I autowire my spring beans in a jersey resource?
I'm trying to cobble together a jersey app which uses spring to initialise the fields in the jax-rs resources. From googling, it seems possible but they are always null. My beans get created but not injected.
My REST resource
#Path ("/clips")
#Component
public class ClipStreamService {
#Autowired
private ClipHandler clipHandler;
#GET
public Response defaultGet() {
Clip clip = clipHandler.getDefault(); <-- ***** throws an NPE *****
The spring WebInitilizer
public class SpringWebInitialiser implements WebApplicationInitializer {
#Override
public void onStartup(ServletContext container) {
// Create the 'root' Spring application context
AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
rootContext.register(RootConfig.class);
rootContext.setServletContext(container);
container.addListener(new ContextLoaderListener(rootContext));
// Create the dispatcher servlet's Spring application context
AnnotationConfigWebApplicationContext dispatcherContext = new AnnotationConfigWebApplicationContext();
dispatcherContext.register(WebConfig.class);
// Register and map the dispatcher servlet
ServletRegistration.Dynamic dispatcher = container.addServlet("dispatcher", new DispatcherServlet(dispatcherContext));
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("/");
}
}
And the bean config (note I've also tried adding the bean to RootConfig)
#Configuration
#ComponentScan ({ ... })
public class WebConfig {
#Bean
public ClipHandler clipHandler() {
return new ClipHandler();
}
}
You can manually invoke autowiring in your jersey resource like below:
#Context
private ServletContext servletContext;
#PostConstruct
public void init() {
SpringBeanAutowiringSupport.processInjectionBasedOnServletContext(this, servletContext);
}

Adding SecurityWebApplicationInitializer to existing Spring app

I try to follow answers to this question, but still cannot make it work.
I have following Java config classes:
public class MyWebAppInitializer implements WebApplicationInitializer {
#Override
public void onStartup(ServletContext container) throws ServletException {
AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
rootContext.register(WebAppConfiguration.class);
container.addListener(new ContextLoaderListener(rootContext));
AnnotationConfigWebApplicationContext dispatcherContext = new AnnotationConfigWebApplicationContext();
ServletRegistration.Dynamic dispatcher = container.addServlet("dispatcher", new DispatcherServlet(dispatcherContext));
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("/");
}
}
And for security:
public class SecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer {
public SecurityWebApplicationInitializer() {
super(WebSecurityConfiguration.class);
}
}
The problem is I get exception like that on startup:
java.lang.IllegalStateException: Cannot initialize context because there is already a root application context present - check whether you have multiple ContextLoader* definitions in your web.xml!
Without SecurityWebApplicationInitializer class it starts up and works fine except of the fact that Spring Security doesn't work.
I understand that the problem is that SecurityWebApplicationInitializer injects it's own context. But then what is the right way to make the Spring Security work for my case?
Thank you.

Why doesnt my Spring Security authentication work?

I have the following configuration placed in /src/main/java/com/dog/bootstrap:
#EnableWebSecurity
#Configuration
public class CustomWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
#Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
System.out.println("hello");
auth.inMemoryAuthentication()
.withUser("user")
.password("password")
.roles("USER");
}
}
and I am loading it as follows:
public class WebInitializer implements WebApplicationInitializer {
#Override
public void onStartup(ServletContext container) {
// Create the dispatcher servlet's Spring application context
AnnotationConfigWebApplicationContext dispatcherContext = new AnnotationConfigWebApplicationContext();
dispatcherContext.scan("com.dog.bootstrap");
// Manage the lifecycle of the root application context
container.addListener(new ContextLoaderListener(dispatcherContext));
// Register and map the dispatcher servlet
ServletRegistration.Dynamic dispatcher =
container.addServlet("dispatcher", new DispatcherServlet(dispatcherContext));
dispatcher.setLoadOnStartup(1);
Set<String> mappingConflicts = dispatcher.addMapping("/");
if (!mappingConflicts.isEmpty()) {
throw new IllegalStateException("'dispatcher' could not be mapped to '/' due " +
"to an existing mapping.");
}
}
My controller:
#Controller
public class DogController {
#RequestMapping(value = {"/dog"}, method = RequestMethod.GET)
#ResponseBody
public String getSource(#PathVariable("domain") String domain) throws Exception {
return "dogs";
}
}
When I startup my app, I do see hello being printed, so configure(AuthenticationManagerBuilder auth) is being called. However, none of my endpoints are requiring me to enter a login page. When I go to localhost:8080/dog it outputs dogs without asking me to authenticate myself.
You're not actually including the filter chain, as described in the last step of this guide. Try adding this default initializer, which maps to /*:
#Component public class SecurityWebApplicationInitializer
extends AbstractSecurityWebApplicationInitializer {
}

Categories