[Admin_상품등록] 다중 이미지 삽입 / 이미지-상품 테이블 조인 / enum 카테고리, 판매 상태(1)

2024. 1. 19. 13:56Project/ShoppingMall

반응형

 

🟢 Constant

 

열거형 : 고정된 값들의 집합

 

▪️ CategoryTypeRole 

제품 카테고리 설정

 

CategoryTypeRole이라는 열거형 정의

열거 상수(ALL, LIVING, BATHROOM, KITCHEN, MEMBERSALE)는 해당 카테고리의 설명(description)을 가지고 있음

 

생성자 : 열거 상수를 정의할 때, 상수의 값을 초기화하기 위해 사용

getter메서드 : 외부에서 열거 상수의 설명을 알고 싶을 때,

                         getDescription 메서드를 호출하여 해당 열거 상수의 설명을 반환

public enum CategoryTypeRole {

  ALL("전체"),
  LIVING("생활용품"),
  BATHROOM("욕실용품"),
  KITCHEN("주방용품"),
  MEMBERSALE("회원전용");

  private final String description;

  CategoryTypeRole(String description) {
    this.description = description;
  }
  public String getDescription() {
    return description;
  }

}

 

더보기

숫자 추가 하는 경우

  ALL(0, "전체"),
  LIVING(1, "생활용품"),
  BATHROOM(2, "욕실용품"),
  KITCHEN(3, "주방용품"),
  MEMBERSALE(4, "회원전용");

  private final int code;
  private final String description;

  CategoryTypeRole(int code, String description) {
    this.code = code;
    this.description = description;
  }

  public int getCode() {
    return code;
  }

  public String getDescription() {
    return description;
  }

▪️ SellstateRole 

제품 판매상태 설정

public enum SellStateRole {

  SELL("판매중"),
  STOP("판매중지"),
  LACK("재고없음");

  private final String description;

  SellStateRole(String description) {
    this.description = description;
  }

  public String getDescription() {
    return description;
  }
}

 

 

🟢 Entity

▪️ ImageEntity 

- imageType을 이용해 이미지 분류

- productId를 이용해 테이블 조인

@Entity
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Table(name = "image")
@SequenceGenerator(
    name = "image_SEQ",
    sequenceName = "image_SEQ",
    initialValue = 1,
    allocationSize = 1
)

public class ImageEntity extends BaseEntity {

  @Id
  @GeneratedValue(strategy = GenerationType.SEQUENCE, generator ="image_SEQ")
  private Integer imageId;

  @Column(name = "imageFile")
  private String imageFile;

  //대표이미지=0, 서브이미지=1, 상세이미지=2
  @Column(name = "imageType")
  private Integer imageType;

  //외래키 (productId) - 상품테이블과 조인 (여러 개의 이미지가 하나의 상품에 매핑)
  @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.REMOVE)
  @JoinColumn(name = "productId")
  private ProductEntity productEntity;

}

 

▪️  ProductEntity

- ImageEntity와 테이블조인

- 상품 하나에 여러 개의 이미지 삽입 가능 : @OneToMany

  //외래키 - 이미지테이블 (하나의 상품에 이미지 여러개)
  //cascade = CascadeType.ALL : 엔터티의 상태 변화가 연관된 엔터티에 전파되는 방식
  @OneToMany(mappedBy = "productEntity", cascade = CascadeType.ALL)
  private List<ImageEntity> productImages = new ArrayList<>();
더보기
@Entity
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Table(name = "product")
@SequenceGenerator(
    name = "product_SEQ",
    sequenceName = "product_SEQ",
    initialValue = 1,
    allocationSize = 1
)
public class ProductEntity extends BaseEntity {

  //기본키
  @Id
  @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "product_SEQ")
  private Integer productId;

  //외래키 - 이미지테이블 (하나의 상품에 이미지 여러개)
  //cascade = CascadeType.ALL : 엔터티의 상태 변화가 연관된 엔터티에 전파되는 방식
  @OneToMany(mappedBy = "productEntity", cascade = CascadeType.ALL)
  private List<ImageEntity> productImages = new ArrayList<>();

  //외래키 - 주문테이블 (하나의 상품은 여러 주문 테이블에)
  //cascade = CascadeType.DETACH : 주문은 삭제되지 않으면서 상품만 삭제
  @OneToMany(mappedBy = "productEntity", cascade = CascadeType.DETACH)
  private List<OrderEntity> orderEntityList = new ArrayList<>();

  //카테고리유형 (전체, 생활용품, 욕실용품, 주방용품, 회원전용)
  @Enumerated(EnumType.STRING)
  private CategoryTypeRole categoryTypeRole;

  //상품판매상태 (SELL(판매중), STOP(판매중지), LACK(재고없음))
  @Enumerated(EnumType.STRING)
  private SellStateRole sellStateRole;

  //상품이름
  @Column(name ="productName", length = 50, nullable = false)
  private String productName;

  //상품설명
  @Column(name ="productContent", length = 200, nullable = false)
  private String productContent;

  //상품상세정보
  @Lob
  @Column(name ="productDetail", length = 500)
  private String productDetail;

  //소비자가(정가)
  @Column(name ="productCost", nullable = false)
  private Integer productCost;

  //판매가
  @Column(name ="productPrice", nullable = false)
  private Integer productPrice;

  //할인율
  @Column(name ="productDis")
  private Integer productDis;

  //상품옵션
  @Column(name ="productOpt")
  private Integer productOpt;

  //상품재고수량
  @Column(name ="productCnt", nullable = false)
  private Integer productCnt;

  //상품좋아요(관심,찜)
  @Column(name ="productLike")
  private Integer productLike;

  //상품조회수
  @ColumnDefault("0")
  @Column(name ="productViewcnt")
  private Integer productViewcnt;

}

 

▪️  BaseEntity

더보기
@Getter
@Setter
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public abstract class BaseEntity {

  @Column(name="reDate")
  @CreatedDate
  private LocalDateTime reDate;      //생성날짜

  @Column(name = "modDate")
  @LastModifiedDate
  private LocalDateTime modDate;      //수정날짜

}

+ Application에 @EnableJpaAuditing 추가

 

🟢 DTO

▪️ ImageDTO

@Getter
@Setter
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class ImageDTO {

  private Integer imageId;          // 이미지 고유번호

  private String imageFile;         // 이미지 파일이름

  private Integer imageType;         // 이미지 종류 (대표이미지=0, 서브이미지=1, 상세이미지=2)

  private Integer productId;        // 상품번호(외래키)

  private Integer noticeId;         // 공지번호(외래키)

}

 

▪️ ProductDTO

@Getter
@Setter
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class ProductDTO {

  //상품등록 부분
  //기본키
  private Integer productId;

  //상품이름
  @NotEmpty(message = "상품이름은 필수 입력입니다.")
  private String productName;

  //상품설명
  @NotEmpty(message = "상품설명은 필수 입력입니다.")
  private String productContent;

  //상품상세정보
  private String productDetail;

  //소비자가(정가)
  @NotNull(message = "가격은 필수 입력입니다.")
  private Integer productCost;

  //판매가(할인가)
  @NotNull(message = "가격은 필수 입력입니다.")
  private Integer productPrice;

  //회원 구매수량
  private Integer productNum;

  //합계 = 판매가 * 옵션 선택 수량
  private Integer producTotal;

  //할인율 = (정가 -할인가)/정가
  private Integer productDis;

  //상품옵션
  private Integer productOpt;

  //재고수
  @NotNull(message = "상품수량은 필수 입력입니다.")
  @Min(value = 0, message = "상품 수량은 0 이상이어야 합니다.")
  private Integer productCnt;

  //상품좋아요(관심,찜)
  private Integer productLike;

  //상품조회수
  private Integer productViewcnt;

  //카테고리유형 (전체, 생활용품, 욕실용품, 주방용품, 회원전용)
  private CategoryTypeRole categoryTypeRole;

  //상품판매상태 (SELL, STOP, LACK)
  private SellStateRole sellStateRole;

  //이미지 관리 DTO
  private List<ImageDTO> imageDTOs;

  //이미지파일 처리
  private List<MultipartFile> images;

  private LocalDateTime reDate;

  private LocalDateTime modDate;

}

 

 

🟢 Repository

▪️ ProductRepository

상품검색 : 상품명, 상품명or상품설명, 카테고리유형, 판매상태로 조회

@Repository
public interface ProductRepository extends JpaRepository<ProductEntity, Integer> {

  //상품 고유번호
  ProductEntity findByProductId(Integer productId);

  //검색부분
  //상품명으로 상품 조회
  @Query("SELECT p FROM ProductEntity p WHERE p.productName LIKE %:keyword%")
  Page<ProductEntity> findProductName(@Param("keyword") String keyword, Pageable pageable);

  // 상품명 또는 상품설명으로 상품 조회
  @Query("SELECT p FROM ProductEntity p WHERE p.productName LIKE %:keyword% OR p.productContent LIKE %:keyword%")
  Page<ProductEntity> findProNameContent(@Param("keyword") String keyword, Pageable pageable);

  // 카테고리 유형으로 상품 조회
  @Query("SELECT p FROM ProductEntity p WHERE p.categoryTypeRole = :categoryType")
  Page<ProductEntity> findByCategoryType(@Param("categoryType") CategoryTypeRole categoryTypeRole, Pageable pageable);

  // 판매 상태로 상품 조회
  @Query("SELECT p FROM ProductEntity p WHERE p.sellStateRole = :sellState")
  Page<ProductEntity> findBySellStateRole(@Param("sellState") SellStateRole sellStateRole, Pageable pageable);

}

 

 

🟢 이미지 경로 설정

imgLocation=C:/solace/item/
uploadPath = file:///C:/solace/

 

 

🟢 Config

▪️ WebMvsConfig

웹 애플리케이션의 MVC (Model-View-Controller) 설정을 정의하는 역할

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

  //application에서 사용자 변수 읽어오기
  @Value(("${uploadPath}"))
  String uploadPath;


  @Override
  public void addResourceHandlers(ResourceHandlerRegistry registry) {
    registry.addResourceHandler("/images/**")
        .addResourceLocations(uploadPath);    //자원의 위치
  }

}
더보기

@Configuration : 해당 클래스가 Spring의 Java-based 설정 클래스임을 나타냄

                            애플리케이션의 설정 정보를 제공

 

@Value 어노테이션을 사용하여 uploadPath 변수를 주입

 

registry.addResourceHandler("/images/**") : "/images/**" 경로로 들어오는 요청에 대해 핸들러를 등록

 

.addResourceLocations(uploadPath): 정적 리소스의 실제 위치를 설정

 

 

🟢 Service

▪️ FileService

@Service
@RequiredArgsConstructor
public class FileService {

  //파일을 저장할 경로
  @Value("${imgLocation}")
  private String imgLocation;


  //저장할 경로,파일명,데이터 값
  public String uploadFile(String originalFileName, byte[] filedata) throws Exception {

    UUID uuid = UUID.randomUUID();    //문자열 생성
    String extendsion = originalFileName.substring(originalFileName.lastIndexOf("."));    //문자열 분리
    String saveFileName = uuid.toString()+extendsion;    //새로운 파일명
    String uploadFullurl = imgLocation+saveFileName;      //저장위치 및 파일명

    //하드디스크에 파일 저장
    FileOutputStream fos = new FileOutputStream(uploadFullurl);
    fos.write(filedata);
    fos.close();

    return saveFileName;    //데이터베이스에 저장할 파일명
  }


  // 파일 삭제 (상품을 수정시 기존 파일을 삭제하고 새로운 파일을 저장)
  public void deleteFile(String fileName) throws Exception {

    String deleteFileName = imgLocation + fileName;

    File deleteFile = new File(deleteFileName);
    if (deleteFile.exists()) {
      deleteFile.delete();
    }
  }
}
더보기

filedata : 업로드된 파일의 데이터를 나타내는 byte 배열

 

imgLocation에 저장할 파일의 경로

 

▪️  ImageService

 

@RequiredArgsConstructor 어노테이션은 생성자 인젝션을 자동으로 생성

@Service
@RequiredArgsConstructor
@Transactional
public class ImageService {

  //파일업로드
  private final FileService fileService;
  private final ModelMapper modelMapper = new ModelMapper();
  private final ImageRepository imageRepository;

  // 삽입
  public void uploadImage(ImageDTO imageDTO, ProductEntity entity, MultipartFile imageFile) throws Exception {
    String originalFileName = imageFile.getOriginalFilename();  //저장 할 파일명
    String newFileName="";                                      //UUID로 생성된 새로운 파일명

    if(originalFileName != null && originalFileName.length() >0) {    //파일존재시 업로드 진행
      newFileName = fileService.uploadFile(originalFileName, imageFile.getBytes());
    }

    imageDTO.setImageFile(newFileName); //새로운 이름으로 변경
    ImageEntity imageEntity = modelMapper.map(imageDTO, ImageEntity.class); //데이터 변환
    imageEntity.setProductEntity(entity);

    try {
      imageRepository.save(imageEntity);
    } catch(Exception e) {
      //
    }

  }


