
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} |

레퍼런스
최근댓글