Code Monkey home page Code Monkey logo

project_used_trading's Introduction

중고 제품 거래 플랫폼 REST API 구현

사람들이 많이 사용하고 있는 중고 거래 플랫폼을 REST API로 구현해보는 프로젝트



⚙ 기술 스택



📅 Market ERD

market_ERD



📁 REST API

💡 ① 중고 물품 관리, 댓글, 제안

git clone 이후, application.propertiesjwt.secret 값을 변경해야 작동합니다.

1. 물품 관리

중고 물품 관리 API

✅ 표시: 로그인 시 JWT 발급 → Auth(Type=Bearer Token): JWT 입력

1. POST /items ✅

Request Body:

{
    "title": "중고 맥북 팝니다",
    "description": "2019년 맥북 프로 13인치 모델입니다",
    "minPriceWanted": 1000000
}

Response Body:

create_item

2. GET /items?page={page}&limit={limit}

Response Body:

viewall_item

3. GET /items/{itemId}

Response Body:

viewone_item

4. PUT /items/{itemId} ✅

Request Body:

{
    "title": "응 안팔아",
    "description": "걍 내가 쓸꺼야",
    "minPriceWanted": 5000000
}

Response Body:

update_item

5. PUT /items/{itemId}/image ✅

Request Body & Response Body:

image_item

6. DELETE /items/{itemId} ✅

Response Body:

delete_item


📁 REST API 돌아가기

2. 물품 댓글

중고 물품 댓글 API

✅ 표시: 로그인 시 JWT 발급 → Auth(Type=Bearer Token): JWT 입력

1. POST /items/{itemId}/comments ✅

Request Body:

{
    "content": "할인 가능하신가요?"
}

Response Body:

img

2. GET /items/{itemId}/comments?page=1

Request Body:
page 값을 파라미터로 10개 단위로 보여준다.

Response Body:

img

3. PUT /items/{itemId}/comments/{commentId} ✅

Request Body:

{
    "content": "1000000 정도면 고려 가능합니다"
}

Response Body:

img

4. PUT /items/{itemId}/comments/{commentId}/reply ✅

Request Body:

{
    "reply": "ㄴㄴ안됨"
}

Response Body:

img

5. DELETE /items/{itemId}/comments/{commentId} ✅

Response Body:

img

6. 답글은 물품 등록 작성자를 제외하고는 달 수 없다. ✅

img

7. ROLE_ADMIN 권한이 있는 사용자는 물품 등록 작성자가 아니어도 댓글을 달 수 있다. ✅

img


📁 REST API 돌아가기

3. 구매 제안

구매 제안 API

✅ 표시: 로그인 시 JWT 발급 → Auth(Type=Bearer Token): JWT 입력

1. POST /items/{itemId}/proposals ✅

Request Body:

{
    // 구매 제안을 올린 구매자
    "suggestedPrice": 1000000
}

Response Body:

img

2. GET http://localhost:8080/items/1/proposal?page=1 ✅

Response Body:

1) 중고 물품을 올린 판매자가 확인할 수 있는 page img

2) 구매 제안을 올린 구매자가 확인할 수 있는 page img

3. PUT /items/{itemId}/proposals/{proposalId} ✅

Request Body:

{
    // 구매 제안을 올린 구매자
    "suggestedPrice": 7777777
}

Response Body:

img

4. DELETE /items/{itemId}/proposals/{proposalId} ✅

Response Body:

img

5. PUT /items/{itemId}/proposals/{proposalId} ✅

Request Body:

{
    // 중고 물품을 올린 판매자
    "status": "거절" // "수락"도 가능
}

Response Body:

img

6. PUT /items/{itemId}/proposals/{proposalId} ✅

Request Body:

{
    // 구매 제안을 올린 구매자
    "status": "확정"
}

Response Body:

img

7. 그 외

PUT /items/{itemId}/proposals/{proposalId}

  • 3번의 PUT(제안 가격 변경)의 경우 구매 제안 작성자만 수정이 가능하며, status가 "제안", SuggestedPrice가 null이 아닐 때만 작동한다.

  • 5번의 PUT(수락, 거절)의 경우 물품 등록 작성자만 수정 가능하며, 상태가 수락, 거절이 되었을 경우 구매 제안 작성자는 글을 수정할 수 없다.

  • 6번의 PUT(구매 확정)의 경우 구매 제안 작성자만 수정이 가능하며, 현재 "수락" 상태이고 Request로 받는 status가 "확정"이면 status는 "확정"으로 변한다.

    물품 등록 게시물 또한 "판매 완료"가 된다. 이 상태에서 게시물, 구매 제안을 지울 수 없다.

    또한 자동으로 모든 구매제안은 "거절" 상태가 된다.

  • ROLE_ADMIN의 권한을 가지고 있다면 구매 제안 API의 모든 기능을 사용할 수 있으며, "판매 완료" 상태가 되어도 수정이나 삭제가 가능하다.


