K-Studio ERP 시스템의 일부를 스프링 프레임워크로 이관하면서 정리한 사항을 포스팅합니다.

샘플코드는 단일키 구조로 설계하였으며 복합키 구조를 유지하려면 레퍼런스 링크를 참고하시면 됩니다.

-> 23년 3월 내부 공유를 위해 업데이트 진행

K-Studio & JPA 아키텍처 비교

Back-End는 K-Studio에서 비즈니스 서비스와 SP 로직을 대체하는 것으로 이해할 수 있습니다.

 

개발가이드

MVC 패턴에 대한 프로세스 흐름입니다.

샘플소스는 Git으로 공유하니 아래 URL 정보 참고 부탁드립니다.

https://github.com/Archon3/employee/wiki/Introduction

 

1. 엔티티 (Entity)

데이터베이스 테이블과 매칭되는 클래스 정의합니다.

ERP 테이블 등록 화면에 스키마 정보 기입하는 것과 유사합니다.

WAS 서버 실행 시 프레임워크에서 @Entity 클래스 정보를 수집하여 테이블 DDL 구문 생성합니다.
@Entity                   // 엔티티로 인식하기 위한 어노테이션
@Table(name = "_TDAEmp")  // 테이블명
@Getter                   // Get메소드를 자동생성 해주는 어노테이션
@NoArgsConstructor        // 생성자 어노테이션
@AllArgsConstructor       // 생성자 어노테이션
public class EmpEntity {    
    @Id    
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "EmpSeq")    
    private Long seq;
    
    @Column(name = "CompanySeq")    
    private Long companySeq;
    
    @Column(name = "EmpName", length = 200)    
    private String empName;
}

 

2. 리포지토리 (Repository)

1개의 Entity에 대해 데이터베이스 CRUD 처리 지원합니다.

Group By, 동적쿼리 등 복잡한 쿼리의 경우 Spring Data JPA, Query DSL을 통해 별도 구현 가능

 

스프링 프레임워크가 기본적으로 지원하는 구문은 아래와 같습니다.

구분 code SQL 변환
조회 findById(Long empSeq) select * From _TDAEmp
Where EmpSeq = :seq (변수)
저장 save(EmpEntity entity) INSERT INTO _TDAEmp
(EmpSeq, CompanySeq,  EmpName)
삭제 deleteById(Long empSeq) Delete From _TDAEmp
Where EmpSeq = :EmpSeq
@Repository // 리포지토리로 인식하기 위한 어노테이션
public interface EmpRepository extends JpaRepository<EmpEntity, Long> {

    // 조회조건 이름으로 조회하는 로직 구현
    List<Emp> findByName(String name);    
}

 

3.  서비스 (Service)

핵심 비즈니스 로직 수행하며 트랜잭션 관리가 가능합니다.

  • Controller로 전달받은 Request DTO를 Repository에 전달하기 위해서는 Entity 클래스로 전환
  • 비즈니스 로직 수행 후 Controller로 전송은 Response DTO 반환
@Service                  // 서비스로 인식하기 위한 어노테이션
@RequiredArgsConstructor  // 생성자 어노테이션
@Slf4j                    // 로그관련 어노테이션
public class EmpService {

    private final EmpRepository empRepository;

    // 전체조회
    @Transactional(readOnly = true)
    public List<EmpResponse> getEmps() {
        return empRepository.findAll()
                .stream()
                .map(EmpResponse::new)
                .collect(Collectors.toList());
    }

    @Transactional(readOnly = true)
    public EmpResponse getEmp(Long empSeq) {
        //Optional : 데이터 Null 여부를 체크할 수 있는 변수
        EmpEntity result = empRepository.findById(empSeq)
                .orElseThrow(NullPointerException::new);

        return new EmpResponse(result);
    }

    // 저장
    @Transactional // 트랜젝션 어노테이션
    public EmpResponse createEmp(EmpRequest request) {
        EmpEntity emp = request.toEntity();
        EmpEntity result = empRepository.save(emp);
        return new EmpResponse(result);
    }

    // 삭제
    @Transactional
    public void deleteEmp(Long empSeq) { empRepository.deleteById(empSeq); }
}

 

4. DTO (Data Transfer Object)

컨트롤러와 서비스 간 데이터를 전송받는 클래스이며 SP에서 항목에 대한 Alias 적용을 대체할 수 있음.

  • Request = (#BIZ_OUT_DATABLOCK1 IN 항목)
  • Response = (#BIZ_OUT_DATABLOCK1 OUT 항목)
@Data // getter, setter 어노테이션
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class EmpRequest {
    private Long empSeq;

    private Long companySeq;

    private String empName;

    /* Dto -> Entity */
    public EmpEntity toEntity() {
        return EmpEntity.builder()
                .seq(this.empSeq)
                .companySeq(this.companySeq)
                .empName(this.empName)
                .build();
    }
}

@Getter // response 클래스는 Getter만 적용하는 것을 권장
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class EmpResponse {
    private Long empSeq;

    private Long companySeq;

    private String empName;
    
    /* Entity -> Dto */
    public EmpResponse(EmpEntity emp) {
        this.empSeq = emp.getSeq();
        this.companySeq = emp.getCompanySeq();
        this.empName = emp.getempName();
    }
}

 

5. 컨트롤러(Controller)

HTTP 요청을 Service 계층으로 DTO 전달하는 역할을 합니다.

Controller에서는 Entity를 직접 Access 하지 않는 것을 원칙으로 한다.
- 기본적으로 해당 레이어에서 사용하기 위해 만든 DTO는 해당 레이어까지만 의존하는 게 좋다.
- 의존관계에 순환 사이클이 생겨서는 안 된다.
@RestController           // 컨트롤러로 인식하기 위한 어노테이션
@RequestMapping("/emp")   // Default URL 경로 설정
@RequiredArgsConstructor  // 생성자 어노테이션
public class EmpController {

    private final EmpService empService;

    @GetMapping()
    public List<EmpResponse> getEmps() { return empService.getEmps(); }

    @GetMapping(path = "/{empSeq}")
    public EmpResponse getEmp(@PathVariable(value ="empSeq") Long empSeq) { return empService.getEmp(empSeq); }

    @PostMapping()
    public EmpResponse createEmp(@RequestBody EmpRequest request) {
        return empService.createEmp(request);
    }

    @DeleteMapping(path = "/{empSeq}")
    public String deleteEmp(@PathVariable(value ="empSeq") Long empSeq) {
        empService.deleteEmp(empSeq);
        return "success";
    }
}
 

6. Swagger3.0

REST API를 설계, 빌드, 문서화 및 사용 가능한 오픈 소스입니다.

@Controller에 연결되어 있는 URL 경로를 자동 Mapping 합니다.

HttpMethod 기능 URL 비고
GET 조회 /members  
POST 등록 /members/{id} 멱등성 X
PUT 수정 /members/{id}  
DELETE 삭제 /members/{id}  

 

 

레퍼런스

https://techblog.woowahan.com/2595/

반응형
  • 네이버 블러그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 카카오스토리 공유하기