My handler was working prior to some dependency updates and ditching of the XML in my app. But now I get this error
org.springframework.web.servlet.DispatcherServlet noHandlerFound
WARNING: No mapping for GET /resources/img/logo.png
My view resolver is working fine, my controller is pointing to the right places it is just my css/js that doesn't seem to map.
public class ConfigClass {
#Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setPrefix("/WEB-INF/view/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
public void addResourceHandlers(final ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
}
WebMvcConfigurationSupport appears to be essential.
public class ConfigClass extends WebMvcConfigurationSupport{
//Rest here
}
EDIT
The initial answer was based on an amateur "cached" answer. The actual solution was using
public class ConfigClass extends WebMvcConfigurerAdapter {
However, this is now deprecated. Am looking into an answer for that.
Related
My use case is running custom code before a controller method by annotating methods.
HandlerInterceptor seems the way to go but it seems impossible to inject dependencies into it because it needs to be registered before the context is being created.
All examples I've found so far use empty constructors (see spring boot adding http request interceptors) or autowire properties in the configuration which fails because I declare dependent beans in the same configuration (Requested bean is currently in creation: Is there an unresolvable circular reference?).
Is there a better way that does not involve AOP?
Assume that your interceptor has constructor dependencies like that:
public class CustomInterceptor extends HandlerInterceptor {
private final DependentBean bean;
public CustomInterceptor(DependentBean bean) {
this.bean = bean;
}
}
Then you can register your handler like that:
#Configuration
public WebConfig extends WebMvcConfigurerAdapater {
#Bean
public DependentBean dependentBean() {
return new DependentBean();
}
#Bean
public CustomInterceptor customInterceptor() {
return new CustomInterceptor(dependentBean());
}
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(customInterceptor());
}
}
#Configuration will ensure each Bean method call return the same bean instance
Building on the answer above from Mạnh, if using component scan for dependency injection of the dependency, then that can be Autowired in the WebConfig
#Configuration
public WebConfig extends WebMvcConfigurerAdapater {
#Autowired
DependentBean dependentBean;
#Bean
public CustomInterceptor customInterceptor() {
return new CustomInterceptor(dependentBean);
}
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(customInterceptor());
}
}
Also building on previous answers, and if you use Lombok, you can further simplify.
Have your interceptor implementation been a #Component
Add a private final DependentBean field to it.
Also add a #RequiredArgsConstructor annotation to it, to have Lombok generating a constructor with a single DependentBean parameter.
In your WebConfig, use the same technic to have a private final CustomInterceptor field been injected by Spring IOC.
This way the CustomInterceptor instance will be available & initialized the right way when addInterceptors will be called
Here are the corresponding code samples :
The CustomInterceptor :
#Component
#RequiredArgsConstructor
public class CustomInterceptor implements HandlerInterceptor {
private final DependentBean dependentBean;
#Override
public boolean preHandle( final HttpServletRequest request,
final HttpServletResponse response,
final Object handler ) throws Exception {
// your Interceptor Implementation goes here ...
}
}
The WebConfig :
#Configuration
#RequiredArgsConstructor
public class WebConfig implements WebMvcConfigurer {
private final CustomInterceptor customInterceptor;
#Override
public void addInterceptors( final InterceptorRegistry registry ) {
registry.addInterceptor( customInterceptor );
}
}
I'm a newer of Spring MVC , and I'm trying to config a simple controller like below ,but when i test it. I got
javax.servlet.ServletException: Circular view path [index]: would dispatch back to the current handler URL [/index] again. Check your ViewResolver setup! (Hint: This may be the result of an unspecified view, due to default view name generation.)
Here is my WebConfig.java Code:
#Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix(".jsp");
return resolver;
}
Here is my IndexController.java Code:
#Controller
#RequestMapping("/index")
public class IndexController {
#RequestMapping(method = RequestMethod.GET)
public String index() {
return "index";
}
}
Here is my Test Fiel :
public class TestIndexController {
#Test
public void testIndexController() throws Exception {
IndexController indexController = new IndexController();
MockMvc mockMvc = standaloneSetup(indexController).build();
mockMvc.perform(get("/index")).andExpect(view().name("index"));
}
}
Every time when i changed the get("/index") to get("/index.jsp") ,i passed the test. but i just can't figure it out, please help me out
In your test setup, you create an instance of the Controller under test, but the context created for the test has no knowledge of the existence of your WebConfig and therefore, no instance of your ViewResolver.
Here is a quick fix :
public void testIndexController() throws Exception {
IndexController indexController = new IndexController();
MockMvc mockMvc = standaloneSetup(indexController)
setViewResolvers((new WebConfig()).viewResolver()).build();
mockMvc.perform(get("/index")).andExpect(view().name("index"));
}
If you don't want to access WebConfig in your test class, you can also create a new instance of ViewResolver and add it to your mockMvc setup.
Hope this helps.
I thought I had this figured out but the setting does not seem to change the index. setOneIndexedParameters(true)
#Configuration
#EnableWebMvc
public class WebMvcConfig extends WebMvcConfigurerAdapter {
#Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
PageableHandlerMethodArgumentResolver resolver = new PageableHandlerMethodArgumentResolver();
resolver.setOneIndexedParameters(true);
argumentResolvers.add(resolver);
super.addArgumentResolvers(argumentResolvers);
}
.... other config stuff
Expected result is that instead of the base URL for spring data rest being http://localhost:8080/api/text?page=0&size=20 it would change to http://localhost:8080/api/text?page=1&size=20 as the initial page.
Did I do this correctly or is this a bug?
The answer was here Spring Data Rest - Configure pagination
I moved the configuration to extending RepositoryRestMvcConfiguration
#Configuration
class CustomRestMvcConfiguration extends RepositoryRestMvcConfiguration {
#Override
#Bean
public HateoasPageableHandlerMethodArgumentResolver pageableResolver() {
HateoasPageableHandlerMethodArgumentResolver resolver = super.pageableResolver();
resolver.setOneIndexedParameters(true);
return resolver;
}
}
In the following setup, the TimingInterceptor and CORSHeaders interceptor execute on all URL requests, except for /resources/** URLs. How do I make the interceptors work for /resources/** URLs served by the ResourceHttpRequestHandler?
#EnableWebMvc //equivalent to mvc:annotation-driven
#Configuration
#PropertySource("classpath:configuration.properties")
public class WebConfig extends WebMvcConfigurerAdapter {
#Inject
private TimingInterceptor timingInterceptor;
#Inject
private CORSHeaders corsHeaders;
// equivalent to mvc:resources
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
}
// equivalent to mvc:interceptors
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(timingInterceptor).addPathPatterns("/**");
registry.addInterceptor(corsHeaders).addPathPatterns("/**");
}
}
Update: As of Spring Framework 5.0.1 (and SPR-16034), interceptors are automatically mapped on ResourceHttpRequestHandler by default.
I think the configured interceptors aren't mappped on the resource handler, but on the one handling #RequestMapping requests.
Maybe try this instead?
#EnableWebMvc //equivalent to mvc:annotation-driven
#Configuration
#PropertySource("classpath:configuration.properties")
public class WebConfig extends WebMvcConfigurerAdapter {
#Inject
private TimingInterceptor timingInterceptor;
#Inject
private CORSHeaders corsHeaders;
// equivalent to mvc:resources
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
}
#Bean
public MappedInterceptor timingInterceptor() {
return new MappedInterceptor(new String[] { "/**" }, timingInterceptor);
}
#Bean
public MappedInterceptor corsHeaders() {
return new MappedInterceptor(new String[] { "/**" }, corsHeaders);
}
}
This should be better documented with SPR-10655.
I never tried to use Spring interceptors for serving resources. The power of interceptors is to have a hook before controller and between controller and view.
To add pre- or post-processing around resources, you'd better use filters.
In the classic web.xml type configuration you could configure context parameters like so
web.xml
...
<context-param>
<param-name>p-name</param-name>
<param-value>-value</param-value>
</context-param>
...
How is this achieved in spring-boot. I have a filter that requires parameters.
I'm using #EnableAutoConfiguration and have included <artifactId>spring-boot-starter-jetty</artifactId> in my pom.
You can set parameters using the server.servlet.context-parameters application property. For example:
server.servlet.context-parameters.p-name=p-value
In Spring Boot 1.x, which is no longer supported, this property was named server.context-parameters:
servlet.context-parameters=p-name=p-value
Alternatively, you can configure parameters programmatically by declaring a ServletContextInitializer bean:
#Bean
public ServletContextInitializer initializer() {
return new ServletContextInitializer() {
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
servletContext.setInitParameter("p-name", "-value");
}
};
}
You can actually achieve this using Java config. If you have filter that requires some parameters, just put them in your application.yml (or .properties), inject them using #Value in your config class and register them in FilterRegistrationBean.
For example:
#Value("${myFilterParam}")
private String myFilterParam;
#Bean(name="myFilter")
public FilterRegistrationBean myFilter() {
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new MyFilter());
filterRegistrationBean.setInitParameters(Collections.singletonMap("p-name", "p-value"));
return filterRegistrationBean;
}
Also JavaDoc for FilterRegistrationBean:
http://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/context/embedded/FilterRegistrationBean.html
Update
You can register parameters for servlet context in SpringBootServletInitializer#onStartup() method. Your Application class can extend the SpringBootServletInitializer and you can override the onStartup method and set the parameters there. Example:
#Configuration
#EnableAutoConfiguration
#ComponentScan
public class Application extends SpringBootServletInitializer {
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Application.class);
}
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
servletContext.setInitParameter("p-name", "p-value");
super.onStartup(servletContext);
}
public static void main(String[] args) {
SpringApplication.run(Application.class);
}
}
Other alternative is to define ServletContextInitializer bean as suggested by Andy Wilkinson.
Since Spring Boot 2.0.0 they updated the way to add context param:
server.servlet.context-parameters.yourProperty.
You can see more updates on this link
Also you can define InitParameterConfiguringServletContextInitializer in your configuration. Example:
#Bean
public InitParameterConfiguringServletContextInitializer initParamsInitializer() {
Map<String, String> contextParams = new HashMap<>();
contextParams.put("p-name", "-value");
return new InitParameterConfiguringServletContextInitializer(contextParams);
}