사용자 시스템 A가 있고, 관리자 시스템 B가 있다. 둘다 백엔드 어플리케이션이다.
A는 B의 설정값을 feign으로 호출하면 B가 DB로 조회해서 응답한다.
결과적으로 A의 프론트가 이를 받아서 A 시스템에 적용한다.
문제는 성능 테스트에서 A는 접속 수가 짧은 시간에 폭발적으로 늘어나고,
따라서 A가 B를 호출하는 횟수가 증가하면 B에게 부담이 갈텐데,
짊어질 부담에 비해 pod의 사이즈가 너무 작다는 것이다;;
(현재 설계가 MSA 구조로 되어 있다)
갑자기 A와 B의 관계를 반대로 뒤집으라고 한다;;
이제 A-FRONT
는 A-BACK
에서 호출하고 A-BACK
이 B-BACK
에 있던 DB 테이블을 가져와 관리하게 된다.
이제 관리자 시스템인 B-BACK
이 설정을 조회/수정시 반대로 A-BACK
을 호출해서 처리해야만 한다.
get은 쉽게 해결했다. (feign 설정은 별도로 포스팅했으니 생략)
@GetMapping("/theme")
ResponseResult selectTheme(@RequestParam("sche") String sche);
service단에서 처리할 때 return type을 Object로 설정할 수도 있다.
다만 Object는 너무 모호해서 웬만해서는 특정 VO로 타입을 지정하려고 한다.
json 결과 반환은 ObjectMapper가 가장 편했다.
(현재 ResponseResult는 status, message, data를 가지며, data가 결과물이다)
public ResSettingVO selectTheme(String sche) {
ResponseResult resp = themeApi.selectTheme(sche);
ObjectMapper mapper = new ObjectMapper();
return mapper.convertValue(resp.getData(), new TypeReference<ResSettingVO>(){});
}
post로 값을 전송할 때 vo 전송을 하는데 자꾸만 null이 들어왔다.
*지금부터는 개인적으로 테스트한 내용을 적은 것이며, 틀릴 수 있습니다.
내가 현재 내린 결론은 feign으로 통신할 때는
1. 어노테이션이 필수다. (보통 스프링부트는 requestBody할 거 아니면 requestParam 생략 가능함)
2. vo 전송이 requestbody할 거 아니면 안된다.
여기서 그냥 엄청~ 헤맸는데, 첨부파일도 전송하려면 우리가 front단에서 formData 객체를 생성해서 백단으로 보내는데
그냥 보내려는 값들을 파일 타입 여부 상관없이 @RequestPart
해서 보내버리는 게 시간절약이라는 결론이다.
RequestPart 어노테이션을 vo 앞에 추가하면 missingServletException~ 예외가 뜬다.
@RequestBody면 제대로 받는데 첨부파일 때문에 프론트에서 백으로 받을 때 requestBody가 아님;
설마 클래스 타입 다르다고 그러나? 생각도 들어서
결과적으로 값들을 개별로 @RequestParam
처리했다. 이제 String 값들을 가져온다.
@PostMapping(value = "/theme")
ResponseResult insertUpdateTheme(@RequestPart("sche") String sche,
@RequestPart("mainColorCd") String mainColorCd,
@RequestPart("themeNo") String themeNo);
이제 설정에서 이미지 파일을 업로드했을 경우 같이 전송해야 하는데
이 과정에서 참 서버를....많이 죽였다.
이번 포스트의 메인, 들어가보자.
일단 vo로 전송했을 때 file도 마찬가지로 null이 나왔다.
String 값들은 @RequestParam
으로 처리하고 MultipartFile만 @RequestPart
로 처리해보았다.
Body Parameter와 Form Parameter?는 섞어쓸 수 없다는 식의 에러가 나온다
즉, 어노테이션을 통일해야 한다.
@Headers
를 추가하고, 메서드의 consumes
타입도 설정해본다.
부족하다. 여전히 안된다.
MultipartFile 객체를 @RequestParam
으로 처리했더니
Failed to convert property value of type 'java.lang.String' to required type 'org.springframework.web.multipart.MultipartFile' for property 'file'; nested exception is java.lang.IllegalStateException: Cannot convert value of type 'java.lang.String' to required type 'org.springframework.web.multipart.MultipartFile' for property 'file': no matching editors or conversion strategy found
대충 string을 multipartfile로 바꾸는게 힘들다고 한다;
import feign.form.spring.SpringFormEncoder;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.cloud.openfeign.support.SpringEncoder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class FeignFileUploadConfig {
private final ObjectFactory<HttpMessageConverters> messageConverters;
public FeignFileUploadConfig(ObjectFactory<HttpMessageConverters> messageConverters) {
this.messageConverters = messageConverters;
}
@Bean
public SpringFormEncoder feignFormEncoder() {
return new SpringFormEncoder(new SpringEncoder(messageConverters));
}
}
@RequestPart
로 통일한다.@PostMapping(value = "/theme", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
@Headers("Content-Type: multipart/form-data")
ResponseResult insertUpdateTheme(@RequestPart("sche") String sche,
@RequestPart(value = "mainColorCd", required = false) String mainColorCd,
@RequestPart(value = "themeNo", required = false) String themeNo,
@RequestPart(value = "fileByFeign", required = false) MultipartFile fileByFeign);
필수값이 아니면 required=false
처리도 한다.
multpart/form-data를 처리하기 위한 어노테이션과 타입들도 확인하자.
여기까지가 송신하는 측이다.
수신하는 측은 어떨까?
수신측에서 vo로 처리했으면 했는데 못받는다;;;
결국 themeVO에 file이라는 변수명이 있음에도, 별도로 fileByFeign
등으로 별도로 @RequestPart
로 처리해야 했다;;;
@Operation(summary = "LMS 테마 수정", description = "LMS 테마 수정")
@PostMapping
public ResponseEntity<ResponseResult> insertUpdateTheme(ThemeVO themeVO,
@RequestPart(value = "fileByFeign", required = false) MultipartFile fileByFeign) throws IOException {
return ResponseEntity.ok(ResponseResult.data(service.insertUpdateTheme(themeVO, fileByFeign)));
}
결과적으로 동작한다.
내 경험으로는 프론트랑 백이랑 통신하는 거랑 백단끼리 feign으로 통신하는 거 미묘하게 다른 거 같다.
기본적으로 프론트에서 백으로 통신할 때는 RequestPart 어노테이션을 쓸 일이 없다. vo로 보내면 다 변수 따라서 자동 매핑 되거든.
이건 feign을 쓸 때만 한 것이지, 보통 http 리퀘스트 보내고 받을 때 꼭 개별 변수명들로 하고~ 파일은 vo랑 별도로 보내는 건 아님.
2024.08.21
DB 구조를 바꾸라고 인프라팀에서 전달옴.
LMS만 테마 설정을 테이블로 관리하는 것이 아니라,
LMI 테마 설정 테이블이 업데이트 될 때마다 LMS 테마 설정 테이블로 데이터 복사를 해오는 것이다;;
즉, LMS, LMI 모두 테이블을 가지고 있다.