Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Detach and set up with WebClient Config #178

Merged
merged 18 commits into from
Nov 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/dev-cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ jobs:
uses: jsdaniell/[email protected]
with:
name: "./src/main/resources/firebase/gifthub-b2dcb-firebase-adminsdk-yj7uq-912097b9ae.json"
json: ${{ secrets.FIREBASE_JSON }}
json: ${{ secrets.FIREBASE_DEVELOPMENT_JSON }}

# Docker 이미지 build 및 push
- name: docker build and push
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/dev-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ jobs:
uses: jsdaniell/[email protected]
with:
name: "./src/main/resources/firebase/gifthub-b2dcb-firebase-adminsdk-yj7uq-912097b9ae.json"
json: ${{ secrets.FIREBASE_JSON }}
json: ${{ secrets.FIREBASE_DEVELOPMENT_JSON }}

# 5. 테스트를 위한 MySQL 설정
- name: Setup MySQL
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/prod-cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,8 @@ jobs:
- name: Create Json
uses: jsdaniell/[email protected]
with:
name: "./src/main/resources/firebase/gifthub-b2dcb-firebase-adminsdk-yj7uq-912097b9ae.json"
json: ${{ secrets.FIREBASE_JSON }}
name: "./src/main/resources/firebase/gifthub-production-3d052-firebase-adminsdk-zkstv-377ec5747b.json"
json: ${{ secrets.FIREBASE_PRODUCTION_JSON }}

# Docker 이미지 build 및 push
- name: docker build and push
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/prod-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ jobs:
uses: jsdaniell/[email protected]
with:
name: "./src/main/resources/firebase/gifthub-b2dcb-firebase-adminsdk-yj7uq-912097b9ae.json"
json: ${{ secrets.FIREBASE_JSON }}
json: ${{ secrets.FIREBASE_DEVELOPMENT_JSON }}

# 5. 테스트를 위한 MySQL 설정
- name: Setup MySQL
Expand Down
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ out/
src/.DS_Store

# Firebase
/src/main/resources/firebase/gifthub-b2dcb-firebase-adminsdk-yj7uq-912097b9ae.json
/src/main/resources/firebase/

# Actions Secrets
actions-secrets.yml
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import java.io.InputStream;
import java.util.List;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
Expand All @@ -15,9 +16,12 @@

