Xem toàn bộ series bài viết hướng dẫn xây dựng ứng dụng Questions Management tại đây.
Trước khi xây dựng API thêm mới option cho Composite Option Service, có mấy việc chúng ta phải làm trước như sau:
Vì Composite Option Service sẽ thao tác liên quan đến các question và các option nên mình sẽ thêm các đối tượng model cho từng loại để chứa thông tin của chúng như sau:
Question:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
package com.huongdanjava.optionservice.dto; import lombok.Data; @Data public class Question { private String id; private String description; private String categoryId; } |
Option:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
package com.huongdanjava.optionservice.dto; import lombok.Data; @Data public class Option { private String id; private String description; private String note; private Boolean isCorrect; private String questionId; } |
Vì Composite Option Service sẽ gọi đến Core Question Service và Core Option Service nên mình sẽ thêm mới trong tập tin application.properties thông tin về chúng như sau:
1 2 |
corequestionservice.url=http://localhost:8081 coreoptionservice.url=http://localhost:8083 |
Để handle việc gọi tới Core Question Service, mình sẽ tạo một interface tên là CoreQuestionService:
1 2 3 4 5 6 7 |
package com.huongdanjava.optionservice.service; public interface CoreQuestionService { String getServiceUrl(); } |
với implementation là CoreQuestionServiceImpl:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
package com.huongdanjava.optionservice.service.impl; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import com.huongdanjava.optionservice.service.CoreQuestionService; @Service public class CoreQuestionServiceImpl implements CoreQuestionService { @Value("${corequestionservice.url}") private String coreQuestionServiceUrl; @Override public String getServiceUrl() { return coreQuestionServiceUrl; } } |
Để handle việc gọi tới Core Option Service, mình sẽ tạo một interface tên là CoreOptionService:
1 2 3 4 5 6 7 |
package com.huongdanjava.optionservice.service; public interface CoreOptionService { String getServiceUrl(); } |
với implementation là CoreOptionServiceImpl:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
package com.huongdanjava.optionservice.service.impl; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import com.huongdanjava.optionservice.service.CoreOptionService; @Service public class CoreOptionServiceImpl implements CoreOptionService { @Value("${coreoptionservice.url}") private String coreOptionServiceUrl; @Override public String getServiceUrl() { return coreOptionServiceUrl; } } |
Mình sẽ chạy service này sử dụng port 8183 nên mình cũng sẽ thêm property server.port trong tập tin application.properties như sau:
1 |
server.port=8183 |
OK, mọi thứ chuẩn bị đã xong, bây giờ mình sẽ đi vào phần chính của bài viết này các bạn nhé!
Đầu tiên, mình sẽ tạo mới một controller tên là CompositeOptionController với nội dung như sau:
1 2 3 4 5 6 7 8 9 10 |
package com.huongdanjava.optionservice; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/option") public class CompositeOptionController { } |
Với khai báo trên, mình cũng đã expose các API cho phần Composite Option Service với request URL bắt đầu là “/option”.
Tiếp theo mình sẽ tạo mới một CompositeOptionService để handle tất cả các thao tác liên quan đến Composite Option Service
1 2 3 4 5 |
package com.huongdanjava.optionservice.service; public interface CompositeOptionService { } |
Thao tác đầu tiên thêm mới option.
Để hiện thực thao tác này, dựa vào thông tin option cần thêm mới, chúng ta sẽ gọi qua Core Question Service xem question id mà option này thuộc về có tồn tại hay không? Nếu tồn tại, chúng ta sẽ gọi qua Core Option Service để thực hiện việc thêm mới option này.
Cụ thể mình sẽ thêm mới một abstract method vào class CompositeOptionService như sau:
1 2 3 4 5 6 7 8 9 10 11 |
package com.huongdanjava.optionservice.service; import com.huongdanjava.optionservice.dto.Option; import reactor.core.publisher.Mono; public interface CompositeOptionService { Mono<Option> addNewOption(Option option); } |
Để hiện thực được phương thức addNewOption() trên, đầu tiên, chúng ta cần gọi tới Core Question Service để tìm question theo id theo questionId mà đối tượng Option cần thêm mới, thuộc về. Bằng cách thêm mới một method trong CoreQuestionService:
1 |
Mono<Question> findById(String questionId); |
với phần implementation trong class CoreQuestionServiceImpl như sau:
1 2 3 4 5 6 7 8 9 10 11 12 |
@Override public Mono<Question> findById(String questionId) { WebClient client = WebClient.builder() .baseUrl(getServiceUrl()) .build(); WebClient.ResponseSpec responseSpec = client.get() .uri("/question/" + questionId) .retrieve(); return responseSpec.bodyToMono(Question.class); } |
Tiếp theo chúng ta sẽ gọi tới Core Option Service để thực hiện việc thêm mới option bằng cách thêm mới một method trong class CoreOptionService:
1 |
Mono<Option> addNewOption(Option option); |
với phần implementation trong class CoreOptionServiceImpl như sau:
1 2 3 4 5 6 7 8 9 10 11 12 |
@Override public Mono<Option> addNewOption(Option option) { WebClient webClient = WebClient.builder() .baseUrl(getServiceUrl()) .build(); return webClient.post() .uri("/option/add") .body(BodyInserters.fromObject(option)) .retrieve() .bodyToMono(Option.class); } |
OK, bây giờ chúng ta sẽ hiện thực phương thức addNewOption() trong class CompositeOptionService các bạn nhé.
Chúng ta sẽ inject 2 class service CoreQuestionService và CoreOptionService vào trước:
1 2 3 4 5 |
@Autowired private CoreQuestionService coreQuestionService; @Autowired private CoreOptionService coreOptionService; |
Trong phương thức addNewOption(), đầu tiên chúng ta sẽ gọi Core Question Service trước:
1 |
coreQuestionService.findById(option.getQuestionId()) |
Nếu tồn tại một question với id mà đối tượng Option cần thêm mới đang nắm giữ, một item sẽ được trả về. Khi đó chúng ta sẽ gọi tới Core Option Service để thực hiện việc thêm mới này.
1 2 3 |
return coreQuestionService.findById(option.getQuestionId()) .flatMap(question -> coreOptionService.addNewOption(option)) .subscribeOn(Schedulers.elastic()); |
Quá trình gọi qua Core Option Service cần thời gian để xử lý nên mình đã cho chạy quá trình này trên một thread khác sử dụng phương thức subscribeOn().
Điều cuối cùng chúng ta cần làm đó là thêm mới một method vào class CompositeOptionController để expose một POST request “/option/add”:
1 2 3 4 |
@PostMapping("/add") public Mono<ResponseEntity<Option>> addNewOption(@RequestBody Option option) { } |
rồi khai báo autowire đối tượng CompositeOptionService vào:
1 2 |
@Autowired private CompositeOptionService compositeOptionService; |
để có thể sử dụng phương thức addNewOption() của CompositeOptionService mà chúng ta đã tạo ra ở trên:
1 2 3 4 5 6 |
@PostMapping("/add") public Mono<ResponseEntity<Option>> addNewOption(@RequestBody Option option) { return compositeOptionService.addNewOption(option) .map(o -> ResponseEntity.ok(o)) .defaultIfEmpty(ResponseEntity.notFound().build()); } |
OK, đến đây là chúng ta đã hoàn thành việc xây dựng API thêm mới option cho Composite Option Service rồi đó các bạn. Test thử xem sao nhé.
Hiện tại mình đang có một số question như sau:
Giả sử bây giờ mình cần thêm mới option cho question với id 5b697df545aac307e5c68be5:
Kết quả sẽ là: