2024. 1. 19. 13:56ㆍProject/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 간의 매핑을 수행
ProductDTO를 ProductEntity로 변환하고, 상품 정보를 데이터베이스에 저장
@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++;
}
}
}
이미지 정보는 ProductDTO의 imageDTOs 리스트에서 가져오고,
실제 이미지 파일은 ProductDTO의 images 리스트에서 가져옴
이미지 등록은 ImageService의 uploadImage 메서드를 사용하여 처리하며,
각 이미지 정보와 상품 엔터티를 함께 전달
상품목록(관리자)
@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";
}
}
'Project > ShoppingMall' 카테고리의 다른 글
[User_공지사항] 댓글 등록, 목록, 수정 / 댓글 좋아요 싫어요 (3) (0) | 2024.01.25 |
---|---|
[User_공지사항] 게시글 목록 / 상세보기 / 조회수 / 이전 다음 페이지 이동 (2) (0) | 2024.01.23 |
[Admin_공지사항] enum 공지사항 유형 / 조회수 증가 / 다중 검색 기능(1) (0) | 2024.01.20 |
[User_상품진열] enum 카테고리별로 진열 / 상품 상세페이지 / 할인율 계산 / 자동합산 / 연관상품 (0) | 2024.01.20 |
[Admin_상품등록] 다중 이미지 삽입 / 이미지-상품 테이블 조인 / enum 카테고리, 판매 상태(2) (0) | 2024.01.19 |