ThymeleafView: java.lang.IllegalArgumentException: Property 'locale' is required - spring-boot

I follow the below tutorial step by step to complete NO.10 Rendering Template Fragments.
https://www.thymeleaf.org/doc/tutorials/3.0/thymeleafspring.html#rendering-template-fragments
And I get an exception: nested exception is java.lang.IllegalArgumentException: Property 'locale' is required.
My code is below, Could someone tell me how to fix it? Thank you very much.
WebConfig.java
public class WebConfig implements WebMvcConfigurer {
#Autowired
private WebApplicationContext context;
#Bean
public ServletContextTemplateResolver templateResolver() {
final ServletContextTemplateResolver resolver = new ServletContextTemplateResolver(context.getServletContext());
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix(".html");
resolver.setTemplateMode(TemplateMode.HTML);
return resolver;
}
#Bean
public SpringTemplateEngine templateEngine() {
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.setTemplateResolver(templateResolver());
return templateEngine;
}
#Bean
public ThymeleafViewResolver viewResolver() {
ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
viewResolver.setTemplateEngine(templateEngine());
return viewResolver;
}
#Bean("messageSource")
public MessageSource messageSource() {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasenames("lang/messages");
messageSource.setDefaultEncoding("UTF-8");
return messageSource;
}
#Bean
public LocaleResolver localeResolver() {
return new CookieLocaleResolver();
}
#Override
public void addInterceptors(InterceptorRegistry registry) {
LocaleChangeInterceptor localeChangeInterceptor = new LocaleChangeInterceptor();
localeChangeInterceptor.setParamName("lang");
registry.addInterceptor(localeChangeInterceptor);
}
#Bean(name = "content-part")
#Scope("prototype")
public ThymeleafView someViewBean() {
ThymeleafView view = new ThymeleafView("index"); // templateName = 'index'
view.setMarkupSelector("content");
return view;
}
}
HomeController.java
public class HomeController {
#RequestMapping("/showContentPart")
public String showContentPart(final Locale locale, HttpServletRequest request, HttpServletResponse response) {
return "content-part";
}
}
index.html
https://i.stack.imgur.com/WOGpR.png

