Hi I am new to Spring MVC 4 I am trying to do the java configuration setup but it seems Spring is not finding my Controller it is running fine no errors on startup I can even explicitly call a jsp but if I try to call my controller it does nothing
e.g.
localhost:8080/apollo/hello.jsp <-- this renders fine if I put my JSP in the webapp directory
What I want is to call my login.jsp using my controller
My project structure is
com
+apollo
-WebAppInitializer.java
-WebConfig.java
src
+main
+webapp
-**hello.jsp**
+WEB-INF
+view
-**login.jsp**
here is my Configuration
package com.apollo;
import java.util.Locale;
import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ResourceBundleMessageSource;
import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
import org.springframework.web.servlet.i18n.SessionLocaleResolver;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = "com.apollo")
public class WebConfig extends WebMvcConfigurerAdapter {
#Bean
public MessageSource messageSource() {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasename("messages");
return messageSource;
}
#Bean
public InternalResourceViewResolver getInternalResourceViewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/view/");
resolver.setSuffix(".jsp");
return resolver;
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
/*registry.addResourceHandler("/pdfs/**").addResourceLocations("/WEB-INF/pdf/");
registry.addResourceHandler("/css/**").addResourceLocations("/WEB-INF/css/");*/
registry.addResourceHandler("/static/**").addResourceLocations("/static/");
}
}
Here is my Initializer Class
package com.apollo;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
public class WebAppInitializer implements WebApplicationInitializer {
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
WebApplicationContext context = getContext();
servletContext.addListener(new ContextLoaderListener(context));
ServletRegistration.Dynamic dispatcher = servletContext.addServlet("DispatcherServlet", new DispatcherServlet(context));
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("*.html");
}
private AnnotationConfigWebApplicationContext getContext() {
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.register(WebConfig.class);
return context;
}
}
here is my Controller
package com.apollo.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
#Controller
public class LoginController {
#RequestMapping(value="/login")
public String greeting (Model model){
System.out.println("controller???");
model.addAttribute("greeting" , "Hello World");
return "login";
}
}
The basePackages mean the package contains the controller
Here is the problem:
#ComponentScan(basePackages = "com.apollo")
You should change to
#ComponentScan(basePackages = "com.apollo.controller")
If you put controller to modules, you should scan like this
#ComponentScan(basePackages = "com.apollo.**.controller")
Related
I am developing a spring boot based application that supports internationalisation
My env:
Jdk11
Spring boot 2.7.0
Spring Security
Here is my web mvc conf
WebMvcConf.java
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
import org.springframework.web.servlet.i18n.SessionLocaleResolver;
import java.util.Locale;
#Configuration
public class WebMvcConf implements WebMvcConfigurer {
public static final Locale idnLocale = Locale.forLanguageTag("id-ID");
#Bean
public LocaleResolver defaultLocaleResolver(){
var resolver = new SessionLocaleResolver();
resolver.setDefaultLocale(idnLocale);
return resolver;
}
#Bean
public LocaleChangeInterceptor localeChangeInterceptor(){
var interceptor = new LocaleChangeInterceptor();
interceptor.setIgnoreInvalidLocale(false);
interceptor.setParamName("lang");
return interceptor;
}
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(localeChangeInterceptor());
}
}
And here is my security config:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.header.HeaderWriterFilter;
import org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestWrapper;
#Configuration
#EnableWebSecurity
public class SecurityConf{
#Bean
public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {
httpSecurity
.cors()//enable cors
.and()
.csrf().disable()//disable csrf
.sessionManagement(session->session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))//stateless session (Rest)
.authorizeHttpRequests(authz->authz
.antMatchers(HttpMethod.GET,"/").permitAll()
.antMatchers(HttpMethod.POST,"/users/login","users/register","users/forgot-password").permitAll()
.antMatchers(HttpMethod.PATCH,"/users/password").permitAll()
.anyRequest().authenticated());//authorize any request except ignored endpoint above
return httpSecurity.build();
}
}
Here is the structure of the message properties:
Here is my application.yml content:
Here is the content of messages_en.properties:
rest.welcome.ok=Welcome to ABC Backend Service, have fun!!!
rest.users.login.ok=Successfully Logged in
#Error Message
rest.500.err=Internal Server Error
rest.422.err=Constraint Violation Error
rest.400.err=Invalid request body
rest.required-req-body-missing.err=Required request body is missing
Here is content of messages.properties:
rest.welcome.ok=Selamat Datang di Service ABC, selamat bersenang-senang!!!
rest.users.login.ok=Login sukses
#Error message
rest.500.err=Kesalahan Internal di sistem
rest.422.err=Error pelanggaran constraint
rest.400.err=Kesalahan pada request body
rest.required-req-body-missing.err=Request body (payload) yang dibutuhkan tidak ditemukan
Here is my test to test the message source:
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.MessageSource;
import java.util.Locale;
#SpringBootTest
public class MessageSourceTest {
#Autowired
private MessageSource messageSource;
#BeforeEach
void init(){
}
#Test
public void message_provided_should_correctly_localized(){
String msgEnglish = messageSource.getMessage("rest.500.err",null, new Locale("en"));
String msgIndo = messageSource.getMessage("rest.500.err",null,Locale.forLanguageTag("id-ID"));
Assertions.assertEquals("Internal Server Error",msgEnglish);
Assertions.assertEquals("Kesalahan Internal di sistem",msgIndo);
}
}
And the test is pass:
But when I try to hit a mvc rest controller and add query parameter lang=en , I always got an error response saying Cannot change HTTP accept header - use a different locale resolution strategy
So I debug the LocaleChangeInterceptor and found that spring boot provide a wrong implementation of the LocaleResolver, they provide AcceptHeaderResolver, which what I want is the SessionLocaleResolver as I state it in my WebMvcConf class. See following picture:
Anyone knows what is wrong and how to fix it?any response will be appreciated
I have a demo application of Spring MVC - I just follow udemy course for it.
I have created the first controller and view. All is working fine, however I have one doubt about.
The pom file of application contains:
<groupId>eu.smartgroup</groupId>
<artifactId>spring-demo-mvc</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
So when I run application on tomcat server it starts, but it is available with url: http://localhost:8080/spring_demo_mvc_war
Is there possibility to configure application so it will be available in the root path: http://localhost:8080/ (without project name after slash)?
Edit:
Here is full application.yml
server:
servlet:
contextPath: /
HelloController.java
package eu.test.springdemo.mvc;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
#Controller
#RequestMapping("/")
public class HelloController {
#GetMapping("/")
public String showPage() {
return "main-menu";
}
}
DemoAppConfig.java
package eu.test.springdemo.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
#Configuration
#EnableWebMvc
#ComponentScan(basePackages="eu.test.springdemo")
public class DemoAppConfig implements WebMvcConfigurer {
// define a bean for ViewResolver
#Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setPrefix("/WEB-INF/view/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
}
}
Add this line to your application.properties:
server.servlet.contextPath=/
I've tried it on my project and it works.
Write back is it working on your.
Check if you have a controller class that is annotated as such:
#Controller
#RequestMapping("spring_demo_mvc_war")
or
#RestController
#RequestMapping("spring_demo_mvc_war")
If that is the case, then make the string empty or remove the #RequestMapping (you can also change it to whatever else you like).
I am following "Spring in action - Craig Walls" book and encountered the below error message. Lot of the issues were mentioned in relation to web.xml. I am using Java config and not web.xml.
Controller in spitter.web package:
package spitter.web;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
#Controller
public class HomeController {
#RequestMapping(value="/", method = RequestMethod.GET)
public String home(){
return "home";
}
}
Dispatcher servlet configuration in spittr.config package:
package spittr.config;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
public class SpittrWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected String[] getServletMappings() {
return new String[] {"/"};
}
#Override
protected Class<?>[] getRootConfigClasses() {
//return new Class<?>[] {RootConfig.Class};
return null;
}
#Override
protected Class<?>[] getServletConfigClasses() {
//return new Class<?>[] {WebConfig.Class};
return null;
}
}
Rootconfig in same package:
package spittr.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
#Configuration
#ComponentScan(basePackages={"spitter"}, excludeFilters={#Filter(type=FilterType.ANNOTATION, value=EnableWebMvc.class)})
public class RootConfig {
}
WebConfig:
package spittr.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
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.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
#Configuration
#EnableWebMvc
#ComponentScan("spitter.web")
public class WebConfig extends WebMvcConfigurerAdapter{
#Bean
public ViewResolver viewResolver(){
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WebContent/WEB-INF/views/");
resolver.setSuffix(".jsp");
resolver.setExposeContextBeansAsAttributes(true);
return resolver;
}
#Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer){
configurer.enable();
}
}
I am using Maven to resolving dependencies and Tomcat 9 within eclipse to run.
Sep 17, 2016 4:46:48 PM org.apache.catalina.startup.Catalina start
INFO: Server startup in 5007 ms Sep 17, 2016 4:46:49 PM
org.springframework.web.servlet.PageNotFound noHandlerFound WARNING:
No mapping found for HTTP request with URI [/SpringMVC/] in
DispatcherServlet with name 'dispatcher'
My view home.jsp is in WebContent/WEB-INF/views/home.jsp.
Thanks for your help. I made the below changes and it is working now.
I move the web.config to the same package as my constructor. Then created the war file and deployed in Apache Tomcat. Now i am able to access the website.
I'm learning SpringMVC and maven these days with the book Spring in Action but i have a question now. The default request to "/" should be mapped to "home.jsp" but not. You can also see the same question described in the book forum.
https://forums.manning.com/posts/list/38046.page
Here are the codes:
package spittr.config;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
public class SpittrWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer{
#Override
protected String[] getServletMappings(){
return new String[]{ "/" };
}
#Override
protected Class<?>[] getRootConfigClasses(){
return new Class<?>[]{ RootConfig.class };
}
#Override
protected Class<?>[] getServletConfigClasses(){
return new Class<?>[]{ WebConfig.class };
}
}
package spittr.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
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.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
#Configuration
#EnableWebMvc
#ComponentScan("spittr.web")
public class WebConfig extends WebMvcConfigurerAdapter{
#Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix(".jsp");
resolver.setExposeContextBeansAsAttributes(true);
return resolver;
}
#Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer){
configurer.enable();
}
}
package spittr.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
#Configuration
#ComponentScan(basePackages={"spitter"}, excludeFilters={
#Filter(type=FilterType.ANNOTATION, value=EnableWebMvc.class)
})
public class RootConfig {
}
package spittr.web;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
#Controller
public class HomeController {
#RequestMapping(value="/", method=RequestMethod.GET)
public String home(){
return "home";
}
}
When i run this on tomcat 7.0, it should show home.jsp. However it still shows index.jsp.
-------------------- update -------------------------
The following test class indicates the controller class is right and this controller can response to the request "/" with home.jsp. So, where is wrong?
package spittr.web;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
import static org.springframework.test.web.servlet.setup.MockMvcBuilders.*;
import org.junit.Test;
import org.springframework.test.web.servlet.MockMvc;
public class HomeControllerTest {
#Test
public void testHomePage() throws Exception{
HomeController controller = new HomeController();
MockMvc mockMvc = standaloneSetup(controller).build();
mockMvc.perform(get("/")).andExpect(view().name("home"));
}
}
update or add in your web.xml
<welcome-file-list>home.jsp</welcome-file-list>
If you do not have web.xml you can generate by
Dynamic Web Project –> RightClick –> Java EE Tools –> Generate
Deployment Descriptor Stub.
Also you can do JSP redirect using JSTL libraries in index.jsp to redirect to home.jsp
<%# taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<c:redirect url="/home.jsp"/>
seems to be a path problem.
First check your path mapping in web.xml file for exact url-pattern for which you are redirecting to dispatcher servlet.Assuming that you have home.jsp views created under
/WEB-INF/views/
folder.
I had the same issue while working on Eclipse, Tomcat 9.0 on my Mac. I have spend hours to see (this small code) that where I was wrong.
However, I was able to make it run on Windows machine with Eclipse and Tomcat 8.5 and 9.0 .
I have the code hosted on GitHub at https://github.com/shortduck/ManningChapter5_SpringMVC
This is a Maven project and not Gradle. Also see the HomeController has the value as value = "/home", this is working as well as '/' will work too. If you have having value as '/' make sure index.jsp or any other "home" page is not on the root.
My next target to find out why is this code not working on Mac.
I have a problem... Well, when I start my test, I throw me the following error, and can not find that he is doing wrong. Agrege corresponding to the "Application-context" where is the notation hibernate settings, but I can not perform my test successfully
"WebAppInitializer":
package com.checkwork.conf;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;
public class WebAppInitializer implements WebApplicationInitializer {
private static final Logger logger = LoggerFactory.getLogger(WebAppInitializer.class);
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
logger.info("Initializing web application with context configuration class {}", WebAppConfigurer.class.getCanonicalName());
//WebApplication Param-Value (Web.XML)
AnnotationConfigWebApplicationContext webAppContext = new AnnotationConfigWebApplicationContext();
webAppContext.register(WebAppConfigurer.class);
//Crea Servlet y mapea las peticiones con "/" sin extensiones.
ServletRegistration.Dynamic dispatcher = servletContext.addServlet("dispatcher",
new DispatcherServlet(webAppContext));
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("/");
}
}
"WebAppConfigurer":
package com.checkwork.conf;
import com.checkwork.model.Empleado;
import java.util.Properties;
import javax.sql.DataSource;
import org.apache.commons.dbcp.BasicDataSource;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.*;
import org.springframework.orm.hibernate4.HibernateTransactionManager;
import org.springframework.orm.hibernate4.LocalSessionFactoryBuilder;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
#Configuration
#EnableTransactionManagement /** Gestor de transacciones que permiten habilitar los componentes para la conexion a la BD */
#EnableWebMvc
#ComponentScan(basePackages = {"com.checkwork"})
public class WebAppConfigurer extends WebMvcConfigurerAdapter {
#Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
#Bean(name = "dataSource")
public DataSource getDataSource() {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/module");
dataSource.setUsername("root");
dataSource.setPassword("root");
return dataSource;
}
private Properties getHibernateProperties() {
Properties properties = new Properties();
properties.put("hibernate.show_sql", "true");
properties.put("hibernate.dialect", "org.hibernate.dialect.MySQLDialect");
return properties;
}
#Autowired
#Bean(name = "sessionFactory")
public SessionFactory getSessionFactory(DataSource dataSource) {
LocalSessionFactoryBuilder sessionBuilder = new LocalSessionFactoryBuilder(dataSource);
sessionBuilder.addProperties(getHibernateProperties());
sessionBuilder.addAnnotatedClasses(Empleado.class);
return sessionBuilder.buildSessionFactory();
}
#Autowired
#Bean(name = "transactionManager")
public HibernateTransactionManager getTransactionManager(
SessionFactory sessionFactory) {
HibernateTransactionManager transactionManager = new HibernateTransactionManager(
sessionFactory);
return transactionManager;
}
/**
* Agrega al Caché la librería OpenUI5 en tiempo de ejecución {WEB-INF/lib}
*/
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("classpath:/resources/", "/resources/**")
.setCachePeriod(31556926);
}
}
Test:
package com.checkwork.service;
import static org.junit.Assert.*;
import javax.transaction.Transactional;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.checkwork.conf.WebAppConfigurer;
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = WebAppConfigurer.class)
public class EmpleadoServiceTest {
private EmpleadoService empleadoService;
#Before
public void setUp() throws Exception{
empleadoService = new EmpleadoService();
}
#Test
#Transactional
public void getAllTest(){
assertNotNull(empleadoService.getAll());
}
}
Error console - Junit:
SEVERE: Caught exception while allowing TestExecutionListener [org.springframework.test.context.support.DependencyInjectionTestExecutionListener#1761de10] to prepare test instance [com.checkwork.service.EmpleadoServiceTest#22df874e]
java.lang.IllegalStateException: Failed to load ApplicationContext...
Change
#ContextConfiguration(classes = WebAppConfigurer.class)
to
#ContextConfiguration(classes = WebAppConfigurer.class, initializers=WebAppInitializer.class)
update
Also include #WebIntegrationTest below #ContextConfiguration