📁 REST API 돌아가기


💡 ② 사용자 인증, 관계 설정, 접근 권한 설정

1. 사용자 인증

로그인(토큰 발급), 회원가입 API
1. POST /users/login

Request Body:

{
  // ROLE_ADMIN 권한을 가진 TEST 계정 존재
  "userId": "운영자",
  "password": "asdf"
}

Response Body:

POST /users/login

2. GET /users/login

Request Body:

(JSON Data)

{
  // 회원가입
  "userId": "유저",
  "password": "asdf"
}

(Form Data) GET /users/login_2-2

Response Body:

GET /users/login_1

DB:

GET /users/login_2


📁 REST API 돌아가기

2. 관계 설정

ERD 수정 및 코드 수정 API

1. 기존 Entity(Item, Comment, Proposal)의 writer, password 삭제 -> User Enitiy와 1:N 매핑
📅 Market ERD 참고

2. ERD 변경에 의한 제대로 된 기능 작동을 위한 코드 수정
📁 REST API - 💡 ① 중고 물품 관리, 댓글, 제안 참고

3. 자세한 수정 사항
ISSUE : 2️⃣ DAY 2 / 관계 설정하기 참고
PULL REQUEST : 관계 설정 및 관계 변경으로 인한 코드 변경 #8 참고


3. 접근 권한 설정

ROLE STATUS 추가

1. Authentication 추가로 인한 등록(삭제, 변경 등), 조회를 사용자 정보에 따라 제한되거나 가능하게 변경

  • ROLE_ADMIN, ROLE_USER 두 권한이 존재하며, ROLE_ADMIN💡 ① 중고 물품 관리, 댓글, 제안의 모든 기능 사용 가능
  • 확정 상태의 구매 제안을 삭제하는 등 제한되어 있는 기능도 사용할 수 있다.

2. 자세한 수정 사항
ISSUE : 3️⃣ DAY 3/ 기능 접근 설정하기 참고


📁 REST API 돌아가기


💡 ③ UI 구현

1. INDEX, 로그인, 회원가입

HOME - GET / -> (redirect)/items/view

GET /users/login/view

회원가입 - GET /users/register/view

GET /users/login/view

로그인 - GET /users/login/view

GET /users/login/view

로그인 후 HOME - GET /items/view

GET /users/login/view


📁 REST API 돌아가기

2. 물품 등록, 이미지 업로드, 물품 화면

물품 등록 - GET /items/register/view

GET /users/login/view

전체 게시물 - GET /items/view

GET /users/login/view

물품 보기 - GET /items/view/{itemId}

GET /users/login/view

댓글 - GET /items/view/{itemId}

댓글 다는 것은 html 상에서 구현되지 않았습니다.

GET /users/login/view


📁 REST API 돌아가기

3. Page

HOME(Page 관련) - GET / -> (redirect)/items/view

글이 10개 이상 넘어가면 게시물 페이지를 넘길 수 있다. 댓글도 가능하며 댓글은 15개가 limit으로 잡혀 있다.

GET /users/login/view GET /users/login/view


📁 REST API 돌아가기



📜 History

📆 2023.06.29 ~ 2023.07.05

펼쳐 보기
2023-06-29: Repository 생성, DTO 추가, SalesItem MVC 구조

2023-06-29

Create: Git Repository - 'MiniProject_Basic_LimHyoungTaek'

dependencies

  • Spring Web
  • Spring Boot DevTools
  • Spring Data JPA
  • Lombok
  • Sqlite

Add:

  • DTO(SalesItem, Negotiation, Comment)
  • Controller, repository, entity, service associated (with SalesItem)

2023-06-30: ResponseDTO 추가, TODO 구현

2023-06-30

Add:

  • DTO(ResponseDto)

TODO:

POST /items
GET /items?page={page}&limit={limit}
GET /items/{itemId}
PUT /items/{itemId}
DELETE /items/{itemId}


2023-07-01: TODO [ PUT /items/{itemId}/image ] 구현

2023-07-01

TODO:

PUT /items/{itemId}/image


2023-07-03: DAY 1 / 중고 물품 관리 요구사항, 중고 물품 댓글 MVC 구조

2023-07-03

DAY 1 / 중고 물품 관리 요구사항

