Spring Boot Project, server를 만들어보자

Jihu Kim·2024년 2월 6일
post-thumbnail

이해가 안되면 외워라.

위의 구조의 각 계층이 스프링 프로젝트에서 실제로 어떻게 상호작용하는지 머릿 속에 그려져야 한다.

간단한 프로젝트를 보고 머릿 속으로 각 계층의 상호작용을 그려보자.

추가로, 실무에서는 MSA 단위로 서비스를 개발하기 때문에 Eureka 서버에 등록된 서버와의 통신을 어떻게하는지 알아야한다. 다음에 알아보도록 하자

1. Entity 생성

JPA에서 Entity는 데이터베이스의 테이블에 대응하는 클래스이다.
Entity를 생성했다면, 데이터베이스와 연동을 해야한다.

package com.wara.store.Entity;

import javax.persistence.*;

import lombok.*;


@Setter
@Getter
@ToString
@AllArgsConstructor
@NoArgsConstructor
@Entity
@Builder
public class StoreEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    Long storeId;
    String storeName;
    String storePhone;
    String storeSeller;
}

2. Repository, DAO 생성

Repository

package com.wara.store.Repository;

import com.wara.store.Entity.StoreEntity;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
public interface StoreRepository extends JpaRepository<StoreEntity, Long> {
    Boolean existsByStoreId(Long storeId);  //storeId로 상점 존재 확인
    Boolean existsByStoreSeller(String storeSeller);    //상점 이름으로 상점 존재 확인

    StoreEntity findByStoreId(Long storeId);    //storeId는 고유하다.
    List<StoreEntity> findByStoreSeller(String storeSeller);    //storeSeller는 여러개의 store를 가질 수 있다.
}

DAO

DAO 인터페이스

package com.wara.store.DAO;

import com.wara.store.Entity.StoreEntity;
import org.springframework.stereotype.Repository;

import java.util.Map;

@Repository
public interface StoreDAO{
    //상점 존재 여부 Exist
    public Map<String, Object> existStoreById(Long storeId);
    public Map<String, Object> existStoreBySeller(String storeSeller);

    //seller가 갖는 상점 list

    //상점 생성 Create
    public Map<String, Object> createStore(StoreEntity storeEntity);

    //상점 읽기 Read
    public Map<String, Object> readStoreById(Long storeId);
    public Map<String, Object> readStoreBySeller(String storeSeller);

    //상점 업데이트 Update
    public Map<String, Object> updateStoreById(StoreEntity storeEntity);

    //상점 삭제 Delete
    public Map<String, Object> deleteStore(Long storeId);
}

DAO 구현체

package com.wara.store.DAO;

import com.wara.store.Entity.StoreEntity;
import com.wara.store.Repository.StoreRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

@Repository
public class StoreDAOImpl implements StoreDAO{
    //Alt + Shift + Enter로 StoreDAO interface의 method를 override

    private final StoreRepository storeRepository;

    public StoreDAOImpl(@Autowired StoreRepository storeRepository) {
        this.storeRepository = storeRepository;
    }

    //Exist
    @Override
    public Map<String, Object> existStoreById(Long storeId) {
        Map<String, Object> result = new HashMap<>();

        if (storeRepository.existsByStoreId(storeId)) {
            result.put("result", "success");
        } else {
            result.put("result", "fail");
        }

        return result;
    }

    @Override
    public Map<String, Object> existStoreBySeller(String storeSeller) {
        Map<String, Object> result = new HashMap<>();

        if (storeRepository.existsByStoreSeller(storeSeller)) {
            result.put("result", "success");
        } else {
            result.put("result", "fail");
        }

        return result;
    }



    //Create
    @Override
    public Map<String, Object> createStore(StoreEntity storeEntity) {
        Map<String, Object> result = new HashMap<>();
        storeRepository.save(storeEntity);

        if (storeRepository.existsByStoreId(storeEntity.getStoreId())) {
            result.put("result", "success");
        } else {
            result.put("result", "fail");
        }

        return result;
    }


    //Read
    @Override
    public Map<String, Object> readStoreById(Long storeId) {
        Map<String, Object> result = new HashMap<>();
        StoreEntity storeEntity = storeRepository.findByStoreId(storeId);

        if (storeEntity == null) {
            result.put("result", "fail");
        } else {
            result.put("result", "success");
            result.put("data", storeEntity);
        }

        return result;
    }

    @Override
    public Map<String, Object> readStoreBySeller(String storeSeller) {
        Map<String, Object> result = new HashMap<>();
        List<StoreEntity> storeEntities = storeRepository.findByStoreSeller(storeSeller);

        if (storeEntities.isEmpty()) {
            result.put("result", "fail");
        } else {
            result.put("result", "success");
            result.put("dataList", storeEntities);
        }

        return result;
    }


