Serve static pages and REST services with Spring

I developed a Spring application that serves Spring MVC REST services. Now I want to implement Angularjs in the webapp directory of my Spring application. The problem is that I do not know how to properly configure this.

What I want to achieve:

  • / api / ... = URL that serves REST services through Spring MVC, e.g. localhost: 8080 / api / user / 1
  • / ... = URL containing static html pages like localhost: 8080 / index.html

I would also like index.html to load by default.

I am currently using the following configuration, which works, but by default it does not load index.html. But I do not know if this is really the case, how to set up static pages in a Spring container:

web.xml

<listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <servlet> <servlet-name>spring</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>dispatchOptionsRequest</param-name> <param-value>true</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>spring</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> 

applicationContext.xml

 <context:property-placeholder properties-ref="deployProperties" /> <!-- Activates various annotations to be detected in bean classes --> <context:annotation-config /> <!-- Scans the classpath for annotated components that will be auto-registered as Spring beans. For example @Controller and @Service. Make sure to set the correct base-package --> <context:component-scan base-package="com.eerra" /> <!-- Configures the annotation-driven Spring MVC Controller programming model. Note that, with Spring 3.0, this tag works in Servlet MVC only! --> <mvc:annotation-driven/> <!-- Tell Spring what to treat as resources --> <mvc:resources mapping="/" location="/resources/ang2/app/"/> 

In the current configuration, everything works, but when I try to point my browser to localhost: 8080 /, instead of downloading the index.html file, 404 appears, not found. When I try with localhost: 8080 / index.html, then everything works.

Can someone point me in the right direction how to set up such a setting?

Below you can see my debug.log. The problem here is as follows:

Did not find a handler method for [/]

