+ 00 00 0000

Have any Questions?

02_Simple Coding – SI-MSA – 레디스DB 실전예제 1-2

02_Simple Coding – SI-MSA – 레디스DB 실전예제 1-2

📃 요약

네이버 카페 등의 게시판을 기본 기능을 제작하는 예제입니다.
기본적인 DB CRUD 를 사용해 제작합니다.
DB 프레임워크는 JPA 를 사용해 자동화기능을 강화합니다.
뷰(Vue) & 스프링부트 연동 기초 예제


  • axios CRUD 함수들과 스프링부트의 컨트롤러 함수들과 네트웍으로 연결됨
    이때 컨트롤러는 @RestController 어노테이션을 사용해야함



  • Vue : axios 라이브러리의 get(), post(), put(), delete() 함수 사용



  • 스프링부트 – @RestController 어노테이션 사용해서 컨트롤러 클래스 생성
    CRUD : @GetMapping, @PostMapping, @PutMapping, @DeleteMapping
    나머지 모델, 레포지토리, 서비스는 JSP 와 동일함



  • 성능 향상 :
    1) Redis 를 이용해 캐싱 DB를 사용해 봄 :
    2) 주로 쇼핑몰에서 이벤트성 기획 페이지에 순간 사용자가 몰릴것을 대비해 사용
    3) 일반적인 게시판에서는 레디스 DB 를 적용하지 않지만 실습을 위해 부서 게시판의 조회와 수정기능에 추가해보도록 함


요소 기술 및 테이블 설계는 아래와 같습니다.

요소 기술 :

– 프론트엔드 : Vue

– 벡엔드 : 스프링부트 & JPA & Oracle 18xe(Oracle Cloud 19c) & Redis 메모리 DB

결과 화면 :

프로젝트 탐색기 : Vue

프로젝트 탐색기 : String Boot

Rest API :

메소드URL설명
GETdept전체 조회
GETdept/{dno}상세조회
POST/dept저장
PUT/dept/{dno}수정
DELETE/dept/deletion/{dno}삭제

📃 기술 구현

스펙 :

- jdk 17
- spring boot 3.x
- gradle

테이블 설계

-- 부서 게시판
DROP SEQUENCE SQ_DEPT;
CREATE SEQUENCE SQ_DEPT START WITH 50 INCREMENT BY  10;

CREATE TABLE TB_DEPT (
                         DNO NUMBER NOT NULL PRIMARY KEY,
                         DNAME VARCHAR2(255),
                         LOC VARCHAR2(255),
                         INSERT_TIME VARCHAR2(255),
                         UPDATE_TIME VARCHAR2(255)
);

부서 게시판 구현을 위한 테이블 설계입니다.

데이터베이스를 오라클을 사용하여 구현해 보겠습니다.

Redis DB 설치 :


  • 윈도우
    1) Redis 설치 프로그램 다운로드 : https://github.com/microsoftarchive/redis/releases
    2) Redis-x64-3.0.504.msi 다운로드 기본설치
    3) Redis 설치 확인 : 설치를 정상적으로 마치면 윈도우 작업 관리자의 서비스 탭에서 실행 중인 것을 확인
    4) 설치한 경로에 redis-cli.exe를 실행하여 redis를 사용
    5) ping 입력 -> pong 뜨면 정상 설치된 것임




  • 1) homebrew 설치된 상태에서 진행
    2) // Homebrew(Mac OS용 패키지 관리자) 설치 여부 확인
    brew –version
    3) // redis 설치
    brew install redis
    4) // redis 설치 확인
    redis-server –version
    5) // redis foreground로 실행
    redis-server
    6) // redis-cli 사용
    redis-cli


Redis 기본 명령어 : 터미널(명령 프롬프트) 명령

서버 가동 & 중지 & 접속 명령어

# 레디스 서버 실행
Redis-server

# 레디스 실행 확인
redis-cli ping
pong  (응답)

# 레디스 서버 중지
redis-cli shutdown  

# localhost:6379접속
redis-cli

# 정보보기
reids-cli info

# 원격접속
redis-cli -h #{호스트명} -p #{포트번호}

CRUD 명령어

