일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
Tags
- 오류
- 플러터
- Firebase
- Maui
- AnimationController
- Flutter
- 마우이
- GitHub
- 바인딩
- MVVM
- db
- page
- 애니메이션
- typescript
- listview
- 함수
- HTML
- 파이어베이스
- 리엑트
- Animation
- MSSQL
- MS-SQL
- .NET
- 닷넷
- JavaScript
- Binding
- React JS
- 깃허브
- spring boot
- 자바스크립트
Archives
- Today
- Total
개발노트
[2024.06.20] 화면에 필요한 JSON 데이터 만들기 (Spring Boot) 본문
반응형
현재 타계열사의 요청으로 새로운 프로젝트에 들어가게 되었고, 개인적으로 가장 머리를 많이 써야한다고 생각하는 부분인 DB 설계를 하다보니 여유가 없었던 탓인지 1인개발을 한동안 하지 못 했다.
다른 일정들도 있어 얼추 마무리가 된 지금, 저번에 이어 서버와 클라이언트 화면을 마저 연결해본다.
API Server와 Flutter간의 연결은 앞에서 많이 해보았지만, 이번에 연결할 부분은,
내가 생각했던 화면에 사용될 DTO를 작성하고 호출하는 것으로 여러 시행착오를 몸소 경험하고 완성시키는 것에 큰 의미가 있다고 생각한다.
화면 시나리오
1. 모든 칵테일을 보여준다. (호출 1)
2. 원하는 칵테일을 클릭한다.
3. 해당 칵테일의 정보를 보여주는 화면이 나온다. (호출 2)
따라서 이렇게 두가지 호출을 만들어 줄 예정
- 호출 1은 메소드 쿼리를 이용하여 FindAll() 로 모든 칵테일을 보여준다.(https://mroh1226.tistory.com/202)
- 호출 2는 클릭된 칵테일의 식별 ID를 파라미터로 받고 DTO를 이용하여 해당 칵테일 상세정보를 맞춤형으로 만들어서 클라이언트에 데이터를 보내준다.(https://mroh1226.tistory.com/212)
관련 포스팅은 이미 작성되어있으나, 다시 정리해본다.
API 서버(Spring Boot) 부분
1. [모든 칵테일을 보여주는 화면]에 사용될 API 호출 만들기 (호출 1)
1). 모든 칵테일을 보여주기 위해 API Server에서 FindAll 을 호출하기 위한 작업들
- 모든 칵테일을 호출하는 화면에 사용될 GET 호출은 칵테일 레시피나 부가적인정보들이 필요없다.
- 이를 위해 Cocktail Entity와 연관된 Entity에 @ManyToOne, @OneToMany로 관계 Mapping을 설정하고 @JasonIgnore 로 불필요한 직렬화를 막아준다.
- 필요에 따라서 @JsonProperty로 필요한 필드만 붙여준다.
@Entity
@Getter
@Setter
@Table(name = "cocktail")
public class Cocktail {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "cocktail_id")
private Long cocktailId;
@OneToMany(mappedBy = "cocktail", fetch = FetchType.LAZY)
@JsonIgnore
@ToString.Exclude
private List<Recipe> recipeList = new ArrayList<>();
@ManyToOne(fetch = FetchType.LAZY)
@JsonIgnore
@JoinColumn(name = "mixtype_id") // MixType 엔티티의 기본 키를 참조하는 외래 키 컬럼명을 지정합니다.
private MixType mixType;
@JsonProperty("mixtype_id")
public Long getMixtypeId() {
return mixType != null ? mixType.getMixtypeId() : null;
}
...
}
2). Repository Layer 작성
- Cocktail Repository를 아래와같이 생성해준다.
@Repository
public interface CocktailRepository extends JpaRepository<Cocktail,Long> {
}
3). Service Layer 작성
- Repository 인터페이스를 이용하여 findAll()을 통해 List<Cocktail> 을 반환하는 getAllCocktails() 라는 메소드를 만들어준다.
@Service
public class CocktailService {
@Autowired
private CocktailRepository cocktailRepository;
public List<Cocktail> getAllCocktails(){
return cocktailRepository.findAll();
}
...
}
4). Controller 작성
- 클라이언트에서도 사용될 엔드포인트를 Restful 하게 작성해주고 서비스에 작성된 getAllCocktails() 메소드로 Json 데이터를 전달한다.
@RestController
@RequestMapping("/cocktails")
public class CocktailController {
@Autowired
private CocktailService cocktailService;
@GetMapping("/all")
public List<Cocktail> getAllCocktails(){
List<Cocktail> cocktails = cocktailService.getAllCocktails();
if(cocktails.isEmpty()){
return null;
}else {
return cocktails;
}
}
2. [모든 칵테일을 보여주는 화면]에서 원하는 칵테일을 클릭 했을 때, [칵테일 상세 정보를 보여주는 화면]에 사용될 API 호출 만들기 (호출 2)
1). 상세 정보에 들어가야하는 필드들을 정한다.
- 아래와 같이 칵테일 설명, 레시피, 재료, 만드는 방법을 보내주려고한다.
- 여기에 사용된 Entity로는 Cocktail, Mixtype, Recipe, Ingredient, Category 총 5개의 Entity가 사용됨
- DB에서 조회해보면 이런 JOIN 관계를 원하는 것
2). 화면에 사용될 Entity 관계 설정하기 @ManyToOne, @OneToMany 등
- Cocktail, Mixtype, Recipe, Ingredient, Category 총 5개의 Entity의 관계를 연결해준다.
- (Repository Layer는 호출 1과 동일하게 작성하니 중복내용은 패스)
- 이전전 포스팅 참고 : https://mroh1226.tistory.com/212
3). 상세정보로 보여줄 DTO 작성
- CocktailsInfoDTO 안에 IngredientDTO를 만들어 레시피에 사용된 재료를 리스트로 가지고 있는 DTO를 만들었다.
- 이외 Amount, categoryName 필드 등 상세정보에 필요한 필드들을 들어가야할 위치에 맞게 추가해주었다.
@Getter
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class CocktailsInfoDTO {
private Long cocktailId;
private String name;
private String nameEng;
private String detail;
private double sweetness;
private double acidity;
private double strength;
private int state;
private Long mixtypeId;
private String mixtypeName;
private List<IngredientDTO> ingredientDTOList;
@Getter
@Builder
@AllArgsConstructor
@NoArgsConstructor
public static class IngredientDTO{
private double recipeAmount;
private Long ingredientId;
private String ingredientName;
private String ingredientDetail;
private int ingredientState;
private Long categoryId;
private String categoryName;
private String categoryUnit;
}
}
4). Service Layer (DTO와 Entity 필드 연결하기)
- Service Layer는 Entity를 DTO로 변환해주는 중요한 단계로 Builder() 메소드를 사용하여 원하는 Entity의 필드를 추가하는 형식으로 작성한다.
@Service
public class CocktailService {
@Autowired
private CocktailRepository cocktailRepository;
public CocktailsInfoDTO mapToCocktailsInfoDTO(Cocktail cocktail){
return CocktailsInfoDTO.builder()
.cocktailId(cocktail.getCocktailId())
.name(cocktail.getName())
.nameEng(cocktail.getName_eng())
.detail(cocktail.getDetail())
.sweetness(cocktail.getSweetness())
.acidity(cocktail.getAcidity())
.strength(cocktail.getStrength())
.state(cocktail.getState())
//.mixtypeId(cocktail.getMixType() != null? cocktail.getMixType().getMixtypeId() : null)
.mixtypeId(Optional.ofNullable(cocktail.getMixType()).map(MixType::getMixtypeId).orElse(null))
.mixtypeName(Optional.ofNullable(cocktail.getMixType()).map(MixType::getName).orElse(null))
.ingredientDTOList(cocktail.getRecipeList().stream()
.map(recipe -> CocktailsInfoDTO.IngredientDTO.builder()
.recipeAmount(recipe.getAmount())
.ingredientId(recipe.getIngredient().getIngredientId())
.ingredientName(recipe.getIngredient().getName())
.ingredientDetail(recipe.getIngredient().getDetail())
.categoryId(recipe.getIngredient().getCategory().getCategoryId())
.categoryName(recipe.getIngredient().getCategory().getName())
.categoryUnit(recipe.getIngredient().getCategory().getUnit())
.build()).collect(Collectors.toList()))
.build();
...
}
5). Controller Layer (DTO와 Entity 필드 연결하기)
- Controller Layer에 엔드포인트를 통해 Cocktail_id를 파라미터로 받을 수 있도록 {cocktail_id}를 설정해주었다.
- cocktailService::mapToCocktailsInfoDTO로 칵테일 엔티티를 CocktailsInfoDTO로 변환한다.
@RestController
@RequestMapping("/cocktails")
public class CocktailController {
@Autowired
private CocktailService cocktailService;
@GetMapping("/info/{cocktail_id}")
CocktailsInfoDTO getCocktailsInfo(@PathVariable("cocktail_id") Long cocktailId){
return cocktailService.findById(cocktailId)
.map(cocktailService::mapToCocktailsInfoDTO)
.orElse(null);
}
...
}
완성!
이글이 포스팅된 시점에서 API Server ↔ Flutter 연결 또한 완료되었다.
다음 포스팅은 API Server ↔ Flutter 연결에 대해서 리마인드할겸 작성해보자
반응형
'1인 개발 일지' 카테고리의 다른 글
[2024.06.28] API 서버에 만든 호출 Flutter 연결하기 (0) | 2024.06.28 |
---|---|
[2024.05.21] API 서버 DTO 작업중 (0) | 2024.05.21 |
[2024.04.19] DB, API Server, Client App 전부 연동 완료 (0) | 2024.04.19 |
[2024.04.12] API Server, DB 연동 완료 (0) | 2024.04.12 |
[2024.04.04] MySQL 스키마 1차 구성완료 (0) | 2024.04.04 |
Comments