๋ฉ‹์‚ฌ Backend Plus 23์ผ์ฐจ ๐Ÿฆ

์‹ ์žฌ์›ยท2023๋…„ 11์›” 23์ผ

์˜ค๋Š˜์€ ์˜ค์ „ ์˜คํ›„ ์ญ‰ ํŒ€ ํ”„๋กœ์ ํŠธ๋งŒ ์ง„ํ–‰ํ•˜์˜€๋‹ค. ์ง„ํ–‰ํ•˜๋ฉด์„œ ๋ฐฐ์› ๊ณ  ๊ฒช์—ˆ๋˜ ์ ์„ ์ •๋ฆฌํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

์˜ค์ „

1 : N ์—ฐ๊ด€๊ด€๊ณ„์ค‘ NPE (Null Point Exception) ๋ฐœ์ƒ

๋ฐฐ๊ฒฝ์œผ๋กœ ์ƒํ’ˆ ํ…Œ์ด๋ธ”, ์ด๋ฏธ์ง€ ํ…Œ์ด๋ธ”์ด ์žˆ์Šต๋‹ˆ๋‹ค.
์ƒํ’ˆ์„ ๋“ฑ๋กํ• ๋•Œ ์—ฌ๋Ÿฌ๊ฐœ์˜ ์ด๋ฏธ์ง€๋ฅผ ๋“ฑ๋กํ• ์ˆ˜ ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•˜์—ฌ ์ƒํ’ˆ ํ…Œ์ด๋ธ”๊ณผ ์ด๋ฏธ์ง€ ํ…Œ์ด๋ธ”์€ 1 : N ๊ด€๊ณ„๋กœ ์ •์˜ ํ•˜์˜€์Šต๋‹ˆ๋‹ค.

@Entity
@Getter
@Table(name = "product")
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@SuperBuilder(toBuilder = true)
public class Product extends BaseEntity {

    @OneToMany(mappedBy = "product")
    private List<Image> productImages = new ArrayList<>();

	// ์—ฐ๊ด€๊ด€๊ณ„ ๋ฉ”์†Œ๋“œ
    // ์„œ๋น„์Šค ๋‹จ์—์„œ createProductImage static ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ 
    // Image ๊ฐ์ฒด ๋ฐ˜ํ™˜ํ›„ addProductImage ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ Image ๊ฐ์ฒด ์ฃผ์ž… 
    public void addProductImage(Image productImage) {
        productImages.add(productImage);
        productImage.setProduct(this);
    }

    public static Image createProductImage(String imageUrl) {
        return new Image(imageUrl);
    }
}

Product ์—”ํ‹ฐํ‹ฐ ํด๋ž˜์Šค์˜ addProductImage ๋ฉ”์†Œ๋“œ์—์„œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.
log ์™€ ๋””๋ฒ„๊น…์„ ํ†ตํ•ด ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๊ฐ’์ด ๋„˜์–ด ์˜ค๋Š”์ง€ ํ™•์ธํ–ˆ์ง€๋งŒ,
์ •์ƒ์ ์œผ๋กœ ๊ฐ’์ด ๋„˜์–ด์™”์œผ๋ฉฐ, productImages, List ๊ฐ์ฒด๊ฐ€ null ์ด๋ผ๋Š” ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.
์ฆ‰ List<Image> ๊ฐ€ ์ดˆ๊ธฐํ™”๊ฐ€ ์•ˆ๋๋‹ค๋Š” ๋œป์ž…๋‹ˆ๋‹ค.

ํ•ด๋‹น ๋ถ€๋ถ„์—์„œ mappedBy ๋งคํ•‘์ด ์ž˜๋ชป ๋˜์—ˆ๋Š”์ง€, ํŠธ๋žœ์žญ์…˜ ์ฒ˜๋ฆฌ๊ฐ€ ์ž˜๋ชป ๋˜์—ˆ๋Š”์ง€ ๋งŽ์€ ์‹œ๊ฐ„์„ ๊ณ ๋ฏผํ•˜์˜€๋‹ค....๐Ÿค•

์›์ธ์œผ๋กœ๋Š” ๋นŒ๋” ํŒจํ„ด์„ ์‚ฌ์šฉ์‹œ ๊ธฐ๋ณธ ์ƒ์„ฑ์ž๋กœ ์ƒ์„ฑํ•œ ์ธ์Šคํ„ด์Šค์˜ ๊ฐ’์€ ๋ฏธ๋ฆฌ ์ง€์ •ํ•ด์ค€ ๊ฐ’์œผ๋กœ ์ƒ์„ฑ๋˜์ง€๋งŒ,

๋นŒ๋”๋ฅผ ์ด์šฉํ•ด์„œ ์ƒ์„ฑํ•œ ์ธ์Šคํ„ด์Šค๋Š” ํ•„๋“œ ์ž๋ฃŒํ˜•์˜ ๊ธฐ๋ณธ ์ดˆ๊ธฐ๊ฐ’์œผ๋กœ ์ƒ์„ฑ์ด ๋ฉ๋‹ˆ๋‹ค.