127.0.0.1:6379> keys *
(empty list or set)

# set key / value 형태로 저장하기
127.0.0.1:6379>set k_one "one"
OK

127.0.0.1:6379>keys *
1) "k_one"

# mset 여러개의 key / value 형태로 저장하기
127.0.0.1:6379> mset k_two "two" k_tree "tree"
OK

127.0.0.1:6379> keys *
1) "k_tree"
2) "k_one"
3) "k_two"

# setex 소멸시간 지정해서 저장하기
127.0.0.1:6379> setex k_four 10 "four"
OK

#mget 여러개의 key를 조회하기
127.0.0.1:6379> mget k_one k_two
1) "one"
2) "two"

# del 해당 key와 value을 삭제하기
127.0.0.1:6379> del k_tree
(integer) 1

127.0.0.1:6379> keys *
1) "k_one"
2) "k_two"

# keys *검색어*  key 검색하기
127.0.0.1:6379> keys *k*
1) "k_one"
2) "k_two"

#rename key의 이름을 변경하기 rename 기존key 변경할key
127.0.0.1:6379> rename k_one one
OK

127.0.0.1:6379> keys *
1) "one"
2) "k_two"

# flushall 모든 데이터(key와 value)를 삭제
127.0.0.1:6379> flushall
OK

Redis 메모리 DB 설정 :

build.gradle 라이브러리 수동 설치 : 레디스 DB 라이브러리 설치

...
//  todo: Redis : cache server
    implementation 'org.springframework.boot:spring-boot-starter-data-redis'
...

설정(application.properties) : 레디스 DB ip & port 추가

# redis server 설정 : redis-server 실행(터미널에 실행해야 스프링 정상 실행됨)
redis.host=localhost
redis.port=6379

설정(Config) 자바 파일 : 레디스 기본 설정하기

RedisConfig.java

package com.example.simpledms.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext.SerializationPair;

import java.time.Duration;

/**
 * packageName : com.example.simpledms.config
 * fileName : RedisConfig
 * author : kangtaegyung
 * date : 2022/06/14
 * description :
 * ===========================================================
 * DATE            AUTHOR             NOTE
 * -----------------------------------------------------------
 * 2022/06/14         kangtaegyung          최초 생성
 */
@Configuration
public class RedisConfig {
    //  Redis IP
    @Value("${redis.host}")
    private String redisHost;

    //  Redis Port Number
    @Value("${redis.port}")
    private int redisPort;

    //  레디스 연결
    @Bean
    public LettuceConnectionFactory redisConnectionFactory() {
        RedisStandaloneConfiguration configuration = new RedisStandaloneConfiguration(redisHost, redisPort);

        return new LettuceConnectionFactory(configuration);
    }

    //  레디스 관리  :  1) 생성 dept          : ttl - 1 minute
//
    @Bean
    public RedisCacheManager cacheManager() {
//    Redis 캐시 설정 함수를 호출해서 래디스 설정
        RedisCacheConfiguration cacheConfig = myDefaultCacheConfig(Duration.ofMinutes(10))
                .disableCachingNullValues(); // 캐싱할 때 null 값을 허용하지 않음

        return RedisCacheManager.builder(redisConnectionFactory())
                .cacheDefaults(cacheConfig)
                .withCacheConfiguration("depts", myDefaultCacheConfig(Duration.ofMinutes(5)))  // depts 캐쉬 생성
                .withCacheConfiguration("dept", myDefaultCacheConfig(Duration.ofMinutes(3)))   // dept 캐쉬 생성
                .withCacheConfiguration("emps", myDefaultCacheConfig(Duration.ofMinutes(5)))   // emps 캐쉬 생성
                .withCacheConfiguration("emp", myDefaultCacheConfig(Duration.ofMinutes(3)))   // emp 캐쉬 생성
                .build();
    }

