Spring boot: 2.3.3.RELEASE
Java: 11
I use webflux + RouterFunction + Thymeleaf and encounter the error "Could not resolve view with name 'index'".
index.html is under "resources/templates".
I put some source code looks important.
Are we not able to use Thymeleaf if we use "RouterFunction"?
Please feel free to put a comment if you need more detail.
######## handler ###########
#Component
public class ItemHandler {
public RouterFunction<ServerResponse> routes = route()
.path("/item", builder -> builder.GET("/", this::index))
.build();
public Mono<ServerResponse> index(ServerRequest request) {
Map<String, Object> attributes = new HashMap<>();
attributes.put("items", "Hello");
return ServerResponse.ok().contentType(MediaType.TEXT_HTML)
.render("index", attributes);
}
}
######## index.html ###########
<!DOCTYPE html>
<html lang="ja"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
<head>
</head>
<body>
<h1>FluxTest</h1>
</body>
</html>
######## entry point ###########
#SpringBootApplication
public class DemoWebfluxApplication {
public static void main(String[] args) {
SpringApplication.run(DemoWebfluxApplication.class, args);
}
}
The default property in charge of handling the location of static files is spring.resources.static-locations.
The default values are /META-INF/resources/, /resources/, /static/, /public/. You can either override the default values or put your index.html in one of these locations.
Related
I want to put our templates folder in a remote host like aws-s3, currently
using a custom urlTemplateResolver and using the thymeleaf replace tag.
#Configuration
public class SpringTemplateConfiguration {
private final SpringResourceTemplateResolver springResourceTemplateResolver;
#Value("${spring.thymeleaf.cache}")
Boolean springThymeleafCache;
public SpringTemplateConfiguration(SpringResourceTemplateResolver springResourceTemplateResolver) {
this.springResourceTemplateResolver = springResourceTemplateResolver;
}
#Bean
public SpringTemplateEngine templateEngine() {
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
UrlTemplateResolver urlTemplateResolver = new UrlTemplateResolver();
urlTemplateResolver.setCacheable(springThymeleafCache); // explicit set cacheable, otherwise it will be always cached
templateEngine.addTemplateResolver(urlTemplateResolver);
templateEngine.addTemplateResolver(springResourceTemplateResolver);
return templateEngine;
}
}
and this is the thymeleaf template
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org" th:replace="~{${url} :: html}">
</html>
is there another way to just use the templates folder from the remote host and just return the view name from the controller ??
It is possible to use another external location but not remote location which doesn't solve our problem.
I wanna change my swagger-ui path from localhost:8080/swagger-ui.html to
localhost:8080/myapi/swagger-ui.html in springboot
redirect is helpless to me
In the application.properties of Spring Boot
springdoc.swagger-ui.path=/swagger-ui-custom.html
in your case it will be
springdoc.swagger-ui.path=/myapi/swagger-ui.html
if for some reason you don't want redirect to /swagger-ui.html you can set itself contents as home view, setting an index.html at resources/static/index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Welcome to another awesome Microservice</title>
</head>
<body>
<script>
document.body.innerHTML = '<object type="text/html" data="/swagger-ui.html" style="overflow:hidden;overflow-x:hidden;overflow-y:hidden;height:100%;width:100%;position:absolute;top:0px;left:0px;right:0px;bottom:0px"></object>';
</script>
</body>
</html>
then accessing to your http://localhost:8080/ you will see your swagger docs.
finally you can customize path and .html file using:
registry.addViewController("/swagger").setViewName("forward:/index.html");
like suggests this answer
You can modify springfox properties in application.properties
For example, to edit the base-url
springfox.documentation.swagger-ui.base-url=documentation
For e.g. setting it to /documentation will put swagger-ui at /documentation/swagger-ui/index.html
If you want to add, for example, documentation prefix - You can do like this for path http://localhost:8080/documentation/swagger-ui.html:
kotlin
#Configuration
#EnableSwagger2
#ConfigurationPropertiesScan("your.package.config")
#Import(value = [BeanValidatorPluginsConfiguration::class])
class SwaggerConfiguration(
private val swaggerContactProp: SwaggerContactProp, private val swaggerProp: SwaggerProp
) : WebMvcConfigurationSupport() {
// https://springfox.github.io/springfox/docs/current/
#Bean
fun api(): Docket = Docket(DocumentationType.SWAGGER_2)
.groupName("Cards")
.apiInfo(getApiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("your.controllers.folder"))
.paths(PathSelectors.any())
.build()
private fun getApiInfo(): ApiInfo {
val contact = Contact(swaggerContactProp.name, swaggerContactProp.url, swaggerContactProp.mail)
return ApiInfoBuilder()
.title(swaggerProp.title)
.description(swaggerProp.description)
.version(swaggerProp.version)
.contact(contact)
.build()
}
override fun addViewControllers(registry: ViewControllerRegistry) {
with(registry) {
addRedirectViewController("/documentation/v2/api-docs", "/v2/api-docs").setKeepQueryParams(true)
addRedirectViewController(
"/documentation/swagger-resources/configuration/ui", "/swagger-resources/configuration/ui"
)
addRedirectViewController(
"/documentation/swagger-resources/configuration/security", "/swagger-resources/configuration/security"
)
addRedirectViewController("/documentation/swagger-resources", "/swagger-resources")
}
}
override fun addResourceHandlers(registry: ResourceHandlerRegistry) {
registry.addResourceHandler("/documentation/**").addResourceLocations("classpath:/META-INF/resources/")
}
}
#ConfigurationProperties(prefix = "swagger")
#ConstructorBinding
data class SwaggerProp(val title: String, val description: String, val version: String)
#ConfigurationProperties(prefix = "swagger.contact")
#ConstructorBinding
data class SwaggerContactProp(val mail: String, val url: String, val name: String)
and in applicatiom.yml:
swagger:
title: Cards
version: 1.0
description: Documentation for API
contact:
mail: email#gmail.com
url: some-url.com
name: COLABA card
Also don't forget to add in build.gradle.kts:
implementation("io.springfox:springfox-swagger2:$swagger")
implementation("io.springfox:springfox-swagger-ui:$swagger")
implementation("io.springfox:springfox-bean-validators:$swagger")
I've found several possible solutions for myself. Maybe it will be helpful for somebody else.
Set springdoc.swagger-ui.path directly
The straightforward way is to set property springdoc.swagger-ui.path=/custom/path. It will work perfectly if you can hardcode swagger path in your application.
Override springdoc.swagger-ui.path property
You can change default swagger-ui path programmatically using ApplicationListener<ApplicationPreparedEvent>. The idea is simple - override springdoc.swagger-ui.path=/custom/path before your Spring Boot application starts.
#Component
public class SwaggerConfiguration implements ApplicationListener<ApplicationPreparedEvent> {
#Override
public void onApplicationEvent(final ApplicationPreparedEvent event) {
ConfigurableEnvironment environment = event.getApplicationContext().getEnvironment();
Properties props = new Properties();
props.put("springdoc.swagger-ui.path", swaggerPath());
environment.getPropertySources()
.addFirst(new PropertiesPropertySource("programmatically", props));
}
private String swaggerPath() {
return "/swagger/path"; //todo: implement your logic here.
}
}
In this case, you must register the listener before your application start:
#SpringBootApplication
#OpenAPIDefinition(info = #Info(title = "APIs", version = "0.0.1", description = "APIs v0.0.1"))
public class App {
public static void main(String[] args) {
SpringApplication application = new SpringApplication(App.class);
application.addListeners(new SwaggerConfiguration());
application.run(args);
}
}
Redirect using controller
You can also register your own controller and make a simple redirect as suggested there.
Redirect code for Spring WebFlux applications:
#RestController
public class SwaggerEndpoint {
#GetMapping("/custom/path")
public Mono<Void> api(ServerHttpResponse response) {
response.setStatusCode(HttpStatus.PERMANENT_REDIRECT);
response.getHeaders().setLocation(URI.create("/swagger-ui.html"));
return response.setComplete();
}
}
The problem with such an approach - your server will still respond if you call it by address "/swagger-ui.html".
You can use this code, it worked for me
package com.swagger.api.redirect;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
public class SwaggerApiReDirector implements WebMvcConfigurer {
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addRedirectViewController("/documentation/v2/api-docs", "/v2/api-docs");
registry.addRedirectViewController("/documentation/configuration/ui", "/configuration/ui");
registry.addRedirectViewController("/documentation/configuration/security", "/configuration/security");
registry.addRedirectViewController("/documentation/swagger-resources", "/swagger-resources");
registry.addRedirectViewController("/documentation/swagger-resources/configuration/ui", "/swagger-resources/configuration/ui");
registry.addRedirectViewController("/documentation", "/documentation/swagger-ui.html");
registry.addRedirectViewController("/documentation/", "/documentation/swagger-ui.html");
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry
.addResourceHandler("/documentation/**").addResourceLocations("classpath:/META-INF/resources/");
}
}
If you are using spring boot then please update
application.properties file and write here
server.servlet.context-path=/myapi
it will redirect you as you want.
I want to have a quick test of how to use Thymeleaf and please see my two screenshots:
The home.html is under my templates/ directory, and it can be displayed correctly when I visit http://localhost:8090/. However, it failed to link to the two static files in the bottom of the home.html file:
<script src="http://code.jquery.com/jquery-latest.js"></script>
<script src="js/home.js"></script>
<link href="css/home.css" rel="stylesheet" type="text/css"/>
Please see the error message:
I don't have specific thymeleaf configurations except the spring configurations:
## web
server.port=8090
## velocity
spring.velocity.allowRequestOverride=false
spring.velocity.allowSessionOverride=false
spring.velocity.cache=false
spring.velocity.checkTemplateLocation=true
spring.velocity.contentType=text/html
spring.velocity.toolbox-config-location=/WEB-INF/toolbox.xml
spring.velocity.exposeRequestAttributes=false
spring.velocity.exposeSessionAttributes=false
spring.velocity.exposeSpringMacroHelpers=false
spring.velocity.resourceLoaderPath=/WEB-INF/templates/
spring.velocity.suffix=.vm
spring.velocity.templateEncoding=UTF-8
spring.velocity.charset=UTF-8
spring.velocity.properties.input.encoding=UTF-8
spring.velocity.properties.output.encoding=UTF-8
spring.velocity.requestContextAttribute=rc
spring.mvc.favicon.enabled = false
logging.config=classpath:log4j2.xml
And my controller:
#RequestMapping("/")
public String welcome(Model model) {
LOGGER.info("Run Successfully");
return "home";
}
My main class:
#SpringBootApplication
#Import({WebConfigurer.class})
#ComponentScan("com.jdd.jnlu.qe")
#PropertySource({"classpath:boot.properties", "classpath:important.properties", "classpath:jss.properties",
"classpath:system.properties", "classpath:ump.properties"})
#EnableAutoConfiguration
public class JnluQEWebStart extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(JnluQEWebStart.class, args);
}
}
Since you're using Thymeleaf, try this:
<script th:src="#{/js/home.js}"></script>
<link th:href="#{/css/home.css}" rel="stylesheet" type="text/css"/>
Don't forget to register Thymeleaf in your page:
<html xmlns:th="http://www.thymeleaf.org">
I'm facing a Spring Boot configuration issue I can't deal with...
I'm trying to build an HelloWorld example for HbbTV with Spring Boot, so I need to serve my "index.html" page with mime-type="application/vnd.hbbtv.xhtml+xml"
my index.html will be accessed as a static page, for instance http://myserver.com/index.html?param=value.
with the following code, no matter how hard I try, I get a text/html content type.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//HbbTV//1.1.1//EN" "http://www.hbbtv.org/dtd/HbbTV-1.1.1.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>MyApp HBBTV</title>
<meta http-equiv="content-type" content="Content-Type: application/vnd.hbbtv.xhtml+xml; charset=UTF-8" />
</head>
<body>
...
</body>
</html>
So I tried to add a "home()" endpoint into a #Controller to force the correct mime-type, and that works.
#RestController
public class HbbTVController {
#RequestMapping(value = "/hbbtv", produces = "application/vnd.hbbtv.xhtml+xml")
String home() {
return "someText";
}
...
}
"That works" mean the jetty server serves me a html file with the correct content-type containing the test someText.
My next try were to replace the #RestController by #Controller (same produce config), and replace "someText" by index.html
#Controller
public class HbbTVController {
#RequestMapping(value = "/hbbtv", produces = "application/vnd.hbbtv.xhtml+xml")
String home() {
return "index.html";
}
...
}
Well, it serves my index.html correctly, but the Content-Type is wrong : text/html instead of application/vnd.hbbtv.xhtml+xml.
Furthermore, I don't want to access to myserver.com/hbbtv to get index.html, but directly to myserver.com/index.html.
How could I do that ?
Thanks...
Well, finally, I found the "Spring boot compliant solution". It's the same as Jamie Birch suggested, but realized with Spring mechanisms.
Spring Boot 1:
#Configuration
public class HbbtvMimeMapping implements EmbeddedServletContainerCustomizer {
#Override
public void customize(ConfigurableEmbeddedServletContainer container) {
MimeMappings mappings = new MimeMappings(MimeMappings.DEFAULT);
mappings.add("html", "application/vnd.hbbtv.xhtml+xml; charset=utf-8");
mappings.add("xhtml", "application/vnd.hbbtv.xhtml+xml; charset=utf-8");
container.setMimeMappings(mappings);
}
}
Spring Boot 2:
#Configuration
public class HbbtvMimeMapping implements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> {
#Override
public void customize(ConfigurableServletWebServerFactory factory) {
MimeMappings mappings = new MimeMappings(MimeMappings.DEFAULT);
mappings.add("html", "application/vnd.hbbtv.xhtml+xml; charset=utf-8");
mappings.add("xhtml", "application/vnd.hbbtv.xhtml+xml; charset=utf-8");
factory.setMimeMappings(mappings);
}
}
I'll extend comment providen by #Cheloute
Sping boot have default mime types
https://github.com/spring-projects/spring-boot/blob/master/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/server/MimeMappings.java
to override already setted mime type you should remove it first
Here is example what I used to override js and css
#Configuration
public class CustomServletConfiguration implements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> {
#Override
public void customize(ConfigurableServletWebServerFactory factory) {
MimeMappings mappings = new MimeMappings(MimeMappings.DEFAULT);
mappings.remove("js");
mappings.add("js", "application/javascript;charset=utf-8");
mappings.remove("css");
mappings.add("css", "text/css;charset=utf-8");
factory.setMimeMappings(mappings);
factory.setPort(9000);
}
}
Can't help with the Spring Boot side, but if you get no other responses, try these:
Set the file-type as .xhtml rather than .html.
Provide a mapping from .xhtml to MIME type application/vnd.hbbtv.xhtml+xml on your Jetty server's mime.properties file. A few more details on how to do that here.
I was trying for two days to set up the index page using spring 4.
After many attempts I got a piece of code that worked
But I did not understand why it worked.
Could you tell me why.
public class MyWebApplicationInitializer
extends AbstractAnnotationConfigDispatcherServletInitializer
{
protected Class<?>[] getRootConfigClasses() {
return new Class[] {AplicationConfig.class};
}
protected Class<?>[] getServletConfigClasses() {
return new Class[] {WebConfiguration .class};
}
protected String[] getServletMappings() {
return new String[] {"/"};
}
}
Here's the snippet of code I found
// #Bean
// public InternalResourceViewResolver internalResourceViewResolver() {
// InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
// viewResolver.setPrefix("/WEB-INF/html/");
// viewResolver.setSuffix(".html");
// return viewResolver;
// }
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/*.html").addResourceLocations("/WEB-INF/html/");
super.addResourceHandlers(registry);
}
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController( "/" ).setViewName( "forward:/index.html" );
// registry.setOrder( Ordered.HIGHEST_PRECEDENCE );
// super.addViewControllers( registry );
}
my folders
1) why InternalResourceViewResolver do not work?
2) How does addResourceHandler and addViewController work? What are these paths?
3)And how do I add the css and javascripts file to the index page? like
<link href="/css/bootstrap.min.css" rel="stylesheet">
The page loads but this without the css and javascript files
I want to thank everyone who helped me because I'm a newbie in spring, thanks guys.
Only configuring InternalResourceViewResolver is not enough to serve static html. You also need to bind a path through controller to serve the page. As this is just a static page you can do that with
addViewControllers.
registry.addViewController("/").setViewName("index");
2.
addResourceHandlers: Add handlers to serve static resources such as images, js, and, css files from specific locations under web application root, the classpath, and others.
addViewControllers: Configure simple automated controllers pre-configured with the response status code and/or a view to render the response body. This is useful in cases where there is no need for custom controller logic -- e.g. render a home page, perform simple site URL redirects, return a 404 status with HTML content, a 204 with no content, and more.
http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/servlet/config/annotation/WebMvcConfigurer.html#addResourceHandlers-org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry-
3.
To make the resources(js, css, img) available, you need to add following configuration inside your addResourceHandlers methods.
registry.addResourceHandler("/css/**").addResourceLocations("/css/");
registry.addResourceHandler("/js/**").addResourceLocations("/js/");
registry.addResourceHandler("/img/**").addResourceLocations("/img/");
And then to include css or js in a JSP page, you can use JSTL tag c:url or Spring tag spring:url.
<link href="<c:url value="/css/styles.css" />" rel="stylesheet">
<spring:url value="/css/styles.css" var="mainCss" />
<link href="${mainCss}" rel="stylesheet" />