@Configuration
public class FCMConfig {
@Value("${firebase.key-path}")
private String keyPath;

@Bean
FirebaseMessaging firebaseMessaging() throws IOException {
ClassPathResource resource = new ClassPathResource("firebase/gifthub-b2dcb-firebase-adminsdk-yj7uq-912097b9ae.json");
ClassPathResource resource = new ClassPathResource(keyPath);

InputStream refreshToken = resource.getInputStream();

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package org.swmaestro.repl.gifthub.config;

import java.time.Duration;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
import org.springframework.web.reactive.function.client.WebClient;

import reactor.netty.http.client.HttpClient;
import reactor.netty.resources.ConnectionProvider;

@Configuration
public class WebClientConfig {
@Bean
public WebClient webClient() {
return WebClient.builder()
.clientConnector(new ReactorClientHttpConnector(httpClient))
.build();
}

HttpClient httpClient = HttpClient.create(
ConnectionProvider.builder("gifthub-connections")
.maxConnections(100)
.maxIdleTime(Duration.ofSeconds(30))
.pendingAcquireTimeout(Duration.ofSeconds(45))
.pendingAcquireMaxCount(-1)
.evictInBackground(Duration.ofSeconds(30))
.lifo()
.build()
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import org.swmaestro.repl.gifthub.vouchers.dto.VoucherShareRequestDto;
import org.swmaestro.repl.gifthub.vouchers.dto.VoucherShareResponseDto;
import org.swmaestro.repl.gifthub.vouchers.dto.VoucherUpdateRequestDto;
import org.swmaestro.repl.gifthub.vouchers.dto.VoucherUpdateResponseDto;
import org.swmaestro.repl.gifthub.vouchers.dto.VoucherUseRequestDto;
import org.swmaestro.repl.gifthub.vouchers.dto.VoucherUseResponseDto;
import org.swmaestro.repl.gifthub.vouchers.service.PendingVoucherService;
Expand Down Expand Up @@ -132,7 +133,7 @@ public ResponseEntity<Message> listVoucher(HttpServletRequest request, @RequestP
})
public ResponseEntity<Message> updateVoucher(HttpServletRequest request, @PathVariable Long voucherId,
@RequestBody VoucherUpdateRequestDto voucherUpdateRequestDto) throws IOException {
VoucherSaveResponseDto updatedVoucher = voucherService.update(voucherId, voucherUpdateRequestDto);
VoucherUpdateResponseDto updatedVoucher = voucherService.update(voucherId, voucherUpdateRequestDto);
return ResponseEntity.ok(
SuccessMessage.builder()
.path(request.getRequestURI())
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package org.swmaestro.repl.gifthub.vouchers.dto;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.databind.annotation.JsonNaming;

import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.ToString;

@Getter
@ToString
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class)
public class VoucherUpdateResponseDto {
private Long id;
private Long productId;
private String barcode;
private String expiresAt;
private Integer price;
private Integer balance;
private String imageUrl;
@JsonProperty("is_accessible")
private boolean accessible;
@JsonProperty("is_shared")
private boolean shared;
@JsonProperty("is_checked")
private boolean checked;

@Builder
public VoucherUpdateResponseDto(Long id, Long productId, String barcode, String expiresAt, Integer price,
Integer balance, String imageUrl, boolean accessible, boolean shared, boolean checked) {
this.id = id;
this.productId = productId;
this.barcode = barcode;
this.expiresAt = expiresAt;
this.price = price;
this.balance = balance;
this.imageUrl = imageUrl;
this.accessible = accessible;
this.shared = shared;
this.checked = checked;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public class Voucher extends BaseTimeEntity {
@JoinColumn(name = "product_id", nullable = false)
private Product product;

@Column(length = 12)
@Column(length = 16)
private String barcode;

@Column
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,9 @@
import java.io.InputStream;
import java.nio.charset.StandardCharsets;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;
import org.swmaestro.repl.gifthub.config.WebClientConfig;
import org.swmaestro.repl.gifthub.vouchers.dto.GptResponseDto;
import org.swmaestro.repl.gifthub.vouchers.dto.VoucherAutoSaveRequestDto;

Expand All @@ -20,19 +19,19 @@

@Service
public class GptService {
private final WebClient gptClient;
@Value("${openai.api-url}")
private String apiUrl;
@Value("${openai.api-key}")
private String apiKey;
private String prompt;

@Autowired
private ObjectMapper objectMapper;
private final WebClientConfig webClientConfig;

public GptService(WebClient.Builder webClientBuilder, @Value("/gpt/question.txt") String promptPath) throws IOException {
this.gptClient = webClientBuilder.build();
public GptService(@Value("/gpt/question.txt") String promptPath, WebClientConfig webClientConfig, ObjectMapper objectMapper) throws IOException {
this.prompt = loadQuestionFromFile(promptPath);
this.webClientConfig = webClientConfig;
this.objectMapper = objectMapper;
}

public Mono<GptResponseDto> getGptResponse(VoucherAutoSaveRequestDto voucherAutoSaveRequestDto) {
Expand All @@ -47,13 +46,14 @@ public Mono<GptResponseDto> getGptResponse(VoucherAutoSaveRequestDto voucherAuto
message.put("role", "assistant");
message.put("content", prompt);

return gptClient.post()
return webClientConfig.webClient().post()
.uri(apiUrl)
.header("Authorization", "Bearer " + apiKey)
.header("Content-Type", "application/json")
.body(Mono.just(requestBody), ObjectNode.class)
.retrieve()
.bodyToMono(GptResponseDto.class);
.bodyToMono(GptResponseDto.class)
.retry(2);
}

public String loadQuestionFromFile(String filePath) throws IOException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,9 @@

import java.util.Base64;

import javax.annotation.PostConstruct;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;
import org.swmaestro.repl.gifthub.config.WebClientConfig;
import org.swmaestro.repl.gifthub.vouchers.dto.SearchResponseDto;

import lombok.RequiredArgsConstructor;
Expand All @@ -21,25 +19,16 @@ public class SearchService {

@Value("${opensearch.password}")
private String password;
private String auth;

@Value("${opensearch.base-url}")
private String baseUrl;

private WebClient openSearchClient;

@PostConstruct
public void init() {
openSearchClient = WebClient.builder()
.baseUrl(baseUrl)
.build();
auth = "Basic " + Base64.getEncoder().encodeToString((username + ":" + password).getBytes());
}
private final WebClientConfig webClientConfig;

public Mono<SearchResponseDto> search(String query) {
return openSearchClient.post()
.uri("/product/_search")
.header("Authorization", auth)
return webClientConfig.webClient().post()
.uri(baseUrl + "/product/_search")
.header("Authorization", "Basic " + Base64.getEncoder().encodeToString((username + ":" + password).getBytes()))
.header("Content-Type", "application/json")
.bodyValue(query)
.retrieve()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ private String getUUidFileName(String fileName) {
}

public String getDefaultImagePath(String dirName) {
return "https://" + cloudFrontBucketName + "/" + dirName + "/" + defaultImageFile;
return "https://" + cloudFrontBucketName + "/" + defaultImageFile;
}

public String getPresignedUrlForSaveVoucher(String dirName, String extension) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,8 @@ public void execute(VoucherAutoSaveRequestDto voucherAutoSaveRequestDto, String
fcmNotificationService.sendNotification("기프티콘 등록 실패", "이미 등록된 기프티콘 입니다.", username);
notificationService.save(userService.read(username), null, NotificationType.REGISTERED, "이미 등록된 기프티콘 입니다.");
} else {
fcmNotificationService.sendNotification("기프티콘 등록 실패", "자동 등록에 실패했습니다. 수동 등록을 이용해 주세요.", username);
notificationService.save(userService.read(username), null, NotificationType.REGISTERED, "자동 등록에 실패했습니다. 수동 등록을 이용해 주세요.");
fcmNotificationService.sendNotification("기프티콘 등록 실패", "자동 등록에 실패했습니다. 다시 시도해 주세요.", username);
notificationService.save(userService.read(username), null, NotificationType.REGISTERED, "자동 등록에 실패했습니다. 다시 시도해 주세요.");
}
});
}
Expand All @@ -83,7 +83,7 @@ public Mono<VoucherSaveRequestDto> handleGptResponse(VoucherAutoSaveRequestDto v
GptTimeoutException {

return gptService.getGptResponse(voucherAutoSaveRequestDto)
.timeout(Duration.ofMinutes(15))
.timeout(Duration.ofMinutes(5))
.onErrorResume(GptTimeoutException.class, throwable -> Mono.error(new GptTimeoutException()))
.flatMap(response -> {
VoucherSaveRequestDto voucherSaveRequestDto = null;
Expand All @@ -102,12 +102,12 @@ public Mono<VoucherSaveRequestDto> handleGptResponse(VoucherAutoSaveRequestDto v

public Mono<VoucherSaveRequestDto> handleSearchResponse(VoucherSaveRequestDto voucherSaveRequestDto, String username, String filename) {
return searchService.search(createQuery(productNameProcessor.preprocessing(voucherSaveRequestDto))).flatMap(searchResponseDto -> {
voucherSaveRequestDto.setImageUrl(filename);
try {
String brandName = searchResponseDto.getHits().getHitsList().get(0).getSource().getBrandName();
String productName = searchResponseDto.getHits().getHitsList().get(0).getSource().getProductName();
voucherSaveRequestDto.setBrandName(brandName);
voucherSaveRequestDto.setProductName(productName);
voucherSaveRequestDto.setImageUrl(filename);
System.out.println("Search response");
System.out.println(brandName);
System.out.println(productName);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import org.swmaestro.repl.gifthub.vouchers.dto.VoucherShareRequestDto;
import org.swmaestro.repl.gifthub.vouchers.dto.VoucherShareResponseDto;
import org.swmaestro.repl.gifthub.vouchers.dto.VoucherUpdateRequestDto;
import org.swmaestro.repl.gifthub.vouchers.dto.VoucherUpdateResponseDto;
import org.swmaestro.repl.gifthub.vouchers.dto.VoucherUseRequestDto;
import org.swmaestro.repl.gifthub.vouchers.dto.VoucherUseResponseDto;
import org.swmaestro.repl.gifthub.vouchers.entity.Brand;
Expand Down Expand Up @@ -164,7 +165,7 @@ public List<Long> list(String username) {
/*
기프티콘 정보 수정 메서드
*/
public VoucherSaveResponseDto update(Long voucherId, VoucherUpdateRequestDto voucherUpdateRequestDto) {
public VoucherUpdateResponseDto update(Long voucherId, VoucherUpdateRequestDto voucherUpdateRequestDto) {
Voucher voucher = voucherRepository.findById(voucherId)
.orElseThrow(() -> new BusinessException("존재하지 않는 상품권 입니다.", StatusEnum.NOT_FOUND));
// Balance 수정
Expand Down Expand Up @@ -211,8 +212,19 @@ public VoucherSaveResponseDto update(Long voucherId, VoucherUpdateRequestDto vou

voucherRepository.save(voucher);

return VoucherSaveResponseDto.builder()
return VoucherUpdateResponseDto.builder()
.id(voucherId)
.accessible(voucher.getDeletedAt() == null)
.id(voucher.getId())
.productId(voucher.getProduct().getId())
.barcode(voucher.getBarcode())
.price(voucher.getProduct().getPrice())
.balance(voucher.getBalance())
.expiresAt(voucher.getExpiresAt().toString())
.imageUrl(voucher.getImageUrl())
.accessible(voucher.getDeletedAt() == null)
.shared(giftCardService.isExist(voucher.getId()))
.checked(voucher.isChecked())
.build();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import org.swmaestro.repl.gifthub.vouchers.dto.VoucherShareRequestDto;
import org.swmaestro.repl.gifthub.vouchers.dto.VoucherShareResponseDto;
import org.swmaestro.repl.gifthub.vouchers.dto.VoucherUpdateRequestDto;
import org.swmaestro.repl.gifthub.vouchers.dto.VoucherUpdateResponseDto;
import org.swmaestro.repl.gifthub.vouchers.dto.VoucherUseRequestDto;
import org.swmaestro.repl.gifthub.vouchers.dto.VoucherUseResponseDto;
import org.swmaestro.repl.gifthub.vouchers.service.GptService;
Expand Down Expand Up @@ -176,20 +177,20 @@ void voucherUpdateTest() throws Exception {
.expiresAt("2023-06-15")
.build();

VoucherSaveResponseDto voucherSaveResponseDto = VoucherSaveResponseDto.builder()
VoucherUpdateResponseDto voucherUpdateResponseDto = VoucherUpdateResponseDto.builder()
.id(1L)
.build();

// when
when(jwtProvider.resolveToken(any())).thenReturn("my_awesome_access_token");
when(jwtProvider.getUsername(anyString())).thenReturn("이진우");
when(voucherService.update(any(), any(VoucherUpdateRequestDto.class))).thenReturn(voucherSaveResponseDto);
when(voucherService.update(any(), any(VoucherUpdateRequestDto.class))).thenReturn(voucherUpdateResponseDto);

// then
mockMvc.perform(patch("/vouchers/1")
.header("Authorization", "Bearer my_awesome_access_token")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(voucherSaveResponseDto)))
.content(objectMapper.writeValueAsString(voucherUpdateResponseDto)))
.andExpect(status().isOk());
}

Expand Down