    //  Redis 캐시 설정 함수 : 1) 설정 default config 2) 설정 ttl 3) 설정 serialize
    private RedisCacheConfiguration myDefaultCacheConfig(Duration duration) {
        return RedisCacheConfiguration
                .defaultCacheConfig()
                .entryTtl(duration)         // ttl(만료시간) 설정
                .serializeValuesWith(SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer())); // Value 를 직렬화할 때 사용하는 규칙. Jackson2 를 많이 사용함
    }
}
  • redisConnectionFactory() : 레디스 DB 연결 (IP & port)
  • cacheManager() : 캐쉬를 이름으로 생성 및 만료시간(ttl : 지워지는 시간) 설정
  • myDefaultCacheConfig() :
    1) 설정 ttl(만료시간)
    2) 통신설정 (json 데이터 ->(변환)-> redis DB 에 (키, 값)으로 넣기)

통신설정시 Json 데이터 ->(변환)-> Redis DB 로 전송

package com.example.simpledms.model.common;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;

import java.util.List;

/**
 * packageName : com.example.backedu.entity
 * fileName : RestPage
 * author : kangtaegyung
 * date : 10/21/23
 * description : Redis Page Json 변환시 오류 해결을 위한 래퍼클래스 (pageable 속성을 레디스가 변환할때 에러가 발생함)
 *              - Page 객체에 포함되어 있는 pageable 를 json 변환시 해당 속성 무시
 *              - content, number, size, totalElements 만 리턴할 수 있도록 재정의함
 * 요약 :
 * <p>
 * ===========================================================
 * DATE            AUTHOR             NOTE
 * -----------------------------------------------------------
 * 10/21/23         kangtaegyung          최초 생성
 */
@JsonIgnoreProperties(ignoreUnknown = true, value = {"pageable"})
public class RestPage<T> extends PageImpl<T> {
    @JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
    public RestPage(@JsonProperty("content") List<T> content,
                    @JsonProperty("number") int page,
                    @JsonProperty("size") int size,
                    @JsonProperty("totalElements") long total) {
        super(content, PageRequest.of(page, size), total);
    }

    public RestPage(Page<T> page) {
        super(page.getContent(), page.getPageable(), page.getTotalElements());
    }

}
  • JPA 페이징처리시 에러가 발생함 : pageable 객체가 Json -> Redis 로 변환시 에러가 발생함
  • Page 객체에 포함되어 있는 pageable 를 json 변환시 해당 속성 무시
  • content, number, size, totalElements 만 리턴할 수 있도록 재정의함

모델 : 엔티티

공통 모델

package com.example.jpaexam.model.common;

import lombok.Getter;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import javax.persistence.EntityListeners;
import javax.persistence.MappedSuperclass;
import javax.persistence.PrePersist;
import javax.persistence.PreUpdate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

/**
 * packageName : com.example.jpaexam.model
 * fileName : BaseTimeEntity
 * author : GGG
 * date : 2023-10-16
 * description : JPA 에서 자동으로 생성일자/수정일자를 만들어 주는 클래스
 * 요약 :
 * <p>
 * ===========================================================
 * DATE            AUTHOR             NOTE
 * —————————————————————————————
 * 2023-10-16         GGG          최초 생성
 */
@Getter
// todo: 자동으로 생성일자/수정일자 컬럼을 sql 문에 추가시키는 어노테이션 2개
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public abstract class BaseTimeEntity {
//    todo: 공통속성 : yyyy-MM-dd HH:mm:ss 아니고 기본 패턴으로 보임
    private String insertTime;

    private String updateTime;

//    todo: 해당 테이블에 데이터가 만들어 질때(insert 문) 실행되는 이벤트 함수
    @PrePersist
    void OnPrePersist() {
        this.insertTime
                = LocalDateTime.now()
                    .format(DateTimeFormatter
                            .ofPattern("yyyy-MM-dd HH:mm:ss"));
    }

//    todo: 해당 테이블에 데이터가 수정 질때(update 문) 실행되는 이벤트 함수
    @PreUpdate
    void OnPreUpdate() {
        this.updateTime
                = LocalDateTime.now()
                .format(DateTimeFormatter
                        .ofPattern("yyyy-MM-dd HH:mm:ss"));
        this.insertTime = this.updateTime; // 생성일시 == 수정일시 동일하게 처리
    }
}

부서 게시판 : 엔티티

package com.example.jpaexam.model.entity.basic;

import com.example.jpaexam.model.common.BaseTimeEntity;
import lombok.*;
import org.hibernate.annotations.DynamicInsert;
import org.hibernate.annotations.DynamicUpdate;

import javax.persistence.*;

/**
 * packageName : com.example.jpaexam.model
 * fileName : Dept
 * author : GGG
 * date : 2023-10-16
 * description : 부서 모델 클래스 ( 엔티티(entity) )
 * 요약 :
 * <p>
 * ===========================================================
 * DATE            AUTHOR             NOTE
 * —————————————————————————————
 * 2023-10-16         GGG          최초 생성
 */
// todo: @Entity - JPA 기능을 클래스에 부여하는 어노테이션
@Entity
// todo: @Table(name = "생성될테이블명")
@Table(name = "TB_DEPT")
// todo 사용법 : @SequenceGenerator(
//        name = "시퀀스함수이름"
//        , sequenceName = "DB에생성된시퀀스이름"
//        , initialValue = 시작값
//        , allocationSize = jpa에서관리용숫자(성능지표)
//)
@SequenceGenerator(
        name = "SQ_DEPT_GENERATOR"
        , sequenceName = "SQ_DEPT"
        , initialValue = 1
        , allocationSize = 1
)
@Getter
@Setter
@ToString
@NoArgsConstructor
@AllArgsConstructor
// todo: jpa 어노테이션 sql 자동 생성시 null 값 컬럼은 제외하고 생성
//   예) insert into 테이블명(컬럼1, 컬럼2, 컬럼3) values(1, 2, null);
//    => insert into 테이블명(컬럼1, 컬럼2) values(1, 2);
@DynamicInsert
@DynamicUpdate
public class Dept extends BaseTimeEntity {
    @Id
//  todo: @GeneratedValue(strategy = GenerationType.SEQUENCE
//            , generator = "시퀀스함수이름"
//    )
    @GeneratedValue(strategy = GenerationType.SEQUENCE
            , generator = "SQ_DEPT_GENERATOR"
    )
//  todo: @Column(columnDefinition = "DB컬럼자료형")
    @Column(columnDefinition = "NUMBER")
    private Integer dno; // 부서번호(기본키) - 시퀀스 기능 부여

    @Column(columnDefinition = "VARCHAR2(255)")
    private String dname; // 부서명

    @Column(columnDefinition = "VARCHAR2(255)")
    private String loc;   // 부서위치
}

부서 레포지토리

package com.example.jpaexam.repository.basic;

import com.example.jpaexam.model.entity.basic.Dept;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

/**
 * packageName : com.example.jpaexam.repository
 * fileName : DeptRepository
 * author : GGG
 * date : 2023-10-16
 * description : JPA 레포지토리 인터페이스 ( DB 접속 함수들(CRUD) 있음)
 *               == DAO 비슷함
 * 요약 :
 * <p>
 * ===========================================================
 * DATE            AUTHOR             NOTE
 * —————————————————————————————
 * 2023-10-16         GGG          최초 생성
 */
// todo: @Repository - 클래스 위에 붙이고, 스프링서버가 실행될때 자동으로
//      객체 1개를 만들어줌 ( IOC )
//   사용법 : 인터페이스명 extends JpaRepository<모델클래스명, 기본키의자료형>
@Repository
public interface DeptRepository extends JpaRepository<Dept, Integer> {
}

select : @Query 이용한 오라클 기반 쿼리(nativeQuery = true) 임

부서 게시판 서비스

package com.example.simpledms.service.basic;

import com.example.simpledms.model.common.RestPage;
import com.example.simpledms.model.entity.basic.Dept;
import com.example.simpledms.repository.basic.DeptRepository;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

import java.util.Optional;

/**
 * packageName : com.example.modelexam.service
 * fileName : DeptService
 * author : kangtaegyung
 * date : 2022/10/12
 * description : 부서 업무 서비스 클래스
 * 요약 :
 *  1) 레디스 캐쉬 적용 : @EnableCaching, @Cacheable,
 *  2)                @CacheEvict
 * <p>
 * ===========================================================
 * DATE            AUTHOR             NOTE
 * -----------------------------------------------------------
 * 2022/10/12         kangtaegyung          최초 생성
 */
