82일차

장바구니 그런거 json으로 보내야하나에 대한 고민이 생긴다.
ajax처리 폼으로 처리하는 것은 쉽지만..?

상품관리 페이지 더 필요한 내용
상품 추가 - 이미지 파일명/main으로 설정하게 하기
수정페이지및처리

페이지네이션

검색(카테고리 상품명 원산지 재고)

가격 정렬 및 필터링

상품 목록 조회
상품 추가
상품 수정
상품 삭제
상품 검색
이미지 업로드
가격 정렬 및 필터링
재고 관리
상품 상세 정보

오늘할일
이미지 아마존 연동하기
수정 페이지 및 처리 get으로 수정페이지 가기 post로 수정처리하기

처리 결과 메시지출력하기 팝업같은거로

100. 댓글 이후 추가 사항

댓글 CRUD를 하고나니 추가적인 업무가 생겨났다.
댓글을 삭제하려면 참조키 제약사항으로 인해서 문제가 생긴다.

댓글 삭제시 게시물을 삭제하기

각 board서비스와 멤버 서비스에서 삭제 해줘야한다.

@Override
@Transactional(rollbackFor = Exception.class)
public boolean remove(Member member) {
    Member dbMember = mapper.selectById(member.getId());
    int cnt = 0;
    // dbMember.getPassword().equals(member.getPassword()
    if (passwordEncoder.matches(member.getPassword(), dbMember.getPassword())) {
        // 암호가 같으면?

        // 이 회원이 작성한 게시물 row 삭제
        boardService.removeByWriter(member.getId());

        // 이 회원이 좋아요한 레코드 삭제
        likeMapper.removeByMemberId(member.getId());

        // 이 회원이 작성한 댓글 삭제
        commentMapper.removeByMemberId(member.getId());

        // 회원 테이블 삭제
        cnt = mapper.deleteById(member.getId());
    }
    return cnt == 1;
}

@Delete("""
        DELETE FROM Comment
        WHERE memberId = #{memberId}
        """)
void removeByMemberId(String memberId);

@Transactional(rollbackFor = Exception.class)
public boolean remove(Integer id) {
    // 파일명 조회
    List<String> fileNames = mapper.selectFileNamesByBoardId(id);

    // FileName 테이블의 데이터 지우기
    mapper.deleteFileNameByBoardId(id);

    // 하드디스크의 파일 지우기
    // s3파일 지우기
    for (String fileName : fileNames) {
        /*
         * String path = "F:\\study\\upload\\" + id + File.separator + fileName; File
         * file = new File(path); if (file.exists()) { file.delete(); }
         */
        String objectKey = "board/" + id + "/" + fileName;
        DeleteObjectRequest dor = DeleteObjectRequest.builder()
                .bucket(bucketName)
                .key(objectKey)
                .build();

        s3.deleteObject(dor);
    }
    // 좋아요 테이블의 데이터 지우기
    likeMapper.deleteByBoardId(id);

    //comment테이블 데이터 지우기
    commentMapper.deleteByBoardId(id);

    // 게시물 테이블의 데이터 지우기
    int cnt = mapper.deleteById(id);
    return cnt == 1;
}

@Delete("""
        DELETE FROM Comment
        WHERE boardId = #{boardId}
        """)
void deleteByBoardId(Integer boardId);

프로젝트

상품관리 페이지 더 필요한 내용
상품 추가 - 이미지 파일명/main으로 설정하게 하기 o
수정페이지및처리 o

페이지네이션
검색(카테고리 상품명 원산지 재고)

1. 상품 추가

상품추가 페이지, 컨트롤러, mapper, 사진 등록 설정, 상품 추가

1.1 컨트롤러

상품등록페이지로 가지는 get요청
상품 등록 처리 파일이름을 따로 저장하기 때문에 파일이름 배열과 상품 DTO에 담아서 가져온다.
등록 성공시 list페이지로 이동, 등록되었다는 메시지 발생시키기
실패시 상품 등록실패 메시지 발생, list페이지로 이동

