Unable to store spring session in Hazelcast - spring

I'm developing a spring boot application with form login. I have a problem if my application works as more than one replica.
When I check where session is located, I found InMemoryWebSessionStore service. And I understood the source of the problem. I made sure that I had to store the session in a central point like redis, hazelcast.
I researched how to do this, and I read that I should use spring-session.
I faced following error:
Caused by:
org.springframework.boot.autoconfigure.session.SessionRepositoryUnavailableException:
No session repository could be auto-configured, check your
configuration (session store type is 'hazelcast')
application.yml:
spring:
session:
store-type: hazelcast
First of all am I on the right way? Anyone have a better solution?
SecurityConfig.kt
#EnableWebFluxSecurity
class SecurityConfig {
#Bean
fun adminWebFilterChain(
http: ServerHttpSecurity,
userService: UserService,
passwordEncoder: PasswordEncoder
): SecurityWebFilterChain {
val userDetailsService = CustomUserDetailsService(userService, passwordEncoder)
val manager = CustomUserAuthenticationManager(userDetailsService)
manager.setPasswordEncoder(passwordEncoder)
return http
.csrf().disable()
.authenticationManager(manager)
.authorizeExchange()
.pathMatchers("/login", "/logout").permitAll()
.anyExchange().authenticated()
.and().formLogin()
.and().logout()
.and().build()
}
#Bean
fun passwordEncoder(): PasswordEncoder {
return BCryptPasswordEncoder()
}
}
HazelcastHttpSessionConfig.kt
#Configuration
#EnableHazelcastHttpSession
class HazelcastHttpSessionConfig {}
Dependencies:
implementation("org.springframework.boot:spring-boot-starter-webflux")
implementation("org.springframework.boot:spring-boot-starter-security")
implementation("io.micrometer:micrometer-registry-prometheus")
implementation("org.springframework.session:spring-session-core")
implementation("org.springframework.session:spring-session-hazelcast")
Am I on the right way? Do you have a better solution?
And do you have any idea about an error that I faced?

Here is what I have done to implement Spring Session with Hazelcast.
HazelcastConfig.java
#Configuration
#EnableHazelcastHttpSession(maxInactiveIntervalInSeconds = 3600)
public class HazelcastConfig {
#Bean
public Config hazelCastConfig() {
final Config config = new Config().setInstanceName("hazelcast-instance");
config.getMapConfig(HazelcastIndexedSessionRepository.DEFAULT_SESSION_MAP_NAME)
.addMapAttributeConfig(springSessionAttributeConfig()).addMapIndexConfig(
new MapIndexConfig(HazelcastIndexedSessionRepository.PRINCIPAL_NAME_ATTRIBUTE, false));
return config;
}
private MapAttributeConfig springSessionAttributeConfig() {
return new MapAttributeConfig()
.setName(HazelcastIndexedSessionRepository.PRINCIPAL_NAME_ATTRIBUTE)
.setExtractor(PrincipalNameExtractor.class.getName());
}
}
In my pom.xml I have the following:
<dependency>
<groupId>com.hazelcast</groupId>
<artifactId>hazelcast</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-hazelcast</artifactId>
</dependency>
I don't set the spring.session.store-type. You can tailor the configuration to your needs (adding kubernetes support, using it as a distributed query cache, etc).

Related

SpringBoot application monitoring Adding Timed annotation cause to error

I'm implementing micrometer to spring web project. While trying to add #Timed annotation. Prior to add #Timed i'm supposed to create TimedSpect bean. But it says could not autowire no bean of MeterRegistry type found
#Configuration
public class MetricsCofiguration {
#Bean
public TimedAspect timedAspect(MeterRegistry registry) {
return new TimedAspect(registry);
}
}
Not sure if you still need this answer but this is what i tried and its working fine.
#Configuration
#EnableAspectJAutoProxy
public class TimedConfiguration {
#Autowired
MeterRegistry registry;
#Bean
public TimedAspect timedAspect(MeterRegistry registry) {
return new TimedAspect(registry);
}
}
Make sure you have below starter dependency in your pom.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>