โžก ๋ง์ด ์กฐ๊ธˆ ์–ด๋ ค์šด๊ฒƒ ๊ฐ™๋‹ค. ์ฝ”๋“œ๋กœ ํ’€์–ด๋ณด์ž๋ฉด, ์•„๋ž˜์™€ ๊ฐ™์„ ๊ฒƒ ๊ฐ™๋‹ค.

@Builder
@AllArgsConstructor
@Getter
public class BuilderTest {
    private String test = "exam";
    private int num = 1;
    private List<Integer> store = new ArrayList<>();
}

public class test1{
public static void main(String[] args) {
		BuilderTest a = new BuilderTest();
        System.out.println(a.getTest()); // exam ์ถœ๋ ฅ
    }
}

public class test2{
public static void main(String[] args) {
		BuilderTest b = BuilderTest.builder().build();
        System.out.println(a.getTest()); // null ๋ฐ˜ํ™˜
    }
}

ํ•ด๊ฒฐ

@Builder.Default ์–ด๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•˜์—ฌ ์ดˆ๊ธฐ๊ฐ’ null ์ด ์•„๋‹Œ ์ž‘์„ฑํ•œ ArrayList๋กœ ์ดˆ๊ธฐํ™” ํ•ฉ๋‹ˆ๋‹ค.

@Entity
@Getter
@Table(name = "product")
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@SuperBuilder(toBuilder = true)
public class Product extends BaseEntity {

    @OneToMany(mappedBy = "product")
    // ํ•ด๋‹น ์–ด๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•˜์—ฌ ๋นŒ๋”๋ฅผ ํ†ตํ•ด ์ƒ์„ฑํ•œ ์ธ์Šคํ„ด์Šค์˜ ๊ธฐ๋ณธ๊ฐ’์„ ์„ธํŒ… ํ•ฉ๋‹ˆ๋‹ค.
    @Builder.Default 
    private List<Image> productImages = new ArrayList<>();

    public void addProductImage(Image productImage) {
        productImages.add(productImage);
        productImage.setProduct(this);
    }

    public static Image createProductImage(String imageUrl) {
        return new Image(imageUrl);
    }
}

์˜คํ›„

๋“ฑ๋กํ•  ์ด๋ฏธ์ง€ ๊ฒฝ๋กœ๋ฅผ yml๋กœ ์žก๊ธฐ

๊ธฐ์กด์˜ ์ƒํ’ˆ์„ ์ด๋ฏธ์ง€๋ฅผ ์ฒจ๋ถ€ํ•ด์„œ ๋“ฑ๋กํ•˜๋Š” ๊ธฐ๋Šฅ์—๋Š” ๊ฐœ์„ ์ ์ด ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.
MultiPartFile ๋ผ๋Š” ํŒŒ์ผ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ๋ฐ›์œผ๋ฉฐ

์‚ฌ์ง„์ด ์ €์žฅ๋  ํŒจํ‚ค์ง€ ๊ฒฝ๋กœ๋ฅผ yml ํ™˜๊ฒฝ๋ณ€์ˆ˜๋กœ ์ถ”์ถœ ํ• ์ˆ˜ ์žˆ๋‹ค๋Š” ์ ์„ ์•Œ์•˜์Šต๋‹ˆ๋‹ค.

public void feedPostImg(final MultipartFile image){
String imageLocation = "product_images/"; // ์‚ฌ์ง„์ด ์ €์žฅ๋  ํŒจํ‚ค์ง€ ๊ฒฝ๋กœ
String imageName = image.getOriginalFilename();
String imagePath = imageLocation + imageName;
// ์ถ”๊ฐ€ ์ฝ”๋“œ ....

}

@Value() ์–ด๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•˜์—ฌ root (๊ธฐ๋ณธ?) yml ๊ฒฝ๋กœ์— ๋งž์ถฐ ํ™˜๊ฒฝ๋ณ€์ˆ˜๋ฅผ ๋งคํ•‘ ํ•ฉ๋‹ˆ๋‹ค.

@Value("${spring.servlet.multipart.location}")
    private String productImagePath;
  • ์•„๋ž˜์™€ ๊ฐ™์ด root (๊ธฐ๋ณธ) yml ์— ํ™˜๊ฒฝ๋ณ€์ˆ˜๋ฅผ ์ž‘์„ฑํ•ด์ฃผ๊ณ , secret.yml ํŒŒ์ผ์„ ๋งŒ๋“ค์–ด ํ™˜๊ฒฝ๋ณ€์ˆ˜์˜ ๊ฐ’์„ ์ž‘์„ฑํ•ด ์ค€๋‹ค.

    โžก secret.yml์„ ์ฝ์–ด๋“œ๋ฆด๋ ค๋ฉด root (๊ธฐ๋ณธ) yml ์— ์•„๋ž˜์™€ ๊ฐ™์ด ์ž‘์„ฑ ํ•ด์•ผ secret.yml ์„ ์ธ์‹ ํ• ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
spring:
  profiles:
    active:
    include: secret

๋ฉ”์†Œ๋“œ ๊ธฐ๋Šฅ ๋‹จ์œ„๋กœ ๋ถ„๋ฆฌ, ์ ‘๊ทผ ์ œ์–ด์ž ์กฐ์ •ํ•˜๊ธฐ

0๊ฐœ์˜ ๋Œ“๊ธ€