    //Update
    @Override
    public Map<String, Object> updateStoreById(StoreEntity storeEntity) {
        Map<String, Object> result = new HashMap<>();
        StoreEntity oldStoreEntity = storeRepository.findByStoreId(storeEntity.getStoreId());

        if (oldStoreEntity != null) {
            storeEntity.setStoreId(Optional.ofNullable(storeEntity.getStoreId()).orElse(oldStoreEntity.getStoreId()));
            storeEntity.setStoreName(Optional.ofNullable(storeEntity.getStoreName()).orElse(oldStoreEntity.getStoreName()));
            storeEntity.setStorePhone(Optional.ofNullable(storeEntity.getStorePhone()).orElse(oldStoreEntity.getStorePhone()));
            storeEntity.setStoreSeller(Optional.ofNullable(storeEntity.getStoreSeller()).orElse(oldStoreEntity.getStoreSeller()));

            storeRepository.save(storeEntity);
            result.put("result", "success");
        } else {
            result.put("result", "fail");
        }

        return result;
    }


    //Delete
    @Override
    public Map<String, Object> deleteStore(Long storeId) {
        Map<String, Object> result = new HashMap<>();
        StoreEntity storeEntity = storeRepository.findByStoreId(storeId);

        if (storeEntity == null) {
            result.put("result", "fail");
        } else {
            storeRepository.delete(storeEntity);
            result.put("result", "success");
        }

        return result;
    }
}

3. DTO 생성

StoreDTO

package com.wara.store.DTO;

import lombok.*;

@Setter
@Getter
@NoArgsConstructor
@AllArgsConstructor
@ToString
@Builder
public class StoreDTO {
    Long storeId;
    String storeName;
    String storePhone;
    String storeSeller;
}

ResponseDTO

package com.wara.store.DTO;

import lombok.*;

@Builder
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class ResponseDTO {
    String result;
    Object data;
}

SimpleResponseDTO

package com.wara.store.DTO;

import lombok.*;

@Builder
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class SimpleResponseDTO {
    String result;
}

4. Service 생성

Service 인터페이스

package com.wara.store.Service;

import com.wara.store.DTO.*;
import com.wara.store.Entity.StoreEntity;
import org.springframework.stereotype.Service;

import java.util.Map;

@Service
public interface StoreService {

    //Exist
    public SimpleResponseDTO existStoreById(Long storeId);
    public SimpleResponseDTO existStoreBySeller(String storeSeller);

    //Create
    public SimpleResponseDTO createStore(StoreDTO storeDTO);

    //Read
    public ResponseDTO readStoreById(Long storeId);
    public ResponseDTO readStoreBySeller(String storeSeller);
    //이미지는 다른 서버에서 가져옴.

    //Update
    public SimpleResponseDTO updateStoreById(StoreDTO storeDTO);

    //Delete
    public SimpleResponseDTO deleteStore(Long storeId);

    //기타 서비스
    public StoreEntity toEntity(StoreDTO storeDTO);
    public ResponseDTO toResponseDTO(Map<String, Object> resultMap);
    public SimpleResponseDTO toSimpleResponseDTO(Map<String, Object> resultMap);
}

Service 구현체

package com.wara.store.Service;

import com.wara.store.DAO.StoreDAO;
import com.wara.store.DTO.ResponseDTO;
import com.wara.store.DTO.SimpleResponseDTO;
import com.wara.store.DTO.StoreDTO;
import com.wara.store.Entity.StoreEntity;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;


@Service
public class StoreServiceImpl implements StoreService{

    private final StoreDAO storeDAO;

    private final static Logger logger = LoggerFactory.getLogger(StoreServiceImpl.class);

    public StoreServiceImpl(@Autowired StoreDAO storeDAO
    ) {
        this.storeDAO = storeDAO;
    }


    //Exist
    @Override
    public SimpleResponseDTO existStoreById(Long storeId) {
        Map<String, Object> resultMap = storeDAO.existStoreById(storeId);

        SimpleResponseDTO simpleResponseDTO = toSimpleResponseDTO(resultMap);
        return simpleResponseDTO;
    }
    @Override
    public SimpleResponseDTO existStoreBySeller(String storeSeller) {
        Map<String, Object> resultMap = storeDAO.existStoreBySeller(storeSeller);

        SimpleResponseDTO simpleResponseDTO = toSimpleResponseDTO(resultMap);
        return simpleResponseDTO;
    }


