vue + jpa project (22) - 공통코드 상세코드관리(1) 본문

프로그램/Vue.js

vue + jpa project (22) - 공통코드 상세코드관리(1)

반응형

이번 장에서는 공통코드 관리 중에서 두번째인 상세코드 쪽을 관리하는 화면들을 진행하겠다.

 

지난번 공통코드 테이블의 설계 모습을 리마인드 차원에서 다시보면 아래와 같다.

1:N 구조인데 이번 장에서는 일단 관계를 좀 잊고 단순한 상세코드 관리로 접근하여 코딩하겠다.

 

우선 첫번째로 상세코드의 백엔드 소스부터 먼저 정리하겠다.

앞에서 했던 것과 유사하지만 리마인드 하면서 진행하겠다.

 

1. 상세ID Class

   ID Class는 처음 나오는데 복합키를 가지는 엔티티의 경우에는 반드시 ID Class를 정의하여야 한다.

   그리고 해당 class는 Serializable 도 꼭 상속받아야 한다. 아래와 같이 복합 키에 대한 필드를 정의한다.

   패키지는 일단 동일한 entity 를 사용하겠다. 

@AllArgsConstructor
@NoArgsConstructor
@ToString
@Builder
public class CodeDetailId implements Serializable {

    private static final long serialVersionUID = -7348032290250970275L;

    private String groupCode;
    private String codeValue;
}

 

2. 상세코드   Entity 

   패키지는 일단 동일한 entity 를 사용하겠다. 항목이 좀 더 많아진 것 말고는 다른 건 없다.

 

@JsonIgnoreProperties(value="hibernateLazyInitializer")
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
@Builder
@Entity
@IdClass(CodeDetailId.class)
@EqualsAndHashCode(of={"groupCode", "codeValue"})
@Table(name="code_detail")
public class CodeDetailEntity {

    @Id
    @Column(length = 3)
    private String groupCode;
    
    @Id
    @Column(length = 3)
    private String codeValue;
    
    @Column(length = 30, nullable = false)
    private String codeName;

    @Column(length = 3, nullable = false)
    private int sortSeq = 0;
    
    @Column(length = 1, nullable = false)
    private String useYn = "Y";

    @JsonFormat(pattern="yyyy-MM-dd")
    @CreationTimestamp
    private LocalDateTime regDate;
    
    @JsonFormat(pattern="yyyy-MM-dd HH:mm")
    //@UpdateTimestamp
    private LocalDateTime updDate;

}

 

 

3. 상세코드 Dto 

   패키지는 다른 엔티티와 같이 dto를 사용하겠다. 

@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@ToString
public class CodeDetailDto {

    private String groupCode;
    private String codeValue;
    private String codeName;
    private int sortSeq;
    private String useYn;
    private String regDate;
    private String updDate;
}

 

 

4. 상세코드 Repository 

   패키지는 다른 엔티티와 같이 repository를 사용하겠다. 

   다른 점이 두가지 정도 있는데 하나는 JpaRepository<CodeDetailEntity, CodeDetailId>에서 두번째 항목이 복합키Class

   이고, 또 하나는 그룹코드와 사용여부 그리고 Paging 처리에 대한 조회 메소드 부분이다.

public interface CodeDetailRepository extends JpaRepository<CodeDetailEntity, CodeDetailId> {

    Page<CodeDetailEntity> findByGroupCodeAndUseYnOrderByCodeValue(String groupCode, String useYn, Pageable pageable);
}

 

 

5. 상세코드 Service

   패키지는 다른 엔티티와 같이 service 를 사용하겠다. 

@RequiredArgsConstructor
@Service
public class CodeDetailService {

    private final MessageSource messageSource;
    private final CodeDetailRepository repository;

    /**
     * 상세코드 목록 가져오기
     */
    public List<CodeDetailDto> getCodeDetailList() {

        List<CodeDetailEntity> codeDetailEntities = repository.findAll();
        List<CodeDetailDto> dtos = new ArrayList<>();

        for (CodeDetailEntity entity : codeDetailEntities) {
            dtos.add(entityToDto(entity));
        }

        return dtos;
    }
    