Therefore, I assume that DispatcherServlet is trying to map the path to the controller. But I do not know how I can avoid this.

 21:55:04.896 [qtp581501261-25] DEBUG org.eclipse.jetty.http.HttpParser - filled 314/314 21:55:04.897 [qtp581501261-25 - /] DEBUG org.eclipse.jetty.server.Server - REQUEST / on AsyncHttpConnection@f908897 ,g=HttpGenerator{s=0,h=-1,b=-1,c=-1},p=HttpParser{s=-5,l=9,c=0},r=1 21:55:04.897 [qtp581501261-25 - /] DEBUG oejserver.handler.ContextHandler - scope null||/ @ omjpJettyWebAppContext{/,file:/C:/Users/charms/Documents/Intellij%20Projects/cardkeeper/src/main/webapp/},file:/C:/Users/charms/Documents/Intellij%20Projects/cardkeeper/src/main/webapp/ 21:55:04.897 [qtp581501261-25 - /] DEBUG oejserver.handler.ContextHandler - context=||/ @ omjpJettyWebAppContext{/,file:/C:/Users/charms/Documents/Intellij%20Projects/cardkeeper/src/main/webapp/},file:/C:/Users/charms/Documents/Intellij%20Projects/cardkeeper/src/main/webapp/ 21:55:04.897 [qtp581501261-25 - /] DEBUG org.eclipse.jetty.server.session - ses sionManager=org.eclipse.jetty.server.session.HashSessionManager@ 70799896 21:55:04.897 [qtp581501261-25 - /] DEBUG org.eclipse.jetty.server.session - session=null 21:55:04.897 [qtp581501261-25 - /] DEBUG oejetty.servlet.ServletHandler - servlet |/|null -> spring 21:55:04.897 [qtp581501261-25 - /] DEBUG oejetty.servlet.ServletHandler - chain=springSecurityFilterChain->spring 21:55:04.897 [qtp581501261-25 - /] DEBUG oejetty.servlet.ServletHandler - call filter springSecurityFilterChain 21:55:04.897 [qtp581501261-25 - /] DEBUG ossweb.util.AntPathRequestMatcher - Checking match of request : '/'; against '/favicon.ico*' 21:55:04.897 [qtp581501261-25 - /] DEBUG ossweb.util.AntPathRequestMatcher - Checking match of request : '/'; against '/resources/**' 21:55:04.897 [qtp581501261-25 - /] DEBUG ossecurity.web.FilterChainProxy - / at position 1 of 9 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter' 21:55:04.898 [qtp581501261-25 - /] DEBUG ossecurity.web.FilterChainProxy - / at position 2 of 9 in additional filter chain; firing Filter: 'LogoutFilter' 21:55:04.898 [qtp581501261-25 - /] DEBUG ossecurity.web.FilterChainProxy - / at position 3 of 9 in additional filter chain; firing Filter: 'UsernamePasswordAuthenticationFilter' 21:55:04.898 [qtp581501261-25 - /] DEBUG ossecurity.web.FilterChainProxy - / at position 4 of 9 in additional filter chain; firing Filter: 'DefaultLoginPageGeneratingFilter' 21:55:04.898 [qtp581501261-25 - /] DEBUG ossecurity.web.FilterChainProxy - / at position 5 of 9 in additional filter chain; firing Filter: 'BasicAuthenticationFilter' 21:55:04.898 [qtp581501261-25 - /] DEBUG ossecurity.web.FilterChainProxy - / at position 6 of 9 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter' 21:55:04.898 [qtp581501261-25 - /] DEBUG ossecurity.web.FilterChainProxy - / at position 7 of 9 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter' 21:55:04.898 [qtp581501261-25 - /] DEBUG osswaAnonymousAuthenticationFilter - Populated SecurityContextHolder with anonymous token: 'org.sprin gframework.security.authentication.AnonymousAuthenticationToken@ 9055c2bc: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.sprin gframework.security.web.authentication.WebAuthenticationDetails@ b364: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: null; Granted Authorities: ROLE_ANONYMOUS' 21:55:04.898 [qtp581501261-25 - /] DEBUG ossecurity.web.FilterChainProxy - / at position 8 of 9 in additional filter chain; firing Filter: 'ExceptionTranslationFilter' 21:55:04.898 [qtp581501261-25 - /] DEBUG ossecurity.web.FilterChainProxy - / at position 9 of 9 in additional filter chain; firing Filter: 'FilterSecurityInterceptor' 21:55:04.898 [qtp581501261-25 - /] DEBUG ossweb.util.AntPathRequestMatcher - Checking match of request : '/'; against '/api/**' 21:55:04.899 [qtp581501261-25 - /] DEBUG osswaiFilterSecurityInterceptor - Public object - authentication not attempted 21:55:04.899 [qtp581501261-25 - /] TRACE oswcsXmlWebApplicationContext - Publishing event in Root WebApplicationContext: org.springframework.security.access.event.PublicInvocationEvent[source=FilterInvocation: URL: /] 21:55:04.899 [qtp581501261-25 - /] DEBUG ossecurity.web.FilterChainProxy - / reached end of additional filter chain; proceeding with original chain 21:55:04.899 [qtp581501261-25 - /] DEBUG oejetty.servlet.ServletHandler - call servlet spring 21:55:04.899 [qtp581501261-25 - /] TRACE osweb.servlet.DispatcherServlet - Bound request context to thread: SecurityContextHolderAwareRequestWrapper[ FirewalledRequest[ (GET /)@604241542 org.eclipse.jetty.server.Request@2403fe86 ]] 21:55:04.899 [qtp581501261-25 - /] DEBUG osweb.servlet.DispatcherServlet - DispatcherServlet with name 'spring' processing GET request for [/] 21:55:04.899 [qtp581501261-25 - /] TRACE osweb.servlet.DispatcherServlet - Testing handler map [org.springframework .web.servlet.mvc.method.annotation.RequestMappingHandlerMapping@ 12440d38] in DispatcherServlet with name 'spring' 21:55:04.899 [qtp581501261-25 - /] DEBUG oswsmmaRequestMappingHandlerMapping - Looking up handler method for path / 21:55:04.912 [qtp581501261-25 - /] DEBUG oswsmmaRequestMappingHandlerMapping - Did not find handler method for [/] 21:55:04.912 [qtp581501261-25 - /] TRACE osweb.servlet.DispatcherServlet - Testing handler map [or g.springframework.web.servlet.handler.BeanNameUrlHandlerMapping@ c518734] in DispatcherServlet with name 'spring' 21:55:04.912 [qtp581501261-25 - /] TRACE oswshBeanNameUrlHandlerMapping - No handler mapping found for [/] 21:55:04.912 [qtp581501261-25 - /] TRACE osweb.servlet.DispatcherServlet - Testing handler map [ org.springframework.web.servlet.handler.SimpleUrlHandlerMapping@ 3c836d3d] in DispatcherServlet with name 'spring' 21:55:04.912 [qtp581501261-25 - /] DEBUG oswshSimpleUrlHandlerMapping - Matching patterns for request [/] are [/**] 21:55:04.912 [qtp581501261-25 - /] DEBUG oswshSimpleUrlHandlerMapping - URI Template variables for request [/] are {} 21:55:04.912 [qtp581501261-25 - /] DEBUG oswshSimpleUrlHandlerMapping - Mapping [/] to HandlerExecutionChain with handler [org. springframework.web.servlet.resource.ResourceHttpRequestHandler@ 6abe6713] and 1 interceptor 21:55:04.912 [qtp581501261-25 - /] TRACE osweb.servlet.DispatcherServlet - Testing handler adapter [org.springframework .web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter@ 7a614724] 21:55:04.912 [qtp581501261-25 - /] TRACE osweb.servlet.DispatcherServlet - Testing handler adapter [ org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter@88 5cb41] 21:55:04.912 [qtp581501261-25 - /] DEBUG osweb.servlet.DispatcherServlet - Last-Modified value for [/] is: -1 21:55:04.912 [qtp581501261-25 - /] DEBUG oswsrResourceHttpRequestHandler - Ignoring invalid resource path [] 21:55:04.913 [qtp581501261-25 - /] DEBUG oswsrResourceHttpRequestHandler - No matching resource found - returning 404 21:55:04.913 [qtp581501261-25 - /] DEBUG osweb.servlet.DispatcherServlet - Null ModelAndView returned to DispatcherServlet with name 'spring': assuming HandlerAdapter completed request handling 21:55:04.913 [qtp581501261-25 - /] TRACE osweb.servlet.DispatcherServlet - Cleared thread-bound request context: SecurityContextHolderAwareRequestWrapper[ FirewalledRequest[ [GET /]@604241542 org.eclipse.jetty.server.Request@2403fe86 ]] 21:55:04.914 [qtp581501261-25 - /] DEBUG osweb.servlet.DispatcherServlet - Successfully completed request 21:55:04.914 [qtp581501261-25 - /] TRACE oswcsXmlWebApplicationContext - Publishing event in WebApplicationContext for namespace 'spring-servlet': ServletRequestHandledEvent: url=[/]; client=[0:0:0:0:0:0:0:1]; method=[GET]; servlet=[spring]; session=[null]; user=[null]; time=[15ms]; status=[OK] 21:55:04.914 [qtp581501261-25 - /] TRACE oswcsXmlWebApplicationContext - Publishing event in Root WebApplicationContext: ServletRequestHandledEvent: url=[/]; client=[0:0:0:0:0:0:0:1]; method=[GET]; servlet=[spring]; session=[null]; user=[null]; time=[15ms]; status=[OK] 21:55:04.914 [qtp581501261-25 - /] DEBUG osswaExceptionTranslationFilter - Chain processed normally 21:55:04.914 [qtp581501261-25 - /] DEBUG osswcSecurityContextPersistenceFilter - SecurityContextHolder now cleared, as request processing completed 21:55:04.914 [qtp581501261-25 - /] DEBUG org.eclipse.jetty.server.Server - RESPONSE / 404 handled=true 21:55:04.915 [qtp581501261-25] DEBUG oejetty.server.AsyncHttpConnection - Enabled read interest SCEP@7cee85c5 {l(/0:0:0:0:0:0:0:1:51001)<->r(/0:0:0:0:0:0:0:1:8080),d=true,open=true,ishut=false,oshut=false,rb=false,wb=false,w=true,i=0r}-{ AsyncHttpConnection@f908897 ,g=HttpGenerator{s=4,h=0,b=0,c=-1},p=HttpParser{s=0,l=9,c=0},r=1} 21:55:04.915 [qtp581501261-25] DEBUG org.eclipse.jetty.http.HttpParser - filled 0/0 
+4
source share
4 answers

I solved my problem as follows.

  • First, I changed the path from servlet mapping to / api / *. As a result, I had to configure the path in MVC controllers from @RequestMapping ("/ api / role") to @RequestMapping ("/ role"). Otherwise, the URL will respond to / api / api / role.
  • Then I turned on urlrewrite http://tuckey.org/urlrewrite/ . I use Maven, so I added it to pom.xml. I did this because the mvc: resource mapping directive only works when using DispatcherServlet. And that was what I wanted to disable for my static html pages.
  • Then I added a filter to the web.xml file and created the urlrewrite.xml file in the WEB-INF directory, as shown below.
  • With urlrewrite, I could set a condition that excludes / api / ** (the directory with my Spring MVC-based REST controllers), but overwrites anything else from the / ** to / resources / ang2 / app directory (my angularjs directory).
  • I also removed the mvc: resource directive from applicationContext.xml.

web.xml

 <!-- Setup urlrewrite filter --> <filter> <filter-name>UrlRewriteFilter</filter-name> <filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class> <init-param> <param-name>logLevel</param-name> <param-value>WARN</param-value> </init-param> </filter> <filter-mapping> <filter-name>UrlRewriteFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- Spring related section --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <servlet> <servlet-name>spring</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>dispatchOptionsRequest</param-name> <param-value>true</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>spring</servlet-name> <url-pattern>/api/*</url-pattern> </servlet-mapping> 

urlrewrite.xml

 <!-- Use urlrewritefilter to redirect / requests to angularjs directory --> <urlrewrite default-match-type="wildcard"> <rule> <!-- exclude everything in /api/** directory --> <condition type="request-uri" operator="notequal">/api/**</condition> <!-- everything else from / is redirected to the angularjs directory --> <from>/**</from> <to>/resources/ang2/app/$1</to> </rule> </urlrewrite> 
0
source

Have you defined a welcome file in your web.xml?

for instance

 <welcome-file-list> <welcome-file>index.html</welcome-file> </welcome-file-list> 

where index.html is the file in the project root folder.

+1
source

I had the same problem, and I decided, as you were advised, the prefix of the rest of the api template managed by Spring.

The only difference is that I did not use the URL redirect because all my angular files are deployed in the root directory of the web application, so they are directly accessible.

My angular project is actually located in another folder as another module and is added during the build of the war with this configuration:

 <plugin> <artifactId>maven-war-plugin</artifactId> <version>2.3</version> <configuration> <webResources> <resource> <directory>${project.parent.basedir}/ANGULAR-PROJECT-NAME </resource> </webResources> </configuration> </plugin> 

as described here . Hope this helps, welcome.

+1
source

The main problem is that the ResourceHttpRequestHandler that is registered to <mvc: resource> does not allow foo / index.html when requesting foo /

An option to enable this behavior will be nice.

+1
source

Source: https://habr.com/ru/post/1502488/


All Articles