diff --git a/module-admin/build.gradle b/module-admin/build.gradle index 4dc4f12..db17af4 100644 --- a/module-admin/build.gradle +++ b/module-admin/build.gradle @@ -1,5 +1,6 @@ plugins { id 'java' + id 'com.google.protobuf' version '0.9.4' } group = 'com.flab' @@ -19,6 +20,7 @@ configurations { repositories { mavenCentral() + maven { url "https://packages.confluent.io/maven/" } } dependencies { @@ -34,14 +36,25 @@ dependencies { testImplementation 'org.springframework.security:spring-security-test' testRuntimeOnly 'org.junit.platform:junit-platform-launcher' - // jwt - implementation 'io.jsonwebtoken:jjwt-api:0.11.5' - implementation 'io.jsonwebtoken:jjwt-impl:0.11.5' - implementation 'io.jsonwebtoken:jjwt-jackson:0.11.5' + // kafka + implementation 'org.springframework.kafka:spring-kafka' - // mysql - implementation 'org.springframework.boot:spring-boot-starter-jdbc' - runtimeOnly 'com.mysql:mysql-connector-j' + // protobuf + implementation 'com.google.protobuf:protobuf-java:3.25.5' + implementation 'io.confluent:kafka-protobuf-serializer:7.4.8' +} + +protobuf { + protoc { + artifact = "com.google.protobuf:protoc:3.25.5" + } + generateProtoTasks { + all().each { task -> + task.builtins { + java { } + } + } + } } tasks.named('test') { diff --git a/module-admin/src/main/java/com/flab/moduleadmin/ModuleAdminApplication.java b/module-admin/src/main/java/com/flab/moduleadmin/ModuleAdminApplication.java index dd7457f..01c242c 100644 --- a/module-admin/src/main/java/com/flab/moduleadmin/ModuleAdminApplication.java +++ b/module-admin/src/main/java/com/flab/moduleadmin/ModuleAdminApplication.java @@ -2,8 +2,10 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; +import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration; -@SpringBootApplication +@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class }) public class ModuleAdminApplication { public static void main(String[] args) { diff --git a/module-admin/src/main/java/com/flab/moduleadmin/admin/domain/Shipment.java b/module-admin/src/main/java/com/flab/moduleadmin/admin/domain/Shipment.java new file mode 100644 index 0000000..c3a2c04 --- /dev/null +++ b/module-admin/src/main/java/com/flab/moduleadmin/admin/domain/Shipment.java @@ -0,0 +1,32 @@ +package com.flab.moduleadmin.admin.domain; + +import lombok.*; + +@Getter +@Setter +@NoArgsConstructor +public class Shipment { + + private String shipmentId; + + private String memberId; + + private String companyName; + + private String shipperName; + + private String businessRegistrationNumber; + + private String fromAddress; + + private String toAddress; + + private String shipmentDate; + + private String shipmentType; + + private String comment; + + private String shipmentStatus; + +} diff --git a/module-admin/src/main/java/com/flab/moduleadmin/admin/service/adminConsumer.java b/module-admin/src/main/java/com/flab/moduleadmin/admin/service/adminConsumer.java new file mode 100644 index 0000000..331f9cc --- /dev/null +++ b/module-admin/src/main/java/com/flab/moduleadmin/admin/service/adminConsumer.java @@ -0,0 +1,20 @@ +package com.flab.moduleadmin.admin.service; + +import com.flab.shipment.kafka.Shipment.ShipmentMessage; +import org.springframework.kafka.annotation.KafkaListener; +import org.springframework.stereotype.Component; + +@Component +public class adminConsumer { + + @KafkaListener(topics = "shipmentMessage", groupId = "group_1") + public void listen(byte[] data) { + try { + ShipmentMessage shipmentMessage = ShipmentMessage.parseFrom(data); + String memberId = shipmentMessage.getMemberId(); + System.out.println("memberId = " + memberId); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/module-admin/src/main/java/com/flab/moduleadmin/config/KafkaConsumerConfig.java b/module-admin/src/main/java/com/flab/moduleadmin/config/KafkaConsumerConfig.java new file mode 100644 index 0000000..70fd794 --- /dev/null +++ b/module-admin/src/main/java/com/flab/moduleadmin/config/KafkaConsumerConfig.java @@ -0,0 +1,42 @@ +package com.flab.moduleadmin.config; + +import io.confluent.kafka.serializers.protobuf.KafkaProtobufDeserializer; +import org.apache.kafka.clients.consumer.ConsumerConfig; +import org.apache.kafka.common.serialization.ByteArrayDeserializer; +import org.apache.kafka.common.serialization.StringDeserializer; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.kafka.config.ConcurrentKafkaListenerContainerFactory; +import org.springframework.kafka.core.ConsumerFactory; +import org.springframework.kafka.core.DefaultKafkaConsumerFactory; +import org.springframework.kafka.support.serializer.JsonDeserializer; + +import java.util.HashMap; +import java.util.Map; + +@Configuration +public class KafkaConsumerConfig { + + @Value("${kafka.server}") + private String kafkaServer; + + @Bean + public ConsumerFactory consumerFactory() { + Map config = new HashMap<>(); + config.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, kafkaServer); + config.put(ConsumerConfig.GROUP_ID_CONFIG, "group_1"); + config.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class); + config.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, ByteArrayDeserializer.class); + + return new DefaultKafkaConsumerFactory<>(config); + } + + @Bean + public ConcurrentKafkaListenerContainerFactory kafkaListenerContainerFactory() { + ConcurrentKafkaListenerContainerFactory factory = new ConcurrentKafkaListenerContainerFactory<>(); + factory.setConsumerFactory(consumerFactory()); + + return factory; + } +} diff --git a/module-admin/src/main/proto/shipment.proto b/module-admin/src/main/proto/shipment.proto new file mode 100644 index 0000000..765bbea --- /dev/null +++ b/module-admin/src/main/proto/shipment.proto @@ -0,0 +1,17 @@ +syntax = "proto3"; + +package com.flab.shipment.kafka; + +message ShipmentMessage { + string shipmentId = 1; + string memberId = 2; + string companyName = 3; + string shipperName = 4; + string businessRegistrationNumber = 5; + string fromAddress = 6; + string toAddress = 7; + string shipmentDate = 8; + string shipmentType = 9; + string comment = 10; + string shipmentStatus = 11; +} diff --git a/module-admin/src/main/resources/application.properties b/module-admin/src/main/resources/application.properties index 1fd303c..de6054d 100644 --- a/module-admin/src/main/resources/application.properties +++ b/module-admin/src/main/resources/application.properties @@ -1,2 +1,4 @@ spring.application.name=module-admin -server.port=8003 \ No newline at end of file +server.port=8003 + +kafka.server=localhost:9092 \ No newline at end of file diff --git a/module-shipper/build.gradle b/module-shipper/build.gradle index 0925dda..bdba9b2 100644 --- a/module-shipper/build.gradle +++ b/module-shipper/build.gradle @@ -1,5 +1,6 @@ plugins { id 'java' + id 'com.google.protobuf' version '0.9.4' } group = 'com.flab' @@ -19,6 +20,7 @@ configurations { repositories { mavenCentral() + maven { url "https://packages.confluent.io/maven/" } } dependencies { @@ -42,6 +44,26 @@ dependencies { // mysql implementation 'org.springframework.boot:spring-boot-starter-jdbc' runtimeOnly 'com.mysql:mysql-connector-j' + + // kafka + implementation 'org.springframework.kafka:spring-kafka' + + // protobuf + implementation 'com.google.protobuf:protobuf-java:3.25.5' + implementation 'io.confluent:kafka-protobuf-serializer:7.4.8' +} + +protobuf { + protoc { + artifact = "com.google.protobuf:protoc:3.25.5" + } + generateProtoTasks { + all().each { task -> + task.builtins { + java { } + } + } + } } tasks.named('test') { diff --git a/module-shipper/src/main/java/com/flab/moduleshipper/config/KafkaProducerConfig.java b/module-shipper/src/main/java/com/flab/moduleshipper/config/KafkaProducerConfig.java new file mode 100644 index 0000000..fc17f52 --- /dev/null +++ b/module-shipper/src/main/java/com/flab/moduleshipper/config/KafkaProducerConfig.java @@ -0,0 +1,39 @@ +package com.flab.moduleshipper.config; + +import io.confluent.kafka.serializers.protobuf.KafkaProtobufSerializer; +import org.apache.kafka.clients.producer.ProducerConfig; +import org.apache.kafka.common.serialization.ByteArraySerializer; +import org.apache.kafka.common.serialization.StringSerializer; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.kafka.core.DefaultKafkaProducerFactory; +import org.springframework.kafka.core.KafkaTemplate; +import org.springframework.kafka.core.ProducerFactory; + +import java.util.HashMap; +import java.util.Map; + +@Configuration +public class KafkaProducerConfig { + + @Value("${kafka.server}") + private String kafkaServer; + + + @Bean + public ProducerFactory producerFactory() { + Map config = new HashMap<>(); + config.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, kafkaServer); + config.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class); + config.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, ByteArraySerializer.class); + + return new DefaultKafkaProducerFactory<>(config); + } + + @Bean + public KafkaTemplate kafkaTemplate() { + return new KafkaTemplate<>(producerFactory()); + } + +} diff --git a/module-shipper/src/main/java/com/flab/moduleshipper/shipment/controller/ShipmentApiController.java b/module-shipper/src/main/java/com/flab/moduleshipper/shipment/controller/ShipmentApiController.java index 389311c..90aeaea 100644 --- a/module-shipper/src/main/java/com/flab/moduleshipper/shipment/controller/ShipmentApiController.java +++ b/module-shipper/src/main/java/com/flab/moduleshipper/shipment/controller/ShipmentApiController.java @@ -8,6 +8,7 @@ import org.springframework.web.bind.annotation.*; import java.util.List; +import java.util.concurrent.CompletableFuture; @RestController @RequiredArgsConstructor @@ -23,9 +24,10 @@ public ResponseEntity create(@RequestBody ShipmentDTO.ShipmentRequest re } @GetMapping("/") - public ResponseEntity> getAll() { - List all = shipmentService.getAll(); - return ResponseEntity.status(HttpStatus.OK).body(all); + public CompletableFuture>> getAll() { + return shipmentService.getAll() + .thenApply(result -> new ResponseEntity<>(result, HttpStatus.OK)) + .exceptionally(ex -> ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build()); } @GetMapping("/{shipmentId}") diff --git a/module-shipper/src/main/java/com/flab/moduleshipper/shipment/service/ShipmentProducer.java b/module-shipper/src/main/java/com/flab/moduleshipper/shipment/service/ShipmentProducer.java new file mode 100644 index 0000000..05aab5f --- /dev/null +++ b/module-shipper/src/main/java/com/flab/moduleshipper/shipment/service/ShipmentProducer.java @@ -0,0 +1,22 @@ +package com.flab.moduleshipper.shipment.service; + +import com.flab.moduleshipper.shipment.domain.Shipment; +import com.flab.shipment.kafka.Shipment.ShipmentMessage; +import lombok.AllArgsConstructor; +import org.springframework.kafka.core.KafkaTemplate; +import org.springframework.stereotype.Component; + +@Component +@AllArgsConstructor +public class ShipmentProducer { + + private final KafkaTemplate kafkaTemplate; + + public void sendShipment(final Shipment shipment) { + ShipmentMessage build = ShipmentMessage.newBuilder() + .setShipmentId(shipment.getShipmentId()) + .setMemberId(shipment.getMemberId()) + .build(); + kafkaTemplate.send("shipmentMessage", build.toByteArray()); + } +} diff --git a/module-shipper/src/main/java/com/flab/moduleshipper/shipment/service/ShipmentService.java b/module-shipper/src/main/java/com/flab/moduleshipper/shipment/service/ShipmentService.java index 503bcf6..03a97eb 100644 --- a/module-shipper/src/main/java/com/flab/moduleshipper/shipment/service/ShipmentService.java +++ b/module-shipper/src/main/java/com/flab/moduleshipper/shipment/service/ShipmentService.java @@ -5,12 +5,14 @@ import com.flab.moduleshipper.shipment.repository.ShipmentRepository; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.ArrayList; import java.util.List; import java.util.Optional; +import java.util.concurrent.CompletableFuture; @Slf4j @Service @@ -18,21 +20,26 @@ public class ShipmentService { private final ShipmentRepository shipmentRepository; + private final ShipmentProducer shipmentProducer; public String create(ShipmentDTO.ShipmentRequest req) { Shipment shipment = req.dtoToDomain(req); Shipment save = shipmentRepository.save(shipment); + shipmentProducer.sendShipment(save); return save.getShipmentId(); } - public List getAll() { - List shipments = shipmentRepository.findAll(); - List basicInfoList = new ArrayList<>(); - for (Shipment shipment : shipments) { - ShipmentDTO.BasicInfo basicInfo = new ShipmentDTO.BasicInfo(shipment); - basicInfoList.add(basicInfo); - } - return basicInfoList; + @Async + public CompletableFuture> getAll() { + return CompletableFuture.supplyAsync(() -> { + List shipments = shipmentRepository.findAll(); + List basicInfoList = new ArrayList<>(); + for (Shipment shipment : shipments) { + ShipmentDTO.BasicInfo basicInfo = new ShipmentDTO.BasicInfo(shipment); + basicInfoList.add(basicInfo); + } + return basicInfoList; + }); } public ShipmentDTO.BasicInfo get(String shipmentId) { diff --git a/module-shipper/src/main/proto/shipment.proto b/module-shipper/src/main/proto/shipment.proto new file mode 100644 index 0000000..765bbea --- /dev/null +++ b/module-shipper/src/main/proto/shipment.proto @@ -0,0 +1,17 @@ +syntax = "proto3"; + +package com.flab.shipment.kafka; + +message ShipmentMessage { + string shipmentId = 1; + string memberId = 2; + string companyName = 3; + string shipperName = 4; + string businessRegistrationNumber = 5; + string fromAddress = 6; + string toAddress = 7; + string shipmentDate = 8; + string shipmentType = 9; + string comment = 10; + string shipmentStatus = 11; +} diff --git a/module-shipper/src/main/resources/application.properties b/module-shipper/src/main/resources/application.properties index 6bf98ca..7e0ed35 100644 --- a/module-shipper/src/main/resources/application.properties +++ b/module-shipper/src/main/resources/application.properties @@ -5,4 +5,7 @@ server.port=8001 spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.url=jdbc:mysql://localhost:3306/truck_matching?serverTimezone=UTC&characterEncoding=UTF-8 spring.datasource.username=root -spring.datasource.password=123963 \ No newline at end of file +spring.datasource.password=123963 + +# kafka +kafka.server=localhost:9092 diff --git a/module-shipper/src/test/java/com/flab/moduleshipper/shipment/service/ShipmentServiceTest.java b/module-shipper/src/test/java/com/flab/moduleshipper/shipment/service/ShipmentServiceTest.java new file mode 100644 index 0000000..d124f7e --- /dev/null +++ b/module-shipper/src/test/java/com/flab/moduleshipper/shipment/service/ShipmentServiceTest.java @@ -0,0 +1,22 @@ +package com.flab.moduleshipper.shipment.service; + +import com.flab.moduleshipper.shipment.dto.ShipmentDTO; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; + +import static org.junit.jupiter.api.Assertions.*; + +@SpringBootTest +class ShipmentServiceTest { + + @Autowired + private ShipmentService shipmentService; + + @Test + void create() { + ShipmentDTO.ShipmentRequest req = new ShipmentDTO.ShipmentRequest(); + req.setMemberId("testMemberId"); + shipmentService.create(req); + } +} \ No newline at end of file diff --git a/module-trucker/src/main/java/com/flab/moduletrucker/ModuleTruckerApplication.java b/module-trucker/src/main/java/com/flab/moduletrucker/ModuleTruckerApplication.java index 47112b2..c2db27e 100644 --- a/module-trucker/src/main/java/com/flab/moduletrucker/ModuleTruckerApplication.java +++ b/module-trucker/src/main/java/com/flab/moduletrucker/ModuleTruckerApplication.java @@ -1,11 +1,14 @@ package com.flab.moduletrucker; import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.ImportAutoConfiguration; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.openfeign.EnableFeignClients; +import org.springframework.cloud.openfeign.FeignAutoConfiguration; @EnableFeignClients @SpringBootApplication +@ImportAutoConfiguration({FeignAutoConfiguration.class}) public class ModuleTruckerApplication { public static void main(String[] args) { diff --git a/module-trucker/src/main/java/com/flab/moduletrucker/truck/controller/TruckerApiController.java b/module-trucker/src/main/java/com/flab/moduletrucker/truck/controller/TruckerApiController.java index a913e00..825afe8 100644 --- a/module-trucker/src/main/java/com/flab/moduletrucker/truck/controller/TruckerApiController.java +++ b/module-trucker/src/main/java/com/flab/moduletrucker/truck/controller/TruckerApiController.java @@ -1,32 +1,57 @@ package com.flab.moduletrucker.truck.controller; import com.flab.moduletrucker.truck.dto.TruckerDTO; -import com.flab.moduletrucker.truck.service.TruckerService; +import com.flab.moduletrucker.truck.service.AccountService; +import com.flab.moduletrucker.truck.service.CarService; +import com.flab.moduletrucker.truck.service.ContractService; import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; @RestController @RequiredArgsConstructor @RequestMapping("/api/v1/trucker") public class TruckerApiController { - private final TruckerService truckerService; + private final AccountService accountService; + private final CarService carService; + private final ContractService contractService; @PostMapping("/car") public ResponseEntity createCar(@RequestBody TruckerDTO.CarRequest req) { - String carId = truckerService.createCar(req); + String carId = carService.createCar(req); return ResponseEntity.status(HttpStatus.OK).body(carId); } + @GetMapping("/car/{carId}") + public ResponseEntity getCar(@PathVariable String carId) { + TruckerDTO.CarInfo car = carService.getCar(carId); + return ResponseEntity.status(HttpStatus.OK).body(car); + } + @PostMapping("/contract") public ResponseEntity createContract(@RequestBody TruckerDTO.ContractRequest req) { - String contractId = truckerService.createContract(req); + String contractId = contractService.createContract(req); return ResponseEntity.status(HttpStatus.OK).body(contractId); } + @PostMapping("/account") + public ResponseEntity createAccount(@RequestBody TruckerDTO.AccountRequest req) { + String accountId = accountService.createAccount(req); + return ResponseEntity.status(HttpStatus.OK).body(accountId); + } + + @PutMapping("/contract/{contractId}/status/{status}") + public ResponseEntity updateContractStatus(@PathVariable String contractId, @PathVariable String status) { + String resultStatus = contractService.updateContractStatus(contractId, status); + return ResponseEntity.status(HttpStatus.OK).body(resultStatus); + } + + @GetMapping("/contract/{contractId}") + public ResponseEntity getContract(@PathVariable String contractId) { + TruckerDTO.ContractResponse contractResponse = contractService.getContract(contractId); + return ResponseEntity.status(HttpStatus.OK).body(contractResponse); + } + } diff --git a/module-trucker/src/main/java/com/flab/moduletrucker/truck/domain/Account.java b/module-trucker/src/main/java/com/flab/moduletrucker/truck/domain/Account.java new file mode 100644 index 0000000..29c3b6c --- /dev/null +++ b/module-trucker/src/main/java/com/flab/moduletrucker/truck/domain/Account.java @@ -0,0 +1,29 @@ +package com.flab.moduletrucker.truck.domain; + +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@Entity(name = "ACCOUNT") +@NoArgsConstructor +@Builder +@AllArgsConstructor +public class Account { + + @Id + @GeneratedValue(strategy = GenerationType.UUID) + private String accountId; + + private String accountNo; + + private String accountName; + + private String accountBank; + +} diff --git a/module-trucker/src/main/java/com/flab/moduletrucker/truck/domain/Contract.java b/module-trucker/src/main/java/com/flab/moduletrucker/truck/domain/Contract.java index 7bd9358..5104635 100644 --- a/module-trucker/src/main/java/com/flab/moduletrucker/truck/domain/Contract.java +++ b/module-trucker/src/main/java/com/flab/moduletrucker/truck/domain/Contract.java @@ -28,4 +28,7 @@ public class Contract { private String contractStatus; + public void changeStatus(String status) { + this.contractStatus = status; + } } diff --git a/module-trucker/src/main/java/com/flab/moduletrucker/truck/dto/TruckerDTO.java b/module-trucker/src/main/java/com/flab/moduletrucker/truck/dto/TruckerDTO.java index c9c5585..4290292 100644 --- a/module-trucker/src/main/java/com/flab/moduletrucker/truck/dto/TruckerDTO.java +++ b/module-trucker/src/main/java/com/flab/moduletrucker/truck/dto/TruckerDTO.java @@ -1,5 +1,6 @@ package com.flab.moduletrucker.truck.dto; +import com.flab.moduletrucker.truck.domain.Account; import com.flab.moduletrucker.truck.domain.Car; import com.flab.moduletrucker.truck.domain.Contract; import lombok.Data; @@ -21,6 +22,20 @@ public Car dtoToDomain(TruckerDTO.CarRequest req) { } } + @Data + @NoArgsConstructor + public static class CarInfo { + private String carId; + private String memberId; + private String carType; + + public CarInfo(Car car) { + this.carId = car.getCarId(); + this.memberId = car.getMemberId(); + this.carType = car.getCarType(); + } + } + @Data @NoArgsConstructor public static class ContractRequest { @@ -39,4 +54,38 @@ public Contract dtoToDomain(TruckerDTO.ContractRequest req) { } } + @Data + @NoArgsConstructor + public static class AccountRequest { + private String accountNo; + private String accountName; + private String accountBank; + + public Account dtoToDomain(TruckerDTO.AccountRequest req) { + return Account.builder() + .accountNo(req.getAccountNo()) + .accountName(req.getAccountName()) + .accountBank(req.getAccountBank()) + .build(); + } + } + + @Data + @NoArgsConstructor + public static class ContractResponse { + private String contractId; + private String truckerMemberId; + private String shipmentId; + private String carId; + private String contractStatus; + + public ContractResponse(Contract contract) { + this.contractId = contract.getContractId(); + this.truckerMemberId = contract.getTruckerMemberId(); + this.shipmentId = contract.getShipmentId(); + this.carId = contract.getCarId(); + this.contractStatus = contract.getContractStatus(); + } + } + } diff --git a/module-trucker/src/main/java/com/flab/moduletrucker/truck/repository/AccountRepository.java b/module-trucker/src/main/java/com/flab/moduletrucker/truck/repository/AccountRepository.java new file mode 100644 index 0000000..888e67c --- /dev/null +++ b/module-trucker/src/main/java/com/flab/moduletrucker/truck/repository/AccountRepository.java @@ -0,0 +1,7 @@ +package com.flab.moduletrucker.truck.repository; + +import com.flab.moduletrucker.truck.domain.Account; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface AccountRepository extends JpaRepository { +} diff --git a/module-trucker/src/main/java/com/flab/moduletrucker/truck/service/AccountService.java b/module-trucker/src/main/java/com/flab/moduletrucker/truck/service/AccountService.java new file mode 100644 index 0000000..a4b4859 --- /dev/null +++ b/module-trucker/src/main/java/com/flab/moduletrucker/truck/service/AccountService.java @@ -0,0 +1,24 @@ +package com.flab.moduletrucker.truck.service; + +import com.flab.moduletrucker.truck.domain.Account; +import com.flab.moduletrucker.truck.dto.TruckerDTO; +import com.flab.moduletrucker.truck.repository.AccountRepository; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; + +@Slf4j +@Service +@RequiredArgsConstructor +public class AccountService { + + private final AccountRepository accountRepository; + + @Async(value = "taskExecutor") + public String createAccount(TruckerDTO.AccountRequest req) { + Account account = req.dtoToDomain(req); + Account save = accountRepository.save(account); + return save.getAccountId(); + } +} diff --git a/module-trucker/src/main/java/com/flab/moduletrucker/truck/service/CarService.java b/module-trucker/src/main/java/com/flab/moduletrucker/truck/service/CarService.java new file mode 100644 index 0000000..591ea4a --- /dev/null +++ b/module-trucker/src/main/java/com/flab/moduletrucker/truck/service/CarService.java @@ -0,0 +1,37 @@ +package com.flab.moduletrucker.truck.service; + +import com.flab.moduletrucker.truck.domain.Car; +import com.flab.moduletrucker.truck.dto.TruckerDTO; +import com.flab.moduletrucker.truck.repository.CarRepository; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; + +import java.util.Optional; + +@Slf4j +@Service +@RequiredArgsConstructor +public class CarService { + + private final CarRepository carRepository; + + @Async(value = "taskExecutor") + public String createCar(TruckerDTO.CarRequest req) { + Car car = req.dtoToDomain(req); + Car save = carRepository.save(car); + return save.getCarId(); + } + + @Async(value = "taskExecutor") + public TruckerDTO.CarInfo getCar(String carId) { + Optional byId = carRepository.findById(carId); + if (byId.isPresent()) { + Car car = byId.get(); + return new TruckerDTO.CarInfo(car); + } else { + throw new RuntimeException("car not found"); + } + } +} diff --git a/module-trucker/src/main/java/com/flab/moduletrucker/truck/service/TruckerService.java b/module-trucker/src/main/java/com/flab/moduletrucker/truck/service/ContractService.java similarity index 58% rename from module-trucker/src/main/java/com/flab/moduletrucker/truck/service/TruckerService.java rename to module-trucker/src/main/java/com/flab/moduletrucker/truck/service/ContractService.java index a5020b3..fc95c6a 100644 --- a/module-trucker/src/main/java/com/flab/moduletrucker/truck/service/TruckerService.java +++ b/module-trucker/src/main/java/com/flab/moduletrucker/truck/service/ContractService.java @@ -1,32 +1,27 @@ package com.flab.moduletrucker.truck.service; import com.flab.moduletrucker.shipment.dto.ShipmentDTO; -import com.flab.moduletrucker.truck.domain.Car; import com.flab.moduletrucker.truck.domain.Contract; import com.flab.moduletrucker.truck.dto.TruckerDTO; import com.flab.moduletrucker.truck.feign.ShipperClient; -import com.flab.moduletrucker.truck.repository.CarRepository; import com.flab.moduletrucker.truck.repository.ContractRepository; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.http.ResponseEntity; +import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; +import java.util.Optional; + @Slf4j @Service @RequiredArgsConstructor -public class TruckerService { +public class ContractService { - private final CarRepository carRepository; private final ContractRepository contractRepository; private final ShipperClient shipperClient; - public String createCar(TruckerDTO.CarRequest req) { - Car car = req.dtoToDomain(req); - Car save = carRepository.save(car); - return save.getCarId(); - } - + @Async(value = "taskExecutor") public String createContract(TruckerDTO.ContractRequest req) { ResponseEntity basicInfoResponseEntity = shipperClient.get(req.getShipmentId()); ShipmentDTO.BasicInfo basicInfo = basicInfoResponseEntity.getBody(); @@ -41,4 +36,26 @@ public String createContract(TruckerDTO.ContractRequest req) { throw new RuntimeException("shipment status is not ready"); } } + + @Async(value = "taskExecutor") + public String updateContractStatus(String contractId, String status) { + Optional byId = contractRepository.findById(contractId); + if (byId.isPresent()) { + Contract contract = byId.get(); + contract.changeStatus(status); + return status; + } else { + throw new RuntimeException("contract not found"); + } + } + + @Async(value = "taskExecutor") + public TruckerDTO.ContractResponse getContract(String contractId) { + Optional byId = contractRepository.findById(contractId); + if (byId.isPresent()) { + return new TruckerDTO.ContractResponse(byId.get()); + } else { + throw new RuntimeException("contract not found"); + } + } } diff --git a/module-trucker/src/main/java/com/flab/moduletrucker/truck/service/ThreadPoolConfiguration.java b/module-trucker/src/main/java/com/flab/moduletrucker/truck/service/ThreadPoolConfiguration.java new file mode 100644 index 0000000..04d9e89 --- /dev/null +++ b/module-trucker/src/main/java/com/flab/moduletrucker/truck/service/ThreadPoolConfiguration.java @@ -0,0 +1,25 @@ +package com.flab.moduletrucker.truck.service; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.task.TaskExecutor; +import org.springframework.scheduling.annotation.EnableAsync; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; + +import java.util.concurrent.ThreadPoolExecutor; + +@Configuration +@EnableAsync +public class ThreadPoolConfiguration { + + @Bean(name = "taskExecutor") + public TaskExecutor taskExecutor() { + ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); + executor.setCorePoolSize(5); + executor.setMaxPoolSize(10); + executor.setQueueCapacity(100); + executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); + executor.setThreadNamePrefix("taskExecutor-"); + return executor; + } +} diff --git a/module-trucker/src/main/resources/application.properties b/module-trucker/src/main/resources/application.properties index 6dd9919..5ff0f0a 100644 --- a/module-trucker/src/main/resources/application.properties +++ b/module-trucker/src/main/resources/application.properties @@ -1,2 +1,8 @@ spring.application.name=module-trucker -server.port=8002 \ No newline at end of file +server.port=8002 + +# mysql +spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver +spring.datasource.url=jdbc:mysql://localhost:3306/truck_matching?serverTimezone=UTC&characterEncoding=UTF-8 +spring.datasource.username=root +spring.datasource.password=123963 \ No newline at end of file diff --git a/module-trucker/src/test/java/com/flab/moduletrucker/truck/mock/FakeShipperClient.java b/module-trucker/src/test/java/com/flab/moduletrucker/truck/mock/FakeShipperClient.java new file mode 100644 index 0000000..1242d0c --- /dev/null +++ b/module-trucker/src/test/java/com/flab/moduletrucker/truck/mock/FakeShipperClient.java @@ -0,0 +1,30 @@ +package com.flab.moduletrucker.truck.mock; + +import com.flab.moduletrucker.shipment.dto.ShipmentDTO; +import com.flab.moduletrucker.truck.feign.ShipperClient; +import org.springframework.http.ResponseEntity; + +public class FakeShipperClient implements ShipperClient { + + @Override + public ResponseEntity get(String shipmentId) { + ShipmentDTO.BasicInfo basicInfo = new ShipmentDTO.BasicInfo(); + switch (shipmentId) { + case "ready": + basicInfo.setShipmentId("ready"); + basicInfo.setShipmentStatus("ready"); + break; + case "other": + basicInfo.setShipmentId("other"); + basicInfo.setShipmentStatus("other"); + break; + } + + return ResponseEntity.ok(basicInfo); + } + + @Override + public void shipmentStatus(String shipmentId, String status) { + + } +} diff --git a/module-trucker/src/test/java/com/flab/moduletrucker/truck/service/TruckerServiceTest.java b/module-trucker/src/test/java/com/flab/moduletrucker/truck/service/TruckerServiceTest.java new file mode 100644 index 0000000..d530925 --- /dev/null +++ b/module-trucker/src/test/java/com/flab/moduletrucker/truck/service/TruckerServiceTest.java @@ -0,0 +1,79 @@ +package com.flab.moduletrucker.truck.service; + +import com.flab.moduletrucker.shipment.dto.ShipmentDTO; +import com.flab.moduletrucker.truck.domain.Contract; +import com.flab.moduletrucker.truck.dto.TruckerDTO; +import com.flab.moduletrucker.truck.feign.ShipperClient; +import com.flab.moduletrucker.truck.mock.FakeShipperClient; +import com.flab.moduletrucker.truck.repository.AccountRepository; +import com.flab.moduletrucker.truck.repository.CarRepository; +import com.flab.moduletrucker.truck.repository.ContractRepository; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +class TruckerServiceTest { + + @InjectMocks + private AccountService accountService; + + @InjectMocks + private CarService carService; + + @InjectMocks + private ContractService contractService; + + @Mock + private AccountRepository accountRepository; + + @Mock + private CarRepository carRepository; + + @Mock + private ContractRepository contractRepository; + + @Mock + private ShipperClient shipperClient; + + @Test + void createContract_성공하는_경우() { + TruckerDTO.ContractRequest req = new TruckerDTO.ContractRequest(); + req.setShipmentId("ready"); + ShipmentDTO.BasicInfo basicInfo = new ShipmentDTO.BasicInfo(); + basicInfo.setShipmentStatus("ready"); + ResponseEntity basicInfoResponseEntity = new ResponseEntity(basicInfo, HttpStatus.OK); + Contract contract = Contract.builder().contractId("testId").build(); + + when(shipperClient.get(req.getShipmentId())).thenReturn(basicInfoResponseEntity); + when(contractRepository.save(any(Contract.class))).thenReturn(contract); + + String contractId = contractService.createContract(req); + Assertions.assertNotNull(contractId); + } + + @Test + void createContract_shipment_ready가_아닌경우() { + TruckerDTO.ContractRequest req = new TruckerDTO.ContractRequest(); + req.setShipmentId("other"); + ShipmentDTO.BasicInfo basicInfo = new ShipmentDTO.BasicInfo(); + basicInfo.setShipmentStatus("other"); + ResponseEntity basicInfoResponseEntity = new ResponseEntity(basicInfo, HttpStatus.OK); + + when(shipperClient.get(req.getShipmentId())).thenReturn(basicInfoResponseEntity); + + Assertions.assertThrows(RuntimeException.class, () -> { + contractService.createContract(req); + }); + } + +} \ No newline at end of file