JAVA-17164 update config and discovery services to use Spring Boot 2.7.X (#13967)
This commit is contained in:
parent
ff30f4648f
commit
920214f38d
@ -18,3 +18,5 @@ spring.redis.port=6379
|
||||
|
||||
spring.sleuth.sampler.percentage=1.0
|
||||
spring.sleuth.web.skipPattern=(^cleanup.*)
|
||||
|
||||
spring.zipkin.baseUrl=http://localhost:9411
|
||||
|
@ -6,25 +6,13 @@ eureka.client.registryFetchIntervalSeconds = 5
|
||||
|
||||
management.security.sessions=always
|
||||
|
||||
zuul.routes.book-service.path=/book-service/**
|
||||
zuul.routes.book-service.sensitive-headers=Set-Cookie,Authorization
|
||||
hystrix.command.book-service.execution.isolation.thread.timeoutInMilliseconds=600000
|
||||
|
||||
zuul.routes.rating-service.path=/rating-service/**
|
||||
zuul.routes.rating-service.sensitive-headers=Set-Cookie,Authorization
|
||||
hystrix.command.rating-service.execution.isolation.thread.timeoutInMilliseconds=600000
|
||||
|
||||
zuul.routes.discovery.path=/discovery/**
|
||||
zuul.routes.discovery.sensitive-headers=Set-Cookie,Authorization
|
||||
zuul.routes.discovery.url=http://localhost:8082
|
||||
hystrix.command.discovery.execution.isolation.thread.timeoutInMilliseconds=600000
|
||||
|
||||
logging.level.org.springframework.web.=debug
|
||||
logging.level.org.springframework.security=debug
|
||||
logging.level.org.springframework.cloud.netflix.zuul=debug
|
||||
|
||||
spring.redis.host=localhost
|
||||
spring.redis.port=6379
|
||||
|
||||
spring.sleuth.sampler.percentage=1.0
|
||||
spring.sleuth.web.skipPattern=(^cleanup.*|.+favicon.*)
|
||||
spring.sleuth.web.skipPattern=(^cleanup.*|.+favicon.*)
|
||||
|
||||
spring.zipkin.baseUrl=http://localhost:9411
|
||||
|
@ -18,3 +18,5 @@ spring.redis.port=6379
|
||||
|
||||
spring.sleuth.sampler.percentage=1.0
|
||||
spring.sleuth.web.skipPattern=(^cleanup.*)
|
||||
|
||||
spring.zipkin.baseUrl=http://localhost:9411
|
||||
|
@ -9,9 +9,9 @@
|
||||
|
||||
<parent>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>parent-boot-1</artifactId>
|
||||
<artifactId>parent-boot-2</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<relativePath>../../../parent-boot-1</relativePath>
|
||||
<relativePath>../../../parent-boot-2</relativePath>
|
||||
</parent>
|
||||
|
||||
<dependencyManagement>
|
||||
@ -33,7 +33,7 @@
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-eureka</artifactId>
|
||||
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
@ -42,7 +42,7 @@
|
||||
</dependencies>
|
||||
|
||||
<properties>
|
||||
<spring-cloud-dependencies.version>Brixton.SR7</spring-cloud-dependencies.version>
|
||||
<spring-cloud-dependencies.version>2021.0.7</spring-cloud-dependencies.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
@ -2,12 +2,12 @@ package com.baeldung.spring.cloud.bootstrap.config;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
|
||||
import org.springframework.cloud.config.server.EnableConfigServer;
|
||||
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
|
||||
|
||||
@SpringBootApplication
|
||||
@EnableConfigServer
|
||||
@EnableEurekaClient
|
||||
@EnableDiscoveryClient
|
||||
public class ConfigApplication {
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(ConfigApplication.class, args);
|
||||
|
@ -1,23 +1,41 @@
|
||||
package com.baeldung.spring.cloud.bootstrap.config;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
public class SecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
public class SecurityConfig {
|
||||
|
||||
@Autowired
|
||||
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth.inMemoryAuthentication().withUser("configUser").password("configPassword").roles("SYSTEM");
|
||||
@Bean
|
||||
public InMemoryUserDetailsManager userDetailsService(BCryptPasswordEncoder bCryptPasswordEncoder) {
|
||||
InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
|
||||
manager.createUser(User.withUsername("configUser")
|
||||
.password(bCryptPasswordEncoder.encode("configPassword"))
|
||||
.roles("SYSTEM")
|
||||
.build());
|
||||
return manager;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http.authorizeRequests().anyRequest().hasRole("SYSTEM").and().httpBasic().and().csrf().disable();
|
||||
@Bean
|
||||
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||
http.authorizeRequests()
|
||||
.anyRequest()
|
||||
.hasRole("SYSTEM")
|
||||
.and()
|
||||
.httpBasic()
|
||||
.and()
|
||||
.csrf()
|
||||
.disable();
|
||||
return http.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public BCryptPasswordEncoder encoder() {
|
||||
return new BCryptPasswordEncoder();
|
||||
}
|
||||
}
|
||||
|
@ -9,9 +9,9 @@
|
||||
|
||||
<parent>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>parent-boot-1</artifactId>
|
||||
<artifactId>parent-boot-2</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<relativePath>../../../parent-boot-1</relativePath>
|
||||
<relativePath>../../../parent-boot-2</relativePath>
|
||||
</parent>
|
||||
|
||||
<dependencyManagement>
|
||||
@ -33,7 +33,11 @@
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-eureka-server</artifactId>
|
||||
<artifactId>spring-cloud-starter-bootstrap</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
@ -41,7 +45,7 @@
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.session</groupId>
|
||||
<artifactId>spring-session</artifactId>
|
||||
<artifactId>spring-session-data-redis</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
@ -50,7 +54,7 @@
|
||||
</dependencies>
|
||||
|
||||
<properties>
|
||||
<spring-cloud-dependencies.version>Edgware.SR5</spring-cloud-dependencies.version>
|
||||
<spring-cloud-dependencies.version>2021.0.7</spring-cloud-dependencies.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
@ -17,7 +17,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Autowired
|
||||
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth.inMemoryAuthentication().withUser("discUser").password("discPassword").roles("SYSTEM");
|
||||
auth.inMemoryAuthentication().withUser("discUser").password("{noop}discPassword").roles("SYSTEM");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -9,9 +9,9 @@
|
||||
|
||||
<parent>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>parent-boot-1</artifactId>
|
||||
<artifactId>parent-boot-2</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<relativePath>../../../parent-boot-1</relativePath>
|
||||
<relativePath>../../../parent-boot-2</relativePath>
|
||||
</parent>
|
||||
|
||||
<dependencyManagement>
|
||||
@ -33,11 +33,15 @@
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-eureka</artifactId>
|
||||
<artifactId>spring-cloud-starter-bootstrap</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-zuul</artifactId>
|
||||
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-gateway</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
@ -45,7 +49,7 @@
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.session</groupId>
|
||||
<artifactId>spring-session</artifactId>
|
||||
<artifactId>spring-session-data-redis</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
@ -53,11 +57,15 @@
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-zipkin</artifactId>
|
||||
<artifactId>spring-cloud-starter-sleuth</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-feign</artifactId>
|
||||
<artifactId>spring-cloud-sleuth-zipkin</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-openfeign</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
@ -97,7 +105,7 @@
|
||||
</build>
|
||||
|
||||
<properties>
|
||||
<spring-cloud-dependencies.version>Dalston.RELEASE</spring-cloud-dependencies.version>
|
||||
<spring-cloud-dependencies.version>2021.0.7</spring-cloud-dependencies.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
@ -1,8 +1,8 @@
|
||||
package com.baeldung.spring.cloud.bootstrap.gateway;
|
||||
|
||||
import org.springframework.boot.web.servlet.ErrorPage;
|
||||
import org.springframework.boot.web.servlet.ErrorPageRegistrar;
|
||||
import org.springframework.boot.web.servlet.ErrorPageRegistry;
|
||||
import org.springframework.boot.web.server.ErrorPage;
|
||||
import org.springframework.boot.web.server.ErrorPageRegistrar;
|
||||
import org.springframework.boot.web.server.ErrorPageRegistry;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
|
@ -1,76 +1,15 @@
|
||||
package com.baeldung.spring.cloud.bootstrap.gateway;
|
||||
|
||||
import com.netflix.appinfo.InstanceInfo;
|
||||
import com.netflix.discovery.EurekaClient;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
|
||||
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
|
||||
import org.springframework.cloud.netflix.feign.EnableFeignClients;
|
||||
import org.springframework.cloud.netflix.ribbon.RibbonClientSpecification;
|
||||
import org.springframework.cloud.netflix.ribbon.SpringClientFactory;
|
||||
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
|
||||
import org.springframework.cloud.sleuth.metric.SpanMetricReporter;
|
||||
import org.springframework.cloud.sleuth.zipkin.HttpZipkinSpanReporter;
|
||||
import org.springframework.cloud.sleuth.zipkin.ZipkinProperties;
|
||||
import org.springframework.cloud.sleuth.zipkin.ZipkinSpanReporter;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import zipkin.Span;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
|
||||
import org.springframework.cloud.openfeign.EnableFeignClients;
|
||||
|
||||
@SpringBootApplication
|
||||
@EnableZuulProxy
|
||||
@EnableEurekaClient
|
||||
@EnableFeignClients
|
||||
@EnableDiscoveryClient
|
||||
public class GatewayApplication {
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(GatewayApplication.class, args);
|
||||
}
|
||||
|
||||
@Autowired(required = false)
|
||||
private List<RibbonClientSpecification> configurations = new ArrayList<>();
|
||||
@Autowired
|
||||
private EurekaClient eurekaClient;
|
||||
@Autowired
|
||||
private SpanMetricReporter spanMetricReporter;
|
||||
@Autowired
|
||||
private ZipkinProperties zipkinProperties;
|
||||
@Value("${spring.sleuth.web.skipPattern}")
|
||||
private String skipPattern;
|
||||
|
||||
@Bean
|
||||
@LoadBalanced
|
||||
RestTemplate restTemplate() {
|
||||
return new RestTemplate();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SpringClientFactory springClientFactory() {
|
||||
SpringClientFactory factory = new SpringClientFactory();
|
||||
factory.setConfigurations(this.configurations);
|
||||
return factory;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ZipkinSpanReporter makeZipkinSpanReporter() {
|
||||
return new ZipkinSpanReporter() {
|
||||
private HttpZipkinSpanReporter delegate;
|
||||
private String baseUrl;
|
||||
|
||||
@Override
|
||||
public void report(Span span) {
|
||||
InstanceInfo instance = eurekaClient.getNextServerFromEureka("zipkin", false);
|
||||
if (baseUrl == null || !instance.getHomePageUrl().equals(baseUrl)) {
|
||||
baseUrl = instance.getHomePageUrl();
|
||||
}
|
||||
delegate = new HttpZipkinSpanReporter(new RestTemplate(), baseUrl, zipkinProperties.getFlushInterval(), spanMetricReporter);
|
||||
if (!span.name.matches(skipPattern)) delegate.report(span);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -1,37 +1,59 @@
|
||||
package com.baeldung.spring.cloud.bootstrap.gateway;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import static org.springframework.security.config.Customizer.withDefaults;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
|
||||
import org.springframework.security.config.web.server.ServerHttpSecurity;
|
||||
import org.springframework.security.core.userdetails.MapReactiveUserDetailsService;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.security.web.server.SecurityWebFilterChain;
|
||||
import org.springframework.security.web.server.authentication.RedirectServerAuthenticationSuccessHandler;
|
||||
|
||||
@EnableWebSecurity
|
||||
@EnableWebFluxSecurity
|
||||
@Configuration
|
||||
public class SecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
public class SecurityConfig {
|
||||
|
||||
@Autowired
|
||||
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth.inMemoryAuthentication()
|
||||
.withUser("user").password("password").roles("USER")
|
||||
.and()
|
||||
.withUser("admin").password("admin").roles("ADMIN");
|
||||
@Bean
|
||||
public MapReactiveUserDetailsService userDetailsService() {
|
||||
UserDetails user = User.withUsername("user")
|
||||
.password(passwordEncoder().encode("password"))
|
||||
.roles("USER")
|
||||
.build();
|
||||
UserDetails adminUser = User.withUsername("admin")
|
||||
.password(passwordEncoder().encode("admin"))
|
||||
.roles("ADMIN")
|
||||
.build();
|
||||
return new MapReactiveUserDetailsService(user, adminUser);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.formLogin()
|
||||
.defaultSuccessUrl("/home/index.html", true)
|
||||
@Bean
|
||||
public PasswordEncoder passwordEncoder() {
|
||||
return new BCryptPasswordEncoder();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
|
||||
http.formLogin()
|
||||
.authenticationSuccessHandler(new RedirectServerAuthenticationSuccessHandler("/home/index.html"))
|
||||
.and()
|
||||
.authorizeRequests()
|
||||
.antMatchers("/book-service/**", "/rating-service/**", "/login*", "/").permitAll()
|
||||
.antMatchers("/eureka/**").hasRole("ADMIN")
|
||||
.anyRequest().authenticated()
|
||||
.authorizeExchange()
|
||||
.pathMatchers("/book-service/**", "/rating-service/**", "/login*", "/")
|
||||
.permitAll()
|
||||
.pathMatchers("/eureka/**")
|
||||
.hasRole("ADMIN")
|
||||
.anyExchange()
|
||||
.authenticated()
|
||||
.and()
|
||||
.logout()
|
||||
.logout()
|
||||
.and()
|
||||
.csrf().disable();
|
||||
.csrf()
|
||||
.disable()
|
||||
.httpBasic(withDefaults());
|
||||
return http.build();
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,10 @@
|
||||
package com.baeldung.spring.cloud.bootstrap.gateway;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.session.data.redis.RedisFlushMode;
|
||||
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;
|
||||
import org.springframework.session.web.context.AbstractHttpSessionApplicationInitializer;
|
||||
import org.springframework.session.data.redis.config.annotation.web.server.EnableRedisWebSession;
|
||||
|
||||
@Configuration
|
||||
@EnableRedisHttpSession(redisFlushMode = RedisFlushMode.IMMEDIATE)
|
||||
public class SessionConfig extends AbstractHttpSessionApplicationInitializer {
|
||||
@EnableRedisWebSession
|
||||
public class SessionConfig {
|
||||
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
package com.baeldung.spring.cloud.bootstrap.gateway.client.book;
|
||||
|
||||
import org.springframework.cloud.netflix.feign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
@ -9,6 +8,6 @@ import org.springframework.web.bind.annotation.RequestMethod;
|
||||
@FeignClient(value = "book-service")
|
||||
public interface BooksClient {
|
||||
|
||||
@RequestMapping(value = "/books/{bookId}", method = {RequestMethod.GET})
|
||||
@RequestMapping(value = "/books/{bookId}", method = { RequestMethod.GET })
|
||||
Book getBookById(@PathVariable("bookId") Long bookId);
|
||||
}
|
||||
|
@ -1,17 +1,16 @@
|
||||
package com.baeldung.spring.cloud.bootstrap.gateway.client.rating;
|
||||
|
||||
import org.springframework.cloud.netflix.feign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.RequestHeader;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@FeignClient(value = "rating-service")
|
||||
public interface RatingsClient {
|
||||
|
||||
@RequestMapping(value = "/ratings", method = {RequestMethod.GET})
|
||||
@RequestMapping(value = "/ratings", method = { RequestMethod.GET })
|
||||
List<Rating> getRatingsByBookId(@RequestParam("bookId") Long bookId, @RequestHeader("Cookie") String session);
|
||||
}
|
||||
|
@ -0,0 +1,25 @@
|
||||
package com.baeldung.spring.cloud.bootstrap.gateway.filter;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
|
||||
import org.springframework.cloud.gateway.filter.GlobalFilter;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
@Component
|
||||
public class SessionSavingPreFilter implements GlobalFilter {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(SessionSavingPreFilter.class);
|
||||
|
||||
@Override
|
||||
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
|
||||
return exchange.getSession()
|
||||
.flatMap(session -> {
|
||||
logger.debug("SessionId: {}", session.getId());
|
||||
return chain.filter(exchange);
|
||||
});
|
||||
}
|
||||
}
|
@ -1,47 +0,0 @@
|
||||
package com.baeldung.spring.cloud.bootstrap.gateway.filter;
|
||||
|
||||
import com.netflix.zuul.ZuulFilter;
|
||||
import com.netflix.zuul.context.RequestContext;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.session.Session;
|
||||
import org.springframework.session.SessionRepository;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
@Component
|
||||
public class SessionSavingZuulPreFilter extends ZuulFilter {
|
||||
|
||||
private Logger log = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
@Autowired
|
||||
private SessionRepository repository;
|
||||
|
||||
@Override
|
||||
public boolean shouldFilter() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object run() {
|
||||
RequestContext context = RequestContext.getCurrentContext();
|
||||
HttpSession httpSession = context.getRequest().getSession();
|
||||
Session session = repository.getSession(httpSession.getId());
|
||||
|
||||
context.addZuulRequestHeader("Cookie", "SESSION=" + httpSession.getId());
|
||||
log.info("ZuulPreFilter session proxy: {}", session.getId());
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String filterType() {
|
||||
return "pre";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int filterOrder() {
|
||||
return 0;
|
||||
}
|
||||
}
|
@ -3,5 +3,7 @@ spring.cloud.config.discovery.service-id=config
|
||||
spring.cloud.config.discovery.enabled=true
|
||||
spring.cloud.config.username=configUser
|
||||
spring.cloud.config.password=configPassword
|
||||
spring.cloud.gateway.discovery.locator.enabled=true
|
||||
spring.cloud.gateway.discovery.locator.lowerCaseServiceId=true
|
||||
|
||||
eureka.client.serviceUrl.defaultZone=http://discUser:discPassword@localhost:8082/eureka/
|
@ -20,7 +20,6 @@
|
||||
<module>gateway</module>
|
||||
<module>svc-book</module>
|
||||
<module>svc-rating</module>
|
||||
<module>zipkin</module>
|
||||
<module>customer-service</module>
|
||||
<module>order-service</module>
|
||||
</modules>
|
||||
|
@ -10,9 +10,9 @@
|
||||
|
||||
<parent>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>parent-boot-1</artifactId>
|
||||
<artifactId>parent-boot-2</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<relativePath>../../../parent-boot-1</relativePath>
|
||||
<relativePath>../../../parent-boot-2</relativePath>
|
||||
</parent>
|
||||
|
||||
<dependencyManagement>
|
||||
@ -34,7 +34,11 @@
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-eureka</artifactId>
|
||||
<artifactId>spring-cloud-starter-bootstrap</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
@ -46,7 +50,7 @@
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.session</groupId>
|
||||
<artifactId>spring-session</artifactId>
|
||||
<artifactId>spring-session-data-redis</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
@ -63,12 +67,16 @@
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-zipkin</artifactId>
|
||||
<artifactId>spring-cloud-starter-sleuth</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-sleuth-zipkin</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<properties>
|
||||
<spring-cloud-dependencies.version>Dalston.RELEASE</spring-cloud-dependencies.version>
|
||||
<spring-cloud-dependencies.version>2021.0.7</spring-cloud-dependencies.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
@ -1,53 +1,14 @@
|
||||
package com.baeldung.spring.cloud.bootstrap.svcbook;
|
||||
|
||||
import com.netflix.appinfo.InstanceInfo;
|
||||
import com.netflix.discovery.EurekaClient;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
|
||||
import org.springframework.cloud.sleuth.metric.SpanMetricReporter;
|
||||
import org.springframework.cloud.sleuth.zipkin.HttpZipkinSpanReporter;
|
||||
import org.springframework.cloud.sleuth.zipkin.ZipkinProperties;
|
||||
import org.springframework.cloud.sleuth.zipkin.ZipkinSpanReporter;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import zipkin.Span;
|
||||
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
|
||||
|
||||
@SpringBootApplication
|
||||
@EnableEurekaClient
|
||||
@EnableDiscoveryClient
|
||||
public class BookServiceApplication {
|
||||
|
||||
@Autowired
|
||||
private EurekaClient eurekaClient;
|
||||
@Autowired
|
||||
private SpanMetricReporter spanMetricReporter;
|
||||
@Autowired
|
||||
private ZipkinProperties zipkinProperties;
|
||||
@Value("${spring.sleuth.web.skipPattern}")
|
||||
private String skipPattern;
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(BookServiceApplication.class, args);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ZipkinSpanReporter makeZipkinSpanReporter() {
|
||||
return new ZipkinSpanReporter() {
|
||||
private HttpZipkinSpanReporter delegate;
|
||||
private String baseUrl;
|
||||
|
||||
@Override
|
||||
public void report(Span span) {
|
||||
InstanceInfo instance = eurekaClient.getNextServerFromEureka("zipkin", false);
|
||||
if (baseUrl == null || !instance.getHomePageUrl().equals(baseUrl)) {
|
||||
baseUrl = instance.getHomePageUrl();
|
||||
}
|
||||
delegate = new HttpZipkinSpanReporter(new RestTemplate(), baseUrl, zipkinProperties.getFlushInterval(), spanMetricReporter);
|
||||
if (!span.name.matches(skipPattern)) delegate.report(span);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,16 @@
|
||||
package com.baeldung.spring.cloud.bootstrap.svcbook;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.session.web.http.DefaultCookieSerializer;
|
||||
|
||||
@Configuration
|
||||
public class CookieConfig {
|
||||
|
||||
@Bean
|
||||
public DefaultCookieSerializer cookieSerializer() {
|
||||
DefaultCookieSerializer serializer = new DefaultCookieSerializer();
|
||||
serializer.setUseBase64Encoding(false);
|
||||
return serializer;
|
||||
}
|
||||
}
|
@ -1,36 +1,37 @@
|
||||
package com.baeldung.spring.cloud.bootstrap.svcbook;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
|
||||
@EnableWebSecurity
|
||||
@Configuration
|
||||
public class SecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
public class SecurityConfig {
|
||||
|
||||
@Autowired
|
||||
public void configureGlobal1(AuthenticationManagerBuilder auth) throws Exception {
|
||||
//try in memory auth with no users to support the case that this will allow for users that are logged in to go anywhere
|
||||
public void registerAuthProvider(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth.inMemoryAuthentication();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http.httpBasic()
|
||||
@Bean
|
||||
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||
return http.authorizeHttpRequests((auth) -> auth.antMatchers(HttpMethod.GET, "/books")
|
||||
.permitAll()
|
||||
.antMatchers(HttpMethod.GET, "/books/*")
|
||||
.permitAll()
|
||||
.antMatchers(HttpMethod.POST, "/books")
|
||||
.hasRole("ADMIN")
|
||||
.antMatchers(HttpMethod.PATCH, "/books/*")
|
||||
.hasRole("ADMIN")
|
||||
.antMatchers(HttpMethod.DELETE, "/books/*")
|
||||
.hasRole("ADMIN"))
|
||||
.csrf()
|
||||
.disable()
|
||||
.authorizeRequests()
|
||||
.antMatchers(HttpMethod.GET, "/books").permitAll()
|
||||
.antMatchers(HttpMethod.GET, "/books/*").permitAll()
|
||||
.antMatchers(HttpMethod.POST, "/books").hasRole("ADMIN")
|
||||
.antMatchers(HttpMethod.PATCH, "/books/*").hasRole("ADMIN")
|
||||
.antMatchers(HttpMethod.DELETE, "/books/*").hasRole("ADMIN")
|
||||
.anyRequest().authenticated()
|
||||
.and()
|
||||
.csrf()
|
||||
.disable();
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,6 @@ package com.baeldung.spring.cloud.bootstrap.svcbook.book;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
@ -23,8 +22,8 @@ public class BookService {
|
||||
}
|
||||
|
||||
public Book findBookById(Long bookId) {
|
||||
return Optional.ofNullable(bookRepository.findOne(bookId))
|
||||
.orElseThrow(() -> new BookNotFoundException("Book not found. ID: " + bookId));
|
||||
return bookRepository.findById(bookId)
|
||||
.orElseThrow(() -> new BookNotFoundException(String.format("Book not found. ID: %s", bookId)));
|
||||
}
|
||||
|
||||
@Transactional(propagation = Propagation.REQUIRED)
|
||||
@ -37,7 +36,7 @@ public class BookService {
|
||||
|
||||
@Transactional(propagation = Propagation.REQUIRED)
|
||||
public void deleteBook(Long bookId) {
|
||||
bookRepository.delete(bookId);
|
||||
bookRepository.deleteById(bookId);
|
||||
}
|
||||
|
||||
@Transactional(propagation = Propagation.REQUIRED)
|
||||
@ -60,7 +59,8 @@ public class BookService {
|
||||
public Book updateBook(Book book, Long bookId) {
|
||||
Preconditions.checkNotNull(book);
|
||||
Preconditions.checkState(book.getId() == bookId);
|
||||
Preconditions.checkNotNull(bookRepository.findOne(bookId));
|
||||
Preconditions.checkArgument(bookRepository.findById(bookId)
|
||||
.isPresent());
|
||||
return bookRepository.save(book);
|
||||
}
|
||||
}
|
||||
|
@ -3,5 +3,7 @@ spring.cloud.config.discovery.service-id=config
|
||||
spring.cloud.config.discovery.enabled=true
|
||||
spring.cloud.config.username=configUser
|
||||
spring.cloud.config.password=configPassword
|
||||
spring.cloud.gateway.discovery.locator.enabled=true
|
||||
spring.cloud.gateway.discovery.locator.lowerCaseServiceId=true
|
||||
|
||||
eureka.client.serviceUrl.defaultZone=http://discUser:discPassword@localhost:8082/eureka/
|
@ -10,9 +10,9 @@
|
||||
|
||||
<parent>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>parent-boot-1</artifactId>
|
||||
<artifactId>parent-boot-2</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<relativePath>../../../parent-boot-1</relativePath>
|
||||
<relativePath>../../../parent-boot-2</relativePath>
|
||||
</parent>
|
||||
|
||||
<dependencyManagement>
|
||||
@ -34,7 +34,11 @@
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-eureka</artifactId>
|
||||
<artifactId>spring-cloud-starter-bootstrap</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
@ -46,7 +50,7 @@
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.session</groupId>
|
||||
<artifactId>spring-session</artifactId>
|
||||
<artifactId>spring-session-data-redis</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
@ -58,25 +62,29 @@
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-hystrix</artifactId>
|
||||
<artifactId>spring-cloud-starter-circuitbreaker-resilience4j</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-sleuth</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-sleuth-zipkin</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-zipkin</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<properties>
|
||||
<spring-cloud-dependencies.version>Dalston.RELEASE</spring-cloud-dependencies.version>
|
||||
<spring-cloud-dependencies.version>2021.0.7</spring-cloud-dependencies.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
@ -0,0 +1,16 @@
|
||||
package com.baeldung.spring.cloud.bootstrap.svcrating;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.session.web.http.DefaultCookieSerializer;
|
||||
|
||||
@Configuration
|
||||
public class CookieConfig {
|
||||
|
||||
@Bean
|
||||
public DefaultCookieSerializer cookieSerializer() {
|
||||
DefaultCookieSerializer serializer = new DefaultCookieSerializer();
|
||||
serializer.setUseBase64Encoding(false);
|
||||
return serializer;
|
||||
}
|
||||
}
|
@ -1,69 +1,18 @@
|
||||
package com.baeldung.spring.cloud.bootstrap.svcrating;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
|
||||
import org.springframework.cloud.netflix.hystrix.EnableHystrix;
|
||||
import org.springframework.cloud.sleuth.metric.SpanMetricReporter;
|
||||
import org.springframework.cloud.sleuth.zipkin.HttpZipkinSpanReporter;
|
||||
import org.springframework.cloud.sleuth.zipkin.ZipkinProperties;
|
||||
import org.springframework.cloud.sleuth.zipkin.ZipkinSpanReporter;
|
||||
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
|
||||
import org.springframework.context.annotation.AdviceMode;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import com.netflix.appinfo.InstanceInfo;
|
||||
import com.netflix.discovery.EurekaClient;
|
||||
import com.netflix.hystrix.contrib.javanica.aop.aspectj.HystrixCommandAspect;
|
||||
|
||||
import zipkin.Span;
|
||||
|
||||
@SpringBootApplication
|
||||
@EnableEurekaClient
|
||||
@EnableHystrix
|
||||
@EnableTransactionManagement(order=Ordered.LOWEST_PRECEDENCE, mode=AdviceMode.ASPECTJ)
|
||||
@EnableDiscoveryClient
|
||||
@EnableTransactionManagement(order = Ordered.LOWEST_PRECEDENCE, mode = AdviceMode.ASPECTJ)
|
||||
public class RatingServiceApplication {
|
||||
@Autowired
|
||||
private EurekaClient eurekaClient;
|
||||
@Autowired
|
||||
private SpanMetricReporter spanMetricReporter;
|
||||
@Autowired
|
||||
private ZipkinProperties zipkinProperties;
|
||||
@Value("${spring.sleuth.web.skipPattern}")
|
||||
private String skipPattern;
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(RatingServiceApplication.class, args);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ZipkinSpanReporter makeZipkinSpanReporter() {
|
||||
return new ZipkinSpanReporter() {
|
||||
private HttpZipkinSpanReporter delegate;
|
||||
private String baseUrl;
|
||||
|
||||
@Override
|
||||
public void report(Span span) {
|
||||
InstanceInfo instance = eurekaClient.getNextServerFromEureka("zipkin", false);
|
||||
if (baseUrl == null || !instance.getHomePageUrl().equals(baseUrl)) {
|
||||
baseUrl = instance.getHomePageUrl();
|
||||
}
|
||||
delegate = new HttpZipkinSpanReporter(new RestTemplate(), baseUrl, zipkinProperties.getFlushInterval(), spanMetricReporter);
|
||||
if (!span.name.matches(skipPattern)) delegate.report(span);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Primary
|
||||
@Order(value=Ordered.HIGHEST_PRECEDENCE)
|
||||
public HystrixCommandAspect hystrixAspect() {
|
||||
return new HystrixCommandAspect();
|
||||
}
|
||||
}
|
@ -1,39 +1,41 @@
|
||||
package com.baeldung.spring.cloud.bootstrap.svcrating;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
|
||||
@EnableWebSecurity
|
||||
@Configuration
|
||||
public class SecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
public class SecurityConfig {
|
||||
|
||||
@Autowired
|
||||
public void configureGlobal1(AuthenticationManagerBuilder auth) throws Exception {
|
||||
//try in memory auth with no users to support the case that this will allow for users that are logged in to go anywhere
|
||||
auth.inMemoryAuthentication();
|
||||
@Bean
|
||||
public UserDetailsService users() {
|
||||
return new InMemoryUserDetailsManager();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.regexMatchers("^/ratings\\?bookId.*$").authenticated()
|
||||
.antMatchers(HttpMethod.POST,"/ratings").authenticated()
|
||||
.antMatchers(HttpMethod.PATCH,"/ratings/*").hasRole("ADMIN")
|
||||
.antMatchers(HttpMethod.DELETE,"/ratings/*").hasRole("ADMIN")
|
||||
.antMatchers(HttpMethod.GET,"/ratings").hasRole("ADMIN")
|
||||
.antMatchers(HttpMethod.GET,"/hystrix").authenticated()
|
||||
.anyRequest().authenticated()
|
||||
@Bean
|
||||
public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {
|
||||
return httpSecurity.authorizeHttpRequests((auth) -> auth.regexMatchers("^/ratings\\?bookId.*$")
|
||||
.authenticated()
|
||||
.antMatchers(HttpMethod.POST, "/ratings")
|
||||
.authenticated()
|
||||
.antMatchers(HttpMethod.PATCH, "/ratings/*")
|
||||
.hasRole("ADMIN")
|
||||
.antMatchers(HttpMethod.DELETE, "/ratings/*")
|
||||
.hasRole("ADMIN")
|
||||
.antMatchers(HttpMethod.GET, "/ratings")
|
||||
.hasRole("ADMIN")
|
||||
.anyRequest()
|
||||
.authenticated())
|
||||
.httpBasic()
|
||||
.and()
|
||||
.httpBasic().and()
|
||||
.csrf()
|
||||
.disable();
|
||||
|
||||
|
||||
.csrf()
|
||||
.disable()
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
@ -5,24 +5,24 @@ import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
|
||||
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
|
||||
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
|
||||
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;
|
||||
import org.springframework.session.web.context.AbstractHttpSessionApplicationInitializer;
|
||||
|
||||
@Configuration
|
||||
@EnableRedisHttpSession
|
||||
public class SessionConfig extends AbstractHttpSessionApplicationInitializer {
|
||||
|
||||
@Autowired
|
||||
Environment properties;
|
||||
|
||||
private Environment properties;
|
||||
|
||||
@Bean
|
||||
@Primary
|
||||
public JedisConnectionFactory connectionFactory() {
|
||||
JedisConnectionFactory factory = new JedisConnectionFactory();
|
||||
factory.setHostName(properties.getProperty("spring.redis.host","localhost"));
|
||||
factory.setPort(properties.getProperty("spring.redis.port", Integer.TYPE,6379));
|
||||
factory.afterPropertiesSet();
|
||||
factory.setUsePool(true);
|
||||
return factory;
|
||||
public LettuceConnectionFactory redisConnectionFactory() {
|
||||
RedisStandaloneConfiguration redisConfiguration = new RedisStandaloneConfiguration();
|
||||
redisConfiguration.setHostName(properties.getProperty("spring.redis.host", "localhost"));
|
||||
redisConfiguration.setPort(properties.getProperty("spring.redis.port", Integer.TYPE, 6379));
|
||||
return new LettuceConnectionFactory(redisConfiguration);
|
||||
}
|
||||
}
|
||||
|
@ -6,21 +6,21 @@ import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
|
||||
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
|
||||
import org.springframework.data.redis.core.SetOperations;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.data.redis.core.ValueOperations;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public class RatingCacheRepository implements InitializingBean {
|
||||
|
||||
@Autowired
|
||||
private JedisConnectionFactory cacheConnectionFactory;
|
||||
private LettuceConnectionFactory cacheConnectionFactory;
|
||||
|
||||
private StringRedisTemplate redisTemplate;
|
||||
private ValueOperations<String, String> valueOps;
|
||||
|
@ -2,7 +2,6 @@ package com.baeldung.spring.cloud.bootstrap.svcrating.rating;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
@ -10,7 +9,8 @@ import org.springframework.transaction.annotation.Propagation;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
|
||||
|
||||
import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker;
|
||||
|
||||
@Service
|
||||
@Transactional(readOnly = true)
|
||||
@ -22,31 +22,31 @@ public class RatingService {
|
||||
@Autowired
|
||||
private RatingCacheRepository cacheRepository;
|
||||
|
||||
@HystrixCommand(commandKey = "ratingsByBookIdFromDB", fallbackMethod = "findCachedRatingsByBookId")
|
||||
@CircuitBreaker(name = "ratingsByBookIdFromDB", fallbackMethod = "findCachedRatingsByBookId")
|
||||
public List<Rating> findRatingsByBookId(Long bookId) {
|
||||
return ratingRepository.findRatingsByBookId(bookId);
|
||||
}
|
||||
|
||||
public List<Rating> findCachedRatingsByBookId(Long bookId) {
|
||||
public List<Rating> findCachedRatingsByBookId(Long bookId, Exception exception) {
|
||||
return cacheRepository.findCachedRatingsByBookId(bookId);
|
||||
}
|
||||
|
||||
@HystrixCommand(commandKey = "ratingsFromDB", fallbackMethod = "findAllCachedRatings")
|
||||
@CircuitBreaker(name = "ratingsFromDB", fallbackMethod = "findAllCachedRatings")
|
||||
public List<Rating> findAllRatings() {
|
||||
return ratingRepository.findAll();
|
||||
}
|
||||
|
||||
public List<Rating> findAllCachedRatings() {
|
||||
public List<Rating> findAllCachedRatings(Exception exception) {
|
||||
return cacheRepository.findAllCachedRatings();
|
||||
}
|
||||
|
||||
@HystrixCommand(commandKey = "ratingsByIdFromDB", fallbackMethod = "findCachedRatingById", ignoreExceptions = { RatingNotFoundException.class })
|
||||
@CircuitBreaker(name = "ratingsByIdFromDB", fallbackMethod = "findCachedRatingById")
|
||||
public Rating findRatingById(Long ratingId) {
|
||||
return Optional.ofNullable(ratingRepository.findOne(ratingId))
|
||||
return ratingRepository.findById(ratingId)
|
||||
.orElseThrow(() -> new RatingNotFoundException("Rating not found. ID: " + ratingId));
|
||||
}
|
||||
|
||||
public Rating findCachedRatingById(Long ratingId) {
|
||||
public Rating findCachedRatingById(Long ratingId, Exception exception) {
|
||||
return cacheRepository.findCachedRatingById(ratingId);
|
||||
}
|
||||
|
||||
@ -62,7 +62,7 @@ public class RatingService {
|
||||
|
||||
@Transactional(propagation = Propagation.REQUIRED)
|
||||
public void deleteRating(Long ratingId) {
|
||||
ratingRepository.delete(ratingId);
|
||||
ratingRepository.deleteById(ratingId);
|
||||
cacheRepository.deleteRating(ratingId);
|
||||
}
|
||||
|
||||
@ -86,7 +86,7 @@ public class RatingService {
|
||||
public Rating updateRating(Rating rating, Long ratingId) {
|
||||
Preconditions.checkNotNull(rating);
|
||||
Preconditions.checkState(rating.getId() == ratingId);
|
||||
Preconditions.checkNotNull(ratingRepository.findOne(ratingId));
|
||||
Preconditions.checkNotNull(ratingRepository.findById(ratingId));
|
||||
return ratingRepository.save(rating);
|
||||
}
|
||||
|
||||
|
@ -3,5 +3,7 @@ spring.cloud.config.discovery.service-id=config
|
||||
spring.cloud.config.discovery.enabled=true
|
||||
spring.cloud.config.username=configUser
|
||||
spring.cloud.config.password=configPassword
|
||||
spring.cloud.gateway.discovery.locator.enabled=true
|
||||
spring.cloud.gateway.discovery.locator.lowerCaseServiceId=true
|
||||
|
||||
eureka.client.serviceUrl.defaultZone=http://discUser:discPassword@localhost:8082/eureka/
|
||||
|
19
spring-cloud-modules/spring-cloud-bootstrap/zipkin/README.md
Normal file
19
spring-cloud-modules/spring-cloud-bootstrap/zipkin/README.md
Normal file
@ -0,0 +1,19 @@
|
||||
# Zipkin server
|
||||
|
||||
Zipkin project [deprecated custom server](https://github.com/openzipkin/zipkin/tree/master/zipkin-server).
|
||||
It's no longer possible to run a custom Zipkin server compatible with Spring Cloud or even Spring Boot.
|
||||
|
||||
The best approach to run a Zipkin server is to use docker. We provided a docker-compose file that you can run:
|
||||
|
||||
```bash
|
||||
$ docker compose up -d
|
||||
```
|
||||
|
||||
After that Zipkin is accessible via [http://localhost:9411](http://localhost:9411)
|
||||
|
||||
Alternatively, you can run the Zipkin Jar file,
|
||||
|
||||
```bash
|
||||
$ curl -sSL https://zipkin.io/quickstart.sh | bash -s
|
||||
$ java -jar zipkin.jar
|
||||
```
|
@ -0,0 +1,6 @@
|
||||
version: "3.9"
|
||||
services:
|
||||
zipkin:
|
||||
image: openzipkin/zipkin
|
||||
ports:
|
||||
- 9411:9411
|
@ -1,53 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>zipkin</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<name>zipkin</name>
|
||||
|
||||
<parent>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>parent-boot-1</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<relativePath>../../../parent-boot-1</relativePath>
|
||||
</parent>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-dependencies</artifactId>
|
||||
<version>${spring-cloud-dependencies.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-config</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-eureka</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.zipkin.java</groupId>
|
||||
<artifactId>zipkin-server</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.zipkin.java</groupId>
|
||||
<artifactId>zipkin-autoconfigure-ui</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<properties>
|
||||
<spring-cloud-dependencies.version>Brixton.SR7</spring-cloud-dependencies.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
@ -1,15 +0,0 @@
|
||||
package com.baeldung.spring.cloud.bootstrap.zipkin;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
|
||||
import zipkin.server.EnableZipkinServer;
|
||||
|
||||
@SpringBootApplication
|
||||
@EnableEurekaClient
|
||||
@EnableZipkinServer
|
||||
public class ZipkinApplication {
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(ZipkinApplication.class, args);
|
||||
}
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
spring.cloud.config.name=zipkin
|
||||
spring.cloud.config.discovery.service-id=config
|
||||
spring.cloud.config.discovery.enabled=true
|
||||
spring.cloud.config.username=configUser
|
||||
spring.cloud.config.password=configPassword
|
||||
|
||||
eureka.client.serviceUrl.defaultZone=http://discUser:discPassword@localhost:8082/eureka/
|
@ -1,13 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration>
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
|
||||
</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<root level="INFO">
|
||||
<appender-ref ref="STDOUT" />
|
||||
</root>
|
||||
</configuration>
|
@ -1,17 +0,0 @@
|
||||
package com.baeldung;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import com.baeldung.spring.cloud.bootstrap.zipkin.ZipkinApplication;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(classes = ZipkinApplication.class)
|
||||
public class SpringContextTest {
|
||||
|
||||
@Test
|
||||
public void whenSpringContextIsBootstrapped_thenNoExceptions() {
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user