  // 수정 (글만 또는 이미지만 또는 글+이미지 수정)
  public void updateImage(ImageDTO imageDTO, ProductEntity productEntity, MultipartFile imageFile) throws Exception {

    String originalFileName = imageFile.getOriginalFilename();  // 기존 파일명
    String newFileName = "";    // UUID로 생성된 새로운 파일명

    // 해당 이미지 존재 여부 확인
    ImageEntity imageEntity = imageRepository
        .findById(imageDTO.getImageId())
        .orElseThrow();

    String deleteFileName = imageEntity.getImageFile();    // 이전 파일명

    if (originalFileName != null && originalFileName.length() > 0) {    // 파일 존재시 업로드 진행
      if (deleteFileName.length() != 0) {      // 이전 파일 존재시 삭제
        fileService.deleteFile(deleteFileName);
      }
      newFileName = fileService.uploadFile(originalFileName, imageFile.getBytes());

      imageDTO.setImageFile(newFileName);
      imageDTO.setImageId(imageEntity.getImageId());    // 새로운 파일명을 재등록

      ImageEntity update = modelMapper.map(imageDTO, ImageEntity.class);    // 데이터 변환

      // 이미지와 제품 간의 관계 설정
      update.setProductEntity(productEntity);

      update.setImageFile(newFileName);
      update.setImageId(imageEntity.getImageId());   // 외래키 받아올 때 엔티티로 선언했기 때문에 id가 아닌 entity로 가져와야 함

      imageRepository.save(update);
    }
  }


  //삭제
  public void deleteImage (Integer imageId) throws Exception {
    imageRepository.deleteById(imageId);

  }

}

 

 

▪️ ProductService

상품등록

 

ModelMapper : 객체 간 데이터 복사를 위한 라이브러리로, DTO와 Entity 간의 매핑을 수행

 

ProductDTOProductEntity로 변환하고, 상품 정보를 데이터베이스에 저장

 

@Service
@RequiredArgsConstructor
@Transactional
public class ProductService {

  private final FileService fileService;
  private final ImageService imageService;
  private final ModelMapper modelMapper = new ModelMapper();

  private final ProductRepository productRepository;


  //제품등록
  //ProductDTO를 ProductEntity로 변환 (데이터베이스에 저장하기 위해)
  public void insertProduct(ProductDTO productDTO, List<MultipartFile> imageFiles) throws Exception {

    //이미지 테이블에 저장할 정보(데이터베이스에 저장), 사용자가 업로드한 실제 이미지 파일
    List<ImageDTO> dataDTO = productDTO.getImageDTOs();
    List<MultipartFile> images = productDTO.getImages();

    //신규 상품 등록
    ProductEntity data = modelMapper.map(productDTO, ProductEntity.class);
    ProductEntity dataEntity = productRepository.save(data);

    int index = 0;

    for (MultipartFile file : images) {
      ImageDTO jobDTO = dataDTO.get(index);
      try {
        //이미지 등록 (실제 이미지 파일과 이미지 정보, 상품 엔터티를 받아서 이미지를 업로드, 이미지 테이블에 정보를 등록)
        //dataEntity : 상품이 데이터베이스에 등록된 후에 반환된 엔터티
        //이미지 정보는 jobDTO에서 가져오며, 이미지 파일은 file에서 가져옴
        imageService.uploadImage(jobDTO, dataEntity, file);
      } catch (IOException e) {
        //
      }
      index++;
    }
  }

}
더보기

이미지 정보는 ProductDTOimageDTOs 리스트에서 가져오고,

실제 이미지 파일은 ProductDTOimages 리스트에서 가져옴

 

이미지 등록은 ImageServiceuploadImage 메서드를 사용하여 처리하며,

각 이미지 정보와 상품 엔터티를 함께 전달

 

상품목록(관리자)

@Service
@RequiredArgsConstructor
@Transactional
public class ProductService {

  private final FileService fileService;
  private final ImageService imageService;
  private final ModelMapper modelMapper = new ModelMapper();

  private final ProductRepository productRepository;