1️⃣ [POST] /items
ItemController.create(), ItemService.createItem()
: 누구든지 중고 거래를 목적으로 물품에 대한 정보를 등록할 수 있다.

ItemEntity - @NotNull
: 이때 반드시 포함되어야 하는 내용은 제목, 설명, 최소 가격, 작성자이다.

ItemService.validPW()
: 또한 사용자가 물품을 등록할 때, 비밀번호 항목을 추가해서 등록한다.

ItemService.createItem()
: 최초로 물품이 등록될 때, 중고 물품의 상태는 판매중 상태가 된다.



2️⃣ [GET] /items?page={page}&limit={limit}
ItemService.readItemsPaged(), Return Type Page<ItemPageInfoDto>
: 등록된 물품 정보는 누구든지 열람할 수 있다.
페이지 단위 조회가 가능하다.

ItemController.readAll(), ItemController.readOne()
: 전체 조회, 단일 조회 모두 가능하다.



3️⃣ [GET] /items/{itemId}
ItemController.readOne()
: 전체 조회, 단일 조회 모두 가능하다.



4️⃣ [PUT] /items/{itemId}
ItemController.update(), ItemService.updateItem()
: 등록된 물품 정보는 수정이 가능하다.

ItemService.validPW()
: 이때, 물품이 등록될 때 추가한 비밀번호를 첨부해야 한다.



5️⃣ [DELETE] /items/{itemId}
ItemController.delete(), ItemService.deleteItem()
: 등록된 물품 정보는 삭제가 가능하다.

ItemService.validPW()
: 이때, 물품이 등록될 때 추가한 비밀번호를 첨부해야 한다.



6️⃣ [PUT] /items/{itemId}/image
ItemController.uploadImage(), ItemService.uploadItemImage()
: 등록된 물품 정보에 이미지를 첨부할 수 있다.

ItemService.validPW()
: 이때, 물품이 등록될 때 추가한 비밀번호를 첨부해야 한다.



7️⃣ 그 외 추가 및 수정사항
getItemById()
: 해당하는 ID가 없을 경우, Not Found 예외 처리하는 과정을 메서드로 분리

validPW()
: Password를 검사하는 부분을 메서드로 분리

ResponseDto
: Controller의 Return Type을 ResponseDto로 수정 후 ResponseBody 출력 형식 message로 변경

ContentinfoDto
: ItemController.readOne()에서 title, description, minPriceWanted, status만 보이게 Dto 설정

PageinfoDto
: ItemController.readAll()에서 id, title, description, minPriceWanted, status만 보이게 Dto 설정
imageUrl -> add @JsonInclude(JsonInclude.Include.NON_NULL) Null 값 일때 미출력


중고 물품 댓글 MVC 구조

Add:

  • CommentController
  • CommentEntity
  • CommentRepository
  • CommentService

TODO:

POST /items/{itemId}/comments
GET /items/{itemId}/comments
PUT /items/{itemId}/comments/{commentId}
PUT /items/{itemId}/comments/{commentId}/reply
DELETE /items/{itemId}/comments/{commentId}


2023-07-04: DAY 2 / 중고 물품 댓글 요구사항

2023-07-04

1️⃣ [POST] /items/{itemId}/comments
CommentController.createComment(), CommentService.postComment()
: 등록된 물품에 대한 질문을 위하여 댓글을 등록할 수 있다.

CommentEntity - @NotNull
: 이때 반드시 포함되어야 하는 내용은 대상 물품, 댓글 내용, 작성자이다.

PasswordValidatable.validatePassword(), CommentEntity - @Override
: 또한 댓글을 등록할 때, 비밀번호 항목을 추가해서 등록한다.



2️⃣ [GET] /items/{itemId}/comments
CommentController.readAllComment(), CommentService.getCommentsPaged()
: 등록된 댓글은 누구든지 열람할 수 있다.

CommentService.getCommentsPaged(), Return Type Page<CommentPageInfoDto>
: 페이지 단위 조회가 가능하다.



3️⃣ [PUT] /items/{itemId}/comments/{commentId}
CommentController.updateComment(), CommentService.modifiedComment()
: 등록된 댓글은 수정이 가능하다.

PasswordValidatable.validatePassword(), CommentEntity - @Override
: 이때, 댓글이 등록될 때 추가한 비밀번호를 첨부해야 한다.



4️⃣ [DELETE] /items/{itemId}/comments/{commentId}
CommentController.delete(), CommentService.deleteComment()
: 등록된 댓글은 삭제가 가능하다.
PasswordValidatable.validatePassword(), CommentEntity - @Override
: 이때, 댓글이 등록될 때 추가한 비밀번호를 첨부해야 한다.



