44

I am using Spring MVC 3 and am having an issue with a URL mapping. I have a method

 @Controller
 public class DocumentController {
      @RequestMapping( value="/docs/pupil/classes/{courseCategoryType}", method=RequestMethod.GET )
      public ModelAndView listClassesForPupil( @PathVariable("courseCategoryType") final String courseCategoryType ){
            System.err.print( "\n\n\n\t\t--- XXXXX ---\n\n\n" );
      }
 }

I am trying to use the Spring URI template syntax, and I know that is getting mapped because in console I see:

 11:22:12,108  INFO DefaultAnnotationHandlerMapping:411 - Mapped URL path [/docs/pupil/classes/{courseCategoryType}] onto handler 'documentController'
 11:22:12,108  INFO DefaultAnnotationHandlerMapping:411 - Mapped URL path [/docs/pupil/classes/{courseCategoryType}.*] onto handler 'documentController'
 11:22:12,108  INFO DefaultAnnotationHandlerMapping:411 - Mapped URL path [/docs/pupil/classes/{courseCategoryType}/] onto handler 'documentController'

However, when I enter the URLhttps://localhost/docs/pupil/classes/ACADEMIC in browser I get a 404 error and I do not see anything printed out in the console. I replaced the print out code that just throws an exception, and it didn't seem to get thrown either. A coworker suggested there should be a way of viewing how the URL resolution is being done but a Google search didn't seem to turn up anything.

Any suggestions as how to debug this?

Sled
  • 18,541
  • 27
  • 119
  • 168
  • Quick check: do other controllers work? Are you sure it's not a problem with context path, `DispatcherServlet`'s url-pattern, etc? – axtavt Mar 28 '11 at 16:31
  • 1
    The other controllers worked, and we solved this particular issue (I turned out that there was filter for the front controller to ignore all but *.bf requests) but I thought this question would be still useful because I'd like to be able to debug request issues like this in the future. – Sled Mar 28 '11 at 16:47

11 Answers11

31

For problems like this I feel like the best "entrypoint" to start debugging is the method getHandler(HttpServletRequest request) of the DispatcherServlet.

Inside this method every configured HandlerMapping is inspected if it responsible for handling your specific request. If your request makes it this far, you can be quite sure that it is a configuration problem inside the spring context.

Watch out for handlers of the type RequestMappingHandlerMapping (or DefaultAnnotationHandlerMapping, if you are using an older version of Spring), these are normally the HandlerMapping used by annotation based Controller configuration.

In the other case, make sure there is nothing "in front" of the DispatcherServlet filtering your requests (like in your case)

