Spring boot application shows file download option when serving static content - spring

I have a spring boot application in which I have some static files kept inside resources/static directory. One of them is a swagger directory. The file system layout looks as follows:
resources
- static
- swagger
- index.html
Now if I send request to my webapp with URI localhost:8080/swagger/index.html then it serves the file correctly. However, if I send request to localhost:8080/swagger then the webapp shows a file download box with an empty binary file named swagger.
In my opinion second URI should actually serve the index.html file automatically. How do I fix this behavior?

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
#Configuration
public class WebConfig {
#Bean
public WebMvcConfigurerAdapter forwardToIndex() {
return new WebMvcConfigurerAdapter() {
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/swagger").setViewName(
"forward:/swagger/index.html");
registry.addViewController("/swagger/").setViewName(
"forward:/swagger/index.html");
}
};
}
}

Related

Transfer a file using Apache Camel file component

I am trying a demo file transfer program using Spring Boot and Apache Camel file component. I have exposed a REST Controller using Spring Boot which is calling an Apache Camel route and it is doing the file transfer. I have three files in the directory C:\CamelDemo\inputFolder namely input1.txt, input2.txt and input3.txt. I want to only transfer the file input2.txt in the output folder. My Spring Boot controller is as below:
package com.example.demo.controller;
import java.util.HashMap;
import java.util.Map;
import org.apache.camel.ProducerTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
#RestController
#RequestMapping("/camel")
public class FileTransferController {
#Autowired private ProducerTemplate producerTemplate;
#RequestMapping(value="/file", method=RequestMethod.GET)
public String callCamelRoute() {
String fileName = "input2.txt";
Map<String, Object> headerMap = new HashMap<String, Object>();
headerMap.put("fileName", fileName);
producerTemplate.sendBodyAndHeaders("direct:transferFile", null, headerMap);
return "Route invoked";
}
}
My Route is as below:
package com.example.demo.route;
import org.apache.camel.LoggingLevel;
import org.apache.camel.builder.RouteBuilder;
import org.springframework.stereotype.Component;
#Component
public class FileTransferRoute extends RouteBuilder {
#SuppressWarnings("deprecation")
#Override
public void configure() {
errorHandler(defaultErrorHandler()
.maximumRedeliveries(3)
.redeliverDelay(1000)
.retryAttemptedLogLevel(LoggingLevel.WARN));
from("direct:transferFile")
.log("Route reached")
.log("file:C:\\CamelDemo\\inputFolder?fileName=${in.headers.fileName}&noop=true")
.pollEnrich("file://C:/CamelDemo/inputFolder?fileName=${in.headers.fileName}&noop=true")
.to("file://C:/CamelDemo/outputFolder?autoCreate=false")
.end();
}
}
But the first time I invoke this route, the file input1.txt is getting transferred even when I have specified the fileName parameter. Please help.
I think the issue is that your file name isn't being set, because you're not telling Camel that you're using a Simple expression, rather than a fixed URI.
Looking at the manual (https://camel.apache.org/manual/latest/pollEnrich-eip.html#_using_dynamic_uris), it implies that you will need
.pollEnrich().simple("file://C:/CamelDemo/inputFolder?fileName=${in.headers.fileName}&noop=true")
to be able to use the dynamic endpoint.

Using a custom error html file in spring boot

I have a url mapping for /error to go to my errorPage.html, but it is not redirecting to this, and I get the normal default spring boot error screen.
package coffee.web;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
#Configuration
public class WebConfig implements WebMvcConfigurer {
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("/index.html");
registry.addRedirectViewController("/admin", "admin/adminIndex.html");
registry.addViewController("/error").setViewName("/errorPage.html");
}
}
when I go to the url /error in the browser I get a status 999. when I go to an nonexistent address I get the default spring boot error page with a 404
ended up writing a explicit controller implement ErrorController

How to exclude some endpoints from server.servlet.path configuration?

