commit d501186ee10bafcec3753b113517bb552e5508de Author: nrodriguez Date: Sun Nov 8 19:21:06 2020 +0100 Hexagonal architecture example with Spring Data diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3dce350 --- /dev/null +++ b/.gitignore @@ -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 + diff --git a/README.adoc b/README.adoc new file mode 100644 index 0000000..5782c52 --- /dev/null +++ b/README.adoc @@ -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 + + diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..74f1005 --- /dev/null +++ b/pom.xml @@ -0,0 +1,55 @@ + + + 4.0.0 + + com.refactorizando + spring-data-hexagonal-architecture + 1.0-SNAPSHOT + + org.springframework.boot + spring-boot-starter-parent + 2.3.0.RELEASE + + + + 11 + ${java.version} + ${java.version} + 1.2.0.Final + + + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-data-jpa + + + com.h2database + h2 + runtime + + + org.projectlombok + lombok + true + + + org.mapstruct + mapstruct-jdk8 + ${mapstruct.version} + + + org.mapstruct + mapstruct-processor + ${mapstruct.version} + + + + \ No newline at end of file diff --git a/src/main/java/com/refactorizando/hexagonalarchitecture/application/repository/UserRepository.java b/src/main/java/com/refactorizando/hexagonalarchitecture/application/repository/UserRepository.java new file mode 100644 index 0000000..2706ced --- /dev/null +++ b/src/main/java/com/refactorizando/hexagonalarchitecture/application/repository/UserRepository.java @@ -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); + +} diff --git a/src/main/java/com/refactorizando/hexagonalarchitecture/application/service/UserService.java b/src/main/java/com/refactorizando/hexagonalarchitecture/application/service/UserService.java new file mode 100644 index 0000000..70efe59 --- /dev/null +++ b/src/main/java/com/refactorizando/hexagonalarchitecture/application/service/UserService.java @@ -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); + + } +} diff --git a/src/main/java/com/refactorizando/hexagonalarchitecture/domain/User.java b/src/main/java/com/refactorizando/hexagonalarchitecture/domain/User.java new file mode 100644 index 0000000..7a9642c --- /dev/null +++ b/src/main/java/com/refactorizando/hexagonalarchitecture/domain/User.java @@ -0,0 +1,11 @@ +package com.refactorizando.hexagonalarchitecture.domain; + + +public class User { + + private Long id; + + private String name; + + private String address; +} diff --git a/src/main/java/com/refactorizando/hexagonalarchitecture/infrastructure/config/spring/SpringBootService.java b/src/main/java/com/refactorizando/hexagonalarchitecture/infrastructure/config/spring/SpringBootService.java new file mode 100644 index 0000000..7c59183 --- /dev/null +++ b/src/main/java/com/refactorizando/hexagonalarchitecture/infrastructure/config/spring/SpringBootService.java @@ -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); + } + +} \ No newline at end of file diff --git a/src/main/java/com/refactorizando/hexagonalarchitecture/infrastructure/config/spring/SpringBootServiceConfig.java b/src/main/java/com/refactorizando/hexagonalarchitecture/infrastructure/config/spring/SpringBootServiceConfig.java new file mode 100644 index 0000000..319f380 --- /dev/null +++ b/src/main/java/com/refactorizando/hexagonalarchitecture/infrastructure/config/spring/SpringBootServiceConfig.java @@ -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); + } +} \ No newline at end of file diff --git a/src/main/java/com/refactorizando/hexagonalarchitecture/infrastructure/db/springdata/config/SpringDataConfig.java b/src/main/java/com/refactorizando/hexagonalarchitecture/infrastructure/db/springdata/config/SpringDataConfig.java new file mode 100644 index 0000000..d8151ae --- /dev/null +++ b/src/main/java/com/refactorizando/hexagonalarchitecture/infrastructure/db/springdata/config/SpringDataConfig.java @@ -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 { + + +} diff --git a/src/main/java/com/refactorizando/hexagonalarchitecture/infrastructure/db/springdata/dbo/UserEntity.java b/src/main/java/com/refactorizando/hexagonalarchitecture/infrastructure/db/springdata/dbo/UserEntity.java new file mode 100644 index 0000000..3b10199 --- /dev/null +++ b/src/main/java/com/refactorizando/hexagonalarchitecture/infrastructure/db/springdata/dbo/UserEntity.java @@ -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; + +} diff --git a/src/main/java/com/refactorizando/hexagonalarchitecture/infrastructure/db/springdata/mapper/UserEntityMapper.java b/src/main/java/com/refactorizando/hexagonalarchitecture/infrastructure/db/springdata/mapper/UserEntityMapper.java new file mode 100644 index 0000000..819d62f --- /dev/null +++ b/src/main/java/com/refactorizando/hexagonalarchitecture/infrastructure/db/springdata/mapper/UserEntityMapper.java @@ -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); + + +} diff --git a/src/main/java/com/refactorizando/hexagonalarchitecture/infrastructure/db/springdata/repository/SpringDataUserRepository.java b/src/main/java/com/refactorizando/hexagonalarchitecture/infrastructure/db/springdata/repository/SpringDataUserRepository.java new file mode 100644 index 0000000..6fd4760 --- /dev/null +++ b/src/main/java/com/refactorizando/hexagonalarchitecture/infrastructure/db/springdata/repository/SpringDataUserRepository.java @@ -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 { + +} diff --git a/src/main/java/com/refactorizando/hexagonalarchitecture/infrastructure/db/springdata/repository/UserDboRepository.java b/src/main/java/com/refactorizando/hexagonalarchitecture/infrastructure/db/springdata/repository/UserDboRepository.java new file mode 100644 index 0000000..52921ea --- /dev/null +++ b/src/main/java/com/refactorizando/hexagonalarchitecture/infrastructure/db/springdata/repository/UserDboRepository.java @@ -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))); + + } +} diff --git a/src/main/java/com/refactorizando/hexagonalarchitecture/infrastructure/rest/spring/dto/UserDto.java b/src/main/java/com/refactorizando/hexagonalarchitecture/infrastructure/rest/spring/dto/UserDto.java new file mode 100644 index 0000000..31128f5 --- /dev/null +++ b/src/main/java/com/refactorizando/hexagonalarchitecture/infrastructure/rest/spring/dto/UserDto.java @@ -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; + +} diff --git a/src/main/java/com/refactorizando/hexagonalarchitecture/infrastructure/rest/spring/mapper/UserMapper.java b/src/main/java/com/refactorizando/hexagonalarchitecture/infrastructure/rest/spring/mapper/UserMapper.java new file mode 100644 index 0000000..7f3d631 --- /dev/null +++ b/src/main/java/com/refactorizando/hexagonalarchitecture/infrastructure/rest/spring/mapper/UserMapper.java @@ -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); +} diff --git a/src/main/java/com/refactorizando/hexagonalarchitecture/infrastructure/rest/spring/resources/Resources.java b/src/main/java/com/refactorizando/hexagonalarchitecture/infrastructure/rest/spring/resources/Resources.java new file mode 100644 index 0000000..3916c58 --- /dev/null +++ b/src/main/java/com/refactorizando/hexagonalarchitecture/infrastructure/rest/spring/resources/Resources.java @@ -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 getUserById(@PathVariable Long id) { + + return new ResponseEntity<>(userMapper.toDto(userService.getUser(id)), HttpStatus.OK); + + } + + @PostMapping("users") + public ResponseEntity saveUser(@RequestBody UserDto userDto) { + + return new ResponseEntity<>(userMapper.toDto(userService.saveUser(userMapper.toDomain(userDto))), + HttpStatus.CREATED); + + } + +} diff --git a/src/main/resources/properties.yml b/src/main/resources/properties.yml new file mode 100644 index 0000000..31e0305 --- /dev/null +++ b/src/main/resources/properties.yml @@ -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