    /**
     * 상세코드 조회(페이징)
     */
    public Header<List<CodeDetailDto>> getCodeDetailList(CodeDetailDto codeDetailDto, Pageable pageable) {
        
        Page<CodeDetailEntity> codeDetailEntities = repository.findByGroupCodeAndUseYnOrderByCodeValue(codeDetailDto.getGroupCode(), codeDetailDto.getUseYn(), pageable);
        List<CodeDetailDto> dtos = new ArrayList<>();

        for (CodeDetailEntity entity : codeDetailEntities) {
            dtos.add(entityToDto(entity));
        }

        Pagination pagination = new Pagination(
                (int)codeDetailEntities.getTotalElements()
                , pageable.getPageNumber() + 1
                , pageable.getPageSize()
                , 10
        );

        return Header.OK(dtos, pagination);
    }
    
    /**
     * 상세코드 중복체크
     */
    public boolean check(CodeDetailDto codeDetailDto) throws Exception {

        return repository.findById(new CodeDetailId(codeDetailDto.getGroupCode(), codeDetailDto.getCodeValue())).isEmpty();
    }

    /**
     * 상세코드 상세조회
     */
    public CodeDetailDto read(CodeDetailDto codeDetailDto) throws Exception {
        
        CodeDetailEntity entity = repository.findById(new CodeDetailId(codeDetailDto.getGroupCode(), codeDetailDto.getCodeValue()))
                .orElseThrow(() -> new RuntimeException(messageSource.getMessage("error.notFound", new String[]{"상세코드"}, Locale.getDefault())));
        return entityToDto(entity);
    }
    
    /**
     * 상세코드 등록
     */
    public CodeDetailEntity create(CodeDetailDto codeDetailDto) {
        System.out.println("codeDetailDto= " + codeDetailDto);
        return repository.save(dtoToEntity(codeDetailDto));
    }

    /**
     * 상세코드 수정
     */
    public CodeDetailEntity update(CodeDetailDto codeDetailDto) {
        
        CodeDetailEntity entity = repository.findById(new CodeDetailId(codeDetailDto.getGroupCode(), codeDetailDto.getCodeValue()))
                .orElseThrow(() -> new RuntimeException(messageSource.getMessage("error.notFound", new String[]{"상세코드"}, Locale.getDefault())));
        entity.setCodeName(codeDetailDto.getCodeName());
        entity.setUseYn(codeDetailDto.getUseYn());
        entity.setUpdDate(LocalDateTime.now());
        
        return repository.save(entity);
    }


    /**
     * 상세코드 삭제
     */
    public void delete(CodeDetailDto codeDetailDto) {
        
        CodeDetailEntity entity = repository.findById(new CodeDetailId(codeDetailDto.getGroupCode(), codeDetailDto.getCodeValue()))
                .orElseThrow(() -> new RuntimeException(messageSource.getMessage("error.notFound", new String[]{"상세코드"}, Locale.getDefault())));
        repository.delete(entity);
    }

    
    /* 입력건 -> 테이블로 */
    private CodeDetailEntity dtoToEntity(CodeDetailDto dto) {
        CodeDetailEntity entity = CodeDetailEntity.builder()
                .groupCode(dto.getGroupCode())
                .codeValue(dto.getCodeValue())
                .codeName(dto.getCodeName())
                .sortSeq(dto.getSortSeq())
                .useYn(dto.getUseYn())
                .regDate(LocalDateTime.now())
                .build();

        return entity;
    }
    
