How to include my class into Spring context? - java

We're running a Spring setup where I don't see any XML config files, seems everything is done via annotation.
I've got some custom component classes in a specific package I need added to the spring context for autowiring and I annotated the class with #Component but it's not making a difference. Am I missing another annotation?
There is one loop I have where I needed to do a component scan to discover all the classes in the package, maybe I can just add them there since I'd already have a BeanDefinition handle on them. If so, what would I have to do?
for (BeanDefinition bd : scanner.findCandidateComponents("com.blah.target")) {
// how to add it to context here?
}

If you don't see any XML config file, then the project should have a package springconfig with a java file called WebConfig.java. This is exact equivalent of XML config file.
Below is a snippet of a typical Webconfig.java
package .....springconfig;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.multipart.MultipartResolver;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
<...>
#Configuration
#EnableWebMvc
#ComponentScan(basePackages="<your source package>")
public class WebConfig extends WebMvcConfigurerAdapter {
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("home");
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry){
String dir="/resources/";
registry.addResourceHandler("/images/**").addResourceLocations(dir + "images/");
...
}
#Bean
public InternalResourceViewResolver viewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/view/");
resolver.setSuffix(".jsp");
return resolver;
}
#Bean
public MultipartResolver multipartResolver() {
CommonsMultipartResolver resolver = new CommonsMultipartResolver();
resolver.setMaxUploadSize(100);
return resolver;
}
}
Check out this tutorial: Simple Spring MVC Web Application It is very nicely explained here.

Related

Why does #ComponentScan behave differently for different configuration files?

I'm relatively new to Spring, and was following some examples.
During one of the examples I noticed that Spring wasn't mapping URI to methods.
I discovered that I put my #ComponentScan annotation on the wrong configuration class and fixed my problem.
So my question is why #ComponentScan works for one of these classes and not with the other?
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = {"org.zerock.controller"}) // This Works.
public class ServletConfig implements WebMvcConfigurer {
#Bean
public MultipartResolver multipartResolver(){
return new StandardServletMultipartResolver();
}
#Override
public void configureViewResolvers(ViewResolverRegistry registry) {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix(".jsp");
registry.viewResolver(resolver);
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
}
}
#Configuration
//#ComponentScan(basePackages = {"org.zerock.controller"}) This Doesn't Work
public class RootConfig {
}
// How the two configuration classes are initialized
public class WebConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class[]{RootConfig.class};
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{ServletConfig.class};
}
I've read that root config classes and servlet classes are set up differently in the application context hierarchy.
I suspect that has something to do with this, but I fail to see how that would cause this.
Javadoc for AbstractAnnotationConfigDispatcherServletInitializer recommend to implement:
getRootConfigClasses() -- for "root" application context (non-web infrastructure) configuration.
getServletConfigClasses() -- for DispatcherServlet application context (Spring MVC infrastructure) configuration.
If an application context hierarchy is not required, applications may return all configuration via getRootConfigClasses()
So a #ComponentScan on the RootConfig should work if there are no duplication on the ServletConfig level.
Could you post the error you get and all classes?
I recommend you to place the RootConfig in the root of you packages and use #ComponentScan without specifying base package.

The type WebMvcConfigurerAdapter is deprecated

