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.
Related
I have this webapp
Here is the controller:
#Controller
#RequestMapping(value = "/update")
public class Update{
#RequestMapping(value = "/tracking_number", method = RequestMethod.POST)
public ResponseEntity<String> updateTrackingNumber(#RequestHeader(value = "order_id")String orderId,
#RequestHeader(value = "tracking_number")String trackingNumber,
HttpSession httpSession){
//url: localhost:8080/update/tracking_number
//this one works perfectly
}
#RequestMapping(value = "/order_products", method = RequestMethod.POST)
public ResponseEntity<String> updateOrderProducts(){
return ResponseEntity.ok().body("i hope to see this text");
}
}
SpringBootApplication:
#SpringBootApplication
public class MainCore extends SpringBootServletInitializer{
public static void main(String[] args){
SpringApplication.run(MainCore.class, args);
}
}
WebApplicationInitializer:
public class AppInitializer implements WebApplicationInitializer{
#Override
public void onStartup(ServletContext container) throws ServletException{
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.scan("com.web.foo");
container.addListener(new ContextLoaderListener(context));
ServletRegistration.Dynamic dispatcher = container.addServlet("mvc", new DispatcherServlet(context));
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("/");
}
}
WebMvcConfigurer:
#EnableWebMvc
#Configuration
#ComponentScan(basePackages = "com.web.foo.controller")
public class WebConfig implements WebMvcConfigurer{
#Bean
public ViewResolver internalResourceViewResolver() {
InternalResourceViewResolver bean = new InternalResourceViewResolver();
bean.setViewClass(JstlView.class);
bean.setPrefix("/WEB-INF/jsp/");
bean.setSuffix(".jsp");
return bean;
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**")
.addResourceLocations("/resources/");
}
}
The structure:
com
- web
- - foo
- - - controller
- - - - Update.java
- - - MainCore.java
- - - AppInitializer.java
- - - WebConfig.java
When I access localhost:8080/update/tracking_number it works perfect.
But when I access localhost:8080/update/order_products it no longer works and gives the response:
{
"timestamp": 1618404297125,
"status": 404,
"error": "Not Found",
"message": "No message available",
"path": "/update/order_products"
}
Can you check if the request has Content-Type header. Also in #RequestMapping add consumes = "application/text" or "application/json" whatever is relevant.
Try add #ResponseBody methods of updateOrderProducts
The project is running directly from Intellij IDEA.
So, in my case, the solution was to Invalidate caches.
servlet not doing redirect, used Spring Boot 2.4.1. Code and comments below.
Class servlet
code
#WebServlet(name = "estore",
urlPatterns = {"/"},
loadOnStartup = 1)
public class EstoreServlet extends HttpServlet {
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws
IOException{
// Here logic and after need redirect
response.sendRedirect("/index.html");
}
}
Information from request
code
Session - org.apache.catalina.session.StandardSessionFacade#2e555cdd
Servlet path - /
Server name - localhost
Local name - 0:0:0:0:0:0:0:1
Local addr - 0:0:0:0:0:0:0:1
Get Remote user - null
Get method - GET
Get protocol - HTTP/1.1
Get content type - null
Get server port - 8080
Get sheme - http
Get Request URI - /
Get Context Path -
Spring MVC configuration file
code
#Configuration
#ServletComponentScan(basePackages = "internet_store.web_ui.servlet")
#EnableWebMvc
public class MvcConfiguration implements WebMvcConfigurer {
#Bean
public SpringResourceTemplateResolver templateResolver() {
SpringResourceTemplateResolver resourceViewResolver = new SpringResourceTemplateResolver();
resourceViewResolver.setPrefix("classpath:/templates/internet_store/");
resourceViewResolver.setSuffix(".html");
resourceViewResolver.setTemplateMode(TemplateMode.HTML);
resourceViewResolver.setCharacterEncoding("UTF-8");
resourceViewResolver.setCheckExistence(false);
return resourceViewResolver;
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry
.addResourceHandler("/resources/**")
.addResourceLocations("/resources/", "classpath:/templates/internet_store/")
.setCachePeriod(320000)
.resourceChain(true)
.addResolver(new PathResourceResolver());
}
#Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable("estore");
}
}
Project structure
Resources
This code return error in browser ERR_TOO_MANY_REDIRECTS. If in controller set return "redirect:/foo" then redirect not doing too. Example below.
code
#GetMapping(value = "/back_client")
public String backButtonClientFormPressed() {
return "service/service";
}
index.html have controller with method
code
#GetMapping(value = "/index")
public String index(ModelMap modelMap) {
updatePage();
Path resourceDirectory = Paths.get("resources");
modelMap.addAttribute("error", "");
refreshData(modelMap);
return "index";
}
Change service/service to redirect:/index going to error ERR_TOO_MANY_REDIRECTS. Maybe problems with resources path? Thank You for You attention.
[SOLVED]
Need delete response.sendRedirect("/index.html"); from servlet class and add
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("forward:/index");
registry.setOrder(Ordered.HIGHEST_PRECEDENCE);
}
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 am new to Spring MVC with annonation and I am just trying a basic example for it. But I am receiving Http Stats 404 error. My files are as below :
It is a maven project. request mapping is the part of controller which is used and jsp page only list.jsp to show that msg.
errors-HTTP Status 404 - /test1/view/list.jsp
public class ADConfiguration extends WebMvcConfigurerAdapter{
#Override
public void configureViewResolvers(ViewResolverRegistry registry) {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
System.out.println("hjshjshdjkah");
viewResolver.setViewClass(JstlView.class);
viewResolver.setPrefix("/view/");
viewResolver.setSuffix(".jsp");
registry.viewResolver(viewResolver);
}
#RequestMapping(value = "/list", method = RequestMethod.GET)
public ModelAndView list() {
System.out.println("####################Controller part methods###");
String message = "HELLO SPRING MVC HOW R U";
return new ModelAndView("list", "message", message);
}
}
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.