Related
So I have a spring boot project that I just added OpenAPI Swagger UI to. It auto generates the documentation really well for all of our controllers and models. But I would like to add some additional configuration such as externalDocs as shown here.
externalDocs:
url: URL
description: DESC
But since its auto generated I don't have a YAML for swagger. I tried the following to add it through a Bean with no luck.
import io.swagger.v3.oas.models.ExternalDocumentation;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.info.License;
import org.springframework.context.annotation.Bean;
public class springShopOpenAPI{
#Bean
public OpenAPI springShopOpenAPI() {
return new OpenAPI()
.info(new Info().title("SpringShop API")
.description("Spring shop sample application")
.version("v0.0.1")
.license(new License().name("Apache 2.0").url("http://springdoc.org")))
.externalDocs(new ExternalDocumentation()
.description("SpringShop Wiki Documentation")
.url("https://springshop.wiki.github.org/docs"));
}
}
Below is my Pom.xml if needed.
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-ui</artifactId>
<version>1.2.28</version>
</dependency>
Thanks for any suggestions.
You'll need to implement the OperationCustomizer interface to add external links. The code should look something like below
#Component
public class EndpointCustomizer implements OperationCustomizer {
#Override
public Operation customize(Operation operation, HandlerMethod handlerMethod) {
// Will add the externalDocs to all the endpoints
operation.externalDocs(new ExternalDocumentation().url("/resource").description("Link to resource"));
return operation;
}
}
You can also perform additional logic to add the externalDocs based on certain criteria.
Once the class is defined, you'll need to create an API Group in the class where you are defining your OpenAPI Bean (the springShopOpenAPI class in your case).
#Bean
public GroupedOpenApi hideApis(EndpointCustomizer endpointCustomizer) {
return GroupedOpenApi.builder().group("default") // or use null instead of default
.addOperationCustomizer(endpointCustomizer)
.build();
}
All I needed to do was add #Configuration and update my pom.xml to have the following.
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-ui</artifactId>
<version>1.4.4</version>
</dependency>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-webmvc-core</artifactId>
<version>1.4.4</version>
</dependency>
import io.swagger.v3.oas.models.ExternalDocumentation;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.info.License;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
#Configuration
public class springShopOpenAPI{
#Bean
public OpenAPI customOpenAPI(){
return new OpenAPI()
.info(new Info().title("SpringShop API")
.description("Spring shop sample application")
.version("v0.0.1")
.license(new License().name("Apache 2.0").url("http://springdoc.org")))
.externalDocs(new ExternalDocumentation()
.description("SpringShop Wiki Documentation")
.url("https://springshop.wiki.github.org/docs"));
}
}
If somebody is trying to add a link to a #Tag, for linking to a wiki page for instance, this can also be done with the externalDocs keyword as follows :
#RestController
#Tag(name = "MyController",
description = "MyController goal is ...",
externalDocs = #ExternalDocumentation(description = "Wiki page about MyController.", url = "https://confluence.mycorp.com/display/..."))
public class MyController { ...
I have googled it, but all example for swagger documentation are using classes.
I would like to include interfaces, as reader is interested in APIs and not implementations.
Here is my code:
Included desired maven dependencies:
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
My SpringBootApplication:
package com.manojk.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
My RestController interface
package com.manojk.demo;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
#RestController
#RequestMapping(value = "/") // this annotation needed for swagger-ui to work
public interface HelloWorldControllerInterface {
#GetMapping
String helloWorld();
}
And implementation
package com.manojk.demo;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
#Component // this annotation needed to initialize this controller
public class HelloWorldController implements HelloWorldControllerInterface {
#Override
public String helloWorld(){
return "Hello World";
}
}
It's all supported by required swagger config:
package com.manojk.demo;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
import static springfox.documentation.builders.PathSelectors.regex;
/**
* Configuration class for Swagger REST API documentation
*
*/
#Configuration
#EnableSwagger2
/**
* Run nad hit http://localhost:8080/swagger-ui.html to see it working
*/
public class SwaggerConfig {
/**
* #return Swagger Docker
*/
#Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2)
.select()
// .apis(RequestHandlerSelectors.basePackage("com.siemens.oss.domain.controller.service")) # does not work for interfaces
.apis(RequestHandlerSelectors.basePackage("com.manojk.demo")) // works for implementations
.paths(regex("/.*"))
.build();
}
}
The code is available as maven project at https://github.com/MKhotele/spring-examples/tree/master/demo.
http://localhost:8080/swagger-ui.html shows "Hello World Controller"; but nothing for "Hello World Controller Interface".
Is it possible to make swagger include interface? How?
Hint has been provided in comments by Segii Zhevzhyk. Thanks!
It should not be possible and hence not possible.
OpenAPI specification(formerly Swagger Specification) is not only about specification of REST APIs. It's also about interacting with them. An interface can never expose an endpoint to interact with; but only an implementation.
Swagger is a set of open-source tools built around the OpenAPI
Specification that can help you design, build, document and consume
REST APIs.
As documented in Introduction to OpenAPI-Specification,
The OpenAPI Specification (OAS) defines a standard, language-agnostic
interface to RESTful APIs which allows both humans and computers to
discover and understand the capabilities of the service without access
to source code, documentation, or through network traffic inspection.
When properly defined, a consumer can understand and interact with the
remote service with a minimal amount of implementation logic.
We have our Spring Boot services behind an API Gateway. With an earlier version of Springfox - 2.1.2 we had no issues in loading the swagger-ui.html page. This worked with Spring Boot 1.4.3.RELEASE. From then, we have upgraded to Boot 1.5.7 and upgraded Springfox to 2.8.0.
Now if we load the page we get an alert box with the following long message.
Unable to infer base url. This is common when using dynamic servlet
registration or when the API is behind an API Gateway. The base url is
the root of where all the swagger resources are served. For e.g. if
the api is available at http://example.org/api/v2/api-docs then the
base url is http://example.org/api/. Please enter the location
manually
I got some hints searching online, but it does not seem those situations apply to us. For one, if I simply revert back the versions, it starts working again through the same API Gateway.
Tracking the traffic, it seems calls to three XHR resources made by the .html page is causing issues. These are returning 401 from our API gateway. And the reason they return 401 is because the cookies are not passed along.
The three calls are:
https://base_address/base_context/swagger-resources/configuration/ui
https://base_address/base_context/swagger-resources/configuration/security
https://base_address/base_context/swagger-resources
If I load these URLs as pure browser requests - they work - because cookies are sent.
I doubt if CORS applies since the HTML is being served from the same address as the swagger JSON and actual service calls.
Any idea why this may be happening? Anybody faced similar issues? Suggestions for workaround? Thanks much in advance.
Add in the security config -- following URLS that are skipped for authentication ::
private static final String[] AUTH_WHITELIST = {
"/swagger-resources/**",
"/swagger-ui.html",
"/v2/api-docs",
"/webjars/**"
};
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers(AUTH_WHITELIST);
}
Adding below annotation at the spring boot class resolved this issue for me.
#EnableSwagger2
I am using swagger version
<version>2.9.2</version>
SEE EDIT BELOW
Do you use spring security?
If yes, probably you skip some resources like this (right?):
"/swagger-resources/**",
"/swagger-ui.html",
"/v2/api-docs",
"/webjars/**"
Try to change it "/swagger-resources/**" to "**/swagger-resources/**".
My specific security config for swagger is:
private static final String[] AUTH_LIST = {
// -- swagger ui
"**/swagger-resources/**",
"/swagger-ui.html",
"/v2/api-docs",
"/webjars/**"
};
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests().antMatchers(AUTH_LIST).authenticated()
.and()
.httpBasic().authenticationEntryPoint(swaggerAuthenticationEntryPoint())
.and()
.csrf().disable();
}
#Bean
public BasicAuthenticationEntryPoint swaggerAuthenticationEntryPoint() {
BasicAuthenticationEntryPoint entryPoint = new BasicAuthenticationEntryPoint();
entryPoint.setRealmName("Swagger Realm");
return entryPoint;
}
If you need/want I can send a sample project to GitHub to you know more about my security/swagger configs.
EDIT 2018/04/10
This problem is caused by a wrong version in springfox. See this issue on github to solve the problem.
To posterity:
In pom.xml
...
<repositories>
<repository>
<id>swagger</id>
<name>swagger</name>
<url>http://oss.jfrog.org/artifactory/oss-snapshot-local</url>
</repository>
</repositories>
...
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.8.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.8.1-SNAPSHOT</version>
</dependency>
...
Class that extends WebSecurityConfigAdapter:
#Configuration
public class WebSecurityConfigEntryPointApplication extends WebSecurityConfigurerAdapter {
private static final List<String> AUTH_LIST = Arrays.asList(
"/swagger-resources/**",
"/swagger-ui.html**",
"/webjars/**",
"favicon.ico");
#Autowired
private RestAuthenticationEntryPoint restAuthenticationEntryPoint;
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/**").authorizeRequests().anyRequest().authenticated()
.and()
.exceptionHandling()
.defaultAuthenticationEntryPointFor(swaggerAuthenticationEntryPoint(), new CustomRequestMatcher(AUTH_LIST))
.and()
.httpBasic()
.authenticationEntryPoint(restAuthenticationEntryPoint)
.and()
.csrf().disable();
}
#Bean
public BasicAuthenticationEntryPoint swaggerAuthenticationEntryPoint() {
BasicAuthenticationEntryPoint entryPoint = new BasicAuthenticationEntryPoint();
entryPoint.setRealmName("Swagger Realm");
return entryPoint;
}
private class CustomRequestMatcher implements RequestMatcher {
private List<AntPathRequestMatcher> matchers;
private CustomRequestMatcher(List<String> matchers) {
this.matchers = matchers.stream().map(AntPathRequestMatcher::new).collect(Collectors.toList());
}
#Override
public boolean matches(HttpServletRequest request) {
return matchers.stream().anyMatch(a -> a.matches(request));
}
}
}
RestAuthenticationEntryPoint:
#Component
public class RestAuthenticationEntryPoint implements AuthenticationEntryPoint {
#Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
}
}
This happened to me, I was using SpringBoot 1.5.16 and Springfox 2.9.1.
In my application.properties, I had defined server.servlet-path=/api, but, somehow, the swagger-ui was ignoring the value defined. I've tried so many different way to make this work, and finally I found a workaround:
#Configuration
#EnableSwagger2
public class SwaggerConfiguration extends WebMvcConfigurationSupport {
#Bean
public Docket apiMonitoramento() {
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.any())
.paths(PathSelectors.any())
.build()
.apiInfo(apiInfo());
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("REST API")
.description("Servicesx")
.build();
}
#Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("swagger-ui.html")
.addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/");
}
}
I was accessing http://localhost:8080/context/swagger-ui.html, but with that configuration the correct URL is: http://localhost:8080/context/api/swagger-ui.html
In my case, the cause of the problem was having:
#ComponentScan(basePackageClasses = {ApplicationRoot.class })
twice in two java files.
after removing the extra one, the problem went away.
Upgrade springfox-swagger2 and springfox-swagger-ui dependencies to 2.9.2 and also ensure the basePackage is given properly
return new Docket(DocumentationType.SWAGGER_2).select()
.apis(RequestHandlerSelectors
.basePackage("org.abc.xyz.controller"))
.paths(PathSelectors.regex("/.*"))
.build().apiInfo(apiEndPointsInfo());
I don't use spring security happened this question. My Project Use Maven Multiple Module, When access to the localhost:8080/swagger-ui.html happend this question, First I add #EnableSwagger2 in the SwaggerConf class ,Last I move #EnableSwagger to SpringBoot Application class ,this question is solved.
First:
#Configuration
#EnableSwagger2
public class SwaggerConfig {
#Bean
public Docket api(){
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.basePackage("com.zuoyan."))
.paths(PathSelectors.any())
.build();
}
}
Finally:
#SpringBootApplication(scanBasePackages = {"com.zuoyan.springboot.appmissionhall"})
#EnableSwagger2
public class ApplicationStartUpApplication {
public static void main(String[] args) {
SpringApplication.run(ApplicationStartUpApplication.class, args);
}
}
If you do not specify any special component scan options you will face this problem if you put the class with the #EnableSwagger2 annotation in a package that is not in the hierarchy of your Spring Boot Application class (#SpringBootApplication).
Assume your Spring Boot Application class in "de.oopexpert.app", then putting #EnableSwagger2 annotated class in ...
de.oopexpert.app will work
de.oopexpert.app.config will work
de.oopexpert.config will NOT work
You may adapt your component scan options by adding #ComponentScan(basePackages = {"de.oopexpert"}) to specify a different root of the hierarchy.
The solution from https://stackoverflow.com/a/56716898/13347514 by adding #EnableSwagger2WebMvc and #Import(SpringDataRestConfiguration.class) to the Main Application Class fixes my problem:
#SpringBootApplication
#EnableSwagger2WebMvc
#Import(SpringDataRestConfiguration.class)
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
In many cases it is due to Java Version incompatibility. Many times it doesn't work with Java 11, try using Java 8
Just clear your browser cache. It worked for me.
My Swagger Docket Bean Config file:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
#Configuration
#EnableSwagger2
public class DocketBean implements WebMvcConfigurer {
#Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.basePackage("com.swagger.demo"))
.paths(PathSelectors.any())
.build();
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
// enabling swagger-ui part for visual documentation
registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
}
}
Swagger Dependencies in POM:
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
The swagger-ui url :
http://localhost:8080/swagger-ui.html
try with port 8080 - worked for me after i changed it to 8080
I added #EnableSwagger2WebMvc to the App class to fix it. I am using Spring boot 2.3.0.BUILD-SNAPSHOT and io.springfox 3.0.0-SNAPSHOT. SpringFoxConfig class stays the same.
package com.telixia.educare.academy;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import springfox.documentation.swagger2.annotations.EnableSwagger2WebMvc;
#EnableSwagger2WebMvc
#SpringBootApplication
public class AcademyApplication {
public static void main(String[] args) {
SpringApplication.run(AcademyApplication.class, args);
}
}
This could also be caused by the springfox-swagger-ui and springfox-swagger2 versions mismatch in the pom.xml, for example, if you updated one but forgot to update another:
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.6.1</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
You need to make sure springfox-swagger-ui and springfox-swagger2 have the same version.
Firstly make sure these 2 dependencies are added and then annotate your main SpringBootApplication class with #EnableSwagger2 and then your problem will be solved.
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
I was facing the same issue with a basic Spring MVC application (no Spring Security).
I replaced
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.
addResourceHandler("/swagger-ui/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/springfox-swagger-ui/")
.resourceChain(false);
}
with
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.
addResourceHandler("/swagger-ui/**")
.addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("**/webjars/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/");
}
and it did the trick
In my case, adding the springfox-spring-webmvc dependency resolved the issue:
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-spring-webmvc</artifactId>
<version>2.10.5</version>
</dependency>
I had the same problem, but just adding #EnableSwagger2 on top of the main App class fixed it.
example :
#SpringBootApplication
#EnableSwagger2
public class AcademyApplication {
public static void main(String[] args) {
SpringApplication.run(AcademyApplication.class, args);
}
#Configuration
class RestTemplateConfig {
#Bean
#LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
}
In my case, My project use Maven multiple module without spring security.
SpringBoot v2.2.7.RELEASE
Swagger2 & Swagger-ui v2.9.2
My solution is change the value of #Profile(), enter the right name of the configuration profile you create in the project resourse directory.
First:
#Configuration
#EnableSwagger2
#Profile({ "dev", "test" })
public class SwaggerConfig {
private ApiInfo getApiInfo(String title, String desc) {
return new ApiInfoBuilder().title(title)
.description(desc)
.version(DOC_VERSION)
.termsOfServiceUrl(URL)
.build();
}
}
Last:
#Configuration
#EnableSwagger2
// #Profile({ "dev", "test" })
#Profile({ "kf-oracle", "kf-mysql" })
public class SwaggerConfig {
private ApiInfo getApiInfo(String title, String desc) {
return new ApiInfoBuilder().title(title)
.description(desc)
.version(DOC_VERSION)
.termsOfServiceUrl(URL)
.build();
}
}
I had the same issue,i had written #EnableSwagger2 annotation at class level in SwaggerConfig file but i forgot to place #Configuration at class level in SwaggerConfig class. Adding that annotation solved my issue.
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
#EnableSwagger2
#Configuration
public class swaggerConfig {
// swagger configuration
#Bean
public Docket productApi() {
return new Docket(DocumentationType.SWAGGER_2).select()
.apis(RequestHandlerSelectors.basePackage("mention your package name here")).build();
}
}
If you have the same issue again then do #ComponentScan(basePackages = "mention your root package name here") in your Application.java file
First, add the Swagger dependency to pom.xml
Swagger Dependency in POM
<!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger2 -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger-ui -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
After that, it's time to configure the Swagger 3rd party that we installed. Therefore follow the order below.
1/Make a package and set name Config
2/Make a class SwaggerConfig
3/After it set below code to that class
#Configuration
public class SwaggerConfig {
#Bean
public Docket SwaggerApi(){
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.any())
.paths(PathSelectors.any())
.build();
}
}
4/checked that class #Configuration and #Bean annotations
5/Need to enable Swagger2 in your main method class
6/use #EnableSwagger2 annotation to Enable Swagger 2
After that go to your browser and get swagger UI to see our UI. For it use this code http://localhost:8081/swagger-ui.html#/ check your server.port
If any doubt coming cheng your spring-boot-starter-parent pom.xml to low version.
Example:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.4</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
your project will run without error and smoothly.
Try the following in "*.yml" file
swagger:
enable: true
or try "swagger.enable=true" in "*.properties"
hi i found solution for this swagger popup as we can see a input box inside a swagger
you need to add /web or what ever url pattern configured in your code
example in popup input text field you need to add like this
popup with error
solution
I am trying to configure Swagger UI with my Spring boot application. Although the v2/api-docs seems to be loading properly, the http://localhost:8080/swagger-ui.html does not load my annotated REST API.
Here is what I have:
pom.xml:
...
<!--Swagger UI-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.6.1</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.4.0</version>
</dependency>
...
SwaggerConfig.java
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
import static springfox.documentation.builders.PathSelectors.regex;
#Configuration
#EnableSwagger2
public class SwaggerConfig
{
#Bean
public Docket api()
{
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.any())
.paths(regex("/.*"))
.build().apiInfo(apiInfo());
}
private ApiInfo apiInfo()
{
ApiInfo apiInfo = new ApiInfo(
"My Project's REST API",
"This is a description of your API.",
"version-1",
"API TOS",
"me#wherever.com",
"API License",
"API License URL"
);
return apiInfo;
}
}
http://localhost:8080/v2/api-docs:
{"swagger":"2.0","info":{"description":"This is a description of your API.","version":"version-1","title":"My Project's REST API","termsOfService":"API TOS","contact":{"name":"me#wherever.com"},"license":{"name":"API License","url":"API License URL"}},"host":"localhost:8080","basePath":"/","tags":[{"name":"test-controller","description":"Test Controller"},{"name":"custom-field-controller","description":"Custom Field Controller"},{"name":"user-controller","description":"User Controller"},{"name":"users-controller","description":"Users Controller"},{"name":"crudapi-controller","description":"CRUDAPI Controller"},{"name":"basic-error-controller","description":"Basic Error Controller"}],"paths":{"/":{"get":{"tags":["crudapi-controller"],"summary":"greeting","operationId":"greetingUsingGET","consumes":["application/json"],"produces":["*/*"],"responses":{"200":{"description":"OK","schema":{"type":"string"}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not Found"}}}},"/api/javainuse":{"get":{"tags":["test-controller"],"summary":"firstPage","operationId":"firstPageUsingGET","consumes":["application/json"],"produces":["*/*"],"responses":{"200":{"description":"OK","schema":{"type":"string"}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not Found"}}}},"/error":{"get":{"tags":["basic-error-controller"],"summary":"errorHtml","operationId":"errorHtmlUsingGET","consumes":["application/json"],"produces":["text/html"],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/ModelAndView"}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not Found"}}},"head":{"tags":["basic-error-controller"],"summary":"errorHtml","operationId":"errorHtmlUsingHEAD","consumes":["application/json"],"produces":["text/html"],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/ModelAndView"}},"401":{"description":"Unauthorized"},"204":{"description":"No Content"},"403":{"description":"Forbidden"}}},"post":{"tags":["basic-error-controller"],"summary":"errorHtml","operationId":"errorHtmlUsingPOST","consumes":["application/json"],"produces":["text/html"],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/ModelAndView"}},"201":{"description":"Created"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not Found"}}},"put":{"tags":["basic-error-controller"],"summary":"errorHtml","operationId":"errorHtmlUsingPUT","consumes":["application/json"],"produces":["text/html"],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/ModelAndView"}},"201":{"description":"Created"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not Found"}}},"delete":{"tags":["basic-error-controller"],"summary":"errorHtml","operationId":"errorHtmlUsingDELETE","consumes":["application/json"],"produces":["text/html"],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/ModelAndView"}},"401":{"description":"Unauthorized"},"204":{"description":"No Content"},"403":{"description":"Forbidden"}}},"options":{"tags":["basic-error-controller"],"summary":"errorHtml","operationId":"errorHtmlUsingOPTIONS","consumes":["application/json"],"produces":["text/html"],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/ModelAndView"}},"401":{"description":"Unauthorized"},"204":{"description":"No Content"},"403":{"description":"Forbidden"}}},"patch":{"tags":["basic-error-controller"],"summary":"errorHtml","operationId":"errorHtmlUsingPATCH","consumes":["application/json"],"produces":["text/html"],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/ModelAndView"}},"401":{"description":"Unauthorized"},"204":{"description":"No Content"},"403":{"description":"Forbidden"}}}},"/fields":{"get":{"tags":["custom-field-controller"],"summary":"greeting","operationId":"greetingUsingGET_1","consumes":["application/json"],"produces":["*/*"],"responses":{"200":{"description":"OK","schema":{"type":"string"}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not Found"}}}},"/fields/{id}":{"get":{"tags":["custom-field-controller"],"summary":"fieldAPIController","operationId":"fieldAPIControllerUsingGET","consumes":["application/json"],"produces":["*/*"],"parameters":[{"name":"id","in":"path","description":"id","required":true,"type":"integer","format":"int32"}],"responses":{"200":{"description":"OK","schema":{"type":"array","items":{"$ref":"#/definitions/CustomField"}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not Found"}}}},"/users":{"get":{"tags":["user-controller"],"summary":"greeting","operationId":"greetingUsingGET_2","consumes":["application/json"],"produces":["*/*"],"responses":{"200":{"description":"OK","schema":{"type":"string"}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not Found"}}}},"/users/":{"get":{"tags":["users-controller"],"summary":"listUsers","operationId":"listUsersUsingGET","consumes":["application/json"],"produces":["*/*"],"responses":{"200":{"description":"OK","schema":{"type":"array","items":{"$ref":"#/definitions/UserJPA"}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not Found"}}},"head":{"tags":["users-controller"],"summary":"listUsers","operationId":"listUsersUsingHEAD","consumes":["application/json"],"produces":["*/*"],"responses":{"200":{"description":"OK","schema":{"type":"array","items":{"$ref":"#/definitions/UserJPA"}}},"401":{"description":"Unauthorized"},"204":{"description":"No Content"},"403":{"description":"Forbidden"}}},"post":{"tags":["users-controller"],"summary":"listUsers","operationId":"listUsersUsingPOST","consumes":["application/json"],"produces":["*/*"],"responses":{"200":{"description":"OK","schema":{"type":"array","items":{"$ref":"#/definitions/UserJPA"}}},"201":{"description":"Created"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not Found"}}},"put":{"tags":["users-controller"],"summary":"listUsers","operationId":"listUsersUsingPUT","consumes":["application/json"],"produces":["*/*"],"responses":{"200":{"description":"OK","schema":{"type":"array","items":{"$ref":"#/definitions/UserJPA"}}},"201":{"description":"Created"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not Found"}}},"delete":{"tags":["users-controller"],"summary":"listUsers","operationId":"listUsersUsingDELETE","consumes":["application/json"],"produces":["*/*"],"responses":{"200":{"description":"OK","schema":{"type":"array","items":{"$ref":"#/definitions/UserJPA"}}},"401":{"description":"Unauthorized"},"204":{"description":"No Content"},"403":{"description":"Forbidden"}}},"options":{"tags":["users-controller"],"summary":"listUsers","operationId":"listUsersUsingOPTIONS","consumes":["application/json"],"produces":["*/*"],"responses":{"200":{"description":"OK","schema":{"type":"array","items":{"$ref":"#/definitions/UserJPA"}}},"401":{"description":"Unauthorized"},"204":{"description":"No Content"},"403":{"description":"Forbidden"}}},"patch":{"tags":["users-controller"],"summary":"listUsers","operationId":"listUsersUsingPATCH","consumes":["application/json"],"produces":["*/*"],"responses":{"200":{"description":"OK","schema":{"type":"array","items":{"$ref":"#/definitions/UserJPA"}}},"401":{"description":"Unauthorized"},"204":{"description":"No Content"},"403":{"description":"Forbidden"}}}},"/users/{id}":{"get":{"tags":["user-controller"],"summary":"userAPIController","operationId":"userAPIControllerUsingGET","consumes":["application/json"],"produces":["*/*"],"parameters":[{"name":"id","in":"path","description":"id","required":true,"type":"integer","format":"int32"}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/Collection«UserJPA»"}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not Found"}}}}},"definitions":{"UserJPA":{"type":"object"},"Collection«UserJPA»":{"type":"object"},"ModelAndView":{"type":"object","properties":{"empty":{"type":"boolean"},"model":{"type":"object"},"modelMap":{"type":"object","additionalProperties":{"type":"object"}},"reference":{"type":"boolean"},"status":{"type":"string","enum":["100","101","102","103","200","201","202","203","204","205","206","207","208","226","300","301","302","303","304","305","307","308","400","401","402","403","404","405","406","407","408","409","410","411","412","413","414","415","416","417","418","419","420","421","422","423","424","426","428","429","431","451","500","501","502","503","504","505","506","507","508","509","510","511"]},"view":{"$ref":"#/definitions/View"},"viewName":{"type":"string"}}},"CustomField":{"type":"object","properties":{"name":{"type":"string"}}},"View":{"type":"object","properties":{"contentType":{"type":"string"}}}}}
The swagger-ui.html (http://localhost:8080/swagger-ui.html) does not show the expected REST calls:
The error in swagger-ui.html from the code inspection:
Failed to load resource: the server responded with a status of 404 ().
I have googled around (tried web-config mvc too) but the error persists. Maybe I am missing a resource reference in the .iml file?
I had this issue today and fixed it by matching up the versions of my springfox-swagger2 and springfox-swagger-ui dependencies:
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.6.1</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.6.1</version>
</dependency>
There's very little other code to just get it up and running. One simple config class:
#Configuration
#EnableSwagger2
class SwaggerConfiguration {
#Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.basePackage("com.foo.samples.swaggersample"))
.paths(PathSelectors.any())
.build();
}
}
And my application.properties
# location of the swagger json
springfox.documentation.swagger.v2.path=/swagger.json
(This is in Spring Boot).
Statement : Generate Swagger UI for the listing of all the REST APIs through Spring Boot Application.
Follow the below steps to generate the Swagger UI through Spring Boot application:
1. Add following dependency in pom.xml –
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.6.1</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.6.1</version>
</dependency>
2. Add the following piece of code in your main application class having the #EnableSwagger2 annotation.
#EnableSwagger2
#SpringBootApplication
public class MyApp {
public static void main(String[] args) {
SpringApplication.run(MyApp.class, args);
}
#Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2).select()
.apis(RequestHandlerSelectors.withClassAnnotation(Api.class))
.paths(PathSelectors.any()).build().pathMapping("/")
.apiInfo(apiInfo()).useDefaultResponseMessages(false);
}
#Bean
public ApiInfo apiInfo() {
final ApiInfoBuilder builder = new ApiInfoBuilder();
builder.title("My Application API through Swagger UI").version("1.0").license("(C) Copyright Test")
.description("List of all the APIs of My Application App through Swagger UI");
return builder.build();
}
}
3. Add the below RootController class in your code to redirect to the Swagger UI page. In this way, you don’t need to put the dist folder of Swagger-UI in your resources directory.
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
#Controller
#RequestMapping("/")
public class RootController {
#RequestMapping(method = RequestMethod.GET)
public String swaggerUi() {
return "redirect:/swagger-ui.html";
}
}
4. Being the final steps, add the #Api and #ApiOperation notation in all your RESTControllers like below –
import static org.springframework.web.bind.annotation.RequestMethod.GET;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
#RestController
#RequestMapping("/hello")
#Api(value = "hello", description = "Sample hello world application")
public class TestController {
#ApiOperation(value = "Just to test the sample test api of My App Service")
#RequestMapping(method = RequestMethod.GET, value = "/test")
// #Produces(MediaType.APPLICATION_JSON)
public String test() {
return "Hello to check Swagger UI";
}
#ResponseStatus(HttpStatus.OK)
#RequestMapping(value = "/test1", method = GET)
#ApiOperation(value = "My App Service get test1 API", position = 1)
public String test1() {
System.out.println("Testing");
if (true) {
return "Tanuj";
}
return "Gupta";
}
}
Now your are done. Now to run your Spring Boot Application, go to browser and type localhost:8080. You will see Swagger UI having all the details of your REST APIs.
Happy Coding. 🙂
The source code of the above implementation is also on my blog if you feel like checking it out.
Swagger is Available with V2 and V3 version
More minimal config
Check this Answer - https://stackoverflow.com/a/64333853/410439
Add a config class like this
#Configuration
public class WebMvcConfiguration extends WebMvcConfigurationSupport {
#Override
public void addResourceHandlers(final ResourceHandlerRegistry registry) {
// Make Swagger meta-data available via <baseURL>/v2/api-docs/
registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
// Make Swagger UI available via <baseURL>/swagger-ui.html
registry.addResourceHandler("/**").addResourceLocations("classpath:/META-INF/resources/");
}
}
Nowadays, just set
springdoc.swagger-ui.disable-swagger-default-url=true
I used maven to do the tutorial https://spring.io/guides/gs/uploading-files/
All the codes I used was copied.
The Application can run, but I get the error:
Whitelabel Error Page This application has no explicit mapping for /error, so you are seeing this as a fallback.
Tue Jun 30 17:24:02 CST 2015 There was an unexpected error (type=Not Found, status=404).
No message available
How can I fix it?
Make sure that your main class is in a root package above other classes.
When you run a Spring Boot Application, (i.e. a class annotated with #SpringBootApplication), Spring will only scan the classes below your main class package.
com
+- APP
+- Application.java <--- your main class should be here, above your controller classes
|
+- model
| +- user.java
+- controller
+- UserController.java
When we create a Spring boot application we annotate it with #SpringBootApplication annotation. This annotation 'wraps up' many other necessary annotations for the application to work. One such annotation is #ComponentScan annotation. This annotation tells Spring to look for Spring components and configure the application to run.
Your application class needs to be top of your package hierarchy, so that Spring can scan sub-packages and find out the other required components.
package com.test.spring.boot;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
Below code snippet works as the controller package is under com.test.spring.boot package
package com.test.spring.boot.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
#RestController
public class HomeController {
#RequestMapping("/")
public String home(){
return "Hello World!";
}
}
Below code snippet does NOT Work as the controller package is NOT under com.test.spring.boot package
package com.test.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
#RestController
public class HomeController {
#RequestMapping("/")
public String home(){
return "Hello World!";
}
}
From Spring Boot documentation:
Many Spring Boot developers always have their main class annotated
with #Configuration, #EnableAutoConfiguration and #ComponentScan.
Since these annotations are so frequently used together (especially if
you follow the best practices above), Spring Boot provides a
convenient #SpringBootApplication alternative.
The #SpringBootApplication annotation is equivalent to using
#Configuration, #EnableAutoConfiguration and #ComponentScan with their
default attributes
You can solve this by adding an ErrorController in your application. You can have the error controller return a view that you need.
Error Controller in my application looks like below:
import org.springframework.boot.autoconfigure.web.ErrorAttributes;
import org.springframework.boot.autoconfigure.web.ErrorController;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import java.util.Map;
/**
* Basic Controller which is called for unhandled errors
*/
#Controller
public class AppErrorController implements ErrorController{
/**
* Error Attributes in the Application
*/
private ErrorAttributes errorAttributes;
private final static String ERROR_PATH = "/error";
/**
* Controller for the Error Controller
* #param errorAttributes
*/
public AppErrorController(ErrorAttributes errorAttributes) {
this.errorAttributes = errorAttributes;
}
/**
* Supports the HTML Error View
* #param request
* #return
*/
#RequestMapping(value = ERROR_PATH, produces = "text/html")
public ModelAndView errorHtml(HttpServletRequest request) {
return new ModelAndView("/errors/error", getErrorAttributes(request, false));
}
/**
* Supports other formats like JSON, XML
* #param request
* #return
*/
#RequestMapping(value = ERROR_PATH)
#ResponseBody
public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
Map<String, Object> body = getErrorAttributes(request, getTraceParameter(request));
HttpStatus status = getStatus(request);
return new ResponseEntity<Map<String, Object>>(body, status);
}
/**
* Returns the path of the error page.
*
* #return the error path
*/
#Override
public String getErrorPath() {
return ERROR_PATH;
}
private boolean getTraceParameter(HttpServletRequest request) {
String parameter = request.getParameter("trace");
if (parameter == null) {
return false;
}
return !"false".equals(parameter.toLowerCase());
}
private Map<String, Object> getErrorAttributes(HttpServletRequest request,
boolean includeStackTrace) {
RequestAttributes requestAttributes = new ServletRequestAttributes(request);
return this.errorAttributes.getErrorAttributes(requestAttributes,
includeStackTrace);
}
private HttpStatus getStatus(HttpServletRequest request) {
Integer statusCode = (Integer) request
.getAttribute("javax.servlet.error.status_code");
if (statusCode != null) {
try {
return HttpStatus.valueOf(statusCode);
}
catch (Exception ex) {
}
}
return HttpStatus.INTERNAL_SERVER_ERROR;
}
}
The above class is based on Springs BasicErrorController class.
You can instantiate the above ErrorController like this in a #Configuration file:
#Autowired
private ErrorAttributes errorAttributes;
#Bean
public AppErrorController appErrorController(){return new AppErrorController(errorAttributes);}
You can choose override the default ErrorAttributes by implementing ErrorAttributes. But in most cases the DefaultErrorAttributes should suffice.
In my case the controller class was annotated with #Controller. Changing that to #RestController resolved the problem.
Basically #RestController is #Controller + #ResponseBody
So either use #RestController , or #Controller with #ResponseBody annotation with each method.
Some useful notes here : https://www.genuitec.com/spring-frameworkrestcontroller-vs-controller/
in my case it because of package position , meaning package of controller must be above main class package
if my main class package is package co.companyname.spring.tutorial; any controller package should package co.companyname.spring.tutorial.WHAT_EVER_HERE;
package co.companyname.spring.tutorial; // package for main class
#SpringBootApplication
public class FirstProjectApplication {
public static void main(String[] args) {
SpringApplication.run(FirstProjectApplication.class, args);
}
}
package co.companyname.spring.tutorial.controllers; // package for controllers
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
#RestController
public class HelloController {
#RequestMapping("/hello")
public String hello() {
return "Hello, world";
}}
after finish coding press boot dashboard
one last thing to make sure your controller is mapping or not just console you should see somehting smilliar
Mapped "{[/hello]}" onto public java.lang.String co.companyname.spring.tutorial.controllers.HelloController.hello()
happy coding
Try adding the dependency.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
This happens when an explicit error page is not defined. To define an error page, create a mapping of /error with a view.
e.g. the below code maps to a string value being returned in case of an error.
package com.rumango.controller;
import org.springframework.boot.web.servlet.error.ErrorController;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
#Controller
public class IndexController implements ErrorController{
private final static String PATH = "/error";
#Override
#RequestMapping(PATH)
#ResponseBody
public String getErrorPath() {
// TODO Auto-generated method stub
return "No Mapping Found";
}
}
By default spring boot will scan current package for bean definition. So if your current package where main class is defined and controller package is not same or controller package is not child package of your main app package it will not scan the controller. To solve this issue one can include list of packages for bean definition in main package
#SpringBootApplication(scanBasePackages = {"com.module.restapi1.controller"})
or create a hierarchy of package where child package is derived from main package
package com.module.restapi;
package com.module.restapi.controller
In the main class, after the configuration "#SpringBootApplication", adding "#ComponentScan" without having any arguments, worked for me !!!
Main Class :
#SpringBootApplication
#ComponentScan
public class CommentStoreApplication {
public static void main(String[] args) {
SpringApplication.run(CommentStoreApplication.class, args);
}
}
RestController Class :
#RestController
public class CommentStoreApp {
#RequestMapping("/")
public String hello() {
return "Hello World!";
}
}
P.S: Don't miss to run mvn clean and mvn install commands, before launching the application
I am developing Spring Boot application for a few weeks.. And I was gettig same error like below;
Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Thu Jan 18 14:12:11 AST 2018
There was an unexpected error (type=Not Found, status=404).
No message available
When I get this error massage I realized my controller or rest controller class is not defined in my project. I mean our all controller packages aren't same package with main class which include #SpringBootApplication annotation.. I mean you need to add you controller package's name to #ComponentScan annotation to your main class which is includes #SpringBootApplication annotation. If you write codes of below your problem will be solving... Most important thing is you have to add your all controller's package to #ComponentScan annotation like I did in the below
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
#SpringBootApplication
#ComponentScan({ "com.controller.package1, com.controller.package2, com.controller.package3, com.controller.packageN", "controller", "service" } // If our Controller class or Service class is not in the same packages we have //to add packages's name like this...directory(package) with main class
public class MainApp {
public static void main(String[] args) {
SpringApplication.run(MainApp.class, args);
}
}
I hope this codes are going to help someone...
If you find another way to solve this error or you have some suggestions for me,
please write to comments... thanks...
I added this dependency and it solved my problem.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
You might be getting the error i.e.
"This application has no explicit mapping for /error, so you are seeing this as a fallback."
This is because it is not scanning your Controller & Service classes which you have to specify in your main() class like this,
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
#Configuration
#EnableAutoConfiguration
**#ComponentScan({"com.example.demo", "controller", "service"})**
public class SpringBootMvcExample1Application {
public static void main(String[] args) {
SpringApplication.run(SpringBootMvcExample1Application.class, args);
}
}
Note: Here, I have specified various classes like demo, controller and service to be scanned then only it will work properly.
Quite late to the party. As per spring official documentation "Spring Boot installs a whitelabel error page that you see in a browser client if you encounter a server error."
https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#howto-customize-the-whitelabel-error-page
You can disable the feature by setting server.error.whitelabel.enabled=false in application.yml or application.properties file.
2.Recommended way is set your error page so that end user can understand. Under resources/templates folder create a error.html file and add dependency in pom.xml file
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
Spring will automatically choose the error.html page as the default error template.
Note:- Don't forget to update maven project after adding dependency.
You have to organize the packages so that the package containing public static main(or where you wrote #SpringBootApplication), the father of all your other packages.
The problem is that you are navigating to localhost:8080/ instead of localhost:8080/upload as prescribed in the guide. Spring Boot has a default error page used when you navigate to an undefined route to avoid giving away server specific details (which can be viewed as a security risk).
You're options are to either: visit the right page, add your own landing page, or override the white error page.
To simplify this particular situation, I updated the guide so that it uses / instead of /upload.
I too got the same error and was able to resolve the error by adding the below dependency to my pom.xml.
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>
Reason is we are using JSP as the view. Default embedded servlet container for Spring Boot Starter Web is tomcat.
To enable support for JSP’s, we would need to add a dependency on tomcat-embed-jasper.
In my case I was returning a JSP as view from controller.
Hope this answer helps someone who are struggling with same issue.
I know it's not exactly answer to question, but this question is first which appears on Google :)
Problem ("This application has no explicit mapping for /error") appears when trying to access Swagger UI.
In my case problems were caused by #RestController("/endpoint"), which isn't handled properly by swagger.
So, this resulted in errors:
#RestController("/endpoint")
public class EndpointController {
And this was fine
#RestController
#RequestMapping("/endpoint")
public class EndpointController {
this can happen if you forget the #RestController annotation on top of your controller class
import import org.springframework.web.bind.annotation.RestController;
and add the annotation as below
refer the simple example below
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RequestMapping;
#RestController
public class HelloController {
#RequestMapping("/")
public String index() {
return "Greetings from Spring Boot!";
}
}
Ensure that you have jasper and jstl in the list of dependencies:
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
Here is a working starter project - https://github.com/spring-projects/spring-boot/tree/master/spring-boot-samples/spring-boot-sample-web-jsp
Author: Biju Kunjummen
I need to mention this way and give the reference to packages and it worked out. You may exclude #EnableAutoConfiguration this annotation but required for me to bypass any DB related depenencies.
#SpringBootApplication
#EnableAutoConfiguration(exclude={DataSourceAutoConfiguration.class})
#ComponentScan(basePackages = {"your package 1", "your package2"})
public class CommentStoreApplication {
public static void main(String[] args) {
SpringApplication.run(CommentStoreApplication.class, args);
}
}
Same problem I have faced recently. I have solved it by just getter and setter method spelling correction!
The tutorial expects you to have the Thymeleaf template engine in classpath. I ran into the same problem and finally figured this out. I'll reach out to the tutorial author to include that info.
The easiest way if you've followed the tutorial is to add the dependency to your pom.xml in the project root folder. Next time you run your app Spring will detect Thymeleaf and use the uploadform template
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
For the full example see their Github repository.
Change #Controller to #RestController in your controller class and everything should go smoothly.
I was facing the same problem, using gradle and it got solved on adding following dependencies-
compile('org.springframework.boot:spring-boot-starter-data-jpa')
compile('org.springframework.boot:spring-boot-starter-web')
testCompile('org.springframework.boot:spring-boot-starter-test')
compile('org.apache.tomcat.embed:tomcat-embed-jasper')
earlier I was missing the last one causing the same error.
I was facing this issue and then later realized that I was missing the #Configuration annotation in the MvcConfig class which basically does the mapping for ViewControllers and setViewNames.
Here is the content of the file :
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
**#Configuration**
public class MvcConfig implements WebMvcConfigurer{
public void addViewControllers(ViewControllerRegistry registry)
{
registry.addViewController("/").setViewName("login");
registry.addViewController("/login").setViewName("login");
registry.addViewController("/dashboard").setViewName("dashboard");
}
}
Hope this helps somebody!!
Make sure #RestController annotation is added right after the #SpringBootApplication.
RestController annotation tells Spring that this code describes an endpoint that should be made available over the web.
You may have not included thymleaf in your pom.xml file.
I had a similar problem. And I had Main.class on the top of all the controllers, yet I was facing this issue. All I needed to do is to create a separate swagger configuration file and initialize docket bean in it.
note: location of this file should be either in the same package of the Main.class file or in a package inside that main package.
SwaggerCongiguration.java file
package com.example.springDataJPAUsingGradle;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
#Configuration
#EnableSwagger2
public class SwaggerConfig {
#Bean
public Docket docket() {
return new Docket(DocumentationType.SWAGGER_2).select().build();
}
}
I also had to add #RequestMapping("/api") in my controller.java.
Here's how:
package com.example.springDataJPAUsingGradle.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.example.springDataJPAUsingGradle.service.StudentService;
#RestController
#RequestMapping("/api")
public class StudentController {
#Autowired(required = true)
#GetMapping("/home")
public String home() {
return "Welcome to home page";
}
}
Then after hitting the url: http://localhost:9090/your-app-root/swagger-ui/ swagger UI will be visible.
For eg, in my case the url is: http://localhost:9090/students/swagger-ui/
All I have done to solve this kind of problem is to mention anotation #Configuration in MVCConfig Class.
Like this one :
package com.example;
/**
* Created by sartika.s.hasibuan on 1/10/2017.
*/
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
#EnableAutoConfiguration
#Configuration
#ComponentScan
public class MvcConfig extends WebMvcConfigurerAdapter {
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/home").setViewName("home");
registry.addViewController("/").setViewName("home");
registry.addViewController("/hello").setViewName("hello");
registry.addViewController("/login").setViewName("login");
}
}
I had a similar mistake, I use the spring boot and velocity, my solution is to check the file application.properties, spring.velocity.toolbox-config-location found that this property is wrong