  //전체 상품 목록 조회 (검색 포함, 페이징 처리) -> 관리자
  public Page<ProductDTO> adminFindAll(String type, String keyword, String sellState, String categoryType, Pageable page) throws Exception {

    int currentPage = page.getPageNumber() - 1;
    int pageLimit = 10;    //한페이지에 총 8개의 상품 진열

    //제품번호 기준 역순으로 정렬
    Pageable pageable = PageRequest.of(currentPage, pageLimit, Sort.by(Sort.Direction.DESC, "productId"));

    Page<ProductEntity> productEntityPage;

    if ("n".equals(type) && keyword != null && !keyword.isEmpty()) {
      // 상품명 조회
      productEntityPage = productRepository.findProductName(keyword, pageable);
      System.out.println("상품명 조회");
    } else if ("nc".equals(type) && keyword != null && !keyword.isEmpty()) {
      // 상품명+내용 조회
      productEntityPage = productRepository.findProNameContent(keyword, pageable);
      System.out.println("상품명+내용 조회");
    } else if ("ca".equals(type) && categoryType != null && !categoryType.isEmpty()) {
      // 카테고리 조회
      productEntityPage = productRepository.findByCategoryType(CategoryTypeRole.valueOf(categoryType), pageable);
      System.out.println("카테고리 조회");
    } else if ("s".equals(type) && sellState != null && !sellState.isEmpty()) {
      // 판매상태 조회
      productEntityPage = productRepository.findBySellStateRole(SellStateRole.valueOf(sellState), pageable);
      System.out.println("판매형태 조회");
    } else {
      // 전체 조회
      productEntityPage = productRepository.findAll(pageable);
      System.out.println("전체 조회");
    }

    // 상품정보 및 이미지들을 Entity에서 DTO로 복수전달
    List<ProductDTO> productDTOList = new ArrayList<>();

    for (ProductEntity entity : productEntityPage) {
      ProductDTO productDTO = ProductDTO.builder()
          .productId(entity.getProductId())
          .productName(entity.getProductName())
          .productContent(entity.getProductContent())
          .productDetail(entity.getProductDetail())
          .productCost(entity.getProductCost())
          .productPrice(entity.getProductPrice())
          .productDis(entity.getProductDis())
          .productOpt(entity.getProductOpt())
          .productCnt(entity.getProductCnt())
          .productLike(entity.getProductLike())
          .productViewcnt(entity.getProductViewcnt())
          .categoryTypeRole(entity.getCategoryTypeRole())
          .sellStateRole(entity.getSellStateRole())
          .reDate(entity.getReDate())
          .modDate(entity.getModDate())
          .imageDTOs(mapImagesToDTOs(entity.getProductImages()))
          .build();

      productDTOList.add(productDTO);
    }
    return new PageImpl<>(productDTOList, pageable, productEntityPage.getTotalElements());
  }

}

 

상품조회

상품 ID를 이용하여 데이터베이스에서 상품을 조회하고, 조회된 결과를 ProductDTO로 변환하는 메서드

@Service
@RequiredArgsConstructor
@Transactional
public class ProductService {

  private final FileService fileService;
  private final ImageService imageService;
  private final ModelMapper modelMapper = new ModelMapper();

  private final ProductRepository productRepository;

  //상품개별조회
  public ProductDTO findOne(Integer productId) throws Exception {

    //modelMapper를 사용하여 엔터티와 DTO 간의 매핑을 수행
    //이미지 관련 필드를 제외하도록 설정 ( 이미지 정보는 별도로 처리할 것이기 때문 )
    modelMapper.typeMap(ProductEntity.class, ProductDTO.class)
        .addMappings(mapper -> mapper.skip(ProductDTO::setImages));


    //Optional에서 데이터를 추출하기 위해 get() 메서드를 사용
    Optional<ProductEntity> data = productRepository.findById(productId);
    ProductEntity entity = data.get();


    //변환
    //Optional에 데이터가 있는 경우, 해당 데이터를 ProductDTO로 변환 (images 필드는 무시)
    ProductDTO result = data.map(mapper -> modelMapper.map(mapper, ProductDTO.class)).orElse(null);


    //상품에 속한 이미지들을 가져오기
    //각 이미지를 ImageDTO로 변환하고, 이를 리스트로 수집
    List<ImageDTO> imageDTOS = entity.getProductImages().stream()
        .map(imageEntity -> modelMapper.map(imageEntity, ImageDTO.class))
        .collect(Collectors.toList());
    result.setImageDTOs(imageDTOS);

    return result;
  }

}

 

