I'm new to spring. There is an existing spring project(Not maven, its a dynamic web project) on 4.3.9 version which is a working fine. I've written a new #RestController in the project and tried to access this controller from different machine. It throws me the
XMLHttpRequest cannot load http://<URL>. No 'Access-Control-Allow-Origin' header is present on the requested
There are only two files available for config here. There are no XML files for configuration. I'm confused where to add the cors filter config for the Application totally. I've added addCorsMappings in the AppInitializer Class. But still it doesnt work.
If I add #CrossOrigin(origins = "*", maxAge = 3600) it works on a controller only. I want for the total application.
#CrossOrigin(origins = "*", maxAge = 3600) -> This works only controller lvel
#RestController
public class CTUController {
// code
}
Kindly suggest me where to add
AppConfig class
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = "net.qdj.spring")
public class AppConfig{
}
AppInitializer
public class AppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#SuppressWarnings({ "rawtypes", "unchecked" })
#Override
protected Class[] getRootConfigClasses() {
return new Class[] { AppConfig.class };
}
#SuppressWarnings({ "rawtypes", "unchecked" })
#Override
protected Class[] getServletConfigClasses() {
return null;
}
#Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
// Added for CORS -> Not working for application level
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**");
}
}
Kindly advice me in this context
Use allowedOrigins.
registry.addMapping("/**").allowedOrigins("http://localhost:9000");
Instead of :
registry.addMapping("/**");
Related
I am using a Spring MVC (5.3.7) app which has a Rest Controller. When I deploy the war using Intellij or manually on Tomcat 10.0 server, the get url gives me 404. After trying different Spring MVC configs which offcourse didn't work. Finally I resorted to the following config but still no luck
My DispatcherServletInitializer,
package com.luv2code.springdemo.config;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
public class MySpringMvcDispatcherServletInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
// TODO Auto-generated method stub
return null;
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class[] { DemoAppConfig.class };
}
#Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
}
My DemoConfig class as below used above,
#Configuration
#EnableWebMvc
#ComponentScan("com.luv2code.springdemo")
public class DemoAppConfig implements WebMvcConfigurer {
}
RestController class
#RestController
#RequestMapping("/api")
public class CustomerRestController {
#GetMapping("/customers")
public List<Customer> getCustomers() {
return customerService.getCustomers();
}
}
I have also added index.jsp in webapp folder in classpath which shows the right html (no 404 in route) when war is deployed. Meaning my MVC setup is fine but I don't know why I cannot reach the controller. I am using Java 11, here are the MAVEN dependencies list,
javax.servlet-api - 4.0.1
javax.servlet.jsp-api - 2.3.3
spring-webmvc - 5.3.7 Final
Packaging - war
Thanks for the suggestion. Downgrading to Tomcat#9 has done the work for me. Everything seems to be working now.
Here is the issue link which describes the incompatibility with Spring MVC 5.3.7 and Tomcat#10
I've experience in Spring MVC, but first time using Cache. These are steps that I've done yet.
Step : 1
// In spring config
#Bean
public CacheManager cacheManager() {
return new ConcurrentMapCacheManager("user");
}
// Cached Object
public class CachedUser {
private String username;
private String token;
// Public getter-setter
}
// AuthServiceImp
#Service
public class AuthServiceImp implements AuthService {
#Override
#Cacheable(value="user", key="#token")
#Transactional
public CachedUser loadUserDetailsFromDb(String username, String token) {
// codes here
}
#Override
#CacheEvict(value="user", key="#token")
#Transactional
public void removeUser(String username, String token) {
// codes here
}
}
// My Filter
public class AuthenticationTokenFilter extends UsernamePasswordAuthenticationFilter {
AuthService authService = WebApplicationContextUtils
.getRequiredWebApplicationContext(this.getServletContext())
.getBean(AuthService.class);
CachedUser user = this.authService.loadUserDetailsFromDb(username, authToken);
}
// Controller
#RestController
public class AuthenticationController {
#Autowired
private AuthService authService;
#GetMapping("logout2")
public ResponseModel logout(#RequestAttribute("username") String username,
HttpServletRequest request) {
String token = request.getHeader(tokenHeader);
authService.removeUser(username, token);
return new ResponseModel(200,"Success",null);
}
}
Whenever calling loadUserDetailsFromDb from AuthenticationTokenFilter it returns cached object (except in first call obviously). That means #Cacheable(value="user", key="#token") is working fine.
But even after I logged out and called authService.removeUser(), calling loadUserDetailsFromDb() fetches the cached object. That means #CacheEvict(value="user", key="#token") is not working.
Step: 2
Referred this and moved removeUser() to another service ( say CacheServiceImp implements CacheService ), yet same problem.
Step: 3
Reffered this and , by my understanding, moved #Cache* annotation to interface AuthService, got following error.
java.lang.IllegalArgumentException: Null key returned for cache
operation (maybe you are using named params on classes without debug
info?)
Note : Is the problem of not evicting, because I'm calling #Cacheable and #CacheEvict methods from different classes. That is from AuthenticationTokenFilter and AuthenticationController
After playing with my code, head and internet, at last, I got this solved. It's a mistake in my Spring (Security) configuration, which I failed to post with the question.
Mistake 1 :
In SecurityInitializer class
public class SecurityInitializer extends AbstractSecurityWebApplicationInitializer {
public SecurityInitializer() {
super(WebSecurityConfiguration.class);
}
}
As the project includes Spring MVC configuration, the constructor must not be implemented. So removed the constructor. This class, then, simply registers the springSecurityFilterChain Filter for every URL.
Mistake 2: ( THE REAL CAUSE OF ABOVE PROBLEM )
I've added my AuthenticationTokenFilter in two ways:
public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
// other overrides
#Override
protected Filter[] getServletFilters() {
return new Filter[]{ new AuthenticationTokenFilter() };
}
}
and
#Configuration
#EnableWebSecurity
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
// Other config
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
//Other config
httpSecurity.addFilterBefore(authTokenFilter,
UsernamePasswordAuthenticationFilter.class);
}
}
This made the filter to be called twice, one inside Spring context and the other as usual Servlet filter
So removed configuration inside WebAppInitializer
Additional change
Removed #ComponentScan from WebSecurityConfiguration because it's already in SpringMvcConfig. This requires both configurations to be loaded in same context. Done by following code.
public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return null;
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class[] { SpringMvcConfig.class, WebSecurityConfiguration.class };
}
#Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
// Removed filter registering from here (Mistake 2)
}
At last, everything working FINE :)
I got a working spring boot rest service. When the path is wrong it doesn't return anything. No response At all. At the same time it doesn't throw error either. Ideally I expected a 404 not found error.
I got a GlobalErrorHandler
#ControllerAdvice
public class GlobalErrorHandler extends ResponseEntityExceptionHandler {
}
There is this method in ResponseEntityExceptionHandler
protected ResponseEntity<Object> handleNoHandlerFoundException(NoHandlerFoundException ex, HttpHeaders headers,
HttpStatus status, WebRequest request) {
return handleExceptionInternal(ex, null, headers, status, request);
}
I have marked error.whitelabel.enabled=false in my properties
What else must I do for this service to throw a 404 not found response back to clients
I referred a lot of threads and don't see this trouble faced by anybody.
This is my main application class
#EnableAutoConfiguration // Sprint Boot Auto Configuration
#ComponentScan(basePackages = "com.xxxx")
#EnableJpaRepositories("com.xxxxxxxx") // To segregate MongoDB
// and JPA repositories.
// Otherwise not needed.
#EnableSwagger // auto generation of API docs
#SpringBootApplication
#EnableAspectJAutoProxy
#EnableConfigurationProperties
public class Application extends SpringBootServletInitializer {
private static Class<Application> appClass = Application.class;
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(appClass).properties(getProperties());
}
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Bean
public FilterRegistrationBean correlationHeaderFilter() {
FilterRegistrationBean filterRegBean = new FilterRegistrationBean();
filterRegBean.setFilter(new CorrelationHeaderFilter());
filterRegBean.setUrlPatterns(Arrays.asList("/*"));
return filterRegBean;
}
#ConfigurationProperties(prefix = "spring.datasource")
#Bean
public DataSource dataSource() {
return DataSourceBuilder.create().build();
}
static Properties getProperties() {
Properties props = new Properties();
props.put("spring.config.location", "classpath:/");
return props;
}
#Bean
public WebMvcConfigurerAdapter webMvcConfigurerAdapter() {
WebMvcConfigurerAdapter webMvcConfigurerAdapter = new WebMvcConfigurerAdapter() {
#Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer.favorPathExtension(false).favorParameter(true).parameterName("media-type")
.ignoreAcceptHeader(false).useJaf(false).defaultContentType(MediaType.APPLICATION_JSON)
.mediaType("xml", MediaType.APPLICATION_XML).mediaType("json", MediaType.APPLICATION_JSON);
}
};
return webMvcConfigurerAdapter;
}
#Bean
public RequestMappingHandlerMapping defaultAnnotationHandlerMapping() {
RequestMappingHandlerMapping bean = new RequestMappingHandlerMapping();
bean.setUseSuffixPatternMatch(false);
return bean;
}
}
The solution is pretty easy:
First you need to implement the controller that will handle all error cases. This controller must have #ControllerAdvice -- required to define #ExceptionHandler that apply to all #RequestMappings.
#ControllerAdvice
public class ExceptionHandlerController {
#ExceptionHandler(NoHandlerFoundException.class)
#ResponseStatus(value= HttpStatus.NOT_FOUND)
#ResponseBody
public ErrorResponse requestHandlingNoHandlerFound() {
return new ErrorResponse("custom_404", "message for 404 error code");
}
}
Provide exception you want to override response in #ExceptionHandler. NoHandlerFoundException is an exception that will be generated when Spring will not be able to delegate request (404 case). You also can specify Throwable to override any exceptions.
Second you need to tell Spring to throw exception in case of 404 (could not resolve handler):
#SpringBootApplication
#EnableWebMvc
public class Application {
public static void main(String[] args) {
ApplicationContext ctx = SpringApplication.run(Application.class, args);
DispatcherServlet dispatcherServlet = (DispatcherServlet)ctx.getBean("dispatcherServlet");
dispatcherServlet.setThrowExceptionIfNoHandlerFound(true);
}
}
Result when I use non defined URL
{
"errorCode": "custom_404",
"errorMessage": "message for 404 error code"
}
UPDATE: In case you configure your SpringBoot application using application.properties then you need to add the following properties instead of configuring DispatcherServlet in main method (thanks to #mengchengfeng):
spring.mvc.throw-exception-if-no-handler-found=true
spring.web.resources.add-mappings=false
I know this is an old question but here is another way to configure the DispatcherServlet in code but not in the main class. You can use a separate #Configuration class:
#EnableWebMvc
#Configuration
public class ExceptionHandlingConfig {
#Autowired
private DispatcherServlet dispatcherServlet;
#PostConstruct
private void configureDispatcherServlet() {
dispatcherServlet.setThrowExceptionIfNoHandlerFound(true);
}
}
Please not that this does not work without the #EnableWebMvc annotation.
Add this to your Properties file.
spring:
mvc:
throw-exception-if-no-handler-found: true
web:
resources:
add-mappings: false
In your #ControllerAdvice class add this:
#ExceptionHandler(NoHandlerFoundException.class)
public ResponseEntity<Object> handleNoHandlerFound404() {
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);;
}
I created to simple spring mvc configuration using java based configuration:
Config file:
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = "com.kitchen")
public class WebMvcConfiguration extends WebMvcConfigurerAdapter {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/kitchen/**").addResourceLocations("/kitchen/");
registry.addResourceHandler("/images/**").addResourceLocations("file:E:/Work/images/");
}
#Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
}
Initializer:
public class WebMvcAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[0];
}
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[]{WebMvcConfiguration.class};
}
protected String[] getServletMappings() {
return new String[]{"/"};
}
#Override
protected Filter[] getServletFilters() {
return new Filter[]{new CORSFilter()};
}
}
Controller:
#Controller
public class IndexController {
#RequestMapping(value = "/")
public String getIndexPage() {
return "kitchen/index.html";
}
}
All files are located in same package. But when I try to deploy in tomcat, nothing is deployed. I am not good in configurations so I would like to ask maybe I forgot something more? I do not want to use web.xml, just plain java configuration.
Also there could be problem creating modules and artifacts in in Idea IDE I moved not a lot of time ogo to it from eclipse. so here is everithing a little bit different. Here are my configurations of project modules and artifacts, can you please tell me what could be problems in my situation?
Screens:
What is the difference between getServletConfigClasses() vs getRootConfigClasses() when extending AbstractAnnotationConfigDispatcherServletInitializer.
I've been reading a lot sources since this morning but I haven't get any clear understanding on the differences yet :
Please have look at these two configurations :
1).
public class SpringMvcInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] { ConServlet.class };
}
#Override
protected Class<?>[] getServletConfigClasses() {
return null;
}
....
....
}
The ConServlet.class is refering to
#EnableWebMvc
#Configuration
#ComponentScan({ "com" })
#Import({ SecurityConfig.class })
public class ConServlet {
#Bean
public InternalResourceViewResolver viewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setViewClass(JstlView.class);
viewResolver.setPrefix("/WEB-INF/pages/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
}
2).
public class WebInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return null;
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[] { WebConfig.class };
}
.....
}
the WebConfig.class is refering to
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = { "....." })
public class WebConfig extends WebMvcConfigurerAdapter {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
}
#Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setViewClass(JstlView.class);
viewResolver.setPrefix("/WEB-INF/views");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
}
I see both ConServlet & WebConfig (more or less) doing the same things like initializating view :
But why :
ConServlet is returned in getRootConfigClasses()
while WebConfig is returned in getServletConfigClasses()
I read the documentation
both getRootConfigClasses() & getServletConfigClasses() is for
Specify #Configuration and/or #Component classes to be provided to..
(their differences )
the root application context for getRootConfigClasses()
the dispatcher servlet application context for getServletConfigClasses()
but why then ConServlet & WebConfig doing same things (like initizialising view), maybe I'm the one misunderstood it. What's are actually root context and dispatcher servlets (I know this one) in the simple term/example
Thank you!
A Bit on ApplicationContext Hierarchies
Spring's ApplicationContext provides the capability of loading multiple (hierarchical) contexts, allowing each to be focused on one particular layer, such as the web layer of an application or middle-tier services.
One of the canonical examples of using hierarchical ApplicationContext is when we have multiple DispatcherServlets in a web application and we're going to share some of the common beans such as datasources between them. This way, we can define a root ApplicationContext that contain all the common beans and multiple WebApplicationContexts that inherit the common beans from the root context.
In the Web MVC framework, each DispatcherServlet has its own WebApplicationContext, which inherits all the beans already defined in the root WebApplicationContext. These inherited beans can be overridden in the servlet-specific scope, and you can define new scope-specific beans local to a given Servlet instance.
Typical context hierarchy in Spring Web MVC (Spring Documentation)
If you're living in a single DispatherServlet world, it is also possible to have just one root context for this scenario:
Single root context in Spring Web MVC (Spring Documentation)
Talk is cheap, Show me the code!
Suppose we're developing a web application and we're going to use Spring MVC, Spring Security and Spring Data JPA. For this simple scenario, we would have at least three different config files. A WebConfig that contains all our web related configurations, such as ViewResolvers, Controllers, ArgumentResolvers, etc. Something like following:
#EnableWebMvc
#Configuration
#ComponentScan(basePackages = "com.so.web")
public class WebConfig extends WebMvcConfigurerAdapter {
#Bean
public InternalResourceViewResolver viewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setPrefix("/WEB-INF/views/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
#Override
public void configurePathMatch(PathMatchConfigurer configurer) {
final boolean DO_NOT_USE_SUFFIX_PATTERN_MATCHING = false;
configurer.setUseSuffixPatternMatch(DO_NOT_USE_SUFFIX_PATTERN_MATCHING);
}
}
Here I'm defining a ViewResolver to resolve my plain old jsps, poor life decisions, basically. We would need a RepositoryConfig, which contains all the data access facilities such as DataSource, EntityManagerFactory, TransactionManager, etc. It probably would be like following:
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(basePackages = "com.so.repository")
public class RepositoryConfig {
#Bean
public DataSource dataSource() { ... }
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() { ... }
#Bean
public PlatformTransactionManager transactionManager() { ... }
}
And a SecurityConfig which contains all the security related stuff!
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
#Autowired
protected void configure(AuthenticationManagerBuilder auth) throws Exception { ... }
#Override
protected void configure(HttpSecurity http) throws Exception { ... }
}
For gluing all these together, we have two options. First, we can define a typical hierarchical ApplicationContext, by adding RepositoryConfig and SecurityConfig in root context and WebConfig in their child context:
public class ServletInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[] { RepositoryConfig.class, SecurityConfig.class };
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[] { WebConfig.class };
}
#Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
}
Since we have a single DispatcherServlet here, we can add the WebConfig to the root context and make the servlet context empty:
public class ServletInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[] { RepositoryConfig.class, SecurityConfig.class, WebConfig.class };
}
#Override
protected Class<?>[] getServletConfigClasses() {
return null;
}
#Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
}
Further Reading
Skaffman did a great job on explaining ApplicationContext hierarchies in this answer, which is highly recommended. Also, you can read Spring Documentation.
Root Config Classes are actually used to Create Beans which are Application Specific and which needs to be available for Filters (As Filters are not part of Servlet).
Servlet Config Classes are actually used to Create Beans which are DispatcherServlet specific such as ViewResolvers, ArgumentResolvers, Interceptor, etc.
Root Config Classes will be loaded first and then Servlet Config Classes will be loaded.
Root Config Classes will be the Parent Context and it will create a ApplicationContext instace. Where as Servlet Config Classes will be the Child Context of the Parent Context and it will create a WebApplicationContext instance.
In your ConServlet Configuration, You don't need to specify the #EnableWebMvc as well the InternalResourceViewResolver bean as they are only required at the WebConfig.