Hexagonal architecture example with Spring Data

This commit is contained in:
nrodriguez
2020-11-08 19:21:06 +01:00
commit d501186ee1
17 changed files with 364 additions and 0 deletions

14
.gitignore vendored Normal file
View File

@@ -0,0 +1,14 @@
.classpath
.project
target/
bin/
.settings/
.idea/
*.iml
/src/main/java/com/stratio/financial/onetradeoperations/infrastructure/rest/spring/dto/
/src/main/java/com/stratio/financial/onetradeoperations/infrastructure/rest/spring/spec/
.swagger-codegen/
.openapi-generator/
.openapi-generator-ignore
.swagger-codegen-ignore

23
README.adoc Normal file
View File

@@ -0,0 +1,23 @@
= Hexagonal Architectura with Spring Data Example =
This is an simple example about how to build an application with Hexagonal Architecture in a Spring Data Application.
This application uses a H2 Data Base, wich is a Data Base in memory.
== How to run it?
```
mvn spring-boot:run
```
== How can I test it?
you have two different endpoints:
Get - http://localhost:8080/users/user/{userId}
Post - http://localhost:8080/users

55
pom.xml Normal file
View File

@@ -0,0 +1,55 @@
<?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.refactorizando</groupId>
<artifactId>spring-data-hexagonal-architecture</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.0.RELEASE</version>
</parent>
<properties>
<java.version>11</java.version>
<maven.compiler.source>${java.version}</maven.compiler.source>
<maven.compiler.target>${java.version}</maven.compiler.target>
<mapstruct.version>1.2.0.Final</mapstruct.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-jdk8</artifactId>
<version>${mapstruct.version}</version>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${mapstruct.version}</version>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,11 @@
package com.refactorizando.hexagonalarchitecture.application.repository;
import com.refactorizando.hexagonalarchitecture.domain.User;
public interface UserRepository {
User findById(Long id);
User save(User user);
}

View File

@@ -0,0 +1,24 @@
package com.refactorizando.hexagonalarchitecture.application.service;
import com.refactorizando.hexagonalarchitecture.application.repository.UserRepository;
import com.refactorizando.hexagonalarchitecture.domain.User;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@RequiredArgsConstructor
@Slf4j
public class UserService {
private final UserRepository userRepository;
public User getUser(Long id) {
return userRepository.findById(id);
}
public User saveUser(User user) {
return userRepository.save(user);
}
}

View File

@@ -0,0 +1,11 @@
package com.refactorizando.hexagonalarchitecture.domain;
public class User {
private Long id;
private String name;
private String address;
}

View File

@@ -0,0 +1,15 @@
package com.refactorizando.hexagonalarchitecture.infrastructure.config.spring;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
@SpringBootApplication(scanBasePackages = "com.refactorizando.hexagonalarchitecture.infrastructure")
@EntityScan(basePackages = "com.refactorizando.hexagonalarchitecture.domain")
public class SpringBootService {
public static void main(String[] args) {
SpringApplication.run(SpringBootService.class, args);
}
}

View File

@@ -0,0 +1,18 @@
package com.refactorizando.hexagonalarchitecture.infrastructure.config.spring;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.refactorizando.hexagonalarchitecture.application.repository.UserRepository;
import com.refactorizando.hexagonalarchitecture.application.service.UserService;
@Configuration
public class SpringBootServiceConfig {
@Bean
public UserService userService(UserRepository userRepository) {
return new UserService(userRepository);
}
}

View File

@@ -0,0 +1,27 @@
package com.refactorizando.hexagonalarchitecture.infrastructure.db.springdata.config;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
@Configuration
@EnableJpaRepositories(
basePackages = "com.refactorizando.hexagonalarchitecture.infrastructure.db.springdata.repository")
@ConfigurationProperties("spring.datasource")
@Slf4j
@NoArgsConstructor
@Getter
@Setter
@EnableJpaAuditing
@EntityScan(basePackages = "com.refactorizando.hexagonalarchitecture.infrastructure.db.springdata.dbo")
public class SpringDataConfig {
}

View File