Spring Security WebFlux and LDAP

What customization's are required in order to secure a Reactive Spring Boot application with LDAP? The examples I've seen so far are based on Spring MVC and the example for securing a WebFlux only shows a simple Reactive example with an in-memory Map.
Here is one solution for this that I have come up with and tested.
Deserving special attention is this information in this class: ReactiveAuthenticationManagerAdapter. There, it states:
Adapts an AuthenticationManager to the reactive APIs. This is somewhat
necessary because many of the ways that credentials are stored (i.e.
JDBC, LDAP, etc) do not have reactive implementations. What's more is
it is generally considered best practice to store passwords in a hash
that is intentionally slow which would block ever request from coming
in unless it was put on another thread.
First, create a configuration class. This will handle the connectivity to LDAP.
#Configuration
public class ReactiveLdapAuthenticationConfig {
// Set this in your application.properties, or hardcode if you want.
#Value("${spring.ldap.urls}")
private String ldapUrl;
#Bean
ReactiveAuthenticationManager authenticationManager(BaseLdapPathContextSource contextSource) {
BindAuthenticator ba = new BindAuthenticator(contextSource);
ba.setUserDnPatterns(new String[] { "cn={0},ou=people" } );
LdapAuthenticationProvider lap = new LdapAuthenticationProvider(ba);
AuthenticationManager am = new ProviderManager(Arrays.asList(lap));
return new ReactiveAuthenticationManagerAdapter(am);
}
#Bean
BaseLdapPathContextSource contextSource() {
LdapContextSource ctx = new LdapContextSource();
ctx.setUrl(ldapUrl);
ctx.afterPropertiesSet();
return ctx;
}
}
After that, you'll want to configure your security following the patterns here. The most basic chain configuration is about this:
#Bean
public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
http
.authorizeExchange()
.anyExchange().authenticated()
.and()
.httpBasic();
return http.build();
}
For completeness, you'll want to make sure you have these:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-ldap</artifactId>
</dependency>
Other References
EnableReactiveMethodSecurity
BindAuthenticator
LdapAuthenticationProvider
ProviderManager
The above example didn't work for me using Windows Active Directory. I could get LDAP Authentication to work in stand-alone (non-Spring) Java, but the above solution always gave me error 52e (user known, but invalid password).
Following on from the example above, I used the same pom.xml and #EnableWebFluxSecurity ... SecurityWebFilterChain(...), but with the following;
#Configuration
public class ReactiveLdapAuthenticatoinConfig {
#Bean
ReactiveAuthenticationManager authenticationManager() {
ActiveDirectoryLdapAuthenticationProvider adlap =
new ActiveDirectoryLdapAuthenticationProvider(
"{my.domain}",
"ldap://{my.ldap.server}.{my.domain}"
);
AuthenticationManager am = new ProviderManager(Arrays.asList(adlap));
return new ReactiveAuthenticationManagerAdapter(am);
}
}
In order to return the signed-in user, one would use something like;
#GetMapping(value = '/user')
public Mono<String> getUser(Mono<Principal> principal) {
return principal.map(Principal::getName);
}

Getting java.net.HttpRetryException: cannot retry due to server authentication, in streaming mode