상품수정

글만 또는 이미지만 또는 글+이미지 수정

@Service
@RequiredArgsConstructor
@Transactional
public class ProductService {

  private final FileService fileService;
  private final ImageService imageService;
  private final ModelMapper modelMapper = new ModelMapper();

  private final ProductRepository productRepository;

  //수정 (글만 또는 이미지만 또는 글+이미지 수정)
  public void updateProductAndImages(ProductDTO productDTO, List<MultipartFile> imageFiles) throws Exception {

    //전달받은 ProductDTO에서 이미지 정보 가져오기
    List<ImageDTO> dataDTO = productDTO.getImageDTOs();  

    //상품 수정 등록
    ProductEntity productEntity = productRepository.save(modelMapper.map(productDTO, ProductEntity.class));

    //이미지 파일 목록에 대한 반복문
    int index = 0;
    for (MultipartFile file : imageFiles) {
      //현재 인덱스에 해당하는 이미지 DTO 가져오기
      ImageDTO imgDTO = dataDTO.get(index);
      imgDTO.setProductid(productEntity.getProductId());

      //이미지 정보를 업데이트하거나 새로운 이미지를 등록
      imageService.updateImage(imgDTO, productEntity, file);
      
      index++;
    }
  }

}

 

상품삭제

@Service
@RequiredArgsConstructor
@Transactional
public class ProductService {

  private final FileService fileService;
  private final ImageService imageService;
  private final ModelMapper modelMapper = new ModelMapper();

  private final ProductRepository productRepository;

  //삭제
  public void delete (Integer productId) throws Exception {

    ProductEntity productEntity = productRepository.findByProductId(productId); //상품조회

    if (productEntity == null) {
      return;
    }

    // 연결된 주문과의 관계를 끊음
    for (OrderEntity orderEntity : productEntity.getOrderEntityList()) {
      orderEntity.setProductEntity(null);
    }

    //연결된 이미지 삭제
    List<ImageEntity> imageEntitys = productEntity.getProductImages();
    for (ImageEntity data : imageEntitys) {
      fileService.deleteFile(data.getImageFile());
    }

    // 상품 삭제
    productRepository.deleteById(productId);
  }



}

 

 

 

🟢 Controller

▪️ ProductController

상품목록

@Slf4j
@Controller
@RequiredArgsConstructor
public class AdminProductController {

  private final ProductService productService;

  //상품목록
  @GetMapping("/admin_productlist")
  public String listForm(@RequestParam(value = "type", defaultValue = "") String type,
                         @RequestParam(value = "keyword", defaultValue = "") String keyword,
                         @RequestParam(value = "sellState", defaultValue = "") String sellState,
                         @RequestParam(value = "categoryType", defaultValue = "") String categoryType,
                         @PageableDefault(page = 1) Pageable pageable,
                         Model model) throws Exception {

    Page<ProductDTO> productDTOS = productService.adminFindAll(type, keyword, sellState, categoryType, pageable);

    //전체 게시글 수
    productDTOS.getTotalElements();

    int blockLimit = 5;
    int startPage = (((int) (Math.ceil((double) pageable.getPageNumber() / blockLimit))) - 1) * blockLimit + 1;
    int endPage = Math.min(startPage + blockLimit - 1, productDTOS.getTotalPages());

    int prevPage = productDTOS.getNumber();
    int currentPage = productDTOS.getNumber() + 1;
    int nextPage = productDTOS.getNumber() + 2;
    int lastPage = productDTOS.getTotalPages();

    // reDate 날짜 표시
    ProductDTO productDTO = new ProductDTO();

    // 모델에 ProductDTO 추가
    model.addAttribute("productDTO", productDTO);
    model.addAttribute("productDTOS", productDTOS);

    model.addAttribute("startPage", startPage);
    model.addAttribute("endPage", endPage);
    model.addAttribute("prevPage", prevPage);
    model.addAttribute("currentPage", currentPage);
    model.addAttribute("nextPage", nextPage);
    model.addAttribute("lastPage", lastPage);

    model.addAttribute("type", type);
    model.addAttribute("keyword", keyword);

    return "/admin/product_list";

  }

}

 

상품등록

@Slf4j
@Controller
@RequiredArgsConstructor
public class AdminProductController {

  private final ProductService productService;