// springboot 프레임워크에 객체를 생성함 : 싱글톤 유형
@Slf4j
@Service
// 레디스 캐싱 기능 활성화
@EnableCaching
public class DeptService {

    @Autowired
    DeptRepository deptRepostory; // 샘플데이터 DB에 접근하는 객체

    public Page<Dept> findAll(Pageable pageable) {
        Page<Dept> page = deptRepostory.findAll(pageable);

        return page;
    }

    @Cacheable("dept")
    public Optional<Dept> findById(int dno) {
        log.debug("캐쉬 안됨");
        Optional<Dept> optionalDept = deptRepostory.findById(dno);

        return optionalDept;
    }

    public Dept insert(Dept dept) {

        Dept dept2 = deptRepostory.save(dept);

        return dept2;
    }

    //    사용법 : @CacheEvict(value = "값", key = "#객체명.속성명")
    @CacheEvict(value = "dept", key = "#dept.dno")
    public Dept update(Dept dept) {

        Dept dept2 = deptRepostory.save(dept);

        return dept2;
    }

    //    사용법 : @CacheEvict(value = "키이름", key = "#매개변수명")
    @CacheEvict(value = "dept", key = "#dno")
    public boolean removeById(int dno) {

        if (deptRepostory.existsById(dno)) {
            deptRepostory.deleteById(dno);
            return true;
        }
        return false;
    }

    public void removeAll() {

        deptRepostory.deleteAll();
    }

    //    dname like 검색
    @Cacheable("depts")
    public Page<Dept> findAllByDnameContaining(String dname, Pageable pageable) {

        Page<Dept> page = deptRepostory.findAllByDnameContaining(dname, pageable);

        return new RestPage<>(page);
    }
}

  • @EnableCaching : 레디스 캐싱 기능 활성화 어노테이션, 클래스 위에 붙임



  • 읽기 전략 : 캐시를 먼저 확인하고, 캐시에 데이터가 없을 경우 DB에서 데이터를 가져오는 전략 사용(Look Aside 전략)



  • 쓰기 전략 : 데이터를 DB 에 업데이트 할 대마다 캐시는 제거하는 전략 사용(Write Around 전략)



  • 사용법 : @Cacheable(value = “cacheManager() 에서 설정한이름”)


    1) 조회 함수 위에 붙임 
    2) 최초에 DB 에 조회시 캐시 DB 에 결과를 저장해둠, 이후에는 캐시 DB에서 결과를 가져옴


  • 사용법 : @CacheEvict(value = “cacheManager() 에서 설정한이름”, key = “#함수의 매개변수명(객체의 속성, 변수등)”)


    1) 수정 함수 위에 붙임
    2) DB 의 데이터가 수정되면 캐싱 DB 의 데이터에 불일치가 발생함, 그래서 캐싱 데이터 삭제하는 어노테이션


  • 사용법 : @CacheEvict(value = “cacheManager() 에서 설정한이름”, key = “#함수의 매개변수명(객체의 속성, 변수등)”)


    1) 삭제 함수 위에 붙임
    2) DB 의 데이터가 수정되면 캐싱 DB 의 데이터에 불일치가 발생함, 그래서 캐싱 데이터 삭제하는 어노테이션

부서 게시판 컨트롤러 : Rest Controller 사용 ( Vue, React, Angular.js 등 )

package com.example.simpledms.controller.basic;

import com.example.simpledms.model.entity.basic.Dept;
import com.example.simpledms.service.basic.DeptService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.*;

/**
 * packageName : com.example.modelexam.controller
 * fileName : DeptController
 * author : kangtaegyung
 * date : 2022/10/12
 * description : 부서 컨트롤러
 * 요약 :
 * <p>
 * ===========================================================
 * DATE            AUTHOR             NOTE
 * -----------------------------------------------------------
 * 2022/10/12         kangtaegyung          최초 생성
 */
@Slf4j
@RestController
@RequestMapping("/api/basic")
public class DeptController {

    @Autowired
    DeptService deptService;