Try this :
#RequestMapping("/showContentPart")
public class HomeController
{
public String showContentPart(final Locale locale, HttpServletRequest request, HttpServletResponse response) {
return "content-part";
}

Related

Spring stops serving static resources after messageSource is created

After creatig messageSource bean in spring webMvcConfigurer my application stops serving static resources(images/css/js) with http status 404, but all files have a right path(I'm completely sure that error somewhere within messageSource because without this bean serving works correctly). Maybe you have idea how to resolve this problem?
My WebMvcConfigurerImpl:
#Configuration
#Import({dbConfig.class})
#EnableWebMvc
#EnableSpringDataWebSupport
#ComponentScan("my.shop.common.fliPusto")
#PropertySource("classpath:properties/resources.properties")
public class mvcConfig implements WebMvcConfigurer {
#Value("${uploadBook.path}")
private String bookPath;
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/images/**")
.addResourceLocations("file:/" + bookPath + "/images/");
registry.addResourceHandler("/scripts/**")
.addResourceLocations("file:/" + bookPath + "/scripts/");
registry.addResourceHandler("/styles/**")
.addResourceLocations("file:/" + bookPath + "/styles/");
}
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/login").setViewName("login");
}
#Bean
public FreeMarkerConfigurer freeMarkerConfigurer() {
FreeMarkerConfigurer configurer = new FreeMarkerConfigurer();
configurer.setTemplateLoaderPath("classpath:freemarkerTemplates/");
configurer.setDefaultEncoding("UTF-8");
return configurer;
}
#Bean
public FreeMarkerViewResolver freeMarkerViewResolver() {
FreeMarkerViewResolver freeMarkerViewResolver = new FreeMarkerViewResolver();
freeMarkerViewResolver.setCache(false);
freeMarkerViewResolver.setPrefix("");
freeMarkerViewResolver.setSuffix(".ftl");
freeMarkerViewResolver.setContentType("text/html; charset=UTF-8");
return freeMarkerViewResolver;
}
#Bean
public MultipartResolver multipartResolver() {
return new StandardServletMultipartResolver();
}
#Bean
public LocalValidatorFactoryBean validator() {
return new LocalValidatorFactoryBean();
}
#Bean
public ResourceBundleMessageSource messageSource() {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasename("/messages/locales");
messageSource.setDefaultEncoding("UTF-8");
return messageSource;
}
}
My securityConfig:
#Configuration
#EnableWebSecurity(debug = true)
#EnableGlobalMethodSecurity(prePostEnabled = true)
#ComponentScan(value = "my.shop.common.fliPusto.services")
public class securityConfig extends WebSecurityConfigurerAdapter {
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder(4);
}
#Bean
public CharacterEncodingFilter characterEncodingFilter() {
CharacterEncodingFilter encodingFilter = new CharacterEncodingFilter();
encodingFilter.setEncoding("UTF-8");
encodingFilter.setForceEncoding(true);
encodingFilter.setForceRequestEncoding(true);
encodingFilter.setForceResponseEncoding(true);
return encodingFilter;
}
#Autowired
void setAuthManagerBuilder(AuthenticationManagerBuilder authenticationManagerBuilder, PasswordEncoder passwordEncoder, UserDetailsService userDetailsService) {
try {
authenticationManagerBuilder.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder);
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/", "/registration", "/test/*", "/book", "/tag/**", "/user/profile/{profile}", "/images/**", "/scripts/**", "/styles/**").permitAll()
.antMatchers("/admin/**").hasAuthority("MODERATOR")
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.logoutSuccessUrl("/")
.permitAll()
.and()
.requiresChannel()
.anyRequest()
.requiresSecure();
http.addFilterBefore(characterEncodingFilter(), CsrfFilter.
}
}
I'm solved this by adding messagesource to another Configuration class and adding this class to the dispatherServlet as the ServletConfigClass
Another config:
#Configuration
public class OtherConfig {
#Bean
public ResourceBundleMessageSource messageSource() {
ResourceBundleMessageSource messageSource = new
ResourceBundleMessageSource();
messageSource.setBasename("/messages/locales");
messageSource.setDefaultEncoding("UTF-8");
return messageSource;
}
}
Servlet class:
public class servlet extends AbstractAnnotationConfigDispatcherServletInitializer {
protected Class<?>[] getRootConfigClasses() {
return new Class[] {mvcConfig.class, securityConfig.class};
}
protected Class<?>[] getServletConfigClasses() {
return new Class[] {OtherConfig.class}; <-------------There
}
protected String[] getServletMappings() {
return new String[] {"/"};
}
#Override
protected Filter[] getServletFilters() {
return new Filter[]{new charsetFilter()};
}
#Override
protected void customizeRegistration(ServletRegistration.Dynamic registration) {
registration.setMultipartConfig(new MultipartConfigElement(""));
}
}

Spring mvc requested resource is not available

Application and my browser cannot render any resource of my app. I saw a lot of similar questions and could not find any solution. App works fine through json(ie without view)
There is my config
#Configuration
#EnableWebMvc
#ComponentScan("ru.practice.web")
public class ChatlocalWebConfig
extends WebMvcConfigurerAdapter {
#Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver resolv = new InternalResourceViewResolver();
resolv.setPrefix("WEB-INF/views/");
resolv.setSuffix(".jsp");
resolv.setViewClass(JstlView.class);
return resolv;
}
}
initializer
public class ChatlocalInitializer
extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[] { ChatlocalWebConfig.class };
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[] { ChatlocalWebConfig.class };
}
}
controller
#Controller
#RequestMapping("/user")
public class UserController {
#Autowired
UserRepository userRepository;
#RequestMapping(value = "/",method = RequestMethod.GET)
public String sayHello(Model model) {
model.addAttribute("greeting", "Hello World");
return "welcome";
}
}
and project structure
image
I think it's your resource path problem. Change
resolv.setPrefix("WEB-INF/views/");
to resolv.setPrefix("/WEB-INF/views/");
and see how it works.
Not sure how to do this with WebMvcConfigurerAdapter but this works:
#Configuration
public class WebConfig extends WebMvcConfigurationSupport {
#Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver r = new InternalResourceViewResolver();
r.setPrefix("/WEB-INF/views/");
r.setSuffix(".jsp");
return r;
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
}
#Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
}

sessionRegistry.getAllPrincipals() is empty

I trying to get all logged-in users using sessionRegistry in my Spring-MVC application, i found a lot of posts and answers on how to resolve it, but i could not fix it. I'm using configuration by annotation.
I'm new to spring mvc and i want to learn a best practice, so all comments about other configurations or about my code are welcome.
Here is my code
#Configuration
#ComponentScan(basePackages = {"com.uno"})
#Import({ SecurityConfig.class })
#EnableWebMvc
public class AppConfig extends WebMvcConfigurerAdapter {
#Bean
public TilesViewResolver tilesViewResolver() {
TilesViewResolver resolver = new TilesViewResolver();
resolver.setViewClass(TilesView.class);
resolver.setOrder(1);
return resolver;
}
#Bean
public TilesConfigurer tilesConfigurer() {
TilesConfigurer tilesConfigurer = new TilesConfigurer();
tilesConfigurer.setCompleteAutoload(true);
tilesConfigurer.setCheckRefresh(true);
return tilesConfigurer;
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations(
"/resources/");
}
#Bean
SessionFactory sessionFactory() {
org.hibernate.cfg.Configuration configuration = new org.hibernate.cfg.Configuration();
configuration.configure();
LocalSessionFactoryBuilder builder = new LocalSessionFactoryBuilder(
dataSource());
builder.scanPackages("com.uno.domain").addProperties(
configuration.getProperties());
return builder.buildSessionFactory();
}
#Bean
public DriverManagerDataSource dataSource() {
DriverManagerDataSource ds = new DriverManagerDataSource();
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost:3306/uno");
ds.setUsername("root");
return ds;
}
#Bean
public HibernateTransactionManager transactionManager() {
return new HibernateTransactionManager(sessionFactory());
}
#Bean
UserDao userDao() {
return new UserDaoImpl();
}
#Bean
UserService userService() {
return new UserServiceImpl();
}
#Bean
RoleDao roleDao() {
return new RoleDaoImpl();
}
#Bean
RoleService roleService() {
return new RoleServiceImpl();
}
#Bean
ConnexionSucessHandler connexionSuccessHandler() {
return new ConnexionSucessHandler();
}
#Bean
PersistentTokenRepository remmeberMeTokenRepository() {
JdbcTokenRepositoryImpl db = new JdbcTokenRepositoryImpl();
db.setDataSource(dataSource());
return db;
}
/* Localization section */
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(localeChangeInterceptor());
}
#Bean
LocaleResolver localeResolver() {
SessionLocaleResolver sessionLocaleResolver = new SessionLocaleResolver();
sessionLocaleResolver.setDefaultLocale(new Locale("en"));
return sessionLocaleResolver;
}
#Bean
LocaleChangeInterceptor localeChangeInterceptor() {
LocaleChangeInterceptor localeChangeInterceptor = new LocaleChangeInterceptor();
localeChangeInterceptor.setParamName("lang");
return localeChangeInterceptor;
}
#Bean
ControllerClassNameHandlerMapping controllerClassNameHandlerMapping() {
ControllerClassNameHandlerMapping controllerClassNameHandlerMapping = new ControllerClassNameHandlerMapping();
Object[] interceptors = new Object[] { localeChangeInterceptor() };
controllerClassNameHandlerMapping.setInterceptors(interceptors);
return controllerClassNameHandlerMapping;
}
#Bean
ReloadableResourceBundleMessageSource messageSource() {
ReloadableResourceBundleMessageSource reloadableResourceBundleMessageSource = new ReloadableResourceBundleMessageSource();
reloadableResourceBundleMessageSource.setBasename("resources/i18n/messages");
reloadableResourceBundleMessageSource.setDefaultEncoding("UTF-8");
return reloadableResourceBundleMessageSource;
}
/* Localization section */
#Bean
CommonsMultipartResolver filterMultipartResolver(){
return new CommonsMultipartResolver();
}
}
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
#Qualifier("userService")
UserService userDetailsService;
#Autowired
ConnexionSucessHandler connexionSucessHandler;
#Autowired
SessionRegistry sessionRegistry;
#Autowired
PersistentTokenRepository remmeberMeTokenRepository;
#Autowired
ConcurrentSessionControlAuthenticationStrategy concurrentSessionControlAuthenticationStrategy;
#Autowired
ConcurrentSessionFilter concurrentSessionFilter;
#Autowired
RegisterSessionAuthenticationStrategy registerSessionAuthenticationStrategy;
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/admin/**").hasRole("ADMIN").antMatchers("/mailManagement/**")
.hasAnyRole("USER", "ADMIN").antMatchers("/user/**").hasAnyRole("USER", "ADMIN")
.antMatchers("/login/**").permitAll().and().formLogin().successHandler(connexionSucessHandler)
.loginPage("/login").failureUrl("/login?error").usernameParameter("username")
.passwordParameter("password").and().logout().invalidateHttpSession(true).deleteCookies("JSESSIONID")
.logoutUrl("/logout").logoutSuccessUrl("/login?logout").and().csrf().and().exceptionHandling()
.accessDeniedPage("/403").and().rememberMe().rememberMeParameter("uno-remember-me")
.rememberMeCookieName("uno-remember-me").tokenValiditySeconds(1296000)
.tokenRepository(remmeberMeTokenRepository).and().sessionManagement()
.sessionAuthenticationStrategy(concurrentSessionControlAuthenticationStrategy).maximumSessions(-1);
}
#Bean
public SessionRegistry sessionRegistry() {
return new SessionRegistryImpl();
}
#Bean
public ConcurrentSessionFilter concurrentSessionFilter(){
return new ConcurrentSessionFilter(sessionRegistry);
}
#Bean
public ConcurrentSessionControlAuthenticationStrategy concurrentSessionControlAuthenticationStrategy(){
return new ConcurrentSessionControlAuthenticationStrategy(sessionRegistry);
}
#Bean
public RegisterSessionAuthenticationStrategy registerSessionAuthenticationStrategy(){
return new RegisterSessionAuthenticationStrategy(sessionRegistry);
}
}
public class SecurityInitializer extends
AbstractSecurityWebApplicationInitializer {
#Override
protected void beforeSpringSecurityFilterChain(ServletContext servletContext) {
insertFilters(servletContext, new MultipartFilter());
}
#Override
protected boolean enableHttpSessionEventPublisher() {
return true;
}
}
public class MvcWebApplicationInitializer extends
AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class[] getRootConfigClasses() {
return new Class[] { AppConfig.class };
}
#Override
protected Class[] getServletConfigClasses() {
return null;
}
#Override
protected String[] getServletMappings() {
return new String[] {"/"};
}
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
servletContext.addListener(new RequestContextListener());
super.onStartup(servletContext);
}
}
public class ConnexionSucessHandler extends SavedRequestAwareAuthenticationSuccessHandler {
#Autowired
UserProfile userProfile;
#Override
public void onAuthenticationSuccess(HttpServletRequest request,
HttpServletResponse response, Authentication auth) throws IOException,
ServletException {
RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
Collection authorities = auth.getAuthorities();
userProfile.loadUser(auth.getName());
for(GrantedAuthority grantedAuthority : authorities){
switch (grantedAuthority.getAuthority()) {
case "ROLE_ADMIN":
redirectStrategy.sendRedirect(request, response, "/admin");
break;
case "ROLE_USER":
redirectStrategy.sendRedirect(request, response, "/user");
break;
}
}
}
}
problem resolved.
I was loading the same configuration twice in both ContextLoaderListener and DispatcherServlet.

Spring MVC 4 java config does not recognize localization change

This is my project structure:
and this is Spring root config:
#EnableWebMvc
#Configuration
#ComponentScan({ "com.rgh.*" })
#EnableTransactionManagement
#Import({ SpringSecurityConfig.class })
public class SpringWebConfig extends WebMvcConfigurerAdapter {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/assets/**").addResourceLocations("/assets/");
}
// Start localization configs
#Bean
public MessageSource messageSource() {
final ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
messageSource.setBasename("classpath:messages");
messageSource.setDefaultEncoding("UTF-8");
return messageSource;
}
#Bean
public LocaleResolver localeResolver() {
CookieLocaleResolver localeResolver = new CookieLocaleResolver();
localeResolver.setDefaultLocale(new Locale("fa"));
return localeResolver;
}
#Bean
public LocaleChangeInterceptor localeChangeInterceptor() {
LocaleChangeInterceptor localeChangeInterceptor = new LocaleChangeInterceptor();
localeChangeInterceptor.setParamName("lang");
return localeChangeInterceptor;
}
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(localeChangeInterceptor());
}
// End localization configs
#Bean
public SessionFactory sessionFactory() {
LocalSessionFactoryBuilder builder = new LocalSessionFactoryBuilder(dataSource());
builder.scanPackages("com.rgh.*.model").addProperties(getHibernateProperties());
return builder.buildSessionFactory();
}
private Properties getHibernateProperties() {
Properties properties = new Properties();
properties.put("hibernate.format.sql", "false");
properties.put("hibernate.show.sql", "true");
properties.put("hibernate.dialect", "org.hibernate.dialect.MySQL5Dialect");
properties.put("hibernate.hbm2ddl.auto", "update");
return properties;
}
#Bean(name = "dataSource")
public BasicDataSource dataSource() {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/framework");
dataSource.setUsername("root");
dataSource.setPassword("root");
return dataSource;
}
#Bean
public HibernateTransactionManager txManager() {
return new HibernateTransactionManager(sessionFactory());
}
#Bean
public InternalResourceViewResolver viewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setViewClass(JstlView.class);
viewResolver.setPrefix("/view/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
}
but when is start the application with localhost:8080, spring does not recognize default locale that set to localeResolver.setDefaultLocale(new Locale("fa")); and load the page with en_US locale and also when i call the page with localhost:8080/?lang=de it load pages with en_US locale again.
Thanks for any idea.
UPDATE
public class SpringWebInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class[]{SpringWebConfig.class};
}
#Override
protected Class<?>[] getServletConfigClasses() {
return null;
}
#Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
}
UPDATE2
These are my new configurations, by default default locale is en_US and messages files does not be loaded, i should open the login page, and enter invalid username and password then press submit, then the messsages_fa.properties will be loaded and locale changed to fa!!!
public class SpringWebInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class[] { SpringWebConfig.class };
}
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] { SpringSecurityConfig.class, SpringPersistanceConfig.class };
}
#Override
protected String[] getServletMappings() {
return new String[] { "/", "/rest/*" };
}
}
#Configuration
#EnableWebSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
#Qualifier("userDetailsService")
UserDetailsService userDetailsService;
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.headers().frameOptions().sameOrigin();
http.authorizeRequests().antMatchers("/assets/**").permitAll().antMatchers("/admin/**").access("hasRole('ROLE_USER')").and().formLogin().loginPage("/login").failureUrl("/login?error").defaultSuccessUrl("/admin").usernameParameter("username").passwordParameter("password").and().logout().logoutSuccessUrl("/login?logout");
}
}
#Configuration
#EnableTransactionManagement
#ComponentScan(basePackages = { "com.rgh.*" }, excludeFilters = { #Filter(Controller.class) })
public class SpringPersistanceConfig {
#Bean
public SessionFactory sessionFactory() {
LocalSessionFactoryBuilder builder = new LocalSessionFactoryBuilder(dataSource());
builder.scanPackages("com.rgh.*.model").addProperties(getHibernateProperties());
return builder.buildSessionFactory();
}
private Properties getHibernateProperties() {
Properties properties = new Properties();
properties.put("hibernate.format.sql", "false");
properties.put("hibernate.show.sql", "true");
properties.put("hibernate.dialect", "org.hibernate.dialect.MySQL5Dialect");
properties.put("hibernate.hbm2ddl.auto", "update");
return properties;
}
#Bean(name = "dataSource")
public BasicDataSource dataSource() {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/framework");
dataSource.setUsername("root");
dataSource.setPassword("root");
return dataSource;
}
#Bean
public HibernateTransactionManager txManager() {
return new HibernateTransactionManager(sessionFactory());
}
}
#Controller
public class BaseController {
#RequestMapping(value = "/admin**", method = RequestMethod.GET)
public ModelAndView adminPage() {
ModelAndView model = new ModelAndView();
model.setViewName("/panel/admin");
return model;
}
#RequestMapping(value = "/login", method = RequestMethod.GET)
public ModelAndView login() {
ModelAndView model = new ModelAndView();
model.setViewName("/panel/login");
return model;
}
}
The problem is that you are loading everything in the root context and some of the beans aren't detected that way. Next to that you should really split your configurations. Create a web, security and persistence configuration and load the security and persistence in the root config and the web in the dispatcher servlet.
#Configuration
#EnableTransactionManagement
#ComponentScan({ "com.rgh"}, excludeFilters = {
#Filter(org.springframework.stereotype.Controller.class)
})
public class PersistenceConfiguration {
// Hibernate, transaction manager, datasource and messageSource go here
}
Then a web configuration
#EnableWebMvc
#Configuration
#ComponentScan({ "com.rgh"}, includeFilters = {
#Filter(org.springframework.stereotype.Controller.class)
}, useDefaultFilters=false )
public class SpringWebConfig extends WebMvcConfigurerAdapter {
/// web related things like view resolvers, controller, interceptors go here
}
Then in your bootstrap class load the correct configuration classes.
public class SpringWebInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class[]{SpringWebSecurity.class, PersistenceConfiguration.class};
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class[] { SpringWebConfig.class};
}
#Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
}
Now you have split your configuration and everything is loaded by the correct one. The includeFilter and excludeFilter as well as the useDefaultFilters properties on the component-scan are important here to avoid duplicating beans. If you don't all your beans would be loaded twice once by the root and once by the dispatcherservlet.

Spring Security Request method 'POST' not supported

The page having status 405 and also authentication is not working.
Error from Spring Boot log
o.s.web.servlet.PageNotFound : Request method 'POST' not supported
Error from jsp page:
Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.
There was an unexpected error (type=Method Not Allowed, status=405).
Request method 'POST' not supported
Spring Info:
- Using Spring Security 3.2.5
- Using Spring Boot App to start up server.
- Spring-Java-Config
Codes:
SecurityConfig.java
#EnableAutoConfiguration
#ComponentScan(basePackages = { "org.myakasha.crm","org.myakasha.crm.controller","org.myakasha.crm.model"})
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter{
#Autowired
DataSource dataSource;
#Autowired
public void registerAuthentication(AuthenticationManagerBuilder auth) throws Exception {
auth.jdbcAuthentication().dataSource(dataSource)
.usersByUsernameQuery("select username,password, enabled from users where username=?")
.authoritiesByUsernameQuery("select username, role from user_roles where username=?");
}
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/resources/**");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/admin/**").access("hasRole('ROLE_ADMIN')")
.and()
.formLogin().loginPage("/login").failureUrl("/login?error").usernameParameter("username").passwordParameter("password")
.and()
.logout().logoutSuccessUrl("/login?logout")
.and()
.exceptionHandling().accessDeniedPage("/403")
.and()
.csrf();
}
}
SecurityController.java
#Controller
public class SecurityController {
#RequestMapping(value = { "/welcome**" }, method = RequestMethod.GET)
public ModelAndView defaultPage() {
ModelAndView model = new ModelAndView();
model.addObject("title", "Spring Security + Hibernate Example");
model.addObject("message", "This is default page!");
model.setViewName("hello");
return model;
}
#RequestMapping(value = "/admin**", method = RequestMethod.GET)
public ModelAndView adminPage() {
ModelAndView model = new ModelAndView();
model.addObject("title", "Spring Security + Hibernate Example");
model.addObject("message", "This page is for ROLE_ADMIN only!");
model.setViewName("admin");
return model;
}
#RequestMapping(value = "/login", method = {RequestMethod.GET} )
public ModelAndView login(#RequestParam(value = "error", required = false) String error,
#RequestParam(value = "logout", required = false) String logout, HttpServletRequest request) {
ModelAndView model = new ModelAndView();
if (error != null) {
model.addObject("error", getErrorMessage(request, "SPRING_SECURITY_LAST_EXCEPTION"));
}
if (logout != null) {
model.addObject("msg", "You've been logged out successfully.");
}
model.setViewName("login");
return model;
}
// customize the error message
private String getErrorMessage(HttpServletRequest request, String key) {
Exception exception = (Exception) request.getSession().getAttribute(key);
String error = "";
if (exception instanceof BadCredentialsException) {
error = "Invalid username and password!";
} else if (exception instanceof LockedException) {
error = exception.getMessage();
} else {
error = "Invalid username and password!";
}
return error;
}
// for 403 access denied page
#RequestMapping(value = "/403", method = RequestMethod.GET)
public ModelAndView accesssDenied() {
ModelAndView model = new ModelAndView();
// check if user is login
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (!(auth instanceof AnonymousAuthenticationToken)) {
UserDetails userDetail = (UserDetails) auth.getPrincipal();
System.out.println(userDetail);
model.addObject("username", userDetail.getUsername());
}
model.setViewName("403");
return model;
}
}
WebConfig.java
#EnableAutoConfiguration
#EnableWebMvc
#ComponentScan(basePackages = {"org.myakasha.crm","org.myakasha.crm.controller","org.myakasha.crm.model"})
public class WebConfig extends WebMvcConfigurerAdapter{
#Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
}
/**
* This function to replace servlet-content.xml
* Resolves views selected for rendering by #Controllers to .jsp resources in the /WEB-INF/views directory
**/
#Bean
public InternalResourceViewResolver getInternalResourceViewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver .setPrefix("/WEB-INF/views/");
viewResolver .setSuffix(".jsp");
return viewResolver ;
}
#Bean
public MessageSource messageSource() {
ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
messageSource.setBasenames("classpath:message");
messageSource.setUseCodeAsDefaultMessage(true);
messageSource.setDefaultEncoding("UTF-8");
return messageSource;
}
}
PersistenceConfig.java
#Configuration
#EnableTransactionManagement
#PropertySource({ "classpath:persistence-mysql.properties" })
#ComponentScan({ "org.myakasha.crm" })
public class PersistenceConfig {
#Autowired
private Environment env;
public PersistenceConfig() {
super();
}
#Bean
public LocalSessionFactoryBean sessionFactory() {
final LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(restDataSource());
sessionFactory.setPackagesToScan(new String[] { "org.myakasha.crm.model" });
sessionFactory.setHibernateProperties(hibernateProperties());
return sessionFactory;
}
#Bean
public DataSource restDataSource() {
final BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName(Preconditions.checkNotNull(env.getProperty("jdbc.driverClassName")));
dataSource.setUrl(Preconditions.checkNotNull(env.getProperty("jdbc.url")));
dataSource.setUsername(Preconditions.checkNotNull(env.getProperty("jdbc.user")));
dataSource.setPassword(Preconditions.checkNotNull(env.getProperty("jdbc.pass")));
return dataSource;
}
#Bean
#Autowired
public HibernateTransactionManager transactionManager(final SessionFactory sessionFactory) {
final HibernateTransactionManager txManager = new HibernateTransactionManager();
txManager.setSessionFactory(sessionFactory);
return txManager;
}
#Bean
public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
return new PersistenceExceptionTranslationPostProcessor();
}
final Properties hibernateProperties() {
final Properties hibernateProperties = new Properties();
hibernateProperties.setProperty("hibernate.hbm2ddl.auto", env.getProperty("hibernate.hbm2ddl.auto"));
hibernateProperties.setProperty("hibernate.dialect", env.getProperty("hibernate.dialect"));
hibernateProperties.setProperty("hibernate.show_sql", "true");
// hibernateProperties.setProperty("hibernate.format_sql", "true");
// hibernateProperties.setProperty("hibernate.globally_quoted_identifiers", "true");
return hibernateProperties;
}
}
try to add login-processing-url to the SecurityConfig
in XML it looks like this
<form-login
login-page="/login"
<!-- for <form method="post" action="/login-process"> -->
login-processing-url="/login_process"
default-target-url="/home"
authentication-failure-url="/login?error"
username-parameter="username"
password-parameter="password" />
it seems to be that you have enabled the CSRF. can you check whether you are passing the CSRF token, in the form. if not please add the following line to your form.
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>

Resources