I've created a test for the creation of a new user:
private static String USERS_ENDPOINT = "http://localhost:8080/users/";
private static String GROUPS_ENDPOINT = "http://localhost:8080/groups/";
#Test
#DirtiesContext(classMode = ClassMode.BEFORE_EACH_TEST_METHOD)
public void whenCreateAppUser() {
AppUser appUser = new AppUser();
appUser.setUsername("test#example.com");
appUser.setPassword("password");
// Throws java.net.HttpRetryException
template.postForEntity(USERS_ENDPOINT, appUser, AppUser.class);
ResponseEntity<AppUser> appUserResponse = template.getForEntity(USERS_ENDPOINT + "1/", AppUser.class);
assertEquals("Username is incorrect. AppUser not created?",
appUser.getUsername(), appUserResponse.getBody().getUsername());
}
However, for some reason I am getting:
Caused by: java.net.HttpRetryException: cannot retry due to server authentication, in streaming mode
at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1692)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1492)
at java.net.HttpURLConnection.getResponseCode(HttpURLConnection.java:480)
at org.springframework.http.client.SimpleClientHttpResponse.getRawStatusCode(SimpleClientHttpResponse.java:55)
at org.springframework.web.client.DefaultResponseErrorHandler.hasError(DefaultResponseErrorHandler.java:49)
at org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:735)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:700)
... 34 more
For the call
template.postForEntity(USERS_ENDPOINT, appUser, AppUser.class);
I actually don't know what I changed because this used to work for me. Any idea what causes this issue?
My WebSecurity settings are:
#Override
public void configure(WebSecurity web) throws Exception {
final String[] SWAGGER_UI = {
"/swagger-resources/**",
"/swagger-ui.html",
"/v2/api-docs",
"/webjars/**"
};
web.ignoring().antMatchers("/pub/**", "/users")
.antMatchers(SWAGGER_UI);
}
Spring's RestTemplate and Spring Boot's TestRestTemplate will on JDK's internal HttpURLConnection implementation by default, which fails to access the body of an HTTP-response with status 401 "Unauthorized".
A magical solution is to include Apache's HTTP Client into the classpath — e.g. with Maven,
For Spring Boot 3.x.x:
<dependency>
<groupId>org.apache.httpcomponents.client5</groupId>
<artifactId>httpclient5</artifactId>
<version>5.2.1</version>
<scope>test</scope>
</dependency>
For Spring Boot 2.x.x:
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.6</version>
<scope>test</scope>
</dependency>
In this case, Spring (Boot) will use Apache's HTTP Client which doesn't face the problem.
See also: https://github.com/spring-projects/spring-security-oauth/issues/441#issuecomment-92033542
Using the HttpClient from the Apache HttpComponents Client library solved the issue for me.
To use the Apache HttpClient you have to configure your RestTemplate the following way:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
#Configuration
public class RestClientConfig {
#Bean
public RestTemplate restTemplate() {
var template = new RestTemplate();
template.setRequestFactory(new HttpComponentsClientHttpRequestFactory());
return template;
}
}
As answered in java.net.HttpRetryException: cannot retry due to server authentication, in streaming mode
an alternative is:
SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
requestFactory.setOutputStreaming(false);
return requestFactory;

Springfox swagger-ui.html unable to infer base URL - Caused by missing cookies

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

Spring boot cache results

I have several read-only resources in my Controller. I want to in-memory cache them, I'm not clear how to do it in Spring Boot.
What I've done:
annotated main Application with #EnableCaching
annotated a resource with #Cacheable
#Cacheable
#RequestMapping(value = "/api/graph", method=RequestMethod.GET, produces = { "application/json"})
public #ResponseBody Iterable<Map<String, String>> graph() {
return Repository.graph();
}
What am I missing?
Since it's a read-only resource I guess I don't neet #CachePut am I right?
Obiouvsly I added spring-boot-starter-cache ad dependency in maven
Here are the steps to enable the Cache. For example i am using Google GuavaCacheManager for this purpose.
Add dependency and Enable the caching by using annotation on Application class.
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>18.0</version>
</dependency>
#SpringBootApplication
#EnableCaching
public class Application extends SpringBootServletInitializer {
}
Expose the GuavaCacheManager as a bean in your Application class.
#Bean
public CacheManager cacheManager() {
GuavaCacheManager cacheManager = new GuavaCacheManager();
// Cache expires every day
cacheManager.setCacheBuilder(CacheBuilder.newBuilder().expireAfterAccess(1,
TimeUnit.DAYS).expireAfterWrite(1, TimeUnit.DAYS));
cacheManager.setCacheNames(Arrays.asList("findUser"));
return cacheManager;
}
Mark the method as Cacheable so all the calls to this method first try to find the entry in Cache if not found then actually calls the method
#Override
#Cacheable("findUser")
public User findUser(String username) {
// biz logic to find the user and return the object
return user;
}

Resources