// 상품 등록 페이지
@GetMapping("reg")
public String reg() {
    return "admin/product/reg";
}

// 상품 등록 처리
@PostMapping("reg")
public String regProc(Product product, @RequestParam("files") MultipartFile[] files, RedirectAttributes rttr) {
    try {
        boolean ok = productService.add(product, files);
        if (ok) {
            rttr.addFlashAttribute("message", "상품이 등록되었습니다.");
            return "redirect:/admin/product/list";
        } else {
            rttr.addFlashAttribute("message", "상품 등록에 실패하였습니다.");
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
    return "redirect:/admin/product/list";
}

1.2 서비스

받아온 Product는 product에 저장하기 파일은 s3에 업로드와 db에 사진 파일명 저장
저장하는 상품경로는 프로젝트/product/상품아이디/파일명

// 상품 추가
@Override
@Transactional(rollbackFor = Exception.class)
public boolean add(Product product, MultipartFile[] files) throws IOException {
    // 상품 등록
    Integer cnt = productMapper.create(product);

    // 파일등록
    for (MultipartFile file : files) {
        if (file.getSize() > 0) {
            String objectKey = "meatshop/product/" + product.getProductId() + "/" + file.getOriginalFilename();

            // s3에 파일 업로드
            PutObjectRequest por = PutObjectRequest.builder()
                    .bucket(bucketName).acl(ObjectCannedACL.PUBLIC_READ).key(objectKey)
                    .build();
            RequestBody rb = RequestBody.fromInputStream(file.getInputStream(),
                    file.getSize());

            s3.putObject(por, rb);

            // db에 관련정보저장 (insert)
            productMapper.insertFileName(product.getProductId(), file.getOriginalFilename());
        }
    }
    return cnt == 1;
}

1.3 매퍼

s3에 저장하기 위해 자동증가되는 컬럼임 상품 아이디를 받아오면서 상품 db에 저장
얻어온 상품id와 파일이름을 이용해서 파일 db에 저장

<!-- 상품 추가 -->
<insert id="create" useGeneratedKeys="true"
    keyProperty="productId">
    INSERT
    INTO products
    (product_name, country_of_origin,
    category_id, price, stock_quantity)
    VALUES
    (#{productName},
    #{countryOfOrigin}, #{categoryId}, #{price},
    #{stockQuantity})
</insert>

<!-- 파일관련 -->
<insert id="insertFileName">
    INSERT INTO productfilename (product_id, file_name)
    VALUES (#{productId}, #{originalFilename})
</insert>

2. 파일 관련 처리

삭제 상품id로 이름 검색, 상품id얻어서 파일이름삭제

2.1 서비스

상품 삭제할때 상품만 삭제되면 안되니 파일도 삭제해줘야한다.
상품id로 데이터 삭제 파일명을 받아온다.
파일명을 받아와서 파일명을 기준으로 fileName데이터를 삭제하고
상품id로 상품 삭제

@Override
@Transactional(rollbackFor = Exception.class)
public Boolean remove(Integer productId) {
    // 상품에 설정된 이미지 파일 삭제
    // 파일명 조회
    List<String> fileNames = productMapper.selectFileNamesByProductId(productId);

    // FileName 테이블의 데이터 지우기
    productMapper.deleteFileNameByProductId(productId);

    // s3파일 지우기
    for (String fileName : fileNames) {

        String objectKey = "meatshop/product/" + productId + "/" + fileName;
        DeleteObjectRequest dor = DeleteObjectRequest.builder().bucket(bucketName).key(objectKey).build();

        s3.deleteObject(dor);
    }

    Integer cnt = productMapper.deleteById(productId);
    return cnt == 1;
}

2.2 매퍼

<!-- 상품id로 파일 삭제 -->
<delete id="deleteFileNameByProductId">
    DELETE FROM productfilename
    WHERE product_id = #{productId}
</delete>

3. 상품 업데이트

이미지 관련 처리를 해줘야한다.

3.1 컨트롤러

수정은 언제나 조회 후 수정의 과정을 거쳐야한다.
상세페이지에서 상품id를 받아서 수정페이지로 이동한다.
수정프로세스는 삭제할 파일 목록, 추가할 파일 목록, Product DTO를 받아서 수정한다.

// 상품 수정 페이지
@GetMapping("modify/{id}")
public String modify(@PathVariable("id") Integer id, Model model) {
    ProductView product = productService.getOneView(id);
    model.addAttribute("product", product);
    return "admin/product/modify";
}

// 상품 수정 페이지
@PostMapping("modify/{id}")
public String modifyProc(Product product,
        @RequestParam(value = "removeFiles", required = false) List<String> removeFileNames,
        @RequestParam(value = "files", required = false) MultipartFile[] files,
        RedirectAttributes rttr) {
    try {
        boolean ok = productService.modify(product, removeFileNames, files);
        if (ok) {
            rttr.addFlashAttribute("message", product.getProductId() + "번 상품이 수정되었습니다.");
            return "redirect:/admin/product/detail/" + product.getProductId();
        } else {
            // 수정폼으로 리디렉션
            rttr.addFlashAttribute("message", "게시물이 수정되지 않았습니다.");
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
    return "redirect:/admin/product/modify/" + product.getProductId();
}

3.2 서비스

받아온 파일 삭제 목록으로 s3에서 파일을 삭제하고 db에서 파일 이름 삭제
상품수정 쿼리 실행
파일 등록 쿼리실행

// 상품 수정
@Override
@Transactional(rollbackFor = Exception.class)
public boolean modify(Product product, List<String> removeFileNames, MultipartFile[] files) throws IOException {
    if (removeFileNames != null && !removeFileNames.isEmpty()) {
        for (String fileName : removeFileNames) {
            // 파일 삭제
            String objectKey = "meatshop/product/" + product.getProductId() + "/" + fileName;
            DeleteObjectRequest dor = DeleteObjectRequest.builder()
                    .bucket(bucketName)
                    .key(objectKey)
                    .build();

            s3.deleteObject(dor);

            // FileName 테이블의 데이터 삭제
            productMapper.deleteFileNameByBoardIdAndFileName(product.getProductId(), fileName);
        }
    }

    // 상품 정보 수정
    int cnt = productMapper.update(product);

    // 파일등록
    for (MultipartFile file : files) {
        if (file.getSize() > 0) {
            String objectKey = "meatshop/product/" + product.getProductId() + "/" + file.getOriginalFilename();

            // s3에 파일 업로드
            PutObjectRequest por = PutObjectRequest.builder()
                    .bucket(bucketName).acl(ObjectCannedACL.PUBLIC_READ).key(objectKey)
                    .build();
            RequestBody rb = RequestBody.fromInputStream(file.getInputStream(),
                    file.getSize());

            s3.putObject(por, rb);

            // db에 관련정보저장 (insert)
            productMapper.insertFileName(product.getProductId(), file.getOriginalFilename());
        }
    }
    return cnt == 1;
}

3.3 매퍼

<!-- 상품 수정 -->
<update id="update">
    UPDATE products SET
    product_name = #{productName},
    country_of_origin = #{countryOfOrigin},
    category_id = #{categoryId},
    price = #{price},
    stock_quantity = #{stockQuantity}
    WHERE product_id = #{productId}
</update>

2023.05.23

aws사진 등록하는거 다시좀 봐보자.

필수 페이징 검색
추가할것
빈칸이면 submit버튼 비활성화 등등을 추가할 것이다.

파일을 업로드를 설정하는데 시간이 많이 걸렸다.
상품관련해서 하나를 삭제하면 다른 것을 삭제하는 유기적인 관계에 대해서 잘 생각해 보아야한다.

'국비 > Project-2 쇼핑몰' 카테고리의 다른 글

2023.05.30 86일차 Team Project  (0) 2023.05.31
2023.05.26 85일차 Team Project  (0) 2023.05.31
2023.05.25 84일차 Team Project  (0) 2023.05.31
2023.05.24 83일차 Team Project  (0) 2023.05.24
2023.05.22 81일차 -2 Team Project  (0) 2023.05.22

+ Recent posts