Patrick
  • 915
  • 1
  • 8
  • 17
  • 8
    Started with this advice but personally found [`doDispatch(HttpServletRequest,HttpServletResponse)`](https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/servlet/DispatcherServlet.html#doDispatch-javax.servlet.http.HttpServletRequest-javax.servlet.http.HttpServletResponse-) as the better place to start. – Sled Feb 20 '18 at 18:54
  • 1
    Where to start to actually see which servlet is picked up? (I have problem with dispatcher servlet not beeng bound) – Antoniossss Dec 11 '18 at 11:54
27

Daniele Torino's post got me down the correct path by mentioning TRACE in addition to DEBUG. In addition to the logging framework, I think it matters which version of Spring you are using. In Spring 3, which we recently moved from, I think DEBUG was enough. However, in Spring 5, the actual mappings aren't listed. I recall that (in Spring 3.x) I used to see the mappings just by setting

<logger name="org.springframework.web" level="DEBUG" />

, but now (in Spring 5.x) that only lists the number of mappings.

DEBUG o.s.w.s.m.m.a.RequestMappingHandlerMapping - 14 mappings in 'org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping'

In Spring 5, the actual mappings weren't logged until I added

<logger name="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping" level="TRACE" /> 

to the log.properties file. (I recommend using TRACE sparingly.) With that in place, the log output includes several lines like:

TRACE o.s.w.s.m.m.a.RequestMappingHandlerMapping - Mapped 1 handler method(s) for class com.yourcompany.YourClass: {public org.springframework.web.servlet.ModelAndView com.yourcompany.YourClass.someMethod(<your parameters and models here>,javax.servlet.http.HttpServletRequest)={[/your-request-mapping-url],methods=[GET]}}
Capricorn1
  • 819
  • 9
  • 17
  • I do not see in my project log.properties file, I see similar - log4j2.properties . And there is no tags, configs are written like this: appender.console.type = Console. Should it work if I add like this: org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping=TRACE ? – Darius.V Apr 15 '22 at 10:35
  • @Darius.V My above example is for a logback logger. For Log4j2, the equivalent of the above would go into the section of the log4j2.xml file. I'm using the documentation to write this so it might not be exact. Something like: – Capricorn1 Apr 19 '22 at 01:22
11

In Spring 4 and Spring BOOT - what helps me was enabling DEBUG logging in application.properties. To do that - simply add:

logging.level.org.springframework.web=DEBUG

update

For Debug mode in latest Spring boot add:

debug=true

into your application.properties file

Witold Kaczurba
  • 9,845
  • 3
  • 58
  • 67
8

The exact answer to this depends on the logging framework that you are using.

If you set the log level for org.springframework.web to DEBUG or TRACE spring mvc will log more detailed information.

Daniele Torino
  • 1,714
  • 2
  • 16
  • 22
5

Thanks for Bartosz Bilicki Actuator tips, that's really nice. I add the following configurations to my applicaton.yml.

management:
  server:
    port: 9001
    address: 127.0.0.1
  endpoints:
    enabled-by-default: true
    web:
      exposure:
        include: '*'

And then I open http://localhost:9001/actuator/mappings, that's all.

Donghua Liu
  • 1,776
  • 2
  • 21
  • 30
2

If you use Spring Boot with Actuator, mappings endpoint will show collated list of all @RequestMapping paths.

See http://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-endpoints.html for more details about endpoints.

See https://spring.io/guides/gs/actuator-service/ for tutorial how to include Actuator module. For Gradle, you just need compile("org.springframework.boot:spring-boot-starter-actuator")

beans endpoint is also useful. It will show all loaded beans. Possible reason for missing HTTP endpoint is the fact that corresponding bean (mapping) was not loaded (because he is not on componentScan path).

Bartosz Bilicki
  • 12,599
  • 13
  • 71
  • 113
  • 1
    If you use Spring Boot Actuator, that is. Many of the "starter" dependencies don't include it. – walen Jan 31 '17 at 17:10
2

You can add a line for CommonsRequestLoggingFilter in your logging configuration (log4j example below):

<logger name="org.springframework.web.filter.CommonsRequestLoggingFilter">
    <level value="DEBUG"/>
</logger>

It will print your URI before and after processing, like this:

org.springframework.web.filter.CommonsRequestLoggingFilter - Before request [uri=/sendMail/D0000/14/en/?null]
org.springframework.web.filter.CommonsRequestLoggingFilter - After request [uri=/sendMail/D0000/14/en/?null;payload={"to":["somebody@somewhere"],"cc":[],"subject":"Test subject","body":null,"replacement":{"TITLE":"Test email","SERVER_NAME":"Whatever"},"attachments":{},"html":true}]

It's really useful, although it doesn't show requests for non-existent resources (like the 404 you're getting).

Another option to get all the requests, if you're using Spring Boot, is Tomcat's access.log. You can enable it in your application.properties like this:

server.tomcat.accesslog.enabled = true
walen
  • 7,103
  • 2
  • 37
  • 58
1

You can display the MVC mappings nicely in the Intellij Run view:

Intellij View

Prerequisites

  • Use Spring Boot
  • Activate the mapping actuator as @Bartosz described:
  1. Include dependency

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    
  2. Properties:

    management.endpoints.enabled-by-default=true
    management.endpoints.web.exposure.include=mappings
    
Matthias M
  • 12,906
  • 17
  • 87
  • 116
0

if you are hosting on an https site on apache which is redirecting to backend the appContext is missing. it should be something like

https://localhost:8443//docs/pupil/classes/ACADEMIC

0

i think you can watch this from Chrom console/network panel ,compare to the url you configed

Smish jack
  • 84
  • 11
-2

Your URL(https://localhost/docs/pupil/classes/ACADEMIC) is missing the appName it should be URL(https://localhost/appName/docs/pupil/classes/ACADEMIC)

Eddy
  • 357
  • 4
  • 6