5️⃣ [PUT] /items/{itemId}/comments/{commentId}/reply
CommentPageInfoDto
: 댓글에는 초기에 비워져 있는 답글 항목이 존재한다.
↳ 그래서 다른 Column과 다르게 @NotNull을 붙이지 않았다. 대신 imageUrlnull 값을 숨길 때 처럼 @JsonInclude(JsonInclude.Include.NON_NULL)을 붙였다.

CommentPageInfoDto
: 답글은 댓글에 포함된 공개 정보이다.
↳ 이 요구사항 때문에 위에서 언급한 @JsonInclude(JsonInclude.Include.NON_NULL)도 추가하지 않을까 하다가 null 값일 경우, 답글이 보이지 않는 경우가 더 많다고 생각해서 유지하였다.

CommentService.modifiedReply()
: 만약 댓글이 등록된 대상 물품을 등록한 사람일 경우, 물품을 등록할 때 사용한 비밀번호를 첨부할 경우 답글 항목을 수정할 수 있다.
↳ 이 부분은 아래 토글을 열어 코드를 참고해주세요.

📄 CommentService.java - modifiedReply()
public class CommentService {
    private final ItemRepository itemRepository;
    private final ItemService itemService;
    private final CommentRepository commentRepository;

    // Post, Modifying Reply
    public void modifiedReply(Long commentId, Long itemId, CommentDto comments) {
        CommentEntity commentEntity = validateCommentByItemId(commentId, itemId);
        ItemEntity itemEntity = itemService.getItemById(itemId);

        // 1. 답글 작성자 != 물품 등록 작성자 -> 예외 처리
        // 댓글에 답글을 달 수 있는 사용자는 물품 정보를 등록한 사용자 뿐
        if (!itemEntity.getWriter().equals(comments.getWriter()))
            throw new ResponseStatusException(HttpStatus.BAD_REQUEST);

        // 2. 물품 등록 작성자 == 답글 작성자 라는건 위의 예외에서 증명
        // 만약 댓글이 등록된 대상 물품을 등록한 사람일 경우
        // -> 물품 등록 == 댓글 == 답글 다 같은 작성자이다.
        if (commentEntity.getWriter().equals(comments.getWriter())) {
            // 물품을 등록할 때 사용한 비밀번호를 첨부할 경우 답글 항목을 수정할 수 있다.
            // 물품 등록 비밀번호 != 답글 비밀번호 -> 예외 처리
            itemEntity.validatePassword(comments.getPassword());
        }
        // Save Reply
        commentEntity.setReply(comments.getReply());
        CommentDto.fromEntity(commentRepository.save(commentEntity));
    }
}



6️⃣ 그 외 추가 및 수정사항
PageinfoDto
: ItemPageInfoDto, CommentPageInfoDto로 구분을 위해 자세하게 이름 설정
dto/mapping으로 경로 설정

PasswordValidatable
: validPWItemEntityCommentEntity에서 받을 수 있게 interface로 변경
Entity에서 implements PasswordValidatable하고 난 후, @Override할 수 있게 변경

CommentService - validateCommentByItemId()
: 각 메서드마다 요청 댓글 유무, 대상 댓글이 대상 게시글의 댓글인지 확인하는 과정이 겹쳐서 따로 분리



2023-07-04: DAY 3 / 구매 제안 기본 CRUD 구조 생성

2023-07-04

구매 제안 기본 CRUD 구조 생성

Add:

  • ProposalController
  • ProposalEntity
  • ProposalRepository
  • ProposalService
  • ProposalPageInfoDto

TODO:

POST /items/{itemId}/proposal
GET /items/{itemId}/proposals?writer=Lim123&password=qwerty1234&page=1
PUT /items/{itemId}/proposals/{proposalId}
DELETE /items/{itemId}/proposals/{proposalId}
PUT /items/{itemId}/proposals/{proposalId}



2023-07-05: DAY 3 / 구매 제안 요구사항

2023-07-05

중고 물품 댓글 MVC 구조

1️⃣ [POST] /items/{itemId}/proposals
ProposalController.createProposal(), ProposalService.postOffer()
: 등록된 물품에 대하여 구매 제안을 등록할 수 있다.

NegotiationDto - @NotNull
: 이때 반드시 포함되어야 하는 내용은 대상 물품, 제안 가격, 작성자이다.
참고로 이전에 Entity에 붙어있던 @NotNull은 다 Dto로 이동함.