    /* 테이블 데이터 -> 화면쪽으로 */
    private CodeDetailDto entityToDto(CodeDetailEntity entity) {

        CodeDetailDto dto = CodeDetailDto.builder()
                .groupCode(entity.getGroupCode())
                .codeValue(entity.getCodeValue())
                .codeName(entity.getCodeName())
                .sortSeq(entity.getSortSeq())
                .useYn(entity.getUseYn())
                .regDate((entity.getRegDate() != null)? entity.getRegDate().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")):null)
                .updDate((entity.getUpdDate() != null)? entity.getUpdDate().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")):null)
                .build();

        return dto;
    }
}

 

CodeGroupService 와 유사하게 만들었다. 자세히 보면 일단 목록 가져오는 기본은 사용하지는 않지만 일단 추가했다.

그리고 페이징 처리되는 서비스를 추가하였고, 레파지토리에 추가된 메소드를 호출하여 사용하도록 하였다. 

그리고 중복 체크를 위해서 메소드를 하나 더 추가하였다.

 

6. 상세코드 Controller

   패키지는 다른 엔티티와 같이 controller 를 사용하겠다. 

@Slf4j
@RequiredArgsConstructor
@RestController
@RequestMapping("/codedetails")
public class CodeDetailController {
    
    private final CodeDetailService service;

    @GetMapping
    public ResponseEntity<List<CodeDetailDto>> list() throws Exception {
        log.info("list");
        
        return new ResponseEntity<>(service.getCodeDetailList(), HttpStatus.OK);
    }
    
    @GetMapping("/list_paging")
    public Header<List<CodeDetailDto>> boardList_paging(
              CodeDetailDto codeDetailDto
            , @PageableDefault Pageable pageable)
    {
        return service.getCodeDetailList(codeDetailDto, pageable); 
    }
    
    
    @GetMapping("/check/{groupCode}/{codeValue}")
    public ResponseEntity<Boolean> check(
            @PathVariable("groupCode") String groupCode,
            @PathVariable("codeValue") String codeValue
            ) throws Exception {

        boolean isEmpty = !service.check(CodeDetailDto.builder().groupCode(groupCode).codeValue(codeValue).build());

        return new ResponseEntity<>(isEmpty, HttpStatus.OK);
    }
    
    
    @GetMapping("/{groupCode}/{codeValue}")
    public ResponseEntity<CodeDetailDto> read(
            @PathVariable("groupCode") String groupCode,
            @PathVariable("codeValue") String codeValue
            ) throws Exception {

        CodeDetailDto codeDetail = service.read(CodeDetailDto.builder().groupCode(groupCode).codeValue(codeValue).build());

        return new ResponseEntity<>(codeDetail, HttpStatus.OK);
    }

    @PostMapping
    public ResponseEntity<CodeDetailDto> create(@Validated @RequestBody CodeDetailDto codeDetailDto) throws Exception {

        service.create(codeDetailDto);
        return new ResponseEntity<>(codeDetailDto, HttpStatus.OK);
    }


    @PatchMapping("/{groupCode}/{codeValue}")
    public ResponseEntity<CodeDetailDto> update(
            @PathVariable("groupCode") String groupCode,
            @PathVariable("codeValue") String codeValue,
            @Validated @RequestBody CodeDetailDto codeDetailDto) throws Exception {

        codeDetailDto.setGroupCode(groupCode);
        codeDetailDto.setCodeValue(codeValue);
        service.update(codeDetailDto);
        
        return new ResponseEntity<>(codeDetailDto, HttpStatus.OK);
    }

    @DeleteMapping("/{groupCode}/{codeValue}")
    public ResponseEntity<Void> delete(
            @PathVariable("groupCode") String groupCode,
            @PathVariable("codeValue") String codeValue) throws Exception {
        
        CodeDetailDto codeDetail = service.read(CodeDetailDto.builder().groupCode(groupCode).codeValue(codeValue).build());
        codeDetail.setUseYn("N");
        codeDetail.setUpdDate(LocalDateTime.now().toString());
        
        service.update(codeDetail);

        return new ResponseEntity<Void>(HttpStatus.NO_CONTENT);
    }
    
}

 

CodeGroupController와 유사하게 상위 맵핑 정보(@RequestMapping("/codedetails"))를 추가하고

나머지는 각각의 메소드에 맵핑되도록 하였다. 상세코드도 삭제 처리시에 데이터를 아예 삭제하지 않고 사용여부를

N으로 바뀌도록 하였다. vue에서 조회시 사용여부가 Y인 것만 조회되도록 할 것이어서 삭제가 된 거

같은 효과를 보일 것이다.

 

다음 장에서는 프론트 쪽을 작성해 보겠다.

반응형

프로그램/Vue.js Related Articles

MORE

Comments