JAVA-3090: updating README.md for spring-reactive

This commit is contained in:
chaos2418
2021-12-15 09:37:47 +05:30
parent 0cb9125701
commit 7432cc2ee2
74 changed files with 10 additions and 3010 deletions
@@ -1,75 +0,0 @@
package com.baeldung.reactive.functional;
import static org.springframework.web.reactive.function.BodyExtractors.toMono;
import static org.springframework.web.reactive.function.server.RequestPredicates.GET;
import static org.springframework.web.reactive.function.server.RequestPredicates.POST;
import static org.springframework.web.reactive.function.server.RouterFunctions.route;
import static org.springframework.web.reactive.function.server.ServerResponse.ok;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.web.server.SecurityWebFilterChain;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.ServerResponse;
import com.baeldung.webflux.Employee;
import com.baeldung.webflux.EmployeeRepository;
@Configuration
public class EmployeeFunctionalConfig {
@Bean
EmployeeRepository employeeRepository() {
return new EmployeeRepository();
}
@Bean
RouterFunction<ServerResponse> getAllEmployeesRoute() {
return route(GET("/employees"),
req -> ok().body(
employeeRepository().findAllEmployees(), Employee.class));
}
@Bean
RouterFunction<ServerResponse> getEmployeeByIdRoute() {
return route(GET("/employees/{id}"),
req -> ok().body(
employeeRepository().findEmployeeById(req.pathVariable("id")), Employee.class));
}
@Bean
RouterFunction<ServerResponse> updateEmployeeRoute() {
return route(POST("/employees/update"),
req -> req.body(toMono(Employee.class))
.doOnNext(employeeRepository()::updateEmployee)
.then(ok().build()));
}
@Bean
RouterFunction<ServerResponse> composedRoutes() {
return
route(GET("/employees"),
req -> ok().body(
employeeRepository().findAllEmployees(), Employee.class))
.and(route(GET("/employees/{id}"),
req -> ok().body(
employeeRepository().findEmployeeById(req.pathVariable("id")), Employee.class)))
.and(route(POST("/employees/update"),
req -> req.body(toMono(Employee.class))
.doOnNext(employeeRepository()::updateEmployee)
.then(ok().build())));
}
@Bean
public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
http.csrf()
.disable()
.authorizeExchange()
.anyExchange()
.permitAll();
return http.build();
}
}
@@ -1,13 +0,0 @@
package com.baeldung.reactive.functional;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class EmployeeSpringFunctionalApplication {
public static void main(String[] args) {
SpringApplication.run(EmployeeSpringFunctionalApplication.class, args);
}
}
@@ -1,37 +0,0 @@
package com.baeldung.reactive.security;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;
import java.security.Principal;
@RestController
public class GreetController {
private GreetService greetService;
public GreetController(GreetService greetService) {
this.greetService = greetService;
}
@GetMapping("/")
public Mono<String> greet(Mono<Principal> principal) {
return principal
.map(Principal::getName)
.map(name -> String.format("Hello, %s", name));
}
@GetMapping("/admin")
public Mono<String> greetAdmin(Mono<Principal> principal) {
return principal
.map(Principal::getName)
.map(name -> String.format("Admin access: %s", name));
}
@GetMapping("/greetService")
public Mono<String> greetService() {
return greetService.greet();
}
}
@@ -1,15 +0,0 @@
package com.baeldung.reactive.security;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Mono;
@Service
public class GreetService {
@PreAuthorize("hasRole('ADMIN')")
public Mono<String> greet() {
return Mono.just("Hello from service!");
}
}
@@ -1,60 +0,0 @@
package com.baeldung.reactive.security;
import org.springframework.boot.actuate.autoconfigure.security.reactive.EndpointRequest;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.method.configuration.EnableReactiveMethodSecurity;
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 com.baeldung.reactive.actuator.FeaturesEndpoint;
@EnableWebFluxSecurity
@EnableReactiveMethodSecurity
public class SecurityConfig {
@Bean
public SecurityWebFilterChain securitygWebFilterChain(ServerHttpSecurity http) {
return http.authorizeExchange()
.pathMatchers("/admin")
.hasAuthority("ROLE_ADMIN")
.matchers(EndpointRequest.to(FeaturesEndpoint.class))
.permitAll()
.anyExchange()
.authenticated()
.and()
.formLogin()
.and()
.csrf()
.disable()
.build();
}
@Bean
public MapReactiveUserDetailsService userDetailsService() {
UserDetails user = User
.withUsername("user")
.password(passwordEncoder().encode("password"))
.roles("USER")
.build();
UserDetails admin = User
.withUsername("admin")
.password(passwordEncoder().encode("password"))
.roles("ADMIN")
.build();
return new MapReactiveUserDetailsService(user, admin);
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
@@ -1,35 +0,0 @@
package com.baeldung.reactive.security;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.http.server.reactive.HttpHandler;
import org.springframework.http.server.reactive.ReactorHttpHandlerAdapter;
import org.springframework.web.reactive.config.EnableWebFlux;
import org.springframework.web.server.adapter.WebHttpHandlerBuilder;
import reactor.netty.DisposableServer;
import reactor.netty.http.server.HttpServer;
@ComponentScan(basePackages = {"com.baeldung.reactive.security"})
@EnableWebFlux
public class SpringSecurity5Application {
public static void main(String[] args) {
try (AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(SpringSecurity5Application.class)) {
context.getBean(DisposableServer.class).onDispose().block();
}
}
@Bean
public DisposableServer disposableServer(ApplicationContext context) {
HttpHandler handler = WebHttpHandlerBuilder.applicationContext(context)
.build();
ReactorHttpHandlerAdapter adapter = new ReactorHttpHandlerAdapter(handler);
HttpServer httpServer = HttpServer.create().host("localhost").port(8083);
return httpServer.handle(adapter).bindNow();
}
}
@@ -1,38 +0,0 @@
package com.baeldung.webflux;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@RestController
@RequestMapping("/employees")
public class EmployeeController {
private EmployeeRepository employeeRepository;
public EmployeeController(EmployeeRepository employeeRepository) {
this.employeeRepository = employeeRepository;
}
@GetMapping("/{id}")
private Mono<Employee> getEmployeeById(@PathVariable String id) {
return employeeRepository.findEmployeeById(id);
}
@GetMapping
private Flux<Employee> getAllEmployees() {
return employeeRepository.findAllEmployees();
}
@PostMapping("/update")
private Mono<Employee> updateEmployee(@RequestBody Employee employee) {
return employeeRepository.updateEmployee(employee);
}
}
@@ -1,64 +0,0 @@
package com.baeldung.webflux;
import java.util.HashMap;
import java.util.Map;
import org.springframework.stereotype.Repository;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@Repository
public class EmployeeRepository {
static Map<String,Employee> employeeData;
static Map<String,String> employeeAccessData;
static
{
employeeData = new HashMap<>();
employeeData.put("1",new Employee("1","Employee 1"));
employeeData.put("2",new Employee("2","Employee 2"));
employeeData.put("3",new Employee("3","Employee 3"));
employeeData.put("4",new Employee("4","Employee 4"));
employeeData.put("5",new Employee("5","Employee 5"));
employeeData.put("6",new Employee("6","Employee 6"));
employeeData.put("7",new Employee("7","Employee 7"));
employeeData.put("8",new Employee("8","Employee 8"));
employeeData.put("9",new Employee("9","Employee 9"));
employeeData.put("10",new Employee("10","Employee 10"));
employeeAccessData=new HashMap<>();
employeeAccessData.put("1", "Employee 1 Access Key");
employeeAccessData.put("2", "Employee 2 Access Key");
employeeAccessData.put("3", "Employee 3 Access Key");
employeeAccessData.put("4", "Employee 4 Access Key");
employeeAccessData.put("5", "Employee 5 Access Key");
employeeAccessData.put("6", "Employee 6 Access Key");
employeeAccessData.put("7", "Employee 7 Access Key");
employeeAccessData.put("8", "Employee 8 Access Key");
employeeAccessData.put("9", "Employee 9 Access Key");
employeeAccessData.put("10", "Employee 10 Access Key");
}
public Mono<Employee> findEmployeeById(String id)
{
return Mono.just(employeeData.get(id));
}
public Flux<Employee> findAllEmployees()
{
return Flux.fromIterable(employeeData.values());
}
public Mono<Employee> updateEmployee(Employee employee)
{
Employee existingEmployee=employeeData.get(employee.getId());
if(existingEmployee!=null)
{
existingEmployee.setName(employee.getName());
}
return Mono.just(existingEmployee);
}
}
@@ -1,17 +0,0 @@
package com.baeldung.webflux;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class EmployeeSpringApplication {
public static void main(String[] args) {
SpringApplication.run(EmployeeSpringApplication.class, args);
EmployeeWebClient employeeWebClient = new EmployeeWebClient();
employeeWebClient.consume();
}
}
@@ -1,28 +0,0 @@
package com.baeldung.webflux;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
public class EmployeeWebClient {
WebClient client = WebClient.create("http://localhost:8080");
public void consume() {
Mono<Employee> employeeMono = client.get()
.uri("/employees/{id}", "1")
.retrieve()
.bodyToMono(Employee.class);
employeeMono.subscribe(System.out::println);
Flux<Employee> employeeFlux = client.get()
.uri("/employees")
.retrieve()
.bodyToFlux(Employee.class);
employeeFlux.subscribe(System.out::println);
}
}
@@ -1,14 +1,13 @@
package com.baeldung;
import com.baeldung.reactive.actuator.Spring5ReactiveApplication;
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.reactive.security.SpringSecurity5Application;
@RunWith(SpringRunner.class)
@SpringBootTest(classes = SpringSecurity5Application.class)
@SpringBootTest(classes = Spring5ReactiveApplication.class)
public class SpringContextTest {
@Test
@@ -1,92 +0,0 @@
package com.baeldung.reactive.functional;
import com.baeldung.webflux.Employee;
import com.baeldung.webflux.EmployeeRepository;
import org.junit.FixMethodOrder;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.MethodSorters;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.reactive.server.WebTestClient;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.util.Arrays;
import java.util.List;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.verify;
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = EmployeeSpringFunctionalApplication.class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class EmployeeSpringFunctionalIntegrationTest {
@Autowired
private EmployeeFunctionalConfig config;
@MockBean
private EmployeeRepository employeeRepository;
@Test
public void givenEmployeeId_whenGetEmployeeById_thenCorrectEmployee() {
WebTestClient client = WebTestClient
.bindToRouterFunction(config.getEmployeeByIdRoute())
.build();
Employee employee = new Employee("1", "Employee 1");
given(employeeRepository.findEmployeeById("1")).willReturn(Mono.just(employee));
client.get()
.uri("/employees/1")
.exchange()
.expectStatus()
.isOk()
.expectBody(Employee.class)
.isEqualTo(employee);
}
@Test
public void whenGetAllEmployees_thenCorrectEmployees() {
WebTestClient client = WebTestClient
.bindToRouterFunction(config.getAllEmployeesRoute())
.build();
List<Employee> employees = Arrays.asList(
new Employee("1", "Employee 1"),
new Employee("2", "Employee 2"));
Flux<Employee> employeeFlux = Flux.fromIterable(employees);
given(employeeRepository.findAllEmployees()).willReturn(employeeFlux);
client.get()
.uri("/employees")
.exchange()
.expectStatus()
.isOk()
.expectBodyList(Employee.class)
.isEqualTo(employees);
}
@Test
public void whenUpdateEmployee_thenEmployeeUpdated() {
WebTestClient client = WebTestClient
.bindToRouterFunction(config.updateEmployeeRoute())
.build();
Employee employee = new Employee("1", "Employee 1 Updated");
client.post()
.uri("/employees/update")
.body(Mono.just(employee), Employee.class)
.exchange()
.expectStatus()
.isOk();
verify(employeeRepository).updateEmployee(employee);
}
}
@@ -1,76 +0,0 @@
package com.baeldung.reactive.webflux;
import static org.mockito.BDDMockito.given;
import java.util.ArrayList;
import java.util.List;
import org.junit.FixMethodOrder;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.MethodSorters;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.reactive.server.WebTestClient;
import com.baeldung.webflux.EmployeeSpringApplication;
import com.baeldung.webflux.Employee;
import com.baeldung.webflux.EmployeeRepository;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes=EmployeeSpringApplication.class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class EmployeeControllerIntegrationTest {
@Autowired
private WebTestClient testClient;
@MockBean
private EmployeeRepository employeeRepository;
@Test
public void givenEmployeeId_whenGetEmployeeById_thenCorrectEmployee() {
Employee employee = new Employee("1", "Employee 1 Name");
given(employeeRepository.findEmployeeById("1")).willReturn(Mono.just(employee));
testClient.get()
.uri("/employees/1")
.exchange()
.expectStatus()
.isOk()
.expectBody(Employee.class)
.isEqualTo(employee);
}
@Test
public void whenGetAllEmployees_thenCorrectEmployees() {
List<Employee> employeeList = new ArrayList<>();
Employee employee1 = new Employee("1", "Employee 1 Name");
Employee employee2 = new Employee("2", "Employee 2 Name");
Employee employee3 = new Employee("3", "Employee 3 Name");
employeeList.add(employee1);
employeeList.add(employee2);
employeeList.add(employee3);
Flux<Employee> employeeFlux = Flux.fromIterable(employeeList);
given(employeeRepository.findAllEmployees()).willReturn(employeeFlux);
testClient.get()
.uri("/employees")
.exchange()
.expectStatus()
.isOk()
.expectBodyList(Employee.class)
.hasSize(3)
.isEqualTo(employeeList);
}
}
@@ -1,41 +0,0 @@
package com.baeldung.security;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.security.test.context.support.WithMockUser;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.reactive.server.WebTestClient;
import com.baeldung.reactive.security.SpringSecurity5Application;
@RunWith(SpringRunner.class)
@ContextConfiguration(classes = SpringSecurity5Application.class)
public class SecurityIntegrationTest {
@Autowired
ApplicationContext context;
private WebTestClient rest;
@Before
public void setup() {
this.rest = WebTestClient.bindToApplicationContext(this.context).configureClient().build();
}
@Test
public void whenNoCredentials_thenRedirectToLogin() {
this.rest.get().uri("/").exchange().expectStatus().is3xxRedirection();
}
@Test
@Ignore
@WithMockUser
public void whenHasCredentials_thenSeesGreeting() {
this.rest.get().uri("/").exchange().expectStatus().isOk().expectBody(String.class).isEqualTo("Hello, user");
}
}