    //Create
    @Override
    public SimpleResponseDTO createStore(StoreDTO storeDTO) {
        StoreEntity storeEntity = toEntity(storeDTO);

        Map<String, Object> resultMap = storeDAO.createStore(storeEntity);
        SimpleResponseDTO simpleResponseDTO = toSimpleResponseDTO(resultMap);
        return simpleResponseDTO;
    }


    //Read
    @Override
    public ResponseDTO readStoreById(Long storeId) {
        Map<String, Object> resultMap = storeDAO.readStoreById(storeId);

        ResponseDTO responseDTO = toResponseDTO(resultMap);
        return responseDTO;
    }
    @Override
    public ResponseDTO readStoreBySeller(String storeSeller) {
        Map<String, Object> resultMap = storeDAO.readStoreBySeller(storeSeller);

        ResponseDTO responseDTO = toResponseDTO(resultMap);
        return responseDTO;
    }


    //Update
    @Override
    public SimpleResponseDTO updateStoreById(StoreDTO storeDTO) {
        StoreEntity storeEntity = toEntity(storeDTO);
        Map<String, Object> existMap = storeDAO.existStoreById(storeDTO.getStoreId());
        SimpleResponseDTO simpleResponseDTO;

        if (existMap.get("result").equals("success")) {
            Map<String, Object> resultMap = storeDAO.updateStoreById(storeEntity);
            simpleResponseDTO = toSimpleResponseDTO(resultMap);
        } else {
            simpleResponseDTO = toSimpleResponseDTO(existMap);
        }

        return simpleResponseDTO;
    }



    //Delete
    @Override
    public SimpleResponseDTO deleteStore(Long storeId) {
        Map<String, Object> resultMap = storeDAO.deleteStore(storeId);

        SimpleResponseDTO simpleResponseDTO = toSimpleResponseDTO(resultMap);
        return simpleResponseDTO;
    }



    //기타 서비스
    @Override
    public StoreEntity toEntity(@NotNull StoreDTO storeDTO) {
        StoreEntity storeEntity = StoreEntity.builder()
                .storeId(storeDTO.getStoreId())
                .storeName(storeDTO.getStoreName())
                .storeSeller(storeDTO.getStoreSeller())
                .storePhone(storeDTO.getStorePhone())

                .build();

        return storeEntity;
    }

    @Override
    public ResponseDTO toResponseDTO(@NotNull Map<String, Object> resultMap) {
        ResponseDTO responseDTO;

        if (resultMap.containsKey("data")) {
            System.out.println("Data type: " + resultMap.get("data").getClass().getName());

            StoreEntity storeEntity = (StoreEntity) resultMap.get("data");
            StoreDTO storeDTO = StoreDTO.builder()
                    .storeId(storeEntity.getStoreId())
                    .storeName(storeEntity.getStoreName())
                    .storeSeller(storeEntity.getStoreSeller())
                    .storePhone(storeEntity.getStorePhone())

                    .build();

            responseDTO = ResponseDTO.builder()
                    .result((String) resultMap.get("result"))
                    .data(storeDTO)
                    .build();
        } else if (resultMap.containsKey("dataList")) {
            System.out.println("DataList type: " + resultMap.get("dataList").getClass().getName());

            List<StoreEntity> storeEntities = (List<StoreEntity>) resultMap.get("dataList");
            List<StoreDTO> storeDTOS = new ArrayList<>();

            for (StoreEntity storeEntity : storeEntities) {
                StoreDTO storeDTO = StoreDTO.builder()
                        .storeId(storeEntity.getStoreId())
                        .storeName(storeEntity.getStoreName())
                        .storeSeller(storeEntity.getStoreSeller())
                        .storePhone(storeEntity.getStorePhone())

                        .build();
                storeDTOS.add(storeDTO);
            }

            responseDTO = ResponseDTO.builder()
                    .result((String) resultMap.get("result"))
                    .data(storeDTOS)
                    .build();
        } else {
            responseDTO = ResponseDTO.builder()
                    .result((String) resultMap.get("result"))
                    .data(null)
                    .build();
        }

        return responseDTO;
    }

    @Override
    public SimpleResponseDTO toSimpleResponseDTO(@NotNull Map<String, Object> resultMap) {
        SimpleResponseDTO simpleResponseDTO;

        simpleResponseDTO = SimpleResponseDTO.builder()
                .result((String) resultMap.get("result"))
                .build();

        return simpleResponseDTO;
    }
}

5. Controller 생성

package com.wara.store.Controller;

import com.wara.store.Service.StoreService;
import com.wara.store.DTO.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api/store")
public class StoreController {

    private final StoreService storeService;
    private final static Logger logger = LoggerFactory.getLogger(StoreController.class);

    public StoreController(@Autowired StoreService storeService) {
        this.storeService = storeService;
    }