PasswordValidatable.validatePassword(), ProposalEntity - @Override
: 또한 구매 제안을 등록할 때, 비밀번호 항목을 추가해서 등록한다.

ProposalService.postOffer() - newProposal.setStatus("제안");
: 구매 제안이 등록될 때, 제안의 상태는 제안 상태가 된다.



2️⃣ [GET] /items/{itemId}/proposal?writer=lim123&password=1qaz2wsx&page=1
ProposalController.readAllProposal()
: 구매 제안은 대상 물품의 주인과 등록한 사용자만 조회할 수 있다.

ProposalService.findPagedOffer(), ProposalRepository.findAll()
: 대상 물품의 주인은, 대상 물품을 등록할 때 사용한 작성자와 비밀번호를 첨부해야 한다.
이때 물품에 등록된 모든 구매 제안이 확인 가능하다.

ProposalService.findPagedOffer(), ProposalRepository.findAllByItemIdAndWriter()
: 등록한 사용자는, 조회를 위해서 자신이 사용한 작성자와 비밀번호를 첨부해야 한다.
이때 자신이 등록한 구매 제안만 확인이 가능하다.

ProposalService.findPagedOffer()
: 페이지 기능을 지원한다.



3️⃣ [PUT] /items/{itemId}/proposals/{proposalId}

1. 구매 제안 작성자의 가격 수정
ProposalController.updateProposal(), ProposalService.putUpdateOffer()
: 등록된 제안은 수정이 가능하다.

PasswordValidatable.validatePassword(), ProposalEntity - @Override
: 이때, 제안이 등록될때 추가한 작성자와 비밀번호를 첨부해야 한다.



2. 물품 등록자의 구매 제안 수락, 거절 상태 변경
ProposalService.{putUpdateOffer(), acceptRejectOffer()}
: 대상 물품의 주인은 구매 제안을 수락할 수 있다.
또한, 대상 물품의 주인은 구매 제안을 거절할 수 있다. 각각 구매 제안의 상태는 수락/거절이 된다.

PasswordValidatable.validatePassword(), ProposalEntity - @Override
: 이때, 제안이 등록될때 추가한 작성자와 비밀번호를 첨부해야 한다.



3. 구매 제안 작성자의 구매 확정 상태 변경
ProposalService.putUpdateOffer() - 2) 현재 "수락" 상태 & Request "확정" 상태 -> 판매 완료 부분

1) 구매 제안을 등록한 사용자는, 자신이 등록한 제안이 수락 상태일 경우, 구매 확정을 할 수 있다.

2) 이때 구매 제안의 상태는 확정 상태가 된다.

3) 구매 제안이 확정될 경우, 대상 물품의 상태는 판매 완료가 된다.
참고로 확정, 판매 완료 상태의 구매 제안과 게시물은 작성자일지라도 삭제하지 못한다.

ProposalService.putUpdateOffer() 작성자 확인 부분,
PasswordValidatable.validatePassword(), ProposalEntity - @Override 비밀번호 확인 부분
: 이를 위해서 제안을 등록할 때 사용한 작성자와 비밀번호를 첨부해야 한다.



4️⃣ [DELETE] /items/{itemId}/proposals/{proposalId}
ProposalController.delete(), ProposalService.deleteOffer()
: 등록된 제안은 수정이 가능하다.

PasswordValidatable.validatePassword(), ProposalEntity - @Override
: 이때, 제안이 등록될때 추가한 작성자와 비밀번호를 첨부해야 한다.


📆 2023.07.26 ~ 2023.08.02

펼쳐 보기
2023-07-26~27: DAY 1 / 사용자 인증

Milestones : 1️⃣ DAY 1 / 인증 만들기
Issues :


2023-07-27~28: DAY 2 / 관계 설정

Milestones : 2️⃣ DAY 2 / 관계 설정하기
Issues : DAY 2 / 관계 설정하기 #6
Pull Requests : 관계 설정 및 관계 변경으로 인한 코드 변경 #8


2023-07-28~31: DAY 3 / 기능 접근 권한 설정

Milestones : 3️⃣ DAY 3/ 기능 접근 설정하기
Issues : DAY 3 / 기능에 대한 접근 권한 설정 #7
Pull Requests : 관계 설정 및 관계 변경으로 인한 코드 변경 #8
Commits :


2023-07-31~: DAY 4 / UI 구현

Milestones : 4️⃣ DAY 4/ UI 구현하기
Issues :

TODO : HTML 댓글 등록 데이터 전달, 구매 제안 부분 구현 중



🙍‍♂️ INFO

project_used_trading's People

Contributors

oh3gwnn avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.