I just migrate to spring mvc version 5.0.1.RELEASE but suddenly in eclipse STS WebMvcConfigurerAdapter is marked as deprecated
public class MvcConfig extends WebMvcConfigurerAdapter {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
// to serve static .html pages...
registry.addResourceHandler("/static/**").addResourceLocations("/resources/static/");
}
....
}
How can i remove this!
Since Spring 5 you just need to implement the interface WebMvcConfigurer:
public class MvcConfig implements WebMvcConfigurer {
This is because Java 8 introduced default methods on interfaces which cover the functionality of the WebMvcConfigurerAdapter class
See here:
https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/servlet/config/annotation/WebMvcConfigurerAdapter.html
I have been working on Swagger equivalent documentation library called Springfox nowadays and I found that in the Spring 5.0.8 (running at present), interface WebMvcConfigurer has been implemented by class WebMvcConfigurationSupport class which we can directly extend.
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
public class WebConfig extends WebMvcConfigurationSupport { }
And this is how I have used it for setting my resource handling mechanism as follows -
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("swagger-ui.html")
.addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/");
}
In Spring every request will go through the DispatcherServlet. To avoid Static file request through DispatcherServlet(Front contoller) we configure MVC Static content.
Spring 3.1. introduced the ResourceHandlerRegistry to configure ResourceHttpRequestHandlers for serving static resources from the classpath, the WAR, or the file system. We can configure the ResourceHandlerRegistry programmatically inside our web context configuration class.
we have added the /js/** pattern to the ResourceHandler, lets include the foo.js resource located in the webapp/js/ directory
we have added the /resources/static/** pattern to the ResourceHandler, lets include the foo.html resource located in the webapp/resources/ directory
#Configuration
#EnableWebMvc
public class StaticResourceConfiguration implements WebMvcConfigurer {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
System.out.println("WebMvcConfigurer - addResourceHandlers() function get loaded...");
registry.addResourceHandler("/resources/static/**")
.addResourceLocations("/resources/");
registry
.addResourceHandler("/js/**")
.addResourceLocations("/js/")
.setCachePeriod(3600)
.resourceChain(true)
.addResolver(new GzipResourceResolver())
.addResolver(new PathResourceResolver());
}
}
XML Configuration
<mvc:annotation-driven />
<mvc:resources mapping="/staticFiles/path/**" location="/staticFilesFolder/js/"
cache-period="60"/>
Spring Boot MVC Static Content if the file is located in the WAR’s webapp/resources folder.
spring.mvc.static-path-pattern=/resources/static/**
Use org.springframework.web.servlet.config.annotation.WebMvcConfigurer
With Spring Boot 2.1.4.RELEASE (Spring Framework 5.1.6.RELEASE), do like this
package vn.bkit;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; // Deprecated.
import org.springframework.web.servlet.view.InternalResourceViewResolver;
#Configuration
#EnableWebMvc
public class MvcConfiguration implements WebMvcConfigurer {
#Bean
public ViewResolver getViewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/");
resolver.setSuffix(".html");
return resolver;
}
#Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
}

What is the best way to configure PropertySourcesPlaceholderConfigurer / resource folders?

I have a (gradle/java/eclipse) project with what seems to me to be quite a standard folder structure
...main
java
...controller
...service
resources
webapp
...resources
WEB-INF
I'm having an issue I just don't understand although I have worked around it in a very messy way. If I specify the controllers folder in the component scan of my WebMvcConfigurerAdapter then the services classes can't pick up properties using the configured PropertySourcesPlaceholderConfigurer bean. If I broaden the component scan out the jsp files don't pick up the css includes!
So with this config class all is well but the properties aren't resolved int he service implementation class
config class
#EnableWebMvc
#Configuration
#ComponentScan({ "comm.app.controller" })
#PropertySource({ "classpath:app.properties" })
public class SpringWebConfig extends WebMvcConfigurerAdapter {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
}
#Bean
public InternalResourceViewResolver viewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setViewClass(JstlView.class);
viewResolver.setPrefix("/WEB-INF/views/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
//used to handle html put and delete rest calls
#Bean(name = "multipartResolver")
public CommonsMultipartResolver createMultipartResolver() {
CommonsMultipartResolver resolver=new CommonsMultipartResolver();
resolver.setDefaultEncoding("utf-8");
return resolver;
}
#Bean
public static PropertySourcesPlaceholderConfigurer propertyConfig() {
return new PropertySourcesPlaceholderConfigurer();
}
}
Service implementation class begins
#Service("appService")
#PropertySource({ "classpath:app.properties" })
public class appServiceImpl implements appService {
private RestTemplate restTemplate = new RestTemplate();
#Value("${property.reference}")
private String propref;
...
In this case ${property.reference} is not picked up but the view page styling (picked up from ...webapp\resources... .css) is fine.
If I change
#ComponentScan({ "comm.app.controller" })
to
#ComponentScan({ "comm.app" })
The properties are picked up (presumably because the propertyConfig bean comes into scope ?) but the local styling files can't be found ? Any link references to files webapp\resources... .css fails.
In the end I came to a bad (!?) solution of
1) keeping the scope of #ComponentScan({ "comm.app.controller" })
2) hacking the serviceimplementation class as so...
#Configuration
#Service("appService")
#PropertySource({ "classpath:app.properties" })
public class appServiceImpl implements appService {
private RestTemplate restTemplate = new RestTemplate();
#Bean
public static PropertySourcesPlaceholderConfigurer propertyConfig() {
return new PropertySourcesPlaceholderConfigurer();
}
#Value("${property.reference}")
private String propref;
...
Can anyone tell me if I've configured the path the the resources file incorrectly or maybe should be doing something differently with the propertyConfig bean ? (maybe injecting it or declaring another one in a different configuration file ?)

Static files can not found Spring MVC + Thymeleaf

I have a spring application which is a starting project. I used Thymeleaf as template engine. But i have problem which is i can not reach to the static files such as CSS or javascript. This is my file structure for this application.
This is the configuration file for Thymeleaf engine. And i also tried to add resource handling which is : SpringBoot with Thymeleaf - css not found
package com.ggk.config;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.thymeleaf.spring4.SpringTemplateEngine;
import org.thymeleaf.spring4.view.ThymeleafViewResolver;
import org.thymeleaf.templateresolver.ServletContextTemplateResolver;
#Configuration
#EnableWebMvc
#ComponentScan("com.ggk")
public class ThymeleafConfig extends WebMvcConfigurerAdapter {
#Bean
public ServletContextTemplateResolver servletContextTemplateResolver() {
ServletContextTemplateResolver servletContextTemplateResolver = new ServletContextTemplateResolver();
servletContextTemplateResolver.setPrefix("/WEB-INF/templates/");
servletContextTemplateResolver.setSuffix(".html");
servletContextTemplateResolver.setTemplateMode("HTML5");
servletContextTemplateResolver.setCacheable(false);
return servletContextTemplateResolver;
}
#Bean
#Autowired
public SpringTemplateEngine springTemplateEngine(ServletContextTemplateResolver servletContextTemplateResolver) {
SpringTemplateEngine springTemplateEngine = new SpringTemplateEngine();
springTemplateEngine.setTemplateResolver(servletContextTemplateResolver);
return springTemplateEngine;
}
#Bean
#Autowired
public ThymeleafViewResolver thymeleafViewResolver(SpringTemplateEngine springTemplateEngine) {
ThymeleafViewResolver thymeleafViewResolver = new ThymeleafViewResolver();
thymeleafViewResolver.setTemplateEngine(springTemplateEngine);
return thymeleafViewResolver;
}
}
here is my index.html adding css files.
<link rel="stylesheet" href="../css/animate.css" th:href="#{/css/animate.css}" type="text/css"/>
I guess you cannot view the static resources directly via chrome as well, like:
http://<domain_name>:<port>/<context_root>/css/animate.css
I think it gives you a 404 error. If this is the case, that means your app needs a configuration to serve static resources. Basically you need to add a ResourceHandler to your config. See following link for an example:
https://stackoverflow.com/a/30663486/878361
In summary you need to:
extend WebMvcConfigurerAdapter (which you've already done)
override addResourceHandlers method and add your resource locations like follows:
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**")
.addResourceLocations("/resources/");
}
Move css and images to webapp.

ViewResolver using Java annotation

Is it possible in Spring 3.1.1 to configure a view resolver using Java annotations?
I am done with all configurations using Java annotations, but I am stuck at view resolver.
Code
package com;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import javax.sql.DataSource;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import com.*;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.UrlBasedViewResolver;
import org.springframework.web.servlet.view.JstlView;
#Configuration
#ComponentScan("com")
public class AppConfig
{
{
//Other bean declarations
}
#Bean
public UrlBasedViewResolver urlBasedViewResolver()
{
UrlBasedViewResolver res = new InternalResourceViewResolver();
res.setViewClass(JstlView.class);
res.setPrefix("/WEB-INF/");
res.setSuffix(".jsp");
return res;
}
}
I used this code and ran the application, but it's not returning the appropriate view. However, if I configure a viewresolver in the app-servlet.xml file, it works fine.
Your class should extend WebMvcConfigurerAdapter class. please have a look at below example
#Configuration
#ComponentScan(basePackages="com")
#EnableWebMvc
public class MvcConfiguration extends WebMvcConfigurerAdapter{
#Bean
public ViewResolver getViewResolver(){
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix(".jsp");
return resolver;
}
}
I tested your scenario with Spring 4.3.4 and it is working ok.
I would suggest double checking packages you scan and that AppConfig is properly provided.
I am attaching all files starting from your AppConfig. Yet it is good to extend WebMvcConfigurerAdapter. The source code attached is not ideal, it s simplistic and only to try to reproduce the problem you have reported.
Starting from AppConfig:
package com;
import org.springframework.context.annotation.*;
import org.springframework.web.servlet.view.*;
#Configuration
#ComponentScan("com")
public class AppConfig {
#Bean
public UrlBasedViewResolver getViewResovler() {
UrlBasedViewResolver urlBasedViewResolver = new UrlBasedViewResolver();
urlBasedViewResolver.setViewClass(JstlView.class);
urlBasedViewResolver.setPrefix("/WEB-INF/jsp/");
urlBasedViewResolver.setSuffix(".jsp");
return urlBasedViewResolver;
}
}
Then:
package com;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
public class WebInit extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[] { };
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[] { AppConfig.class };
}
#Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
}
Finally:
package com;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
#Controller
public class MainController {
#RequestMapping("/")
public ModelAndView asdf() {
return new ModelAndView("ABC");
}
}
The problem with the above is that the DispatcherServlet.initViewResolvers get's called before the bean getViewResolver is defined and it cannot find the bean so it never adds the view resolver.
If you move the bean definition into an xml definition, it get's picked up. For some reason the MvcConfiguration class you have defined does not trigger a DispatcherServlet refresh if there are no ViewResolvers defined in the XML.

Categories