728x90
- 상품 이미지 엔티티는 이미지파일명, 원본 이미지 파일명, 이미지 조회 경로, 대표 이미지 여부를 갖도록 설계
- 대표 이미지 여부가 'Y'인 경우 메인 페이지에서 상품을 보여줄 때 사용
itemImg.java
package com.shop.entity;
import lombok.Getter;
import lombok.Setter;
import javax.persistence.*;
@Entity
@Table(name = "item_img")
@Getter@Setter
public class ItemImg extends BaseEntity{
@Id
@Column(name = "item_img_id")
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String imgName;
private String oriImgName;
private String imgUrl;
private String repimgYn;
@ManyToOne(fetch = FetchType.LAZY)
//상품엔티티와 다대일 단방향 관계로 매핑
//지연로딩을 설정하여 매핑된 상품 엔티티 정보가 필요할 경우 데이터 조회
@JoinColumn(name = "item_id")
private Item item;
//원본 이미지 파일명, 업데이트할 이미지 파일명, 이미지 경로를
//파라미터로 입력받아서 이미지 정보를 업데이트하는 메소드
public void updateItemImg(String oriImgName, String imgName, String imgUrl){
this.oriImgName = oriImgName;
this.imgName = imgName;
this.imgUrl = imgUrl;
}
}
- 상품 등록 및 수정에 사용할 데이터 전달용 DTO 클래스를 만들겠습니다.
- 엔티티 자체를 화면으로 반환 할수도 있지만 그럴 때 엔티티 클래스에 화면에서만 사용하는 값이 추가 된다.
- 상품을 등록할 때는 화면으로부터 전달받은 DTO 객체를 엔티티 객체로 변환하는 작업을 한다.
- 상품을 조회할 때는 엔티티 객체를 DTO 객체로 바꿔주는 작업을 한다.
- 이를 도와주는 라이브러리로 modelmapper라이브러리 가 있다.
- 라이브러리는 서로 다른 클래스의 값을 필드의 이름과 자료형이 같으면 getter, setter를 통해 값을 복사해서 객체를 반환
pom.xml
<dependency>
<groupId>org.modelmapper</groupId>
<artifactId>modelmapper</artifactId>
<version>2.3.9</version>
</dependency>
ItemImgDto.java
package com.shop.dto;
import com.shop.entity.ItemImg;
import lombok.Getter;
import lombok.Setter;
import org.modelmapper.ModelMapper;
@Getter@Setter
public class ItemImgDto {
private Long id;
private String imgName;
private String oriImgName;
private String imgUrl;
private String repImgYn;
//멤버 변수로 ModelMapper객체를 추가
private static ModelMapper modelMapper = new ModelMapper();
//ItemImg 엔티티 객체를 파라미터로 받아서 ItemImg 객체의 자료형과
// 멤버변수의 이름이 같을 때 ItemImgDto로 값을 복사
// static메소드로 선언해 ItemImgDto 객체를 생성하지 않아도 호출 할 수 있도록 한다.
public static ItemImgDto of(ItemImg itemImg){
return modelMapper.map(itemImg,ItemImgDto.class);
}
}
ItemFromDto.java
package com.shop.dto;
import com.shop.constant.ItemSellStatus;
import com.shop.entity.Item;
import lombok.Getter;
import lombok.Setter;
import org.modelmapper.ModelMapper;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.util.ArrayList;
import java.util.List;
@Getter@Setter
public class ItemFormDto {
private Long id;
@NotBlank(message = "상품명은 필수 입력 값입니다.")
private String itemNm;
@NotNull(message = "가격은 필수 입력값입니다.")
private Integer price;
@NotBlank(message = "이름은 필수 입력값입니다.")
private String itemDetail;
@NotNull(message = "재고는 필수 입력값입니다.")
private Integer stockNumber;
private ItemSellStatus itemSellStatus;
//상품 저장 후 수정할 때 상품 이미지 정보를 저장하는 리스트
private List<ItemImgDto> itemImgDtoList = new ArrayList<>();
//상품의 이미지 아이디를 저장하는 리스트
//상품 등록시에는 아직 상품의 이미지를 저장하지 않았기 때문에
//아무값도 들어가 있지 않고 수정 시에 이미지 아이디를 담아둘 용도
private List<Long> itemImgIds = new ArrayList<>();
private static ModelMapper modelMapper = new ModelMapper();
public Item createItem(){
//modelMapper를 이용하여 엔티티 객체와 DTO 객체간의 데이터를 복사하여
//복사한 객첼르 반환해주는 메소드입니다.
return modelMapper.map(this, Item.class);
}
public static ItemFormDto of(Item item){
return modelMapper.map(item, ItemFormDto.class);
}
}
ItemController.java
@GetMapping(value = "/admin/item/new")
public String itemForm(Model model){
model.addAttribute("itemFormDto", new ItemFormDto());
return "/item/itemForm";
}
- 상품 등록 같은 관리자 페이지에서 중요한 것은 데이터의 무결성을 보장
- 데이터가 의도와 다르게 저장된다거나, 잘못된 값이 저장되지 않도록 밸리데이터(validation)을 해야한다.
- 특히 데이터끼리 서로 연관이 있으면 어떤 데이터가 변함에 따라서 다른 데이터로 함께 체크
ItemForm.html
<div layout:fragment="content">
<form role="form" method="post" enctype="multipart/form-data" th:object="${itemFormDto}">
<p class="h2">
상품 등록
</p>
<input type="hidden" th:field="*{id}">
<div class="form-group">
<select th:field="*{itemSellStatus}" class="custom-select">
<option value="SELL">판매중</option>
<option value="SOLD_OUT">품절</option>
</select>
</div>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text">상품명</span>
</div>
<input type="text" th:field="*{itemNm}" class="form-control" placeholder="상품명을 입력해주세요">
</div>
<p th:if="${#fields.hasErrors('itemNm')}" th:errors="*{itemNm}" class="fieldError">Incorrect data</p>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text">가격</span>
</div>
<input type="number" th:field="*{price}" class="form-control" placeholder="상품의 가격을 입력해주세요">
</div>
<p th:if="${#fields.hasErrors('price')}" th:errors="*{price}" class="fieldError">Incorrect data</p>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text">재고</span>
</div>
<input type="number" th:field="*{stockNumber}" class="form-control" placeholder="상품의 재고를 입력해주세요">
</div>
<p th:if="${#fields.hasErrors('stockNumber')}" th:errors="*{stockNumber}" class="fieldError">Incorrect data</p>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text">상품 상세 내용</span>
</div>
<textarea class="form-control" aria-label="With textarea" th:field="*{itemDetail}"></textarea>
</div>
<p th:if="${#fields.hasErrors('itemDetail')}" th:errors="*{itemDetail}" class="fieldError">Incorrect data</p>
<div th:if="${#lists.isEmpty(itemFormDto.itemImgDtoList)}">
<div class="form-group" th:each="num: ${#numbers.sequence(1,5)}">
<div class="custom-file img-div">
<input type="file" class="custom-file-input" name="itemImgFile">
<label class="custom-file-label" th:text="상품이미지 + ${num}"></label>
</div>
</div>
</div>
<div th:if = "${not #lists.isEmpty(itemFormDto.itemImgDtoList)}">
<div class="form-group" th:each="itemImgDto, status: ${itemFormDto.itemImgDtoList}">
<div class="custom-file img-div">
<input type="file" class="custom-file-input" name="itemImgFile">
<input type="hidden" name="itemImgIds" th:value="${itemImgDto.id}">
<label class="custom-file-label" th:text="${not #strings.isEmpty(itemImgDto.oriImgName)} ? ${itemImgDto.oriImgName} : '상품이미지' + ${status.index+1}"></label>
</div>
</div>
</div>
<div th:if="${#strings.isEmpty(itemFormDto.id)}" style="text-align: center">
<button th:formaction="@{/admin/item/new}" type="submit" class="btn btn-primary">저장</button>
</div>
<div th:unless="${#strings.isEmpty(itemFormDto.id)}" style="text-align: center">
<button th:formaction="@{'/admin/item/' + ${itemFormDto.id} }" type="submit" class="btn btn-primary">수정</button>
</div>
<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}">
</form>
</div>
728x90
'project > 쇼핑몰 프로젝트' 카테고리의 다른 글
[쇼핑몰] 상품 등록하기 - 3 (0) | 2023.08.09 |
---|---|
[쇼핑몰] 상품 등록하기 - 2 (0) | 2023.08.08 |
[쇼핑몰] 페이지 권한 설정 - 2 (0) | 2023.07.13 |
[쇼핑몰] 페이지 권한 설정 - 1 (0) | 2023.07.12 |
[쇼핑몰] 로그인/로그아웃 구현하기 - 3 (0) | 2023.07.11 |