    //exist
    @GetMapping(value = "/exist/id/{storeId}")
    public ResponseEntity<SimpleResponseDTO> existStoreById(@PathVariable("storeId") Long storeId) {
        logger.info("[Request] : ExistStoreById");
        logger.info("[Data]: " + storeId);
        SimpleResponseDTO response = storeService.existStoreById(storeId);
        logger.info("[Response] : " + response.toString());

        if(response.getResult().equals("success")){
            return ResponseEntity.status(200).body(response);
        }
        return ResponseEntity.status(400).body(null);
    }

    @GetMapping(value = "/exist/seller/{storeSeller}")
    public ResponseEntity<SimpleResponseDTO> existStoreBySeller(@PathVariable("storeSeller") String storeSeller) {
        logger.info("[Request] : ExistStoreBySeller");
        logger.info("[Data]: " + storeSeller);
        SimpleResponseDTO response = storeService.existStoreBySeller(storeSeller);
        logger.info("[Response] : " + response.toString());

        if(response.getResult().equals("success")){
            return ResponseEntity.status(200).body(response);
        }
        return ResponseEntity.status(400).body(null);
    }


    //create
    @PostMapping(value = "/create", consumes = "application/json")
    public ResponseEntity<SimpleResponseDTO> createStore(@RequestBody StoreDTO storeDTO) {
        logger.info("[Request] : CreateStore(No Image)");
        logger.info("[Data]: " + storeDTO.toString());
        SimpleResponseDTO response = storeService.createStore(storeDTO);
        logger.info("[Response] : " + response.toString());

        if(response.getResult().equals("success")){
            return ResponseEntity.status(201).body(response);
        }
        return ResponseEntity.status(400).body(null);
    }


    //read
    @GetMapping(value = "/read/id/{storeId}")
    public ResponseEntity<ResponseDTO> readStoreById(@PathVariable("storeId") Long storeId) {
        logger.info("[Request] : ReadStoreById");
        logger.info("[Data]: " + storeId);
        ResponseDTO response = storeService.readStoreById(storeId);
        logger.info("[Response] : " + response.toString());

        if(response.getResult().equals("success")){
            return ResponseEntity.status(200).body(response);
        }
        return ResponseEntity.status(400).body(null);
    }

    @GetMapping(value = "/read/seller/{storeSeller}")
    public ResponseEntity<ResponseDTO> readStoreBySeller(@PathVariable("storeSeller") String storeSeller) {
        logger.info("[Request] : ReadStoreBySeller");
        logger.info("[Data]: " + storeSeller);
        ResponseDTO response = storeService.readStoreBySeller(storeSeller);
        logger.info("[Response] : " + response.toString());

        if(response.getResult().equals("success")){
            return ResponseEntity.status(200).body(response);
        }
        return ResponseEntity.status(400).body(null);
    }


    //update
    @PutMapping(value = "/update/id", consumes = "application/json")
    public ResponseEntity<SimpleResponseDTO> updateStoreById(@RequestBody StoreDTO storeDTO) {
        logger.info("[Request] : UpdateStoreById(No Image)");
        logger.info("[Data]: " + storeDTO.toString());
        SimpleResponseDTO response = storeService.updateStoreById(storeDTO);
        logger.info("[Response] : " + response.toString());

        if(response.getResult().equals("success")){
            return ResponseEntity.status(200).body(response);
        }
        return ResponseEntity.status(400).body(null);
    }


    //delete
    @DeleteMapping(value = "/delete/id/{storeId}")
    public ResponseEntity<SimpleResponseDTO> deleteStore(@PathVariable("storeId") Long storeId) {
        logger.info("[Request] : DeleteStoreById");
        logger.info("[Data]: " + storeId);
        SimpleResponseDTO response = storeService.deleteStore(storeId);
        logger.info("[Response] : " + response.toString());

        if(response.getResult().equals("success")){
            return ResponseEntity.status(200).body(response);
        }
        return ResponseEntity.status(400).body(null);
    }
}

6. Test 해보기

PostMan을 이용해 Test 해보기


PostMan을 통해서 위와 같은 요청을 보낼 수 있고, 아래와 같이 데이터베이스에 잘 반영되는 것을 확인할 수 있다.

Test 코드를 작성해 Test 해보기

테스트하고자하는 클래스를 선택하고 ctrl + shift + T

테스트하고자하는 Member 선택하고, OK버튼 클릭시 Test파일이 생성된다.


다음으로 해볼 것..

  • Eureka 서버에 등록하기
  • Eureka 서버에 등록된 다른 서버와 서버간 통신하기(ServiceDiscovery)
  • 서버 배포하기
profile
Jihukimme

0개의 댓글