@@ -0,0 +1,23 @@
package com.refactorizando.hexagonalarchitecture.infrastructure.db.springdata.dbo;
import javax.persistence.Entity;
import javax.persistence.Id;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Entity
@Getter
@Setter
@NoArgsConstructor
public class UserEntity {
@Id
private Long id;
private String name;
private String address;
}

View File

@@ -0,0 +1,16 @@
package com.refactorizando.hexagonalarchitecture.infrastructure.db.springdata.mapper;
import org.mapstruct.Mapper;
import com.refactorizando.hexagonalarchitecture.domain.User;
import com.refactorizando.hexagonalarchitecture.infrastructure.db.springdata.dbo.UserEntity;
@Mapper(componentModel = "spring")
public interface UserEntityMapper {
User toDomain(UserEntity userEntity);
UserEntity toDbo(User user);
}

View File

@@ -0,0 +1,12 @@
package com.refactorizando.hexagonalarchitecture.infrastructure.db.springdata.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import com.refactorizando.hexagonalarchitecture.infrastructure.db.springdata.dbo.UserEntity;
@Repository
public interface SpringDataUserRepository extends JpaRepository<UserEntity, Long> {
}

View File

@@ -0,0 +1,34 @@
package com.refactorizando.hexagonalarchitecture.infrastructure.db.springdata.repository;
import java.util.Optional;
import org.springframework.stereotype.Service;
import com.refactorizando.hexagonalarchitecture.application.repository.UserRepository;
import com.refactorizando.hexagonalarchitecture.domain.User;
import com.refactorizando.hexagonalarchitecture.infrastructure.db.springdata.mapper.UserEntityMapper;
import com.refactorizando.hexagonalarchitecture.infrastructure.rest.spring.mapper.UserMapper;
import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor
@Service
public class UserDboRepository implements UserRepository {
private final SpringDataUserRepository userRepository;
private final UserEntityMapper userMapper;
@Override
public User findById(Long id) {
return userMapper.toDomain(userRepository.findById(id).orElseThrow());
}
@Override
public User save(User user) {
return userMapper.toDomain(userRepository.save(userMapper.toDbo(user)));
}
}

View File

@@ -0,0 +1,20 @@
package com.refactorizando.hexagonalarchitecture.infrastructure.rest.spring.dto;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class UserDto {
private Long id;
private String name;
private String address;
}

View File

@@ -0,0 +1,14 @@
package com.refactorizando.hexagonalarchitecture.infrastructure.rest.spring.mapper;
import org.mapstruct.Mapper;
import com.refactorizando.hexagonalarchitecture.domain.User;
import com.refactorizando.hexagonalarchitecture.infrastructure.rest.spring.dto.UserDto;
@Mapper(componentModel = "spring")
public interface UserMapper {
UserDto toDto (User user);
User toDomain(UserDto userDto);
}

View File

@@ -0,0 +1,39 @@
package com.refactorizando.hexagonalarchitecture.infrastructure.rest.spring.resources;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
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.RestController;
import com.refactorizando.hexagonalarchitecture.application.service.UserService;
import com.refactorizando.hexagonalarchitecture.infrastructure.rest.spring.dto.UserDto;
import com.refactorizando.hexagonalarchitecture.infrastructure.rest.spring.mapper.UserMapper;
import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor
@RestController
public class Resources {
private final UserService userService;
private final UserMapper userMapper;
@GetMapping("users/user/{id}")
public ResponseEntity<UserDto> getUserById(@PathVariable Long id) {
return new ResponseEntity<>(userMapper.toDto(userService.getUser(id)), HttpStatus.OK);
}
@PostMapping("users")
public ResponseEntity<UserDto> saveUser(@RequestBody UserDto userDto) {
return new ResponseEntity<>(userMapper.toDto(userService.saveUser(userMapper.toDomain(userDto))),
HttpStatus.CREATED);
}
}

View File

@@ -0,0 +1,8 @@
spring:
datasource:
url: jdbc:h2:mem:testdb
driverClassName: org.h2.Driver
username: sa
password: password
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect