I ran the spring-boot-sample-web-static project from here, made this alteration to the pom
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</dependency>
And added this class to serve a duplicate page index2.html from the same static folder location:
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
#Controller
public class Rester {
#RequestMapping(value = "/rand", produces = MediaType.APPLICATION_JSON_VALUE)
#ResponseBody
private RandomObj jsonEndpoint() {
return new RandomObj();
}
#RequestMapping(value = "/tw")
public String somePg() {
return "index2";
}
}
The json url works fine, but when I try to access localhost:8080/tw I get a blank page, and this error in the console:
2017-02-22 15:37:22.076 ERROR 21494 --- [nio-8080-exec-9] o.s.boot.web.support.ErrorPageFilter : Cannot forward to error page for request [/tw] as the response has already been committed. As a result, the response may have the wrong status code. If your application is running on WebSphere Application Server you may be able to resolve this problem by setting com.ibm.ws.webcontainer.invokeFlushAfterService to false
Am I doing something wrong?
Static files should be served from resources, not from a controller.
Spring Boot will automatically add static web resources located within
any of the following directories:
/META-INF/resources/
/resources/
/static/
/public/
refs:
https://spring.io/blog/2013/12/19/serving-static-web-content-with-spring-boot
https://spring.io/guides/gs/serving-web-content/
In Spring boot, /META-INF/resources/, /resources/, static/ and public/ directories are available to serve static contents.
So you can create a static/ or public/ directory under resources/ directory and put your static contents there. And they will be accessible by: http://localhost:8080/your-file.ext. (assuming the server.port is 8080)
You can customize these directories using spring.resources.static-locations in the application.properties.
For example:
spring.resources.static-locations=classpath:/custom/
Now you can use custom/ folder under resources/ to serve static files.
This is also possible using Java config in Spring Boot 2:
#Configuration
public class StaticConfig implements WebMvcConfigurer {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/static/**").addResourceLocations("classpath:/custom/");
}
}
This confugration maps contents of custom directory to the http://localhost:8080/static/** url.
I am using :: Spring Boot :: (v2.0.4.RELEASE) with Spring Framework 5
Spring Boot 2.0 requires Java 8 as a minimum version. Many existing APIs have been updated to take advantage of Java 8 features such as: default methods on interfaces, functional callbacks, and new APIs such as javax.time.
Static Content
By default, Spring Boot serves static content from a directory called /static (or /public or /resources or /META-INF/resources) in the classpath or from the root of the ServletContext. It uses the ResourceHttpRequestHandler from Spring MVC so that you can modify that behavior by adding your own WebMvcConfigurer and overriding the addResourceHandlers method.
By default, resources are mapped on /** and located on /static directory.
But you can customize the static loactions programmatically inside our web context configuration class.
#Configuration #EnableWebMvc
public class Static_ResourceHandler implements WebMvcConfigurer {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
// When overriding default behavior, you need to add default(/) as well as added static paths(/webapp).
// src/main/resources/static/...
registry
//.addResourceHandler("/**") // « /css/myStatic.css
.addResourceHandler("/static/**") // « /static/css/myStatic.css
.addResourceLocations("classpath:/static/") // Default Static Loaction
.setCachePeriod( 3600 )
.resourceChain(true) // 4.1
.addResolver(new GzipResourceResolver()) // 4.1
.addResolver(new PathResourceResolver()); //4.1
// src/main/resources/templates/static/...
registry
.addResourceHandler("/templates/**") // « /templates/style.css
.addResourceLocations("classpath:/templates/static/");
// Do not use the src/main/webapp/... directory if your application is packaged as a jar.
registry
.addResourceHandler("/webapp/**") // « /webapp/css/style.css
.addResourceLocations("/");
// File located on disk
registry
.addResourceHandler("/system/files/**")
.addResourceLocations("file:///D:/");
}
}
http://localhost:8080/handlerPath/resource-path+name
/static /css/myStatic.css
/webapp /css/style.css
/templates /style.css
In Spring every request will go through the DispatcherServlet. To avoid Static file request through DispatcherServlet(Front contoller) we configure MVC Static content.
As #STEEL said static resources should not go through Controller. Thymleaf is a ViewResolver which takes the view name form controller and adds prefix and suffix to View Layer.
As it is written before, some folders (/META-INF/resources/, /resources/, /static/, /public/) serve static content by default, conroller misconfiguration can break this behaviour.
It is a common pitfall that people define the base url of a controller in the #RestController annotation, instead of the #RequestMapping annotation on the top of the controllers.
This is wrong:
#RestController("/api/base")
public class MyController {
#PostMapping
public String myPostMethod( ...) {
The above example will prevent you from opening the index.html. The Spring expects a POST method at the root, because the myPostMethod is mapped to the "/" path.
You have to use this instead:
#RestController
#RequestMapping("/api/base")
public class MyController {
#PostMapping
public String myPostMethod( ...) {
I had to add thymeleaf dependency to pom.xml. Without this dependency Spring boot didn't find static resources.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
You can quickly serve static content in JAVA Spring-boot App via thymeleaf (ref: source)
I assume you have already added Spring Boot plugin apply plugin: 'org.springframework.boot' and the necessary buildscript
Then go ahead and ADD thymeleaf to your build.gradle ==>
dependencies {
compile('org.springframework.boot:spring-boot-starter-web')
compile("org.springframework.boot:spring-boot-starter-thymeleaf")
testCompile('org.springframework.boot:spring-boot-starter-test')
}
Lets assume you have added home.html at src/main/resources
To serve this file, you will need to create a controller.
package com.ajinkya.th.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
#Controller
public class HomePageController {
#RequestMapping("/")
public String homePage() {
return "home";
}
}
Thats it ! Now restart your gradle server. ./gradlew bootRun
Related
I have a Spring Boot app setup as a REST api. I now also want to be able to serve simple HTML pages to the client, without the use on any template engine like Thymeleaf. I want access to the HTML pages to fall under the same security constraints setup by Spring Security with the use of WebSecurityConfigurerAdapter, already present in my app.
What I've tried is having a Controller:
#Controller
public class HtmlPageController {
#RequestMapping(value = "/some/path/test", method = RequestMethod.GET)
public String getTestPage() {
return "test.html";
}
}
and placing the test.html file in /resources/test.html or /webapp/WEB-INF/test.html.
Every time I try to access the page at localhost:8080/some/path/test a 404 is returned.
How do I make this work?
Okey so apparently Spring Boot supports this without any additional configuration or controllers.
All I had to do was to place the HTML file in the correct directory /resources/static/some/path/test.html and it can be reached at localhost:8080/some/path/test.html.
In my attempts to change the directory from which the file is served I was unsuccessful. It seems that providing a separate #EnableWebMvc (needed for configuring the resource handlers) breaks the Spring Boot configuration. But I can live with using the default /static directory.
There is a Spring MVC mecanism that exists to provide static resources.
In the config class, overide this method :
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry
.addResourceHandler("some/path/*.html")
.addResourceLocations("/static/");
}
And place your html files in the src/main/webapp/static/ folder.
If you request some/path/test.html (note the .html), it will return the test.html file located in static folder.
You can obviously use a different folder or a more sofiticated directory structure.
This way you don't have to create a controller. Note that your config class should implements WebMvcConfigurer.
Your html, js and css files should be under the src/main/resources/static directory. and your return statement you can try removing .html.
#RestController
public class HtmlPageController {
#GetMapping("/some/path/test")
public String getTestPage() {
return "test";
}
}
See tutotrial example how to define html view in Spring MVC configuration
#Bean
public InternalResourceViewResolver htmlViewResolver() {
InternalResourceViewResolver bean = new InternalResourceViewResolver();
bean.setPrefix("/WEB-INF/html/");
bean.setSuffix(".html");
bean.setOrder(2);
return bean;
}
setOrder is set to 2 because it include also JSP support in example
Also you need to change to return without .html suffix
return "test.html";
I have a spring boot app serving angular resources in my static [resources/static] folder. I also am using the same project to serve my JSON-REST-API endpoints.
Hence I have defined my REST api under localhost:9090/api/...
My Angular2 app-build is served under localhost:9090/ui/... via static resources
Now I want to forward all my ui/** urls to ui/index.html/**
How do I do this?
P.S. I have introduced a custom static resource url pattern
spring.mvc.static-path-pattern=/ui/**
Then all my ui/** request will look to the static/**
This way I was able to secure my /api/** and "permitAll" ui/** requests
This simple configuration will do the trick and will even refresh your # routes in angular 2 if enabled.
#Configuration
public class WebMvcConfiguration extends WebMvcConfigurerAdapter {
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/ui").setViewName("forward:/ui/index.html");
registry.addViewController("/ui/").setViewName("forward:/ui/index.html");
registry.setOrder(Ordered.HIGHEST_PRECEDENCE);
}
}
Pointers:
- #SpringBootApplication should be annotated where the spring boot app is run
- Do not have #EnableWebMvc as this breaks all auto configuration done by spring boot
- See whether this configuration is under a directory you have marked for
#ComponentScan({"com.foo.config"})
- This implementation is specifically tailored for situations where you have a custom spring.mvc.static-path-pattern defined [ui/]
I have this in com.tuke.doto.Controllers / RootController.java:
package com.tuke.doto.Controllers;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
#Controller
public class RootController {
#RequestMapping("/")
public String root() {
return "frontpage";
}
}
and I have frontpage.html in main/resources/static (I also tried to move it into main/resources/templates
When I do request on localhost:8080 I see this:
HTTP Status [404] – [Not Found]
Type Status Report
Description The origin server did not find a current representation for the target resource or is not willing to disclose that one exists.
Apache Tomcat/8.5.15
and in my console on jetbrains intellij I see this:
javax.servlet.ServletException: Circular view path [error]: would dispatch back to the current handler URL [/error] again. Check your ViewResolver setup! (Hint: This may be the result of an unspecified view, due to default view name generation.)
I've also included server.error.whitelabel.enabled=false into main/resources/application.properties
Where is the problem? Isn't that the simplest example so why it doesn't work?
EDIT maybe I should install some dependency to make it work...
this is how my build.gradle looks right now:
dependencies {
compile('org.springframework.boot:spring-boot-starter-web')
compile('org.springframework.boot:spring-boot-starter-websocket')
compile("org.springframework.boot:spring-boot-devtools")
testCompile('org.springframework.boot:spring-boot-starter-test')
}
IF you are just using static html, you may not need a template library like thyme leaf. Simple return ModelAndViewObject. Place your html in src/main/resources/static
example
#GetMapping("/")
public ModelAndView index() {
return new ModelAndView("frontpage.html");
}
There are a few assumptions we have to make with this question. Do you mean src/main/templates? We also have to assume you are using Thymeleaf? Is that dependency in your gradle path?
compile 'org.springframework.boot:spring-boot-starter-thymeleaf'
Try to adding the following to your configuration class
#Bean
public EmbeddedServletContainerFactory factory(){
TomcatEmbeddedServletContainerFactory factory = new TomcatEmbeddedServletContainerFactory();
factory.setContextPath("/myapp");
return factory;
}
and the following to application.config
spring.resources.chain.strategy.fixed.enabled=true
spring.resources.chain.strategy.fixed.paths=/**
put .html file inside src/main/resources/templates
And then try to access localhost:8080/myapp/frontpage
If you are trying to simply run an html file, do ensure that the project structure is the following for a Spring Boot app
After following this structure, you will be able to access index.html via launching localhost:8080
For CRA React, below 2 methods can be used
Copy contents from CRA build folder to either target/classes/static or target/classes/public
This will automatically map index.html with MVC. You can see this during startup of spring-boot application as Adding welcome page: class path resource [public/index.html]
Incase this Method fails, alternatively use below
create a ModelAndView object as below
#RequestMapping("/")
public ModelAndView frontend(){
return new ModelAndView("frontend.html")
}
The Problem
My spring-boot application recently changed routing from host/endpoint to host/middle/endpoint. Since the change, I am running into an issue where the resources are not being found relative to the new url structure. Before, I could reference resources like css stylesheets like link(rel='stylesheet', href='css/style.css'), but now the logger shows an error saying it can't find the resource at /middleman/css/style.css.
From my research, I have found that what I need to do is use a resource handler registry. I have created one (as shown below) but it doesn't seem to be working. I think the problem is that even though I now have the resource registry, I am not referencing resources in the registry. What is the proper way to solve this problem and have all resources point load from the same place regardless of the endpoint? I very well may be missing some obvious piece of SOP
Note: This is all a dumbed down representation of my project in order to give the idea of what is going on without giving unnecessary information.
Project Structure
src
main
java
com.mystuff.cool
configurations
ResourceConfiguration.java
controllers
RoutingController.java
application
Application.java
resources
static
css
footer.css
style.css
images
place1.png
location1.png
spot1.png
favicon.ico
javascripts
layout.js
templates
home.jade
Application Class
#ComponentScan(basePackages = {"my.packages"})
#EnableAutoConfiguration
#EnableSAMLSSO
#Configuration
public class Application
{
public static void main(String[] args)
{
SpringApplication.run(new Object[]{ Application.class, ServiceConfig.class, ResourceConfiguration.class}, args);
}
}
Resource Configuration
#EnableWebMvc
#Configuration
public class ResourceConfiguration extends WebMvcConfigurerAdapter
{
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry)
{
registry.addResourceHandler("/css/**").addResourceLocations("/css/").setCachePeriod(31556926);
registry.addResourceHandler("/img/**").addResourceLocations("/img/").setCachePeriod(31556926);
registry.addResourceHandler("/js/**").addResourceLocations("/js/").setCachePeriod(31556926);
}
#Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer)
{
configurer.enable();
}
}
Controller
#Controller
public class RoutingController
{
#RequestMapping("/house/home")
public String home(Model model)
{
model.addAttribute("title", "Home is where the heart is");
commonModelTribs(model);
return "home";
}
}
Home Page
doctype html
html
title Place-spedia #{title}
link(rel='icon', href='images/favicon.ico')
link(rel='stylesheet', href='css/style.css')
script(src='javascripts/layout.js')
link(rel='stylesheet', href='css/footer.css')
body
div#footer-icons
a(href='place1')
img#place1(src="images/place1.png")
a(href='location1')
img#location1(src="images/location1.png")
a(href='spot1')
img#spot1(src='images/spot1.png')
If you are using spring boot, you don't need to worry about the resource configuration since you are already configuring the resource directory through the auto configuration. The default behavior for the autoconfiguration is to look within resources/static.
Your issue is with your href values, try inserting a leading forward slash:
link(rel='icon', href='/images/favicon.ico')
link(rel='stylesheet', href='/css/style.css')
script(src='javascripts/layout.js')
link(rel='stylesheet', href='/css/footer.css')
Spring is routing your application to a new relative path, so by putting the leading / in your href attributes, you are telling the router to look absolutely within the static directory instead of relatively from the middle directory.
I have a Spring (4) MVC servlet running on Tomcat 8 in Eclipse. When I start tomcat, there are no errors in the console and all the correct request mappings for my controllers are logged. If I try to access localhost:8080/app/login my controller method executes (checked via debugging), but I get a 404 page with the following:
message /app/WEB-INF/jsp/login.jsp
description The requested resource is not available.
My project has the following directory structure:
project-root
|-src
|-WebContent
|-WEB-INF
|-jsp
|-login.jsp
My configuration class:
#EnableWebMvc
#Configuration
#ComponentScan(basePackages = "com.example")
public class WebConfig extends WebMvcConfigurerAdapter {
#Override
public void configureViewResolvers(final ViewResolverRegistry registry) {
registry.jsp("/WEB-INF/jsp/", ".jsp").viewClass(JstlView.class);
}
//Other stuff
}
Controller:
#Controller
#RequestMapping("/login")
public class AuthnRequestController {
#RequestMapping(value = "", method = RequestMethod.GET)
public ModelAndView getLoginPage() {
return new ModelAndView("login");
}
//Other stuff
}
The application was working fine in the past, but I was screwing around with my workspace/projects working on something else, and am unable to get this working again now that I'm coming back to it.
AFAIK, By default in a maven war project the jsp files are expected under /src/main/resources/. Since you have given a jsp file prefix of /WEB-INF/jsp/ in your config, please try moving the jsp files to the below location.
/src/main/webapp/WEB-INF/jsp/
Assumptions:
a mapping to root/WebContent is not provided in Web deployment assembly.
a mapping to /src/main/webapp is present in Web deployment assembly.
your eclipse is using maven war plugin