공모전을 준비하며 어깨 너머 배운 것들을 정리해보았습니다.
@Valid
하고, requestDTO
에서 필수 값 지정할 수 있음toEntity()
로 DB에 저장@Getter
@AllArgsConstructor
public class NFTAddRequestDTO {
@NotBlank
private String assetContractAddress;
@NotBlank
private String tokenId;
public NFT toEntity() {
return new NFT(assetContractAddress, tokenId);
}
}
@AllArgsConstructor
를 하지 않고 생성자를 직접 만든 이유 : @AllArgsConstructor
어노테이션을 하면 id 값도 파라미터로 만들어줘야 하기 때문임@Entity
@Getter
@NoArgsConstructor
public class NFT extends DateTimeEntity {
@Id
@GeneratedValue
@Column(name = "nft_id")
private Long id;
private String assetContractAddress;
private String tokenId;
public NFT(String assetContractAddress, String tokenId) {
this.assetContractAddress = assetContractAddress;
this.tokenId = tokenId;
}
}
NFT nft = requestDTO.toEntity();
@RestController
@RequiredArgsConstructor
@RequestMapping("drawing")
@Api(tags = "🖼 그림 API")
public class DrawingController {
private final DrawingService drawingService;
...
@PutMapping("{drawingId}/nft")
@ApiOperation(value = "NFT 정보 넣기", notes = "본인 그림에만 가능")
@ResponseStatus(NO_CONTENT)
public DrawingResponseDTO addNft(@AuthDTO AuthMemberDTO memberDTO, @PathVariable Long drawingId,
@Valid @RequestBody NFTAddRequestDTO requestDTO) {
Member member = memberService.getMember(memberDTO.getId());
NFT nft = requestDTO.toEntity();
return drawingService.putNft(member, drawingId, nft);
}
}
from
이라고 함수 짓기@Getter
@AllArgsConstructor
public class NFTResponseDTO {
private final String assetContractAddress;
private final String tokenId;
public static NFTResponseDTO from(NFT nft) {
return new NFTResponseDTO(nft.getAssetContractAddress(), nft.getTokenId());
}
}
@Service
@RequiredArgsConstructor
public class DrawingService {
...
@Transactional
public DrawingResponseDTO putNft(Member member, Long drawingId, NFT nft) {
Drawing drawing = getDrawingById(drawingId);
validateDrawingOwner(member, drawing);
NFT savedNFT = nftRepository.save(nft);
drawing.putNftInfo(savedNFT);
return DrawingResponseDTO.from(drawing);
}
public void validateDrawingOwner(Member member, Drawing drawing) {
if (!drawing.ownerEquals(member))
throw new DrawingOwnerException(); // custom excetption
}
}
builder
를 생성하면 좋음@Getter
@AllArgsConstructor
@Builder(access = PRIVATE)
public class MemberResponseDTO {
private final Long id;
private final String name;
private final String profileImage;
private final String accountEmail;
public static MemberResponseDTO from(Member member) {
return MemberResponseDTO.builder()
.id(member.getId())
.name(member.getName())
.accountEmail(member.getAccountEmail())
.profileImage(member.getProfileImage())
.build();
}
}
@Getter
@AllArgsConstructor(access = AccessLevel.PRIVATE)
@Builder(access = AccessLevel.PRIVATE)
public class DrawingResponseDTO {
private final Long id;
private final String title;
private final String description;
private final String fileName;
@JsonFormat(
shape = JsonFormat.Shape.STRING,
pattern = "yyyy-MM-dd HH:mm:ss",
locale = "Asia/Seoul"
)
private final LocalDateTime createdAt;
private final MemberResponseDTO member;
private final Set<TagResponseDTO> tags;
private final Integer heartCount;
private final Integer scrapCount;
private NFTResponseDTO nft;
public static DrawingResponseDTO from(Drawing drawing) {
Set<TagResponseDTO> tags = drawing.getTags()
.stream()
.map(TagResponseDTO::from)
.collect(Collectors.toSet());
NFTResponseDTO nft = NFTResponseDTO.from(drawing.getNft());
MemberResponseDTO member = MemberResponseDTO.from(drawing.getMember());
return DrawingResponseDTO.builder()
.id(drawing.getId())
.title(drawing.getTitle())
.description(drawing.getDescription())
.fileName(drawing.getImage().getFileName())
.createdAt(drawing.getCreatedAt())
.member(member)
.tags(tags)
.heartCount(drawing.getHeartCount())
.scrapCount(drawing.getScrapCount())
.nft(nft)
.build();
}
}