Every request in my java application produces 2 other requests with a HTTP 302 error.
For example, if a request is made to view a webpage called board.html, this request is made from home.html. I get 3 requests produced in the following order:
POST home.html - 302 Moved Temporarily
GET board.html - 302 Moved Temporarily
GET board.html - 200 OK
I expect to get just the final request only and cant find out why the other 2 are occurring.
This pattern occurs for all requests causing my filters to fire 3 times.
The project uses spring webflow.
After lot of reading was finally able to change the default behaviour
( default behaviour was - Get request , post (302/303 - redirect as per location appended for each request ) , finally a get call.
So for one request we will send a Get Request then Service will return 302/303 with location attribute ( ie redirected with query param ) and as a response HTML with QueryString usually e1s1 is loaded. Sample proj is in this link and following is the change that is been implemented to avoid this default behaviour as following
To avoid 303/302 which has unpredictable behaviour i have stoped redirection with following addition to Config Class
#Configuration
public class WebFlowWithMvcConfig extends AbstractFlowConfiguration {
//implements WebMvcConfigurer
#Autowired
private LocalValidatorFactoryBean localValidatorFacotryBean;
/*
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LogInterceptor());
}
*/
#Bean
public FlowDefinitionRegistry flowRegistry() {
return getFlowDefinitionRegistryBuilder() //
.setBasePath("classpath:flows") //
.addFlowLocationPattern("/**/*-flow.xml") //
.setFlowBuilderServices(this.flowBuilderServices()) //
.build();
}
#Bean
public FlowExecutor flowExecutor() {
return getFlowExecutorBuilder(this.flowRegistry())
.setAlwaysRedirectOnPause(false)
.setRedirectInSameState(false)
.build();
}
#Bean
public FlowBuilderServices flowBuilderServices() {
return getFlowBuilderServicesBuilder() //
.setViewFactoryCreator(this.mvcViewFactoryCreator()) // Important!
.setValidator(this.localValidatorFacotryBean)
.build();
}
// ----------------------------------------------------------
#Bean
public FlowHandlerMapping flowHandlerMapping() {
FlowHandlerMapping handlerMapping = new FlowHandlerMapping();
handlerMapping.setOrder(-1);
handlerMapping.setFlowRegistry(this.flowRegistry());
//handlerMapping.setInterceptors(new LogInterceptor());
return handlerMapping;
}
#Bean
public FlowHandlerAdapter flowHandlerAdapter() {
FlowHandlerAdapter handlerAdapter = new FlowHandlerAdapter();
handlerAdapter.setFlowExecutor(this.flowExecutor());
handlerAdapter.setSaveOutputToFlashScopeOnRedirect(true);
//handlerAdapter.setStatusCode(HttpStatus.SEE_OTHER);
//handlerAdapter.setStatusCode(HttpStatus.TEMPORARY_REDIRECT);
return handlerAdapter;
}
#Bean
public ViewFactoryCreator mvcViewFactoryCreator() {
MvcViewFactoryCreator factoryCreator = new MvcViewFactoryCreator();
factoryCreator.setViewResolvers(Collections.singletonList(this.thymeleafViewResolver()));
factoryCreator.setUseSpringBeanBinding(true);
return factoryCreator;
}
#Bean
#Description("Thymeleaf AJAX view resolver for Spring WebFlow")
public AjaxThymeleafViewResolver thymeleafViewResolver() {
AjaxThymeleafViewResolver viewResolver = new AjaxThymeleafViewResolver();
viewResolver.setViewClass(FlowAjaxThymeleafView.class);
viewResolver.setTemplateEngine(this.templateEngine());
viewResolver.setCharacterEncoding("UTF-8");
return viewResolver;
}
#Bean
#Description("Thymeleaf template resolver serving HTML 5")
public ClassLoaderTemplateResolver templateResolver() {
ClassLoaderTemplateResolver templateResolver = new ClassLoaderTemplateResolver();
templateResolver.setPrefix("templates/");
templateResolver.setCacheable(false);
templateResolver.setSuffix(".html");
templateResolver.setTemplateMode("HTML5");
templateResolver.setCharacterEncoding("UTF-8");
return templateResolver;
}
#Bean
#Description("Thymeleaf template engine with Spring integration")
public SpringTemplateEngine templateEngine() {
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.setTemplateResolver(this.templateResolver());
return templateEngine;
}
}
So we have made following as false
.setAlwaysRedirectOnPause(false)
.setRedirectInSameState(false)
Which will avoid location redirect now the similar change has to be implemented in the template html's too. So the change was to add an action url to html template wherever form is present as following
<form .. th:action="${flowExecutionUrl}">
Which successfully does form submission and responds with 200 Ok http status and html page. Hence no more (GET - 200 to 302 redirect to 200) instead direct single request call with Get 200/Post 200 and response is binded to Html page.
In this way just the final request only with response is present.
I hope this would be helpful for others.
Related
Assume that Project is our POJO class. Following function provides to delete a row from database. It is successfully working with POSTMAN requests.
#RestController
#RequestMapping(value = "/project")
#CrossOrigin
public class ProjectController {
private final ProjectServiceImpl projectServiceImpl;
------------
#DeleteMapping
#RequestMapping("/delete/{id}")
public ResponseEntity<Boolean> deleteProject(#PathVariable Long id) {
boolean result = projectServiceImpl.delete(id);
return ResponseEntity.ok(result);
}
------------
}
But requests from Angular project are rejecting with 403 message. And following message is appearing in console screen.
After some searches. I learned, the application have to answer pre-flight requests with 200. To provide this, following function was added to controller.
#GetMapping
#RequestMapping("/delete/{id:[0-9]+}")
public ResponseEntity.BodyBuilder retreive(#PathVariable Long id) {
return ResponseEntity.ok();
}
I used regex for request mapping because without it Spring Framework throws /project/delete/{id} already mapped with another function. Angular get its 200OK for pre-flight request with this way. But the application response is 406 for delete operation. Angular is sending http://localhost:8080/project/delete/2 url to the application. If I send same link without have a function for CORS. Row has id with 2 will delete successfully. Am I missing something?
Sources:
Why Angular sending OPTIONS message before DELETE
How to add CORS support to Spring Boot application
To implement server side proxy: proxy.conf.json
{
"/project/**": {
"target": "http://localhost:8080",
"secure": false
}
}
modified section in angular.json
"serve": {
"builder": "#angular-devkit/build-angular:dev-server",
"options": {
"browserTarget": "issue-management:build",
"proxyConfig": "proxy.conf.json"
},
and Angular project started with ng serve --proxy-config proxy.conf.json but result didn't change. Plus, suggestions in this article applied, again result didn't change.
Your applications are running on two different ports, that causing the CORS issue.
Add the proxy(file proxy.conf.json) in your Angular application.
{
"/project/**": {
"target": "http://localhost:8080",
"secure": false
}
}
and run this ng serve --proxy-config proxy.conf.json
Refference Angular doc
Update:
#Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedMethods("*")
.allowedOrigins("http://localhost:4200");
}
};
}
worked, For some reason Angular proxy is not working
If you are using spring security use the following:
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
// by default uses a Bean by the name of corsConfigurationSource
.cors(withDefaults())
...
}
#Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("https://example.com"));
configuration.setAllowedMethods(Arrays.asList("GET","POST"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}
See spring documentation: https://docs.spring.io/spring-security/site/docs/current/reference/html5/#cors
Global configuration:
#Configuration
#EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
#Value("${cors.origins.urls}")
public String allowedOrigins;
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedMethods("GET", "POST", "PUT", "DELETE")
.allowedOrigins(allowedOrigins.split(","));
}
}
I currently have a Spring Boot application that is using React JS for the front end. I'm running inside Visual Studio, and via webpack, I'm compiling resources and outputting them to a Maven target folder. You can see the structure of the directory with the Java classes sitting inside the 'classes' folder and the client application sitting now inside the webapp folder - notice the index.html.
As this is a single page application I only need this page to resolve. As such my controller is configured to return the index file.
#SpringBootApplication
public class AdminApplication
{
public static void main( String[] args )
{
SpringApplication.run( AdminApplication.class, args );
}
}
#Controller
public class DefaultController
{
#RequestMapping( "/**" )
public ModelAndView reactApp()
{
return new ModelAndView( "index" );
}
}
Now. My problem comes with telling my view resolver to talk to this directory.
As you can see from the commented code, I've tried only a couple of hundred options for trying to get it to resolve the view. I've got the full file path to my project directory available on the documentRoot so if necessary and thought potentially I would need that.
I've put a breakpoint in the controller and this definitely does get hit, it just returns a 404 when trying to find the relevant view each time. Any guidance on what my viewResolver might need to look like appreciated. I can see there's a couple of Classes that may or may not be correct:
e.g. SpringResourceTemplateResolver and ClassLoaderTemplateResolver - not sure on which of these is most relevant for my requirements
#EnableWebMvc
#Configuration
public class MvcConfig implements WebMvcConfigurer,ApplicationContextAware {
private ApplicationContext context;
#Value("${server.document-root:}")
private String documentRoot;
#Override
public void setApplicationContext( ApplicationContext applicationContext ) {
this.context = applicationContext;
}
// private ITemplateResolver htmlTemplateResolver() {
// SpringResourceTemplateResolver resolver = new
// SpringResourceTemplateResolver();
// resolver.setApplicationContext(applicationContext);
// resolver.setPrefix(documentRoot);
// resolver.setCacheable(false);
// resolver.setTemplateMode(TemplateMode.HTML);
// return resolver;
// }
// #Bean
// public SpringResourceTemplateResolver templateResolver() {
// SpringResourceTemplateResolver templateResolver = new
// SpringResourceTemplateResolver();
// templateResolver.setPrefix( "/webapp/" );
// templateResolver.setCacheable(false);
// templateResolver.setSuffix(".html");
// templateResolver.setTemplateMode("HTML");
// return templateResolver;
// }
private ITemplateResolver templateResolver() {
SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver();
resolver.setApplicationContext(context);
resolver.setPrefix("templates/");
resolver.setSuffix(".html");
resolver.setTemplateMode(TemplateMode.HTML);
return resolver;
}
// public ITemplateResolver templateResolver() {
// ClassLoaderTemplateResolver templateResolver = new ClassLoaderTemplateResolver();
// templateResolver.setPrefix("templates/");
// templateResolver.setCacheable(false);
// templateResolver.setSuffix(".html");
// templateResolver.setTemplateMode(TemplateMode.HTML);
// templateResolver.setCharacterEncoding("UTF-8");
// return templateResolver;
// }
}
you don't need MvcConfig
just set the static-locations property in src/main/resources/application.properties to spring.resources.static-locations=classpath:/webapp/
map all possible request to your index-page like:
#GetMapping({"/index","/","/home"})
public String reactApp()
{
return "/index.html";
}
optional you could redirect the requests to your index-page
#GetMapping({"/index","/","/home"})
public String reactApp()
{
return "redirect:/index.html";
}
You don't need the MvcConfig class, Spring boot auto-configure the view resolver. All you have to do is to put your templates to the src/main/resources/templates/ directory and make a simple controller mapping like this
#RequestMapping(value = "/")
public String index() {
return "index";
}
in your home controller.
You can also check out this React.js and Spring example
you will need to configure your resource handler, that way:
#Configuration
public class StaticResourceConfiguration implements WebMvcConfigurer {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/**")
.addResourceLocations("file:/path/to/dir/webapp/");
}
}
Notice, that in unix you will use file:/ and for windows
file:///C:/path/to/dir/webapp/
And then redirect the/ to index.html
#RequestMapping
#RestController
public class IndexEndpoint {
#GetMapping("/")
public String reactApp() {
return "/index.html";
}
}
I have tested it on a MacOS and it worked prefect.
I have Spring Boot application with REST API mapped on /api. I need to define additional servlet on /. I want all request that match /api was handled by REST API and all others requests by the servlet. How to do this?
#SpringBootApplication
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
#RestController
#RequestMapping("/api")
public class ApiController {
#GetMapping
public String get() {
return "api";
}
}
#Bean
public ServletRegistrationBean customServletBean() {
return new ServletRegistrationBean<>(new HttpServlet() {
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
resp.getWriter().println("custom");
}
}, "/*");
}
}
In code above I want something like this:
curl http://localhost:8080/api/
> api⏎
curl http://localhost:8080/custom/
> custom
I have tried with filter to redirect requests, but all requests go to custom servlet:
#Bean
public FilterRegistrationBean apiResolverFilter() {
final FilterRegistrationBean registrationBean = new FilterRegistrationBean<>();
registrationBean.setFilter((req, response, chain) -> {
HttpServletRequest request = (HttpServletRequest) req;
String path = request.getRequestURI().substring(request.getContextPath().length());
if (path.startsWith("/api/")) {
request.getRequestDispatcher(path).forward(request, response);
} else {
chain.doFilter(request, response);
}
});
registrationBean.addUrlPatterns("/*");
return registrationBean;
}
This project is available on github: https://github.com/mariuszs/nestedweb
When mapping a servlet to the root path you will override the mapping for the DispatcherServlet which, by default, is mapped to /.
There are basically 3 solutions you could try
Map the DispatcherServlet to /api and modify the mappings in your controllers
Use a ServletForwardingController to forward the request to the configured but unmapped Servlet
Use a ServletWrappingController to wrap a Servlet instance
Number 2 and 3 are almost the same, with this difference that with option 3 Spring also manages the Servlet instance whereas with option 2, the Servlet container manages the Servlet.
Mapping DispatcherServlet to /api
Option 1 can be an option if all of your controllers are mapped under /api, if they aren't this isn't an option. In your application.properties you would set the spring.mvc.servlet.path to /api. Then you would configure your other Servlet like you did in your question.
Use a ServletForwardingController
Spring provides a ServletForwardingController which will lookup a Servlet in the ServletContext given the name of the servlet and forward the request to it. You will still have to register the Servlet but prevent it from being mapped.
Next you would need a SimpleUrlHandlerMapping to map the URLs to this controller or set it as the default handler (basically a catch all).
#Bean
public ServletForwardingController forwarder() {
ServletForwardingController controller = new ServletForwardingController();
controller.setServletName("my-servlet");
return controller;
}
#Bean
public CustomServlet customServlet() {
return new CustomServlet();
}
#Bean
public ServletRegistrationBean customServletRegistration() {
ServletRegistrationBean registration = new ServletRegistrationBean(customServlet(), false);
registration.setServletName("customServlet");
return registration;
}
#Bean
public SimpleUrlHandlerMapping simpleUrlHandlerMapping() {
SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
mapping.setDefaultHandler(forwarder());
mapping.setOrder(LOWEST_PRECEDENCE - 2);
return mapping;
}
Use a ServletWrappingController
Spring provides a ServletWrappingController which will internally create and configure a Servlet instance. It acts as an adapter from/to the Servlet to a Spring Controller. You don't have to register the CustomServlet in this case and is thus slightly easier to configure the then ServletForwardingController.
Next you would need a SimpleUrlHandlerMapping to map the URLs to this controller or set it as the default handler (basically a catch all).
#Bean
public ServletWrappingController wrapper() {
ServletWrappingController controller = new ServletWrappingController ();
controller.setServletName("my-servlet");
controller.setServletClass(CustomerServlet.class);
return controller;
}
#Bean
public SimpleUrlHandlerMapping simpleUrlHandlerMapping() {
SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
mapping.setDefaultHandler(wrapper());
mapping.setOrder(LOWEST_PRECEDENCE - 2);
return mapping;
}
Depending on your architecture and url structure you might want to go for option 1 or option 3.
I encounter a very strange issue in my project using spring web flow 2.4.0.
In the documentation of web-flow project we can read on chapter 2 the following statement:
By default Web Flow does a client-side redirect upon entering every
view state.
My concern is when i submit a form web flow do not make redirection that implies a new form submission is made if user reload or refresh the page. This is very boring.
I tried many things and found a couple of solutions on the web
for example make the redirection programmaticaly with the following code :
context.getExternalContext().requestFlowExecutionRedirect();
And i finally found an attribute "redirect" for the tag view-state in flow configuration. when it is set to true everything works fine.
Since web flow documentation mentions that this behavior (redirect automatically ) is the default one , does anyone heard about a better way to do this after form submission.
I am looking for a kind of POST REDIRECT GET pattern.
Thank you and sorry for my english :)
Just verify your springwebflow xml file configuration, it could be because of
redirect flag set to false in the flow-execution-attributes.
<webflow:flow-execution-attributes>
<webflow:always-redirect-on-pause value="true"/>
<webflow:redirect-in-same-state value="true"/>
</webflow:flow-execution-attributes>
</webflow:flow-executor>
To do the same
following is the code in Bean Level
#Bean
public FlowExecutor flowExecutor() {
return getFlowExecutorBuilder(this.flowRegistry())
.setRedirectInSameState(true)
.setAlwaysRedirectOnPause(true)
.build();
}
where the class extends AbstractFlowConfiguration
After lot of reading was finally able to change the default behaviour
( default behaviour was - Get request , post (302/303 - redirect as per location appended for each request ) , finally a get call.
So for one request we will send a Get Request then Service will return 302/303 with location attribute ( ie redirected with query param ) and as a response HTML with QueryString usually e1s1 is loaded. Sample proj is in this link and following is the change that is been implemented to avoid this default behaviour as following
To avoid 303/302 which has unpredictable behaviour i have stoped redirection with following addition to Config Class
#Configuration
public class WebFlowWithMvcConfig extends AbstractFlowConfiguration {
//implements WebMvcConfigurer
#Autowired
private LocalValidatorFactoryBean localValidatorFacotryBean;
/*
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LogInterceptor());
}
*/
#Bean
public FlowDefinitionRegistry flowRegistry() {
return getFlowDefinitionRegistryBuilder() //
.setBasePath("classpath:flows") //
.addFlowLocationPattern("/**/*-flow.xml") //
.setFlowBuilderServices(this.flowBuilderServices()) //
.build();
}
#Bean
public FlowExecutor flowExecutor() {
return getFlowExecutorBuilder(this.flowRegistry())
.setAlwaysRedirectOnPause(false)
.setRedirectInSameState(false)
.build();
}
#Bean
public FlowBuilderServices flowBuilderServices() {
return getFlowBuilderServicesBuilder() //
.setViewFactoryCreator(this.mvcViewFactoryCreator()) // Important!
.setValidator(this.localValidatorFacotryBean)
.build();
}
// ----------------------------------------------------------
#Bean
public FlowHandlerMapping flowHandlerMapping() {
FlowHandlerMapping handlerMapping = new FlowHandlerMapping();
handlerMapping.setOrder(-1);
handlerMapping.setFlowRegistry(this.flowRegistry());
//handlerMapping.setInterceptors(new LogInterceptor());
return handlerMapping;
}
#Bean
public FlowHandlerAdapter flowHandlerAdapter() {
FlowHandlerAdapter handlerAdapter = new FlowHandlerAdapter();
handlerAdapter.setFlowExecutor(this.flowExecutor());
handlerAdapter.setSaveOutputToFlashScopeOnRedirect(true);
//handlerAdapter.setStatusCode(HttpStatus.SEE_OTHER);
//handlerAdapter.setStatusCode(HttpStatus.TEMPORARY_REDIRECT);
return handlerAdapter;
}
#Bean
public ViewFactoryCreator mvcViewFactoryCreator() {
MvcViewFactoryCreator factoryCreator = new MvcViewFactoryCreator();
factoryCreator.setViewResolvers(Collections.singletonList(this.thymeleafViewResolver()));
factoryCreator.setUseSpringBeanBinding(true);
return factoryCreator;
}
#Bean
#Description("Thymeleaf AJAX view resolver for Spring WebFlow")
public AjaxThymeleafViewResolver thymeleafViewResolver() {
AjaxThymeleafViewResolver viewResolver = new AjaxThymeleafViewResolver();
viewResolver.setViewClass(FlowAjaxThymeleafView.class);
viewResolver.setTemplateEngine(this.templateEngine());
viewResolver.setCharacterEncoding("UTF-8");
return viewResolver;
}
#Bean
#Description("Thymeleaf template resolver serving HTML 5")
public ClassLoaderTemplateResolver templateResolver() {
ClassLoaderTemplateResolver templateResolver = new ClassLoaderTemplateResolver();
templateResolver.setPrefix("templates/");
templateResolver.setCacheable(false);
templateResolver.setSuffix(".html");
templateResolver.setTemplateMode("HTML5");
templateResolver.setCharacterEncoding("UTF-8");
return templateResolver;
}
#Bean
#Description("Thymeleaf template engine with Spring integration")
public SpringTemplateEngine templateEngine() {
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.setTemplateResolver(this.templateResolver());
return templateEngine;
}
}
So we have made following as false
.setAlwaysRedirectOnPause(false)
.setRedirectInSameState(false)
Which will avoid location redirect now the similar change has to be implemented in the template html's too. So the change was to add an action url to html template wherever form is present as following
<form .. th:action="${flowExecutionUrl}">
Which successfully does form submission and responds with 200 Ok http status and html page. Hence no more (GET - 200 to 302 redirect to 200) instead direct single request call with Get 200/Post 200 and response is binded to Html page.
This question already has answers here:
Why does Spring MVC respond with a 404 and report "No mapping found for HTTP request with URI [...] in DispatcherServlet"?
(13 answers)
Closed 6 years ago.
I declared UrlBasedViewResolver method in RestAppConfig to render jsp page.
#Bean
public UrlBasedViewResolver urlBasedViewResolver(){
UrlBasedViewResolver res = new InternalResourceViewResolver(); //new UrlBasedViewResolver();//
res.setOrder(10);
res.setViewClass(JstlView.class);
res.setPrefix("/views/templates/");
res.setSuffix(".jsp");
return res;
}
and delclared ModelAndView method in controller BaseController
#Configuration
#EnableWebMvc
#ComponentScan(basePackages={"kr.co.cdefi.base.restapp.controller"}
, useDefaultFilters=false
, includeFilters={#Filter(Controller.class)
, #Filter(ControllerAdvice.class)})
public class RestAppConfig extends WebMvcConfigurerAdapter{
#Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer
.useJaf(true)
.favorPathExtension(true)
.favorParameter(false)
.ignoreAcceptHeader(false)
.defaultContentType(MediaType.APPLICATION_JSON)
.mediaType("json", MediaType.APPLICATION_JSON)
.mediaType("xml", MediaType.APPLICATION_XML);
};
#Bean
public UrlBasedViewResolver urlBasedViewResolver(){
UrlBasedViewResolver res = new InternalResourceViewResolver(); //new UrlBasedViewResolver();//
res.setOrder(10);
res.setViewClass(JstlView.class);
res.setPrefix("/views/templates/");
res.setSuffix(".jsp");
return res;
}
}
finally, I run tomcat8 server using Eclipse.
But requested URI /home just responses this.
WARN o.s.web.servlet.PageNotFound - No mapping found for HTTP request with URI [/TheBigs/views/templates/index.jsp] in DispatcherServlet with name 'rest-app'
I opened deployment location
...\org.eclipse.wst.server.core\tmp1\wtpwebapps\TheBigs\views\templates\
... files exists. What is the problem? Is there anything I missing?
I added my controller code BaseController
#Controller
public class BaseController {
Logger logger = LoggerFactory.getLogger(BaseController.class);
#Autowired UserService userService;
#RequestMapping(value="/home", method = RequestMethod.GET)
public ModelAndView home(){
logger.debug("home!");
ModelAndView view = new ModelAndView();
view.setViewName("index");
return view;
}
#RequestMapping(value="/", method = RequestMethod.GET)
public String index(Model model){
logger.debug("index page!");
model.addAttribute("message", "success");
return "test";
}
}
There images are jsp files directory, and Web Deployment Assembly defined.
Solved. It caused by servlet-mapping.
I changed url-pattern set to / from /*, then works.