    @GetMapping("/dept")
    public ResponseEntity<Object> findAllByDnameContaining(@RequestParam(defaultValue = "") String dname,
                                             @RequestParam(defaultValue = "0") int page,
                                             @RequestParam(defaultValue = "3") int size
    ) {

        try {

//            페이지 변수 저장
            Pageable pageable = PageRequest.of(page, size);

//            List<Dept> list = Collections.emptyList();
            Page<Dept> deptPage;

            deptPage = deptService.findAllByDnameContaining(dname, pageable);

            Map<String, Object> response = new HashMap<>();
            response.put("dept", deptPage.getContent());
            response.put("currentPage", deptPage.getNumber());
            response.put("totalItems", deptPage.getTotalElements());
            response.put("totalPages", deptPage.getTotalPages());

            if (deptPage.isEmpty() == false) {
//                성공
                return new ResponseEntity<>(response, HttpStatus.OK);
            } else {
//                데이터 없음
                return new ResponseEntity<>(HttpStatus.NO_CONTENT);
            }
        } catch (Exception e) {
//            서버 에러
            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }

    @GetMapping("/dept/{dno}")
    public ResponseEntity<Object> findById(@PathVariable int dno) {

        try {
            Optional<Dept> optionalDept = deptService.findById(dno);

            if (optionalDept.isPresent()) {
//                성공
                return new ResponseEntity<>(optionalDept.get(), HttpStatus.OK);
            } else {
//                데이터 없음
                return new ResponseEntity<>(HttpStatus.NO_CONTENT);
            }
        } catch (Exception e) {
//            서버 에러
            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }

    @PostMapping("/dept")
    public ResponseEntity<Object> create(@RequestBody Dept dept) {

        try {
            Dept dept2 = deptService.save(dept);

            return new ResponseEntity<>(dept2, HttpStatus.OK);
        } catch (Exception e) {
//            DB 에러가 났을경우 : INTERNAL_SERVER_ERROR 프론트엔드로 전송
            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }

    @PutMapping("/dept/{dno}")
    public ResponseEntity<Object> update(@PathVariable int dno, @RequestBody Dept dept) {

        try {
            Dept dept2 = deptService.save(dept);

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

        } catch (Exception e) {
//            DB 에러가 났을경우 : INTERNAL_SERVER_ERROR 프론트엔드로 전송
            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }

    @DeleteMapping("/dept/deletion/{dno}")
    public ResponseEntity<Object> delete(@PathVariable int dno) {

//        프론트엔드 쪽으로 상태정보를 보내줌
        try {
            boolean bSuccess = deptService.removeById(dno);

            if (bSuccess == true) {
//                delete 문이 성공했을 경우
                return new ResponseEntity<>(HttpStatus.OK);
            }
//            delete 실패했을 경우( 0건 삭제가 될경우 )
            return new ResponseEntity<>(HttpStatus.NO_CONTENT);
        } catch (Exception e) {
//            DB 에러가 날경우
            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }

    @DeleteMapping("/dept/all")
    public ResponseEntity<Object> deleteAll() {

//        프론트엔드 쪽으로 상태정보를 보내줌
        try {
            deptService.removeAll();

            return new ResponseEntity<>(HttpStatus.OK);
        } catch (Exception e) {
//            DB 에러가 날경우
            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }
}

Vue 페이지 : 부서와 동일 생략

📃 결론

부서 게시판 샘플 예제를 Vue & Spring boot 연동 예제를 살펴보았습니다.
기본적인 CRUD 기능을 구현했으며 게시판의 페이징 처리도 해봤습니다.
Spring Boot 는 @RestController 어노테이션을 이용해 구현했으며, 결과는 JSON 데이터로 리턴했으며,
Vue 에 axios 라이브러리를 이용해 전달했습니댜.

DB 프레임워크는 JPA 를 이용해서 sql 문을 직접 제작하지 않고 자동화기능을 이용해 구현했습니다.
Mybatis 의 직접 sql 문 제작 기능에 대응해 자주 반복되고 쉬운 기능은 JPA 의 sql 자동생성 기능을 이용하고,
복잡한 sql 문은 @Query 를 이용해 직접 작성할 수 있어 요즘 많이 서비스 업체 기준으로 사용되고 있습니다.

감사합니다.

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다