I want to handle unmapped urls/404 errors in Spring MVC App I have found an example Here SO Answer, I Java Based Configuration and tried in this way
#EnableWebMvc
#Configuration
#ComponentScan(basePackages = { "com.app.controller" })
public class ServletConfigurer extends WebMvcConfigurerAdapter {
private Properties errorResolverProperties;
private Properties errorProperties;
/// Here I'm configuring <beans as mentioned in SO Answer
#Bean
public SimpleUrlHandlerMapping simpleUrlHandlerMapping() {
SimpleUrlHandlerMapping simpleUrlHandlerMapping = new SimpleUrlHandlerMapping();
errorResolverProperties = new Properties();
errorProperties = new Properties();
errorProperties.put("/**", pageNotFoundController());
errorResolverProperties.put("mappings", errorProperties);
return simpleUrlHandlerMapping;
}
// this is my Controller
#Bean
public PageNotFoundController pageNotFoundController(){
return new PageNotFoundController();
}
#Bean
public TilesConfigurer tilesConfigurer() {
TilesConfigurer tilesConfigurer = new TilesConfigurer();
tilesConfigurer.setDefinitions("/WEB-INF/tiles_xml/tiles.xml");
return tilesConfigurer;
}
}
My controller is
#Controller
public class PageNotFoundController {
#ExceptionHandler
#ResponseStatus(HttpStatus.NOT_FOUND)
public String handleINFException(PageNotFoundException ex) {
return "error";
}
}
and finally the
public class PageNotFoundException extends RuntimeException {
private static final long serialVersionUID = 1L;
public PageNotFoundException(String message) {
super(message);
}
}
but it always shows the same error page of Apache not the custom/my error page.
UPDATE
public class AppInitializer implements WebApplicationInitializer {
public void onStartup(ServletContext servletContext) throws ServletException {
WebApplicationContext rootContext = getWebApplicationContext();
servletContext.addListener(new ContextLoaderListener(rootContext));
servletContext.setInitParameter("defaultHtmlEscape", "true");
// add the dispatcher servlet and map it to /
DispatcherServlet dispatcherServlet = new DispatcherServlet(rootContext);
dispatcherServlet.setThrowExceptionIfNoHandlerFound(true);
ServletRegistration.Dynamic dispatcher = servletContext.addServlet(
"springDispatcher", dispatcherServlet);
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("/");
}
private AnnotationConfigWebApplicationContext getWebApplicationContext() {
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.setConfigLocation("com.app.config");
return context;
}
}
that is it..
If you want to catch it globally, you need a ControllerAdvice:
#ControllerAdvice
public class ExceptionHandlerController {
public static final String DEFAULT_ERROR_VIEW = "error";
public static final String STATUS_CODE = "404";
public static final String TYPE = "Custom Type";
#ExceptionHandler(value = {NoHandlerFoundException.class})
public ModelAndView defaultErrorHandler(HttpServletRequest request, Exception e) {
ModelAndView mav = new ModelAndView(DEFAULT_ERROR_VIEW);
mav.addObject("timestamp", new Date());
mav.addObject("status", STATUS_CODE);
mav.addObject("type", TYPE);
mav.addObject("message", String.format("The requested url is: %s", request.getRequestURL()));
return mav;
}
}
Now you need to activate, that an Exception is thrown in case of 404:
#Autowired
public void configureDispatcher(DispatcherServlet dispatcherServlet){
dispatcherServlet.setThrowExceptionIfNoHandlerFound(true);
}
Insert it in any #Configuration annotated class.
That's it!
UPDATE
Change your class to
#Configuration
public class AppInitializer implements WebApplicationInitializer {
public void onStartup(ServletContext servletContext) throws ServletException {
WebApplicationContext rootContext = getWebApplicationContext();
servletContext.addListener(new ContextLoaderListener(rootContext));
servletContext.setInitParameter("defaultHtmlEscape", "true");
}
private AnnotationConfigWebApplicationContext getWebApplicationContext() {
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.setConfigLocation("com.app.config");
return context;
}
#Autowired
public void configureDispatcher(DispatcherServlet dispatcherServlet){
dispatcherServlet.setThrowExceptionIfNoHandlerFound(true);
}
}
Related
I got AuthenticationCredentialsNotFoundException running my Spring Rest Service which should be secured with basic authentication. This leads to HTTP 500 instead of the expected 403.
Anything missing in the configuration?
My Spring security config:
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true, proxyTargetClass = true)
public class MySecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
public void configureGlobalSecurity(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("bill").password("abc123").roles("USER");
}
}
My Spring config:
#Configuration
#ComponentScan(basePackages = {"com.dummy"})
#EnableWebMvc
#Import({MySecurityConfig.class})
public class MySpringConfig extends WebMvcConfigurerAdapter implements WebApplicationInitializer {
#Override
public void onStartup(final ServletContext servletContext) throws ServletException {
final AnnotationConfigWebApplicationContext context = getContext();
servletContext.addListener(new ContextLoaderListener(context));
final ServletRegistration.Dynamic dispatcher = servletContext.addServlet("springDispatcher",
new DispatcherServlet(context));
dispatcher.setLoadOnStartup(0);
dispatcher.addMapping("/");
}
private AnnotationConfigWebApplicationContext getContext() {
final AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.register(MySpringConfig.class);
return context;
}
}
My secured Controller:
#RestController
#RequestMapping("/dummy")
public class MyController {
#PreAuthorize("hasRole('USER')")
#RequestMapping(method = RequestMethod.POST)
public HttpEntity<?> doSomething() {
return new ResponseEntity<>(HttpStatus.CREATED);
}
}
My failing Test (actual: 500, expected: 403):
#RunWith(SpringJUnit4ClassRunner.class)
#WebAppConfiguration
#ContextConfiguration(classes = MySpringConfig.class)
public class MyControllerTest {
#Autowired
protected WebApplicationContext context;
protected MockMvc mvc;
#Before
public void setUp() throws Exception {
new TestContextManager(getClass()).prepareTestInstance(this);
this.mvc = MockMvcBuilders.webAppContextSetup(this.context).build();
}
#Test
public void doDummy_not_authorized_403() throws Exception {
final MockHttpServletResponse response = this.mvc.perform(post("/dummy")).andDo(MockMvcResultHandlers.print()).andReturn().getResponse();
assertThat(response.getStatus(), equalTo(403));
}
}
I have a problem with my Spring app that i'm deploying at OpenShift. Everything seems to be working except my static resource files (css, js, images). I'm getting the following error:
2015-12-11 12:46:31,302 WARN [org.springframework.web.servlet.PageNotFound] (de
fault task-2) No mapping found for HTTP request with URI [/resource/js/jquery-1.
11.3.min.js] in DispatcherServlet with name 'springDispatcher'
2015-12-11 12:46:31,395 WARN [org.springframework.web.servlet.PageNotFound] (de
fault task-3) No mapping found for HTTP request with URI [/resource/js/example.j
s] in DispatcherServlet with name 'springDispatcher'
2015-12-11 12:46:31,419 WARN [org.springframework.web.servlet.PageNotFound] (de
fault task-4) No mapping found for HTTP request with URI [/resource/css/example.
css] in DispatcherServlet with name 'springDispatcher'
This is my Code:
#Order(1)
public class FrameworkBootstrap implements WebApplicationInitializer
{
private static final Logger log = LogManager.getLogger();
#Override
public void onStartup(ServletContext container) throws ServletException
{
log.info("Executing framework bootstrap.");
AnnotationConfigWebApplicationContext rootContext =
new AnnotationConfigWebApplicationContext();
rootContext.register(RootContextConfiguration.class);
container.addListener(new ContextLoaderListener(rootContext));
AnnotationConfigWebApplicationContext servletContext =
new AnnotationConfigWebApplicationContext();
servletContext.register(ServletContextConfiguration.class);
ServletRegistration.Dynamic dispatcher = container.addServlet(
"springDispatcher", new DispatcherServlet(servletContext)
);
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("/");
FilterRegistration.Dynamic registration = container.addFilter(
"preSecurityLoggingFilter", new PreSecurityLoggingFilter()
);
registration.addMappingForUrlPatterns(null, false, "/*");
}
}
And the config...
#Configuration
#EnableWebMvc
#ComponentScan(
basePackages = "com.example.site",
useDefaultFilters = false,
includeFilters = #ComponentScan.Filter(Controller.class)
)
public class ServletContextConfiguration extends WebMvcConfigurerAdapter {
private static final Logger log = LogManager.getLogger();
#Inject ApplicationContext applicationContext;
#Inject ObjectMapper objectMapper;
#Inject Marshaller marshaller;
#Inject Unmarshaller unmarshaller;
#Inject SpringValidatorAdapter validator;
#Bean
public MultipartResolver multipartResolver() {
return new StandardServletMultipartResolver();
}
#Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setViewClass(JstlView.class);
resolver.setPrefix("/WEB-INF/jsp/view/");
resolver.setSuffix(".jsp");
return resolver;
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
log.info("Adding Resource Handlers");
registry.addResourceHandler("/resource/**").addResourceLocations("/resource/");
registry.setOrder(Integer.MAX_VALUE);
}
#Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
#Override
public void configureMessageConverters(
List<HttpMessageConverter<?>> converters
) {
converters.add(new ByteArrayHttpMessageConverter());
converters.add(new StringHttpMessageConverter());
converters.add(new FormHttpMessageConverter());
converters.add(new SourceHttpMessageConverter<>());
MarshallingHttpMessageConverter xmlConverter
= new MarshallingHttpMessageConverter();
xmlConverter.setSupportedMediaTypes(Arrays.asList(
new MediaType("application", "xml"),
new MediaType("text", "xml")
));
xmlConverter.setMarshaller(this.marshaller);
xmlConverter.setUnmarshaller(this.unmarshaller);
converters.add(xmlConverter);
MappingJackson2HttpMessageConverter jsonConverter
= new MappingJackson2HttpMessageConverter();
jsonConverter.setSupportedMediaTypes(Arrays.asList(
new MediaType("application", "json"),
new MediaType("text", "json")
));
jsonConverter.setObjectMapper(this.objectMapper);
converters.add(jsonConverter);
}
#Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer.favorPathExtension(true).favorParameter(false)
.parameterName("mediaType").ignoreAcceptHeader(false)
.useJaf(false).defaultContentType(MediaType.APPLICATION_XML)
.mediaType("xml", MediaType.APPLICATION_XML)
.mediaType("json", MediaType.APPLICATION_JSON);
}
#Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers)
{
Sort defaultSort = new Sort(new Sort.Order(Sort.Direction.ASC, "id"));
Pageable defaultPageable = new PageRequest(0, 10, defaultSort);
SortHandlerMethodArgumentResolver sortResolver =
new SortHandlerMethodArgumentResolver();
sortResolver.setSortParameter("paging.sort");
sortResolver.setFallbackSort(defaultSort);
PageableHandlerMethodArgumentResolver pageableResolver =
new PageableHandlerMethodArgumentResolver(sortResolver);
pageableResolver.setMaxPageSize(100);
pageableResolver.setOneIndexedParameters(true);
pageableResolver.setPrefix("paging.");
pageableResolver.setFallbackPageable(defaultPageable);
resolvers.add(sortResolver);
resolvers.add(pageableResolver);
}
#Override
public void addFormatters(FormatterRegistry registry)
{
if(!(registry instanceof FormattingConversionService))
{
log.warn("Unable to register Spring Data JPA converter.");
return;
}
DomainClassConverter<FormattingConversionService> converter =
new DomainClassConverter<>((FormattingConversionService)registry);
converter.setApplicationContext(this.applicationContext);
}
#Override
public Validator getValidator()
{
return this.validator;
}
#Override
public void addInterceptors(InterceptorRegistry registry)
{
super.addInterceptors(registry);
registry.addInterceptor(new LocaleChangeInterceptor());
}
#Bean
public LocaleResolver localeResolver() {
return new SessionLocaleResolver();
}
#Bean
public RequestToViewNameTranslator viewNameTranslator() {
return new DefaultRequestToViewNameTranslator();
}
}
The application is running, i'm just can't reach the files which are on the server in the following path.
src > main > webapp > resource > css > file.css
I can't find out what is wrong... Please Help!
In order to overcome LazyInitializationException I've decided to use OpenEntityManagerInViewFilter - here's code from my AppInitializer class which implements WebApplicationInitializer:
public class AppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer implements WebApplicationInitializer {
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
registerListener(servletContext);
registerDipsatcherServlet(servletContext);
registerOpenEntityManagerInViewFilter(servletContext);
}
private void registerListener(ServletContext servletContext) {
// Create the 'root' Spring application context
AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
// Manage the lifecycle of the root application context
servletContext.addListener(new ContextLoaderListener(rootContext));
}
private void registerDipsatcherServlet(ServletContext servletContext) {
// Create the dispatcher servlet's Spring application context
AnnotationConfigWebApplicationContext dispatcherServlet = new AnnotationConfigWebApplicationContext();
dispatcherServlet.register(MvcConfiguration.class);
// Register and map the dispatcher servlet
ServletRegistration.Dynamic dispatcher = servletContext.addServlet("dispatcher", new DispatcherServlet(dispatcherServlet));
customizeRegistration(dispatcher);
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("/");
}
private void registerOpenEntityManagerInViewFilter(ServletContext servletContext) {
FilterRegistration.Dynamic registration = servletContext.addFilter("openEntityManagerInView", new OpenEntityManagerInViewFilter());
registration.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD), false, "/*");
}
#Override
protected void customizeRegistration(ServletRegistration.Dynamic registration) {
registration.setInitParameter("throwExceptionIfNoHandlerFound", "true");
}
#Override
protected Class<?>[] getRootConfigClasses() {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
#Override
protected Class<?>[] getServletConfigClasses() {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
#Override
protected String[] getServletMappings() {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
}
And here's the #Configuration class which defines the bean:
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(entityManagerFactoryRef = "entityManagerFactory", transactionManagerRef = "transactionManager", basePackages = "podraza.piotr.eshopper.repository")
public class PersistenceConfiguration {
#Autowired
private JpaVendorAdapter jpaVendorAdapter;
#Value("${jpa.show-sql:false}")
private boolean showSql;
#Value("${jpa.datasource.url}")
private String databaseUrl;
#Value("${jpa.datasource.username}")
private String username;
#Value("${jpa.datasource.password}")
private String password;
#Value("${jpa.datasource.driverClassName}")
private String driverClassName;
/*
#Value("${jpa.hibernate.ddl-auto}")
private String hibernateDdlAuto;
*/
#Bean
public HibernateJpaVendorAdapter hibernateJpaVendorAdapter() {
HibernateJpaVendorAdapter hibernateJpaVendorAdapter = new HibernateJpaVendorAdapter();
hibernateJpaVendorAdapter.setShowSql(showSql);
//hibernateJpaVendorAdapter.getJpaPropertyMap().put("hibernate.hbm2ddl.auto", hibernateDdlAuto);
hibernateJpaVendorAdapter.setDatabase(Database.POSTGRESQL);
return hibernateJpaVendorAdapter;
}
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource(databaseUrl, username, password);
dataSource.setDriverClassName(driverClassName);
return dataSource;
}
#Bean
public EntityManager entityManager() {
return entityManagerFactory().createEntityManager();
}
#Bean
public EntityManagerFactory entityManagerFactory() {
LocalContainerEntityManagerFactoryBean lef = new LocalContainerEntityManagerFactoryBean();
lef.setDataSource(dataSource());
lef.setJpaVendorAdapter(jpaVendorAdapter);
lef.setPackagesToScan("podraza.piotr.eshopper.entity");
lef.setPersistenceUnitName("defaultPersistenceUnit");
lef.afterPropertiesSet();
return lef.getObject();
}
#Bean
public PlatformTransactionManager transactionManager() {
return new JpaTransactionManager(entityManagerFactory());
}
}
How can I indicate this bean for the filter?
You are using Spring classes and the first thing you do is not use it. Replace your AppInitializer with the following.
public class AppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected void customizeRegistration(ServletRegistration.Dynamic registration) {
registration.setInitParameter("throwExceptionIfNoHandlerFound", "true");
}
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] {PersistenceConfiguration.class}
}
#Override
protected Class<?>[] getServletConfigClasses() {
throw new Class[] {MvcConfiguration.class};
}
#Override
protected String[] getServletMappings() {
return new String[] {"/"};
}
protected Filter[] getServletFilters() {
return return new Filter[] {new OpenentityManagerInViewFilter()};
}
}
Also make sure that in your MvcConfiguration you aren't loading the PersistenceConfiguration class again as that would lead to bean duplication.
I am doing little project using Spring+Hibernate. When I deploy my war and get 404 status all the time. I have checked some answers about it, but I didnt find my mistake. I tried to switch between / and /*, it didnt help. Tomcat doesnt show any errors in logs. Thanks in advance.
My WebConfig class
#Configuration
#EnableWebMvc
#ComponentScan({"controller", "dao"})
#EnableTransactionManagement
public class WebConfig extends WebMvcConfigurerAdapter {
#Bean
public DataSource dataSource() {
SimpleDriverDataSource ds =
new SimpleDriverDataSource(org.h2.Driver.load(), "jdbc:h2:~/testdb", "sa", "sa");
return ds;
}
#Bean
#DependsOn("dataSource")
public LocalSessionFactoryBean sessionFactoryBean() {
LocalSessionFactoryBean sessionFactoryBean = new LocalSessionFactoryBean();
sessionFactoryBean.setDataSource(dataSource());
sessionFactoryBean.setPackagesToScan("entity");
sessionFactoryBean.setHibernateProperties(hibernateProperties());
return sessionFactoryBean;
}
private Properties hibernateProperties() {
Properties p = new Properties();
p.setProperty("hibernate.dialect", "org.hibernate.dialect.H2Dialect");
p.setProperty("hibernate.hbm2ddl.auto", "update");
p.setProperty("hibernate.hbm2ddl.import_files_sql_extractor", "org.hibernate.tool.hbm2ddl.MultipleLinesSqlCommandExtractor");
p.setProperty("hibernate.show_sql", "true");
p.setProperty("hibernate.format_sql", "true");
return p;
}
#Bean
#DependsOn("sessionFactoryBean")
public PlatformTransactionManager transactionManager() {
SessionFactory sessionFactory = sessionFactoryBean().getObject();
HibernateTransactionManager tm = new HibernateTransactionManager(sessionFactory);
return tm;
}
#Bean(name = "viewResolver")
public InternalResourceViewResolver getViewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setPrefix("/WEB-INF/pages/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
}
My WebAppInitializer class
public class SpringWebAppInitializer implements WebApplicationInitializer {
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
AnnotationConfigWebApplicationContext appContext = new AnnotationConfigWebApplicationContext();
appContext.register(WebConfig.class);
ServletRegistration.Dynamic dispatcher = servletContext.addServlet(
"SpringDispatcher", new DispatcherServlet(appContext));
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("/*");
}
}
My Controller class
#Controller
public class MainController {
#Autowired
IDisksDao d;
#RequestMapping("/")
#Transactional
#ResponseBody
public String hello() {
return "hi";
}
#RequestMapping("disks/")
#Transactional
#ResponseBody
public ModelAndView getDisks() {
ModelAndView model = new ModelAndView("disks");
model.addObject("disks", d.getAllDisks() );
return model;
}
#RequestMapping("u/disks/{id}")
#Transactional
#ResponseBody
public List<Disk> getUserDisks(#PathVariable int id) {
return d.getAllUserDisks(id);
}
}
My project structure
I use java-based Spring Mvc configuration.
I register the Spring dispatcher servlet in the WebApplicationInitializer implementation.
Load Spring ApplicationContext configuration files. Logic of Spring profiles management is implemented in the ApplicationContextInitializer implementation. And it worked fine.
Here are full examples of the original files:
WebApplicationInitializer
public class SpringMvcExampleWebApplicationInitializer implements WebApplicationInitializer {
private static final String DISPATCHER_SERVLET_NAME = "dispatcher";
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
registerDispatcherServlet(servletContext);
registerHiddenHttpMethodFilter(servletContext);
}
private void registerDispatcherServlet(final ServletContext servletContext) {
WebApplicationContext dispatcherContext = createContext(WebMvcContextConfiguration.class, InfrastructureContextConfiguration.class);
DispatcherServlet dispatcherServlet = new DispatcherServlet(dispatcherContext);
dispatcherServlet.setContextInitializers(new SpringMvcExampleProfilesInitializer());
ServletRegistration.Dynamic dispatcher = servletContext.addServlet(DISPATCHER_SERVLET_NAME, dispatcherServlet);
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("/");
}
private WebApplicationContext createContext(final Class<?>... annotatedClasses) {
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.register(annotatedClasses);
return context;
}
private void registerHiddenHttpMethodFilter(ServletContext servletContext) {
FilterRegistration.Dynamic registration = servletContext.addFilter("hiddenHttpMethodFilter", HiddenHttpMethodFilter.class);
registration.addMappingForServletNames(EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD),
false, DISPATCHER_SERVLET_NAME);
}
}
SpringMvcExampleProfilesInitializer
public class SpringMvcExampleProfilesInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
#Override
public void initialize(ConfigurableApplicationContext ctx) {
ConfigurableEnvironment environment = ctx.getEnvironment();
List<String> profiles = new ArrayList<String>(getProfiles());
if( profiles == null || profiles.isEmpty() )
{
throw new IllegalArgumentException("Profiles have not been configured");
}
environment.setActiveProfiles(profiles.toArray( new String[0]));
}
//TODO add logic
private Collection<String> getProfiles() {
return Lists.newArrayList("file_based", "test_data");
}
}
InfrastructureContextConfiguration
#Configuration
#ComponentScan(basePackages = {"com.savdev.springmvcexample.repository", "com.savdev.springmvcexample.config"})
#EnableTransactionManagement
#EnableJpaRepositories(basePackages = {"com.savdev.springmvcexample.repository"})
public class InfrastructureContextConfiguration {
#Configuration
#Profile(value = "file_based")
#PropertySource("classpath:/db/config/file_based.properties")
public static class FileBasedConfiguration {
#Inject
private Environment environment;
#Bean
public DataSource dataSource() {
BasicDataSource dataSource = new org.apache.commons.dbcp.BasicDataSource();
dataSource.setDriverClassName(environment.getProperty("jdbc.driver"));
dataSource.setUrl(environment.getProperty("jdbc.url"));
dataSource.setUsername(environment.getProperty("jdbc.username"));
dataSource.setPassword(environment.getProperty("jdbc.password"));
return dataSource;
}
}
#Bean
public SpringLiquibase liquibase(DataSource dataSource) {
SpringLiquibase liquibase = new SpringLiquibase();
liquibase.setDataSource(dataSource);
liquibase.setChangeLog("classpath:/db/liquibase/changelog/db.changelog-master.xml");
liquibase.setDropFirst(true);
return liquibase;
}
Then I added Spring Security context configuration to the application. To use it the DelegatingFilterProxy have to be loaded. I\ve updated the configuration:
Added new method and invoked it in the onStartup:
private void registerSpringSecurityFilterChain(ServletContext servletContext) {
FilterRegistration.Dynamic springSecurityFilterChain = servletContext.addFilter(
BeanIds.SPRING_SECURITY_FILTER_CHAIN,
new DelegatingFilterProxy());
springSecurityFilterChain.addMappingForUrlPatterns(null, false, "/*");
}
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
...
registerDispatcherServlet(servletContext);
...
registerSpringSecurityFilterChain(servletContext);
}
Now when I try to request any url I'm getting the error:
message No WebApplicationContext found: no ContextLoaderListener registered?
description The server encountered an internal error that prevented it from fulfilling this request.
exception
java.lang.IllegalStateException: No WebApplicationContext found: no ContextLoaderListener registered?
org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:251)
Ok, I added the following:
private static final Class<?>[] configurationClasses = new Class<?>[]{
WebMvcContextConfiguration.class, InfrastructureContextConfiguration.class};
...
private void registerListener(ServletContext servletContext) {
WebApplicationContext rootContext = createContext(configurationClasses);
servletContext.addListener(new ContextLoaderListener(rootContext));
}
And invoked it from:
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
registerListener(servletContext);
registerDispatcherServlet(servletContext);
registerHiddenHttpMethodFilter(servletContext);
registerSpringSecurityFilterChain(servletContext);
}
The error has gone.
But all beans that depend on Spring profile are not loaded now. Adding the ContextLoaderListener has broken the SpringMvcExampleProfilesInitializer logic.
No qualifying bean of type [javax.sql.DataSource] found for dependency
What can I do to resolve it? Any ideas, please?
Here is the full updated web initializer class:
public class SpringMvcExampleWebApplicationInitializer implements WebApplicationInitializer {
private static final String DISPATCHER_SERVLET_NAME = "dispatcher";
private static final Class<?>[] configurationClasses = new Class<?>[]{
WebMvcContextConfiguration.class, InfrastructureContextConfiguration.class};
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
registerListener(servletContext);
registerDispatcherServlet(servletContext);
registerHiddenHttpMethodFilter(servletContext);
registerSpringSecurityFilterChain(servletContext);
}
private void registerSpringSecurityFilterChain(ServletContext servletContext) {
FilterRegistration.Dynamic springSecurityFilterChain = servletContext.addFilter(
BeanIds.SPRING_SECURITY_FILTER_CHAIN,
new DelegatingFilterProxy());
springSecurityFilterChain.addMappingForUrlPatterns(null, false, "/*");
}
private void registerDispatcherServlet(final ServletContext servletContext) {
WebApplicationContext dispatcherContext = createContext(WebMvcContextConfiguration.class, InfrastructureContextConfiguration.class);
DispatcherServlet dispatcherServlet = new DispatcherServlet(dispatcherContext);
dispatcherServlet.setContextInitializers(new SpringMvcExampleProfilesInitializer());
ServletRegistration.Dynamic dispatcher = servletContext.addServlet(DISPATCHER_SERVLET_NAME, dispatcherServlet);
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("/");
}
private WebApplicationContext createContext(final Class<?>... annotatedClasses) {
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.register(annotatedClasses);
// context.refresh();
return context;
}
private void registerListener(ServletContext servletContext) {
WebApplicationContext rootContext = createContext(configurationClasses);
servletContext.addListener(new ContextLoaderListener(rootContext));
// servletContext.addListener(new RequestContextListener());
}
private void registerHiddenHttpMethodFilter(ServletContext servletContext) {
FilterRegistration.Dynamic registration = servletContext.addFilter("hiddenHttpMethodFilter", HiddenHttpMethodFilter.class);
registration.addMappingForServletNames(EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD),
false, DISPATCHER_SERVLET_NAME);
}
}
As M.Deinum recommended I set the profiles initialier to the ServletContext, instead of setting it to DispatcherServlet. Here is the updated configuration:
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
configureServletContext( servletContext );
registerListener(servletContext);
registerDispatcherServlet(servletContext);
...
}
private void configureServletContext(ServletContext servletContext) {
String initializerClasses = servletContext.getInitParameter(ContextLoader.CONTEXT_INITIALIZER_CLASSES_PARAM);
String profilesInitClassName = SpringMvcExampleProfilesInitializer.class.getName();
if (StringUtils.hasText(initializerClasses)) {
initializerClasses += " " + profilesInitClassName;
}
else {
initializerClasses = profilesInitClassName;
}
servletContext.setInitParameter(ContextLoader.CONTEXT_INITIALIZER_CLASSES_PARAM, initializerClasses);
}