I have Spring Boot application with a single index.html page.
I need to have server.servlet.path=/api setting.
In order to get index.html I have to go localhost:8080/api/ becase of my setting described above.
I want to be able to get index.html by localhost:8080/ and any else endpoints by localhost:8080/api/**.
How can I do it?
Thanks
Once you configured server.servlet.path=/api, DispatcherServlet is going to handle only request matching URL Patterns /api/**.
One way to achieve your requirement is to use a plain Servlet.
import org.springframework.core.io.ClassPathResource;
import org.springframework.util.StreamUtils;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.Charset;
#WebServlet(urlPatterns = {"/"})
public class RootServlet extends HttpServlet {
#Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws IOException {
ClassPathResource resource = new ClassPathResource("static/index.html");
String content = StreamUtils.copyToString(resource.getInputStream(), Charset.defaultCharset() );
resp.getWriter().write(content);
}
}
Now you can register the Servlet using #ServletComponentScan annotation. Assuming you put RootServlet in com.myapp.servlets package:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
#SpringBootApplication
#ServletComponentScan(basePackages = "com.myapp.servlets")
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
For more info see https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#howto-add-a-servlet-filter-or-listener

How to display "welcome.jsp" in spring boot?

Facing issues while displaying customized welcome.jsp in spring boot application.
It always displays "index.html" while I want to display customized jsp file "welcome.jsp"..
Request help.
1) make sure springmvc options in application.properties
spring.mvc.view.prefix: /WEB-INF/jsp/
spring.mvc.view.suffix: .jsp
2) add src/main/webapp/WEB-INF/jsp/welcome.jsp
3) modify Application like this:
package com.lenicliu.spring.boot;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
#SpringBootApplication
public class Application extends WebMvcConfigurerAdapter {
public static void main(String[] args) throws Exception {
SpringApplication.run(Application.class, args);
}
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("welcome");
}
}
Please refer to http://docs.spring.io/spring/docs/4.2.6.RELEASE/spring-framework-reference/htmlsingle/#mvc-config-view-controller
Then, run application, and you can find the log:
Root mapping to handler of type [class org.springframework.web.servlet.mvc.ParameterizableViewController]

How to service external static HTML files in Spring Boot Embedded tomcat?

I'm new to Spring framework and Spring Boot.
I've implemented a very simple RESTful Spring Boot web application.
You can see the nearly full source code in another question: Spring Boot: How to externalize JDBC datasource configuration?
How can the app service external static HTML, css js files?
For example, the directory structure may be as follows:
MyApp\
MyApp.jar (this is the Spring Boot app that services the static files below)
static\
index.htm
images\
logo.jpg
js\
main.js
sub.js
css\
app.css
part\
main.htm
sub.htm
I've read the method to build a .WAR file that contains static HTML files, but since it requires rebuild and redeploy of WAR file even on single HTML file modification, that method is unacceptable.
An exact and concrete answer is preferable since my knowledge of Spring is very limited.
I see from another of your questions that what you actually want is to be able to change the path to static resources in your application from the default values. Leaving aside the question of why you would want to do that, there are several possible answers.
One is that you can provide a normal Spring MVC #Bean of type WebMvcConfigurerAdapter and use the addResourceHandlers() method to add additional paths to static resources (see WebMvcAutoConfiguration for the defaults).
Another approach is to use the ConfigurableEmbeddedServletContainerFactory features to set the servlet context root path.
The full "nuclear option" for that is to provide a #Bean definition of type EmbeddedServletContainerFactory that set up the servlet container in the way you want it. If you use one of the existing concrete implementations they extend the Abstract* class that you already found, so they even have a setter for a property called documentRoot. You can also do a lot of common manipulations using a #Bean of type EmbeddedServletContainerCustomizer.
Is enough if you specify '-cp .' option in command 'java -jar blabla.jar' and in current directory is 'static' directory
Take a look at this Dave Syer's answer implementation.
You can set the document root directory which will be used by the web context to serve static files using ConfigurableEmbeddedServletContainer.setDocumentRoot(File documentRoot).
Working example:
package com.example.config;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.embedded.ConfigurableEmbeddedServletContainer;
import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer;
import org.springframework.boot.web.servlet.ServletContextInitializer;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.util.StringUtils;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import java.io.File;
import java.nio.file.Paths;
#Configuration
public class WebConfigurer implements ServletContextInitializer, EmbeddedServletContainerCustomizer {
private final Logger log = LoggerFactory.getLogger(WebConfigurer.class);
private final Environment env;
private static final String STATIC_ASSETS_FOLDER_PARAM = "static-assets-folder";
private final String staticAssetsFolderPath;
public WebConfigurer(Environment env, #Value("${" + STATIC_ASSETS_FOLDER_PARAM + ":}") String staticAssetsFolderPath) {
this.env = env;
this.staticAssetsFolderPath = staticAssetsFolderPath;
}
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
if (env.getActiveProfiles().length > 0) {
log.info("Web application configuration, profiles: {}", (Object[]) env.getActiveProfiles());
}
log.info(STATIC_ASSETS_FOLDER_PARAM + ": '{}'", staticAssetsFolderPath);
}
private void customizeDocumentRoot(ConfigurableEmbeddedServletContainer container) {
if (!StringUtils.isEmpty(staticAssetsFolderPath)) {
File docRoot;
if (staticAssetsFolderPath.startsWith(File.separator)) {
docRoot = new File(staticAssetsFolderPath);
} else {
final String workPath = Paths.get(".").toUri().normalize().getPath();
docRoot = new File(workPath + staticAssetsFolderPath);
}
if (docRoot.exists() && docRoot.isDirectory()) {
log.info("Custom location is used for static assets, document root folder: {}",
docRoot.getAbsolutePath());
container.setDocumentRoot(docRoot);
} else {
log.warn("Custom document root folder {} doesn't exist, custom location for static assets was not used.",
docRoot.getAbsolutePath());
}
}
}
#Override
public void customize(ConfigurableEmbeddedServletContainer container) {
customizeDocumentRoot(container);
}
}
Now you can customize your app with command line and profiles (src\main\resources\application-myprofile.yml):
> java -jar demo-0.0.1-SNAPSHOT.jar --static-assets-folder="myfolder"
> java -jar demo-0.0.1-SNAPSHOT.jar --spring.profiles.active=myprofile

Resources