Initial commit
This commit is contained in:
75
.gitignore
vendored
Normal file
75
.gitignore
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
*/bin/*
|
||||
|
||||
*.class
|
||||
|
||||
# Package Files #
|
||||
*.war
|
||||
*.ear
|
||||
|
||||
|
||||
# Eclipse
|
||||
.settings/
|
||||
*.project
|
||||
*.classpath
|
||||
.prefs
|
||||
*.prefs
|
||||
.metadata/
|
||||
|
||||
# Intellij
|
||||
.idea/
|
||||
*.iml
|
||||
*.iws
|
||||
|
||||
# Mac
|
||||
.DS_Store
|
||||
|
||||
# Maven
|
||||
log/
|
||||
target/
|
||||
|
||||
spring-openid/src/main/resources/application.properties
|
||||
.recommenders/
|
||||
/spring-hibernate4/nbproject/
|
||||
spring-security-openid/src/main/resources/application.properties
|
||||
|
||||
spring-all/*.log
|
||||
|
||||
SpringDataInjectionDemo/.mvn/wrapper/maven-wrapper.properties
|
||||
|
||||
spring-call-getters-using-reflection/.mvn/wrapper/maven-wrapper.properties
|
||||
|
||||
spring-check-if-a-property-is-null/.mvn/wrapper/maven-wrapper.properties
|
||||
*.springBeans
|
||||
|
||||
20171220-JMeter.csv
|
||||
|
||||
.factorypath
|
||||
dependency-reduced-pom.xml
|
||||
*.so
|
||||
*.dylib
|
||||
*.dll
|
||||
|
||||
xml/src/test/resources/example_dom4j_new.xml
|
||||
xml/src/test/resources/example_dom4j_updated.xml
|
||||
xml/src/test/resources/example_jaxb_new.xml
|
||||
core-java-io/hard_link.txt
|
||||
core-java-io/target_link.txt
|
||||
core-java/src/main/java/com/baeldung/manifest/MANIFEST.MF
|
||||
ethereum/logs/
|
||||
jmeter/src/main/resources/*-JMeter.csv
|
||||
|
||||
**/node_modules/
|
||||
**/dist
|
||||
**/tmp
|
||||
**/out-tsc
|
||||
**/nbproject/
|
||||
**/nb-configuration.xml
|
||||
core-scala/.cache-main
|
||||
core-scala/.cache-tests
|
||||
|
||||
|
||||
persistence-modules/hibernate5/transaction.log
|
||||
apache-avro/src/main/java/com/baeldung/avro/model/
|
||||
jta/transaction-logs/
|
||||
software-security/sql-injection-samples/derby.log
|
||||
spring-soap/src/main/java/com/baeldung/springsoap/gen/
|
||||
2
README.md
Normal file
2
README.md
Normal file
@@ -0,0 +1,2 @@
|
||||
### Relevant Articles:
|
||||
- [A quick and practical example of Hexagonal Architecture in Java](http://www.baeldung.com/a-quick-and-practical-example-of-hexagonal-architecture-in-java/)
|
||||
227
pom.xml
Normal file
227
pom.xml
Normal file
@@ -0,0 +1,227 @@
|
||||
<?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>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>hexagonal</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<description>A quick and practical example of Hexagonal Architecture in Java</description>
|
||||
<packaging>pom</packaging>
|
||||
<modules>
|
||||
<module>store-core</module>
|
||||
<module>store-persistence</module>
|
||||
<module>store-email-sender</module>
|
||||
<module>store-application</module>
|
||||
</modules>
|
||||
|
||||
<dependencies>
|
||||
<!-- logging -->
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
<version>${org.slf4j.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<version>${logback.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-core</artifactId>
|
||||
<version>${logback.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>jcl-over-slf4j</artifactId>
|
||||
<version>${org.slf4j.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- test -->
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>${junit.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-engine</artifactId>
|
||||
<version>${junit-jupiter.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-params</artifactId>
|
||||
<version>${junit-jupiter.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-api</artifactId>
|
||||
<version>${junit-jupiter.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hamcrest</groupId>
|
||||
<artifactId>hamcrest-core</artifactId>
|
||||
<version>${org.hamcrest.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hamcrest</groupId>
|
||||
<artifactId>hamcrest-library</artifactId>
|
||||
<version>${org.hamcrest.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hamcrest</groupId>
|
||||
<artifactId>hamcrest-all</artifactId>
|
||||
<version>${org.hamcrest.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<version>${mockito.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.maven.surefire</groupId>
|
||||
<artifactId>surefire-logger-api</artifactId>
|
||||
<version>${maven-surefire-plugin.version}</version>
|
||||
<!-- to get around bug https://github.com/junit-team/junit5/issues/801 -->
|
||||
<scope>test</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>exec-maven-plugin</artifactId>
|
||||
<version>${exec-maven-plugin.version}</version>
|
||||
<configuration>
|
||||
<executable>maven</executable>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>${maven-surefire-plugin.version}</version>
|
||||
<configuration>
|
||||
<forkCount>3</forkCount>
|
||||
<reuseForks>true</reuseForks>
|
||||
<excludes>
|
||||
<exclude>**/*IntegrationTest.java</exclude>
|
||||
<exclude>**/*IntTest.java</exclude>
|
||||
<exclude>**/*LongRunningUnitTest.java</exclude>
|
||||
<exclude>**/*ManualTest.java</exclude>
|
||||
<exclude>**/JdbcTest.java</exclude>
|
||||
<exclude>**/*LiveTest.java</exclude>
|
||||
</excludes>
|
||||
</configuration>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.junit.platform</groupId>
|
||||
<artifactId>junit-platform-surefire-provider</artifactId>
|
||||
<version>${junit-platform.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-engine</artifactId>
|
||||
<version>${junit-jupiter.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.vintage</groupId>
|
||||
<artifactId>junit-vintage-engine</artifactId>
|
||||
<version>${junit-jupiter.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>${maven-compiler-plugin.version}</version>
|
||||
<configuration>
|
||||
<source>${java.version}</source>
|
||||
<target>${java.version}</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
|
||||
<pluginManagement>
|
||||
<plugins>
|
||||
<!--This plugin's configuration is used to store Eclipse m2e settings
|
||||
only. It has no influence on the Maven build itself. -->
|
||||
<plugin>
|
||||
<groupId>org.eclipse.m2e</groupId>
|
||||
<artifactId>lifecycle-mapping</artifactId>
|
||||
<version>1.0.0</version>
|
||||
<configuration>
|
||||
<lifecycleMappingMetadata>
|
||||
<pluginExecutions>
|
||||
<pluginExecution>
|
||||
<pluginExecutionFilter>
|
||||
<groupId>
|
||||
org.commonjava.maven.plugins
|
||||
</groupId>
|
||||
<artifactId>
|
||||
directory-maven-plugin
|
||||
</artifactId>
|
||||
<versionRange>
|
||||
[0.3.1,)
|
||||
</versionRange>
|
||||
<goals>
|
||||
<goal>directory-of</goal>
|
||||
</goals>
|
||||
</pluginExecutionFilter>
|
||||
<action>
|
||||
<ignore></ignore>
|
||||
</action>
|
||||
</pluginExecution>
|
||||
<pluginExecution>
|
||||
<pluginExecutionFilter>
|
||||
<groupId>
|
||||
org.apache.maven.plugins
|
||||
</groupId>
|
||||
<artifactId>
|
||||
maven-install-plugin
|
||||
</artifactId>
|
||||
<versionRange>
|
||||
[2.5.1,)
|
||||
</versionRange>
|
||||
<goals>
|
||||
<goal>install-file</goal>
|
||||
</goals>
|
||||
</pluginExecutionFilter>
|
||||
<action>
|
||||
<ignore></ignore>
|
||||
</action>
|
||||
</pluginExecution>
|
||||
</pluginExecutions>
|
||||
</lifecycleMappingMetadata>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
</build>
|
||||
|
||||
|
||||
<properties>
|
||||
<junit.version>4.12</junit.version>
|
||||
<org.hamcrest.version>1.3</org.hamcrest.version>
|
||||
<mockito.version>2.21.0</mockito.version>
|
||||
<!-- plugins -->
|
||||
<maven-surefire-plugin.version>2.21.0</maven-surefire-plugin.version>
|
||||
<maven-compiler-plugin.version>3.7.0</maven-compiler-plugin.version>
|
||||
<exec-maven-plugin.version>1.6.0</exec-maven-plugin.version>
|
||||
<java.version>1.8</java.version>
|
||||
<junit-jupiter.version>5.2.0</junit-jupiter.version>
|
||||
<!-- logging -->
|
||||
<org.slf4j.version>1.7.21</org.slf4j.version>
|
||||
<junit-platform.version>1.2.0</junit-platform.version>
|
||||
<logback.version>1.1.7</logback.version>
|
||||
</properties>
|
||||
</project>
|
||||
89
store-application/pom.xml
Normal file
89
store-application/pom.xml
Normal file
@@ -0,0 +1,89 @@
|
||||
<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>store-application</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<parent>
|
||||
<artifactId>hexagonal-architecture</artifactId>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<relativePath>../../hexagonal-architecture</relativePath>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>store-core</artifactId>
|
||||
<version>${store.core.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>store-persistence</artifactId>
|
||||
<version>${store.core.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>store-email-sender</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-dependencies</artifactId>
|
||||
<version>${spring.boot.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>${maven-compiler-plugin.version}</version>
|
||||
<configuration>
|
||||
<source>${java.version}</source>
|
||||
<target>${java.version}</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<properties>
|
||||
<spring.boot.version>2.1.3.RELEASE</spring.boot.version>
|
||||
<store.core.version>1.0-SNAPSHOT</store.core.version>
|
||||
<store.persistence.version>1.0-SNAPSHOT</store.persistence.version>
|
||||
</properties>
|
||||
</project>
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.baeldung.hexagonal.store.application;
|
||||
|
||||
import com.baeldung.hexagonal.store.emailsender.EmailSenderConfig;
|
||||
import com.baeldung.hexagonal.store.persistence.PersistenceConfig;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
@SpringBootApplication
|
||||
@ComponentScan(basePackages = {"com.baeldung.hexagonal.store.application","com.baeldung.hexagonal.store.core"})
|
||||
@Import({PersistenceConfig.class, EmailSenderConfig.class})
|
||||
public class StoreApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(StoreApplication.class, args);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.baeldung.hexagonal.store.application.base;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public interface Mapper<F, T> {
|
||||
T map(F source);
|
||||
|
||||
default List<T> mapList(List<F> sourceList) {
|
||||
return sourceList.stream().map(this::map).collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.baeldung.hexagonal.store.application.controller;
|
||||
|
||||
import com.baeldung.hexagonal.store.application.base.Mapper;
|
||||
import com.baeldung.hexagonal.store.application.dto.request.OrderCreateRequestDto;
|
||||
import com.baeldung.hexagonal.store.application.dto.response.OrderResponseDto;
|
||||
import com.baeldung.hexagonal.store.core.context.customer.exception.OrderNotFoundException;
|
||||
import com.baeldung.hexagonal.store.core.context.order.entity.Order;
|
||||
import com.baeldung.hexagonal.store.core.context.order.service.OrderService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/orders")
|
||||
public class OrderController {
|
||||
Mapper<Order, OrderResponseDto> orderResponseDtoMapper;
|
||||
OrderService orderService;
|
||||
|
||||
@Autowired
|
||||
public OrderController(OrderService orderService, Mapper<Order, OrderResponseDto> orderResponseDtoMapper) {
|
||||
this.orderService = orderService;
|
||||
this.orderResponseDtoMapper = orderResponseDtoMapper;
|
||||
}
|
||||
|
||||
@GetMapping("/{id}")
|
||||
public ResponseEntity<OrderResponseDto> getOrder(@PathVariable("id") int id) {
|
||||
Optional<Order> order = this.orderService.getOrderById(id);
|
||||
if (order.isPresent()) {
|
||||
return new ResponseEntity<>(this.orderResponseDtoMapper.map(order.get()), HttpStatus.OK);
|
||||
} else {
|
||||
throw new OrderNotFoundException();
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/customer/{customerId}")
|
||||
public ResponseEntity<OrderResponseDto> createOrder(@PathVariable("customerId") int customerId, @RequestBody OrderCreateRequestDto requestDto) {
|
||||
Optional<Order> order = this.orderService.processNewCustomerOrder(customerId, requestDto.getProductQuantityMap());
|
||||
return new ResponseEntity<>(this.orderResponseDtoMapper.map(order.get()), HttpStatus.OK);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package com.baeldung.hexagonal.store.application.controller.exception;
|
||||
|
||||
import com.baeldung.hexagonal.store.core.context.customer.exception.CustomerNotFoundException;
|
||||
import com.baeldung.hexagonal.store.core.context.customer.exception.NotEnoughFundsException;
|
||||
import com.baeldung.hexagonal.store.core.context.customer.exception.OrderNotFoundException;
|
||||
import com.baeldung.hexagonal.store.core.context.order.exception.ProductNotFoundException;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
import org.springframework.web.context.request.WebRequest;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
|
||||
|
||||
@RestControllerAdvice
|
||||
public class RestResponseEntityExceptionHandler
|
||||
extends ResponseEntityExceptionHandler {
|
||||
|
||||
@ResponseStatus(HttpStatus.NOT_FOUND)
|
||||
@ExceptionHandler(value = {ProductNotFoundException.class, CustomerNotFoundException.class})
|
||||
protected ResponseEntity<JsonResponse> handleNotFoundException(
|
||||
RuntimeException ex, WebRequest request) {
|
||||
return new ResponseEntity<>(new JsonResponse(ex.getMessage()), HttpStatus.NOT_FOUND);
|
||||
}
|
||||
|
||||
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
||||
@ExceptionHandler(value = {OrderNotFoundException.class, NotEnoughFundsException.class})
|
||||
protected ResponseEntity<JsonResponse> handleBadRequestException(
|
||||
RuntimeException ex, WebRequest request) {
|
||||
return new ResponseEntity<>(new JsonResponse(ex.getMessage()), HttpStatus.BAD_REQUEST);
|
||||
}
|
||||
|
||||
private static class JsonResponse {
|
||||
String message;
|
||||
|
||||
public JsonResponse() {
|
||||
}
|
||||
|
||||
public JsonResponse(String message) {
|
||||
super();
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public void setMessage(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package com.baeldung.hexagonal.store.application.dto.entity;
|
||||
|
||||
public class CustomerDto {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.baeldung.hexagonal.store.application.dto.mapper;
|
||||
|
||||
import com.baeldung.hexagonal.store.application.base.Mapper;
|
||||
import com.baeldung.hexagonal.store.application.dto.response.OrderProductResponseDto;
|
||||
import com.baeldung.hexagonal.store.application.dto.response.OrderResponseDto;
|
||||
import com.baeldung.hexagonal.store.core.context.order.entity.Order;
|
||||
import com.baeldung.hexagonal.store.core.context.order.entity.OrderProduct;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class OrderEntityToDtoMapper implements Mapper<Order, OrderResponseDto> {
|
||||
|
||||
@Autowired
|
||||
Mapper<OrderProduct, OrderProductResponseDto> orderProductResponseDtoMapper;
|
||||
|
||||
@Override
|
||||
public OrderResponseDto map(Order source) {
|
||||
OrderResponseDto responseDto = new OrderResponseDto();
|
||||
responseDto.setId(source.getId());
|
||||
responseDto.setStatus(source.getStatus());
|
||||
responseDto.setOrderProducts(orderProductResponseDtoMapper.mapList(source.getOrderProducts()));
|
||||
return responseDto;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.baeldung.hexagonal.store.application.dto.mapper;
|
||||
|
||||
import com.baeldung.hexagonal.store.application.base.Mapper;
|
||||
import com.baeldung.hexagonal.store.application.dto.response.OrderProductResponseDto;
|
||||
import com.baeldung.hexagonal.store.application.dto.response.ProductResponseDto;
|
||||
import com.baeldung.hexagonal.store.core.context.order.entity.OrderProduct;
|
||||
import com.baeldung.hexagonal.store.core.context.order.entity.Product;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class OrderProductEntityToDtoMapper implements Mapper<OrderProduct, OrderProductResponseDto> {
|
||||
final Mapper<Product, ProductResponseDto> productResponseDtoMapper;
|
||||
|
||||
@Autowired
|
||||
public OrderProductEntityToDtoMapper(Mapper<Product, ProductResponseDto> productResponseDtoMapper) {
|
||||
this.productResponseDtoMapper = productResponseDtoMapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OrderProductResponseDto map(OrderProduct source) {
|
||||
OrderProductResponseDto orderProductResponseDto = new OrderProductResponseDto();
|
||||
orderProductResponseDto.setProduct(this.productResponseDtoMapper.map(source.getProduct()));
|
||||
orderProductResponseDto.setQuantity(source.getQuantity());
|
||||
return orderProductResponseDto;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.baeldung.hexagonal.store.application.dto.mapper;
|
||||
|
||||
import com.baeldung.hexagonal.store.application.base.Mapper;
|
||||
import com.baeldung.hexagonal.store.application.dto.response.ProductResponseDto;
|
||||
import com.baeldung.hexagonal.store.core.context.order.entity.Product;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class ProductEntityToDtoMapper implements Mapper<Product, ProductResponseDto> {
|
||||
|
||||
@Override
|
||||
public ProductResponseDto map(Product source) {
|
||||
ProductResponseDto responseDto = new ProductResponseDto();
|
||||
responseDto.setId(source.getId());
|
||||
responseDto.setName(source.getName());
|
||||
responseDto.setPrice(source.getPrice());
|
||||
return responseDto;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.baeldung.hexagonal.store.application.dto.request;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class OrderCreateRequestDto {
|
||||
List<OrderProductDescriptor> productIds;
|
||||
|
||||
public List<OrderProductDescriptor> getProductIds() {
|
||||
return productIds;
|
||||
}
|
||||
|
||||
public void setProductIds(List<OrderProductDescriptor> productIds) {
|
||||
this.productIds = productIds;
|
||||
}
|
||||
|
||||
public Map<Long, Integer> getProductQuantityMap() {
|
||||
return this.productIds
|
||||
.stream()
|
||||
.collect(Collectors.toMap(OrderProductDescriptor::getProductId, OrderProductDescriptor::getQuantity));
|
||||
}
|
||||
|
||||
public static class OrderProductDescriptor {
|
||||
private long productId;
|
||||
private int quantity;
|
||||
|
||||
public int getQuantity() {
|
||||
return quantity;
|
||||
}
|
||||
|
||||
public void setQuantity(int quantity) {
|
||||
this.quantity = quantity;
|
||||
}
|
||||
|
||||
public long getProductId() {
|
||||
return productId;
|
||||
}
|
||||
|
||||
public void setProductId(long productId) {
|
||||
this.productId = productId;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.baeldung.hexagonal.store.application.dto.response;
|
||||
|
||||
public class OrderProductResponseDto {
|
||||
|
||||
private Integer quantity;
|
||||
private ProductResponseDto product;
|
||||
|
||||
public Integer getQuantity() {
|
||||
return quantity;
|
||||
}
|
||||
|
||||
public void setQuantity(Integer quantity) {
|
||||
this.quantity = quantity;
|
||||
}
|
||||
|
||||
public ProductResponseDto getProduct() {
|
||||
return product;
|
||||
}
|
||||
|
||||
public void setProduct(ProductResponseDto product) {
|
||||
this.product = product;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.baeldung.hexagonal.store.application.dto.response;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class OrderResponseDto {
|
||||
private String status;
|
||||
private Long id;
|
||||
private List<OrderProductResponseDto> orderProducts;
|
||||
|
||||
public String getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(String status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public List<OrderProductResponseDto> getOrderProducts() {
|
||||
return orderProducts;
|
||||
}
|
||||
|
||||
public void setOrderProducts(List<OrderProductResponseDto> orderProducts) {
|
||||
this.orderProducts = orderProducts;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.baeldung.hexagonal.store.application.dto.response;
|
||||
|
||||
public class ProductResponseDto {
|
||||
private String name;
|
||||
private Double price;
|
||||
private Long id;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Double getPrice() {
|
||||
return price;
|
||||
}
|
||||
|
||||
public void setPrice(Double price) {
|
||||
this.price = price;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
spring.h2.console.enabled=true
|
||||
@@ -0,0 +1,16 @@
|
||||
package org.baeldung;
|
||||
|
||||
import com.baeldung.hexagonal.store.application.StoreApplication;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(classes = StoreApplication.class)
|
||||
public class SpringContextIntegrationTest {
|
||||
|
||||
@Test
|
||||
public void whenSpringContextIsBootstrapped_thenNoExceptions() {
|
||||
}
|
||||
}
|
||||
46
store-core/pom.xml
Normal file
46
store-core/pom.xml
Normal file
@@ -0,0 +1,46 @@
|
||||
<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>store-core</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>8</source>
|
||||
<target>8</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<parent>
|
||||
<artifactId>hexagonal-architecture</artifactId>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<relativePath>../../hexagonal-architecture</relativePath>
|
||||
</parent>
|
||||
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
<version>${spring.context.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.persistence</groupId>
|
||||
<artifactId>javax.persistence-api</artifactId>
|
||||
<version>${javax.persistence.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<properties>
|
||||
<lombok.version>1.16.8</lombok.version>
|
||||
<spring.context.version>5.1.5.RELEASE</spring.context.version>
|
||||
<javax.persistence.version>2.2</javax.persistence.version>
|
||||
</properties>
|
||||
</project>
|
||||
@@ -0,0 +1,91 @@
|
||||
package com.baeldung.hexagonal.store.core.context.customer.entity;
|
||||
|
||||
import com.baeldung.hexagonal.store.core.context.order.entity.Order;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Entity
|
||||
public class Customer implements StoreCustomer {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
protected Long id;
|
||||
|
||||
String firstname, lastname;
|
||||
String email;
|
||||
Double balance;
|
||||
|
||||
@OneToMany(
|
||||
mappedBy = "customer",
|
||||
cascade = CascadeType.ALL,
|
||||
orphanRemoval = true
|
||||
)
|
||||
List<Order> orders = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public boolean isNegativeBalanceAllowed() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double getBalance() {
|
||||
return balance;
|
||||
}
|
||||
|
||||
public String getFirstname() {
|
||||
return firstname;
|
||||
}
|
||||
|
||||
public void setFirstname(String firstname) {
|
||||
this.firstname = firstname;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getLastname() {
|
||||
return lastname;
|
||||
}
|
||||
|
||||
public void setLastname(String lastname) {
|
||||
this.lastname = lastname;
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public void setEmail(String email) {
|
||||
this.email = email;
|
||||
}
|
||||
|
||||
public void setBalance(Double balance) {
|
||||
this.balance = balance;
|
||||
}
|
||||
|
||||
public void withdrawFunds(Double sum) {
|
||||
this.balance -= sum;
|
||||
}
|
||||
|
||||
public boolean hasEnoughFunds(Double amount) {
|
||||
return this.balance >= amount;
|
||||
}
|
||||
|
||||
public void topUpFunds(Double sum) {
|
||||
this.balance += sum;
|
||||
}
|
||||
|
||||
public List<Order> getOrders() {
|
||||
return orders;
|
||||
}
|
||||
|
||||
public void setOrders(List<Order> orders) {
|
||||
this.orders = orders;
|
||||
}
|
||||
|
||||
public void addOrder(Order order) {
|
||||
this.orders.add(order);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.baeldung.hexagonal.store.core.context.customer.entity;
|
||||
|
||||
public interface StoreCustomer {
|
||||
boolean isNegativeBalanceAllowed();
|
||||
|
||||
Double getBalance();
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.baeldung.hexagonal.store.core.context.customer.exception;
|
||||
|
||||
public class CustomerNotFoundException extends RuntimeException {
|
||||
public CustomerNotFoundException() {
|
||||
super("Customer not found!");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.baeldung.hexagonal.store.core.context.customer.exception;
|
||||
|
||||
public class NotEnoughFundsException extends RuntimeException {
|
||||
public NotEnoughFundsException() {
|
||||
super("Not enough funds!");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.baeldung.hexagonal.store.core.context.customer.exception;
|
||||
|
||||
public class OrderNotFoundException extends RuntimeException {
|
||||
public OrderNotFoundException() {
|
||||
super("Order not found!");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.baeldung.hexagonal.store.core.context.customer.infrastructure;
|
||||
|
||||
import com.baeldung.hexagonal.store.core.context.customer.entity.Customer;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public interface CustomerDataStore {
|
||||
Customer save(Customer customer);
|
||||
|
||||
Optional<Customer> findById(Long customerId);
|
||||
|
||||
Iterable<Customer> findAll();
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.baeldung.hexagonal.store.core.context.customer.service;
|
||||
|
||||
import com.baeldung.hexagonal.store.core.context.customer.entity.Customer;
|
||||
|
||||
public interface CustomerService {
|
||||
Iterable<Customer> getAllCustomers();
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.baeldung.hexagonal.store.core.context.customer.service;
|
||||
|
||||
import com.baeldung.hexagonal.store.core.context.customer.entity.Customer;
|
||||
import com.baeldung.hexagonal.store.core.context.customer.infrastructure.CustomerDataStore;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class CustomerServiceImpl implements CustomerService {
|
||||
private CustomerDataStore customerDataStore;
|
||||
|
||||
@Autowired
|
||||
public CustomerServiceImpl(CustomerDataStore customerDataStore) {
|
||||
this.customerDataStore = customerDataStore;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<Customer> getAllCustomers() {
|
||||
return this.customerDataStore.findAll();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
package com.baeldung.hexagonal.store.core.context.order.entity;
|
||||
|
||||
import com.baeldung.hexagonal.store.core.context.customer.entity.Customer;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Entity
|
||||
@Table(name = "orders")
|
||||
public class Order {
|
||||
|
||||
private String status;
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
protected Long id;
|
||||
|
||||
@OneToMany(mappedBy = "id.order", cascade = CascadeType.ALL)
|
||||
private List<OrderProduct> orderProducts = new ArrayList<>();
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "customer_id")
|
||||
private Customer customer;
|
||||
|
||||
|
||||
@Transient
|
||||
public Double getTotalOrderPrice() {
|
||||
return getOrderProducts()
|
||||
.stream()
|
||||
.reduce(
|
||||
0D,
|
||||
(aDouble, orderProduct) -> orderProduct.getTotalPrice(),
|
||||
(aDouble, aDouble2) -> aDouble + aDouble2);
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(String status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public List<OrderProduct> getOrderProducts() {
|
||||
return orderProducts;
|
||||
}
|
||||
|
||||
public void setOrderProducts(List<OrderProduct> orderProducts) {
|
||||
this.orderProducts = orderProducts;
|
||||
}
|
||||
|
||||
public void addOrderProduct(OrderProduct product) {
|
||||
this.orderProducts.add(product);
|
||||
}
|
||||
|
||||
@Transient
|
||||
public int getNumberOfProducts() {
|
||||
return this.orderProducts.size();
|
||||
}
|
||||
|
||||
public Customer getCustomer() {
|
||||
return customer;
|
||||
}
|
||||
|
||||
public void setCustomer(Customer customer) {
|
||||
this.customer = customer;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
package com.baeldung.hexagonal.store.core.context.order.entity;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.EmbeddedId;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Transient;
|
||||
|
||||
@Entity
|
||||
public class OrderProduct {
|
||||
|
||||
@EmbeddedId
|
||||
private OrderProductId id;
|
||||
|
||||
@Column(nullable = false)
|
||||
private Integer quantity;
|
||||
|
||||
public OrderProduct() {
|
||||
super();
|
||||
}
|
||||
|
||||
public OrderProduct(Order order, Product product, Integer quantity) {
|
||||
id = new OrderProductId();
|
||||
id.setOrder(order);
|
||||
id.setProduct(product);
|
||||
this.quantity = quantity;
|
||||
}
|
||||
|
||||
@Transient
|
||||
public Product getProduct() {
|
||||
return this.id.getProduct();
|
||||
}
|
||||
|
||||
@Transient
|
||||
public Double getTotalPrice() {
|
||||
return getProduct().getPrice() * getQuantity();
|
||||
}
|
||||
|
||||
public OrderProductId getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(OrderProductId id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Integer getQuantity() {
|
||||
return quantity;
|
||||
}
|
||||
|
||||
public void setQuantity(Integer quantity) {
|
||||
this.quantity = quantity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((id == null) ? 0 : id.hashCode());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
OrderProduct other = (OrderProduct) obj;
|
||||
if (id == null) {
|
||||
if (other.id != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!id.equals(other.id)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
package com.baeldung.hexagonal.store.core.context.order.entity;
|
||||
|
||||
import javax.persistence.Embeddable;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import java.io.Serializable;
|
||||
|
||||
@Embeddable
|
||||
public class OrderProductId implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 476151177562655457L;
|
||||
|
||||
@ManyToOne(optional = false, fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "order_id")
|
||||
private Order order;
|
||||
|
||||
@ManyToOne(optional = false, fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "product_id")
|
||||
private Product product;
|
||||
|
||||
public OrderProductId(Order order, Product product) {
|
||||
this.order = order;
|
||||
this.product = product;
|
||||
}
|
||||
|
||||
public OrderProductId() {
|
||||
}
|
||||
|
||||
public Order getOrder() {
|
||||
return order;
|
||||
}
|
||||
|
||||
public void setOrder(Order order) {
|
||||
this.order = order;
|
||||
}
|
||||
|
||||
public Product getProduct() {
|
||||
return product;
|
||||
}
|
||||
|
||||
public void setProduct(Product product) {
|
||||
this.product = product;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
|
||||
result = prime * result + ((order.getId() == null)
|
||||
? 0
|
||||
: order
|
||||
.getId()
|
||||
.hashCode());
|
||||
result = prime * result + ((product.getId() == null)
|
||||
? 0
|
||||
: product
|
||||
.getId()
|
||||
.hashCode());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
OrderProductId other = (OrderProductId) obj;
|
||||
if (order == null) {
|
||||
if (other.order != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!order.equals(other.order)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (product == null) {
|
||||
if (other.product != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!product.equals(other.product)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.baeldung.hexagonal.store.core.context.order.entity;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
|
||||
@Entity
|
||||
public class Product {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
protected Long id;
|
||||
|
||||
private String name;
|
||||
|
||||
private Double price;
|
||||
|
||||
public Product() {
|
||||
}
|
||||
|
||||
public Double getPrice() {
|
||||
return price;
|
||||
}
|
||||
|
||||
public void setPrice(Double price) {
|
||||
this.price = price;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.baeldung.hexagonal.store.core.context.order.exception;
|
||||
|
||||
public class ProductNotFoundException extends RuntimeException {
|
||||
public ProductNotFoundException() {
|
||||
super("Product not found!");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package com.baeldung.hexagonal.store.core.context.order.infrastructure;
|
||||
|
||||
public interface EmailNotificationSender {
|
||||
void sendEmailMessage(String targetEmail, String subject, String body);
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.baeldung.hexagonal.store.core.context.order.infrastructure;
|
||||
|
||||
import com.baeldung.hexagonal.store.core.context.order.entity.Order;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public interface OrderDataStore {
|
||||
Order save(Order orderProduct);
|
||||
Optional<Order> findById(Long orderId);
|
||||
Iterable<Order> findAll();
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.baeldung.hexagonal.store.core.context.order.infrastructure;
|
||||
|
||||
import com.baeldung.hexagonal.store.core.context.order.entity.OrderProductId;
|
||||
import com.baeldung.hexagonal.store.core.context.order.entity.OrderProduct;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public interface OrderProductDataStore {
|
||||
OrderProduct save(OrderProduct orderProduct);
|
||||
|
||||
Optional<OrderProduct> findById(OrderProductId orderProductPkId);
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.baeldung.hexagonal.store.core.context.order.infrastructure;
|
||||
|
||||
import com.baeldung.hexagonal.store.core.context.order.entity.Product;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public interface ProductDataStore {
|
||||
Product save(Product product);
|
||||
|
||||
Optional<Product> findById(Long productId);
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.baeldung.hexagonal.store.core.context.order.service;
|
||||
|
||||
import com.baeldung.hexagonal.store.core.context.customer.exception.CustomerNotFoundException;
|
||||
import com.baeldung.hexagonal.store.core.context.customer.exception.NotEnoughFundsException;
|
||||
import com.baeldung.hexagonal.store.core.context.order.exception.ProductNotFoundException;
|
||||
import com.baeldung.hexagonal.store.core.context.order.entity.Order;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
public interface OrderService {
|
||||
Iterable<Order> getAllOrders();
|
||||
|
||||
Optional<Order> getOrderById(int id);
|
||||
|
||||
Optional<Order> processNewCustomerOrder(long customerId, Map<Long, Integer> productQuantityMap) throws CustomerNotFoundException, ProductNotFoundException, NotEnoughFundsException;
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
package com.baeldung.hexagonal.store.core.context.order.service;
|
||||
|
||||
import com.baeldung.hexagonal.store.core.context.customer.entity.Customer;
|
||||
import com.baeldung.hexagonal.store.core.context.customer.exception.CustomerNotFoundException;
|
||||
import com.baeldung.hexagonal.store.core.context.customer.exception.NotEnoughFundsException;
|
||||
import com.baeldung.hexagonal.store.core.context.customer.infrastructure.CustomerDataStore;
|
||||
import com.baeldung.hexagonal.store.core.context.order.infrastructure.EmailNotificationSender;
|
||||
import com.baeldung.hexagonal.store.core.context.order.infrastructure.OrderDataStore;
|
||||
import com.baeldung.hexagonal.store.core.context.order.entity.Order;
|
||||
import com.baeldung.hexagonal.store.core.context.order.entity.OrderProduct;
|
||||
import com.baeldung.hexagonal.store.core.context.order.entity.Product;
|
||||
import com.baeldung.hexagonal.store.core.context.order.exception.ProductNotFoundException;
|
||||
import com.baeldung.hexagonal.store.core.context.order.infrastructure.ProductDataStore;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
@Service
|
||||
public class OrderServiceImpl implements OrderService {
|
||||
private CustomerDataStore customerDataStore;
|
||||
private OrderDataStore orderDataStore;
|
||||
private ProductDataStore productDataStore;
|
||||
private EmailNotificationSender emailNotificationSender;
|
||||
|
||||
@Autowired
|
||||
public OrderServiceImpl(CustomerDataStore customerDataStore, OrderDataStore orderDataStore, ProductDataStore productDataStore, EmailNotificationSender emailNotificationSender) {
|
||||
this.customerDataStore = customerDataStore;
|
||||
this.orderDataStore = orderDataStore;
|
||||
this.productDataStore = productDataStore;
|
||||
this.emailNotificationSender = emailNotificationSender;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<Order> getAllOrders() {
|
||||
return orderDataStore.findAll();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Order> getOrderById(int id) {
|
||||
return this.orderDataStore.findById((long) id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Order> processNewCustomerOrder(long customerId, Map<Long, Integer> productQuantityMap)
|
||||
throws CustomerNotFoundException, ProductNotFoundException, NotEnoughFundsException {
|
||||
Optional<Customer> customer = this.customerDataStore.findById(customerId);
|
||||
if (!customer.isPresent()) {
|
||||
throw new CustomerNotFoundException();
|
||||
}
|
||||
Customer existingCustomer = customer.get();
|
||||
Order order = new Order();
|
||||
List<OrderProduct> orderProducts = new ArrayList<>();
|
||||
for (Map.Entry<Long, Integer> productEntry : productQuantityMap.entrySet()) {
|
||||
Optional<Product> product = productDataStore.findById(productEntry.getKey());
|
||||
if (!product.isPresent()) {
|
||||
throw new ProductNotFoundException();
|
||||
}
|
||||
OrderProduct orderProduct = new OrderProduct(order, product.get(), productEntry.getValue());
|
||||
orderProducts.add(orderProduct);
|
||||
}
|
||||
order.setOrderProducts(orderProducts);
|
||||
Double finalPrice = order.getTotalOrderPrice();
|
||||
if (!existingCustomer.hasEnoughFunds(finalPrice) && !existingCustomer.isNegativeBalanceAllowed()) {
|
||||
throw new NotEnoughFundsException();
|
||||
}
|
||||
existingCustomer.withdrawFunds(finalPrice);
|
||||
order.setStatus("Completed");
|
||||
order.setCustomer(existingCustomer);
|
||||
this.orderDataStore.save(order);
|
||||
this.notifyCustomerAboutNewOrder(existingCustomer, order);
|
||||
return Optional.of(order);
|
||||
}
|
||||
|
||||
private void notifyCustomerAboutNewOrder(Customer customer, Order order) {
|
||||
this.emailNotificationSender.sendEmailMessage(
|
||||
customer.getEmail(),
|
||||
"New order " + order.getId() + " was created in the Baeldung store",
|
||||
"Order total is: " + order.getTotalOrderPrice());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package com.baeldung.hexagonal.store.core;
|
||||
|
||||
import com.baeldung.hexagonal.store.core.context.customer.infrastructure.CustomerDataStore;
|
||||
import com.baeldung.hexagonal.store.core.context.order.entity.Order;
|
||||
import com.baeldung.hexagonal.store.core.context.order.infrastructure.EmailNotificationSender;
|
||||
import com.baeldung.hexagonal.store.core.context.order.infrastructure.OrderDataStore;
|
||||
import com.baeldung.hexagonal.store.core.context.order.infrastructure.ProductDataStore;
|
||||
import com.baeldung.hexagonal.store.core.context.order.service.OrderServiceImpl;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
public class MockDataStoreUnitTest {
|
||||
|
||||
|
||||
@Test
|
||||
public void givenMockedRepo_whenCalledGetAll_thenReturnMockedData() {
|
||||
// Arrange
|
||||
EmailNotificationSender emailSender = mock(EmailNotificationSender.class);
|
||||
OrderDataStore orderDataStore = mock(OrderDataStore.class);
|
||||
CustomerDataStore customerDataStore = mock(CustomerDataStore.class);
|
||||
ProductDataStore productDataStore = mock(ProductDataStore.class);
|
||||
OrderServiceImpl orderService = new OrderServiceImpl(customerDataStore, orderDataStore, productDataStore, emailSender);
|
||||
long orderId = 2323L;
|
||||
String status = "Pending";
|
||||
Order order = createFakeOrder(orderId, status);
|
||||
when(orderDataStore.findAll()).thenReturn(Collections.singletonList(order));
|
||||
// Act
|
||||
|
||||
Iterable<Order> orders = orderService.getAllOrders();
|
||||
|
||||
// Assert
|
||||
assertTrue(orders.iterator().hasNext());
|
||||
Order firstItem = orders.iterator().next();
|
||||
assertNotNull(firstItem);
|
||||
assertEquals(orderId, (long) firstItem.getId());
|
||||
assertEquals(status, firstItem.getStatus());
|
||||
}
|
||||
|
||||
private static Order createFakeOrder(long id, String status) {
|
||||
Order order = new Order();
|
||||
order.setId(id);
|
||||
order.setStatus(status);
|
||||
return order;
|
||||
}
|
||||
|
||||
}
|
||||
38
store-email-sender/pom.xml
Normal file
38
store-email-sender/pom.xml
Normal file
@@ -0,0 +1,38 @@
|
||||
<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>store-email-sender</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
|
||||
<parent>
|
||||
<artifactId>hexagonal-architecture</artifactId>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<relativePath>../../hexagonal-architecture</relativePath>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>store-core</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sun.mail</groupId>
|
||||
<artifactId>javax.mail</artifactId>
|
||||
<version>${javax.mail.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
<version>${spring.context.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<properties>
|
||||
<spring.context.version>5.1.5.RELEASE</spring.context.version>
|
||||
<javax.mail.version>1.5.5</javax.mail.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.baeldung.hexagonal.store.emailsender;
|
||||
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
@ComponentScan(basePackages = {"com.baeldung.hexagonal.store.emailsender"})
|
||||
public class EmailSenderConfig {
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package com.baeldung.hexagonal.store.emailsender;
|
||||
|
||||
import com.baeldung.hexagonal.store.core.context.order.infrastructure.EmailNotificationSender;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.mail.Message;
|
||||
import javax.mail.MessagingException;
|
||||
import javax.mail.Session;
|
||||
import javax.mail.Transport;
|
||||
import javax.mail.internet.InternetAddress;
|
||||
import javax.mail.internet.MimeMessage;
|
||||
import java.util.Properties;
|
||||
|
||||
@Component
|
||||
public class SMTPEmailSender implements EmailNotificationSender {
|
||||
|
||||
public static final String FROM_MAIL = "example@baeldung.com";
|
||||
|
||||
@Override
|
||||
public void sendEmailMessage(String targetEmail, String subject, String body) {
|
||||
try {
|
||||
Session session = createSession();
|
||||
MimeMessage message = new MimeMessage(session);
|
||||
message.setContent(body, "text/html; charset=utf-8");
|
||||
message.setFrom(new InternetAddress(FROM_MAIL));
|
||||
message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(targetEmail));
|
||||
message.setSubject(subject);
|
||||
Transport.send(message);
|
||||
} catch (MessagingException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private static Session createSession() {
|
||||
Properties props = new Properties();
|
||||
props.put("mail.smtp.auth", "true");
|
||||
props.put("mail.smtp.starttls.enable", "true");
|
||||
props.put("mail.smtp.host", "smtp.baeldung.com");
|
||||
props.put("mail.smtp.port", "587");
|
||||
return Session.getInstance(props);
|
||||
}
|
||||
}
|
||||
62
store-persistence/pom.xml
Normal file
62
store-persistence/pom.xml
Normal file
@@ -0,0 +1,62 @@
|
||||
<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>store-persistence</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
|
||||
<parent>
|
||||
<artifactId>hexagonal-architecture</artifactId>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<relativePath>../../hexagonal-architecture</relativePath>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.javafaker</groupId>
|
||||
<artifactId>javafaker</artifactId>
|
||||
<version>${faker.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>store-core</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-dependencies</artifactId>
|
||||
<version>${spring.boot.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<properties>
|
||||
<spring.boot.version>2.1.3.RELEASE</spring.boot.version>
|
||||
<faker.version>0.17.2</faker.version>
|
||||
</properties>
|
||||
</project>
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.baeldung.hexagonal.store.persistence;
|
||||
|
||||
import com.baeldung.hexagonal.store.persistence.config.EntityConfig;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
|
||||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||
|
||||
@Configuration
|
||||
@EnableTransactionManagement
|
||||
@EnableJpaRepositories("com.baeldung.hexagonal.store.persistence")
|
||||
@Import({EntityConfig.class})
|
||||
@ComponentScan(basePackages = "com.baeldung.hexagonal.store.persistence")
|
||||
public class PersistenceConfig {
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.baeldung.hexagonal.store.persistence.config;
|
||||
|
||||
import org.springframework.boot.autoconfigure.domain.EntityScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
@EntityScan(basePackages = {"com.baeldung.hexagonal.store.core"})
|
||||
public class EntityConfig {
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
package com.baeldung.hexagonal.store.persistence.listener;
|
||||
|
||||
import com.baeldung.hexagonal.store.core.context.customer.entity.Customer;
|
||||
import com.baeldung.hexagonal.store.core.context.order.entity.Order;
|
||||
import com.baeldung.hexagonal.store.core.context.order.entity.OrderProduct;
|
||||
import com.baeldung.hexagonal.store.core.context.order.entity.OrderProductId;
|
||||
import com.baeldung.hexagonal.store.core.context.order.entity.Product;
|
||||
import com.baeldung.hexagonal.store.persistence.repo.customer.CustomerRepository;
|
||||
import com.baeldung.hexagonal.store.persistence.repo.order.OrderProductRepository;
|
||||
import com.baeldung.hexagonal.store.persistence.repo.order.OrderRepository;
|
||||
import com.baeldung.hexagonal.store.persistence.repo.product.ProductRepository;
|
||||
import com.github.javafaker.Faker;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.context.event.ApplicationReadyEvent;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Component
|
||||
public class StartupFakeDataSeeder implements ApplicationListener<ApplicationReadyEvent> {
|
||||
public static final int FAKE_CUSTOMER_COUNT = 10;
|
||||
public static final int FAKE_PRODUCT_COUNT = 40;
|
||||
private final OrderRepository orderRepository;
|
||||
private final OrderProductRepository orderProductRepository;
|
||||
private final ProductRepository productRepository;
|
||||
private final CustomerRepository customerRepository;
|
||||
private Faker faker = new Faker();
|
||||
|
||||
@Autowired
|
||||
public StartupFakeDataSeeder(CustomerRepository customerRepository, OrderRepository orderRepository, OrderProductRepository orderProductRepository, ProductRepository productRepository) {
|
||||
this.customerRepository = customerRepository;
|
||||
this.orderRepository = orderRepository;
|
||||
this.orderProductRepository = orderProductRepository;
|
||||
this.productRepository = productRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(ApplicationReadyEvent applicationReadyEvent) {
|
||||
seedData();
|
||||
}
|
||||
|
||||
private void seedData() {
|
||||
List<Product> products = generateRandomProducts();
|
||||
for (int i = 0; i < FAKE_CUSTOMER_COUNT; i++) {
|
||||
Customer customer = new Customer();
|
||||
customer.setFirstname(faker.name().firstName());
|
||||
customer.setLastname(faker.name().lastName());
|
||||
customer.setBalance(faker.number().randomDouble(3, 0, 2000));
|
||||
customer.setEmail(faker.internet().emailAddress());
|
||||
Order order = generateRandomOrder(products);
|
||||
order.setCustomer(customer);
|
||||
order.setStatus(faker.code().asin());
|
||||
customer.addOrder(order);
|
||||
customerRepository.save(customer);
|
||||
}
|
||||
}
|
||||
|
||||
private Order generateRandomOrder(List<Product> products) {
|
||||
Order order = new Order();
|
||||
long orderItems = faker.number().randomNumber(1, false);
|
||||
List<OrderProduct> orderProducts = new ArrayList<>();
|
||||
List<Product> addedProducts = new ArrayList<>();
|
||||
for (int i = 0; i < orderItems; i++) {
|
||||
Product product = null;
|
||||
while (product == null || addedProducts.contains(product)) {
|
||||
product = products.get(faker.random().nextInt(0, products.size() - 1));
|
||||
}
|
||||
OrderProduct orderProduct = new OrderProduct();
|
||||
orderProduct.setId(new OrderProductId(order, product));
|
||||
addedProducts.add(product);
|
||||
orderProduct.setQuantity((int) faker.number().randomNumber(1, false));
|
||||
orderProducts.add(orderProduct);
|
||||
}
|
||||
order.setOrderProducts(orderProducts);
|
||||
return order;
|
||||
}
|
||||
|
||||
private List<Product> generateRandomProducts() {
|
||||
List<Product> products = new ArrayList<>();
|
||||
for (int i = 0; i < FAKE_PRODUCT_COUNT; i++) {
|
||||
Product product = new Product();
|
||||
product.setName(faker.commerce().productName());
|
||||
product.setPrice(faker.random().nextDouble() * 100);
|
||||
productRepository.save(product);
|
||||
products.add(product);
|
||||
}
|
||||
return products;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.baeldung.hexagonal.store.persistence.repo.customer;
|
||||
|
||||
import com.baeldung.hexagonal.store.core.context.customer.entity.Customer;
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public interface CustomerRepository extends CrudRepository<Customer, Long> {
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.baeldung.hexagonal.store.persistence.repo.customer;
|
||||
|
||||
import com.baeldung.hexagonal.store.core.context.customer.entity.Customer;
|
||||
import com.baeldung.hexagonal.store.core.context.customer.infrastructure.CustomerDataStore;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@Component
|
||||
public class CustomerRepositoryImpl implements CustomerDataStore {
|
||||
@Autowired
|
||||
private CustomerRepository customerRepository;
|
||||
|
||||
@Override
|
||||
public Customer save(Customer customer) {
|
||||
return customerRepository.save(customer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Customer> findById(Long customerId) {
|
||||
return customerRepository.findById(customerId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<Customer> findAll() {
|
||||
return customerRepository.findAll();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.baeldung.hexagonal.store.persistence.repo.order;
|
||||
|
||||
import com.baeldung.hexagonal.store.core.context.order.entity.OrderProduct;
|
||||
import com.baeldung.hexagonal.store.core.context.order.entity.OrderProductId;
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public interface OrderProductRepository extends CrudRepository<OrderProduct, OrderProductId> {
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.baeldung.hexagonal.store.persistence.repo.order;
|
||||
|
||||
import com.baeldung.hexagonal.store.core.context.order.entity.OrderProduct;
|
||||
import com.baeldung.hexagonal.store.core.context.order.entity.OrderProductId;
|
||||
import com.baeldung.hexagonal.store.core.context.order.infrastructure.OrderProductDataStore;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@Component
|
||||
public class OrderProductRepositoryImpl implements OrderProductDataStore {
|
||||
@Autowired
|
||||
private OrderProductRepository orderProductRepository;
|
||||
|
||||
@Override
|
||||
public OrderProduct save(OrderProduct orderProduct) {
|
||||
return this.orderProductRepository.save(orderProduct);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<OrderProduct> findById(OrderProductId orderProductPkId) {
|
||||
return this.orderProductRepository.findById(orderProductPkId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.baeldung.hexagonal.store.persistence.repo.order;
|
||||
|
||||
import com.baeldung.hexagonal.store.core.context.order.entity.Order;
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public interface OrderRepository extends CrudRepository<Order, Long> {
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.baeldung.hexagonal.store.persistence.repo.order;
|
||||
|
||||
import com.baeldung.hexagonal.store.core.context.order.entity.Order;
|
||||
import com.baeldung.hexagonal.store.core.context.order.infrastructure.OrderDataStore;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@Component
|
||||
public class OrderRepositoryImpl implements OrderDataStore {
|
||||
@Autowired
|
||||
private OrderRepository orderRepository;
|
||||
|
||||
@Override
|
||||
public Order save(Order order) {
|
||||
return this.orderRepository.save(order);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Order> findById(Long orderId) {
|
||||
return this.orderRepository.findById(orderId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<Order> findAll() {
|
||||
return this.orderRepository.findAll();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.baeldung.hexagonal.store.persistence.repo.product;
|
||||
|
||||
import com.baeldung.hexagonal.store.core.context.order.entity.Product;
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public interface ProductRepository extends CrudRepository<Product, Long> {
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.baeldung.hexagonal.store.persistence.repo.product;
|
||||
|
||||
import com.baeldung.hexagonal.store.core.context.order.entity.Product;
|
||||
import com.baeldung.hexagonal.store.core.context.order.infrastructure.ProductDataStore;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@Component
|
||||
public class ProductRepositoryImpl implements ProductDataStore {
|
||||
@Autowired
|
||||
private ProductRepository productRepository;
|
||||
|
||||
@Override
|
||||
public Product save(Product product) {
|
||||
return this.productRepository.save(product);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Product> findById(Long productId) {
|
||||
return this.productRepository.findById(productId);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user