  //제품등록
  @GetMapping("/admin_product_insert")
  public String productInsertForm(Model model) throws Exception {

    ProductDTO productDTO = new ProductDTO();

    model.addAttribute("productDTO", productDTO);
    model.addAttribute("categoryType", CategoryTypeRole.values());
    model.addAttribute("sellsState", SellStateRole.values());

    return "/admin/product_insert";
  }

  // 상품 등록 처리 (상품 정보 및 이미지 업로드)
  @PostMapping("/admin_product_insert")
  public String productInsertProc(@Valid @ModelAttribute("productDTO") ProductDTO productDTO,
                                  BindingResult bindingResult,
                                  @RequestParam("images") List<MultipartFile> imageFiles,
                                  Model model) {

    //검증오류
    if (bindingResult.hasErrors()) {
      model.addAttribute("categoryType",CategoryTypeRole.values());
      model.addAttribute("sellsState",SellStateRole.values());
      return "/admin/product_insert";
    }

    try {
      productService.insertProduct(productDTO, imageFiles);
      model.addAttribute("success", "상품 등록이 완료되었습니다.");
      model.addAttribute("searchUrl", "/admin_productlist");
      return "message";
    } catch (Exception e) {
      model.addAttribute("error", "상품 등록 실패! 다시 등록해주세요.");
      model.addAttribute("searchUrl", "/admin_product_insert");
      return "message";
    }

  }

}

 

상품상세

@Slf4j
@Controller
@RequiredArgsConstructor
public class AdminProductController {

  private final ProductService productService;

   //제품 상세페이지
  @GetMapping("/admin_product_indetail")
  public String productDetailForm(Integer productId, Model model) throws Exception {

    ProductDTO productDTO = productService.findOne(productId);
    model.addAttribute("productDTO", productDTO);

    return "/admin/product_detail";

 	}
    
 }

 

상품수정

@Slf4j
@Controller
@RequiredArgsConstructor
public class AdminProductController {

  private final ProductService productService;

//제품 상세페이지 수정폼  (글만 또는 이미지만 또는 글+이미지 수정)
  @GetMapping("/admin_product_update")
  public String productUpdateForm(Integer productId, Model model) throws Exception {

    ProductDTO productDTO = productService.findOne(productId);

    //열거형 목록
    model.addAttribute("sellState", SellStateRole.values());
    model.addAttribute("categoryType", CategoryTypeRole.values());

    model.addAttribute("productDTO", productDTO); //데이터
    model.addAttribute("imageDTOs", productDTO.getImageDTOs()); //이미지

    return "admin/product_update";
  }
  // 제품 상세페이지 수정처리
  @PostMapping("/admin_product_update")
  public String productUpdateProc(@Valid ProductDTO productDTO, BindingResult bindingResult,
                                  @RequestParam("images") List<MultipartFile> imageFiles,
                                  Model model) throws Exception {

    if (bindingResult.hasErrors()) {
      model.addAttribute("sellState", SellStateRole.values());
      model.addAttribute("categoryType", CategoryTypeRole.values());

      return "admin/product_update";
    }

    try {
      // 상품 정보 및 이미지 업데이트
      productService.updateProductAndImages(productDTO, imageFiles);

      return "redirect:/admin_productlist";
    } catch (Exception e) {

      e.printStackTrace();

      model.addAttribute("error", "상품 수정에 실패하였습니다.");

      model.addAttribute("sellState", SellStateRole.values());
      model.addAttribute("categoryType", CategoryTypeRole.values());
      return "admin/product_update";   //"/admin_product_update";
    }
  }
    
 }

 

상품삭제

@Slf4j
@Controller
@RequiredArgsConstructor
public class AdminProductController {

  private final ProductService productService;

  //제품등록 상세페이지 삭제
  @GetMapping("/admin_product_delete")
  public String productDeleteForm(Integer productId) throws Exception {
    productService.delete(productId);
    return "redirect:/admin_productlist";
  }
    
}

 

 

 

 

 

[Admin_상품등록] 다중 이미지 삽입 / 이미지-상품 테이블 조인 / enum 카테고리, 판매 상태(2)

[Admin_상품등록] 다중 이미지 삽입 / 이미지-상품 테이블 조인 / enum 카테고리, 판매 상태(1) 🟢 Constant 열거형 : 고정된 값들의 집합 ▪️ CategoryTypeRole 제품 카테고리 설정 CategoryTypeRole이라는 열거

dalhyehye.tistory.com

 

반응형