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} |
레퍼런스
반응형
최근댓글