본문 바로가기
실습/리눅스 서버 + 스프링 부트

03. RestfulAPI_MariaDB

by 이민우 2021. 5. 19.
728x90
반응형

지난 포스팅에서 설치 및 준비가 끝이났다.

그러니 이번에는 스프링 부트를 사용해 간단한 RestfulAPI를 제작해보자.

 

 

가장 먼저 할 것은 MariaDB에 대한 CRUD Restful API 개발이다.

 

마리아 디비는 오픈 소스의 RDBMS이다.

 

MySQL이 오라클에 인수된 후 MySQL의 핵심 개발자들이 제작한 오픈소스로, MySQL과 굉장히 유사하며, 오픈소스이기 때문에 무료인 덕에 상업용으로도 많이 사용되는 DB이다.

 

구현은 간단하게 아이디-패스워드로 구성된 테이블을 사용할 것이다.

 

JPA를 사용한 구현을 진행할 것이기 때문에 다음의 설정을 application.properties에 추가해주었다.

그 외의 다양한 설정은 다음 포스팅 참고

 

끝이났으면 일단 마리아디비에 linuxTest 이름의 데이터베이스 생성.

JPA를 사용할 예정이기에 굳이 테이블까지 만들어줄 필요는 없다. spring.jpa.hibernate.ddl-auto 설정에 따라 자동으로 존재하지 않는 테이블은 만들어지기 때문이다.

 

 

설정이 끝났으면 코딩을 시작한다.

여느 JPA 프로그램들과 마찬가지로 구조는

Domain - Repository - Service - Controller 로 작성한다.

 

여기서 각 클래스의 역할은 다음과 같다.

  1.  Domain : DTO로, 데이터를 담기 위한 클래스.
  2.  Repository : Spring Data JPA 방식으로, 데이터베이스에 접근하는 클래스.
  3.  Service : 비즈니스 로직을 처리하는 클래스.
  4.  Controller : 클라이언트와 데이터를 주고받는 클래스.

 

가장 먼저 도메인 클래스를 작성해준다.

앞서 언급한대로 아이디-비밀번호로 간단하게 이루어진 테이블을 사용할 것이다.

 

MariaDomain.java

package kr.co.opensource.maria;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

import com.fasterxml.jackson.annotation.JsonInclude;

import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

@JsonInclude(JsonInclude.Include.NON_NULL) //Json 입력 데이터를 클래스 내 각 변수에 자동 매핑
@Entity
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Table(name="test_table2") // 매핑되는 테이블 설정
@ToString
public class MariaDomain {
	@Id //기본키
	@Column(name="test_key", columnDefinition="varchar(10)", nullable=false) // 칼럼 매핑 및 칼럼 정보
	private String key;
	
	@Column(name="test_val", columnDefinition="varchar(10) NOT NULL DEFAULT \"hi\"") // NULLABLE 여부는 이렇게도 설정 가능
	private String val;
}

 

이제 앞서 만든 도메인을 DB에 연동하여 사용할 Repository 클래스를 만든다.

CrudRepository를 사용할 예정이고, 구현 시 <> 안에 사용할 도메인과 해당 도메인의 private key 타입을 넣어준다.

만약 private key가 여러 개라면 pk만 모아놓은 별도의 클래스 파일을 사용해야 한다.

 

MariaRepository.java

package kr.co.opensource.maria;

import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface MariaRepository extends CrudRepository<MariaDomain, String>{

}

 

다음은 Repository와 연동될 Service 클래스이다.

비즈니스 로직은 전부 Service에 작성한다.

Service의 로직은 다음과 같이 설정했고, CommonCode 클래스 파일에 기재되어있다.

  • 0 : 로직을 성공적으로 마쳤을 때
  • 1 : 이미 존재하는 데이터 / 존재하지 않는 데이터
  • 2 : JPA 내부에서 에러가 발생했을 때

 

MariaService.java

package kr.co.opensource.maria;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import kr.co.opensource.CommonCode;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
public class MariaService {

	@Autowired MariaRepository repo;
	
	public int save(MariaDomain domain) {
		log.info("MariaService.save init : {}", domain.toString());
		
		if(repo.findById(domain.getKey()).orElse(null) != null) {
			//이미 존재하는 데이터
			log.info("MariaService.save data already exists : {}", domain.getKey());
			
			return CommonCode.EXCEPTION;
		}
		
		try {
			repo.save(domain);
		}
		catch(Exception e) {
			//쿼리 과정 중 에러 발생
			log.error("MariaService.save some internal error occured : {}", e.getMessage());
			
			return CommonCode.ERROR;
		}
		
		return CommonCode.SUCCESS;
	}
	
	public int update(MariaDomain domain) {
		log.info("MariaService.update init : {}", domain.toString());
		
		if(repo.findById(domain.getKey()).orElse(null) == null) {
			//존재하지 않는 데이터
			log.info("MariaService.update data not exists : {}", domain.getKey());
			
			return CommonCode.EXCEPTION;
		}
		
		try {
			repo.save(domain);
		}
		catch(Exception e) {
			//쿼리 과정 중 에러 발생
			log.error("MariaService.update some internal error occured : {}", e.getMessage());
			
			return CommonCode.ERROR;
		}
		
		return CommonCode.SUCCESS;
	}
	
	public int delete(String key) {
		log.info("MariaService.delete init : {}", key);
		
		if(repo.findById(key).orElse(null) == null) {
			//존재하지 않는 데이터
			log.info("MariaService.delete data not exists : {}", key);
			
			return CommonCode.EXCEPTION;
		}
		
		try {
			repo.deleteById(key);
		}
		catch(Exception e) {
			log.error("MariaService.delete some internal error occured : {}", e.getMessage());
			
			return CommonCode.ERROR;
		}
		return CommonCode.SUCCESS;
	}
	
	public MariaDomain find(String key) {
		log.info("MariaService.find init : {}", key);
		
		return repo.findById(key).orElse(null);
	}
	
	public List<MariaDomain> findAll() {
		log.info("MariaService.findAll init");
		
		Iterator<MariaDomain> domainItr = repo.findAll().iterator();
		List<MariaDomain> domainList = new ArrayList();
		
		while(domainItr.hasNext()) {
			domainList.add(domainItr.next());
		}
		
		return domainList;
	}

}

마지막으로 Service와 연동되며, 사용자와 직접 상호작용할 Controller 클래스를 작성한다.

어노테이션은 rest이기 때문에 당연히 @Controller 가 아닌 @RestController 어노테이션을 사용한다.

그리고 편의상 모든 작업 요청에 대한 Response Status 값은 201로 고정하였다.

 

MariaRestController.java

package kr.co.opensource.maria;

import java.nio.charset.Charset;
import java.util.List;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import kr.co.opensource.CommonCode;
import kr.co.opensource.ResponseMessage;
import kr.co.opensource.ResponseVO;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@RestController // REST API 용 컨트롤러. 만약 UI 기반이면 @Controller
public class MariaRestController {
	@Autowired MariaService service;
	
	@RequestMapping(value={"/maria","/maria/{key}"}, method= {RequestMethod.GET, RequestMethod.POST, RequestMethod.PUT, RequestMethod.DELETE})
	public @ResponseBody ResponseEntity<ResponseVO> controller(HttpServletRequest req,
													  @PathVariable(value="key", required=false) String key,
													  @RequestBody(required=false) MariaDomain domain) {

		log.info("MariaRestController.controller init http: {}", req.getMethod());
		
		ResponseVO msg = new ResponseVO();
		HttpHeaders headers = new HttpHeaders();
		headers.setContentType(new MediaType("application", "json", Charset.forName("UTF-8")));
		
		String method = req.getMethod();
		
		if(method.equals("GET")) {
			if(key == null) {
				
				log.info("MariaRestController.controller get all data");
				
				List<MariaDomain> mariaDomainList = service.findAll();
				
				msg.setStatus(HttpStatus.OK);
				msg.setMessage(ResponseMessage.OK);
				msg.setData(mariaDomainList);
				
				//편의상 에러는 전부 BAD_REQUEST로 기재
				return new ResponseEntity<ResponseVO>(msg, headers, HttpStatus.OK);
			}
			
			log.info("MariaRestController.controller get one data : {}", key);
			MariaDomain returnDomain = service.find(key);
			
			if(returnDomain == null) {
				log.warn("MariaRestController.controller not exists data : {}", key);
				
				msg.setStatus(HttpStatus.BAD_REQUEST);
				msg.setMessage(ResponseMessage.NOT_EXISTS);
				msg.setData(null);

				return new ResponseEntity<ResponseVO>(msg, headers, HttpStatus.BAD_REQUEST);
			}
			
			msg.setStatus(HttpStatus.OK);
			msg.setMessage(ResponseMessage.OK);
			msg.setData(returnDomain);
			return new ResponseEntity<ResponseVO>(msg, headers, HttpStatus.OK);
		}
		else if(method.equals("POST")) {
			log.info("MariaRestController.controller save data : {}", domain);
			
			if(domain == null) {
				log.error("MariaRestController.controller required parameter not exists");
				
				msg.setStatus(HttpStatus.BAD_REQUEST);
				msg.setMessage(ResponseMessage.NOT_EXISTS_BODY);
				msg.setData(null);

				return new ResponseEntity<ResponseVO>(msg, headers, HttpStatus.BAD_REQUEST);
			}
			
			int result = service.save(domain);
			
			if(result == CommonCode.EXCEPTION) {
				//이미 존재하는 데이터
				log.warn("MariaRestController.controller already exist data : {}", domain);
				
				msg.setStatus(HttpStatus.BAD_REQUEST);
				msg.setMessage(ResponseMessage.EXISTS);
				msg.setData(null);

				return new ResponseEntity<ResponseVO>(msg, headers, HttpStatus.BAD_REQUEST);
			}
			else if(result == CommonCode.ERROR) {
				//쿼리 실패
				log.warn("MariaRestController.controller some interner error exists");
				
				msg.setStatus(HttpStatus.BAD_REQUEST);
				msg.setMessage(ResponseMessage.INTERNAL_ERROR);
				msg.setData(null);

				return new ResponseEntity<ResponseVO>(msg, headers, HttpStatus.BAD_REQUEST);
			}
			else {
				//성공
				log.info("MariaRestController.controller successfully saved data : {}", domain);
				
				msg.setStatus(HttpStatus.CREATED);
				msg.setMessage(ResponseMessage.CREATED);
				msg.setData(domain);
				
				return new ResponseEntity<ResponseVO>(msg, headers, HttpStatus.CREATED);
			}
		}
		else if(method.equals("PUT")) {
			log.info("MariaRestController.controller update data : {}", key);
			
			if(key == null) {
				log.warn("MariaRestController.controller required parameter not exists");
				
				msg.setStatus(HttpStatus.BAD_REQUEST);
				msg.setMessage(ResponseMessage.NOT_EXISTS_KEY);
				msg.setData(null);
				
				return new ResponseEntity<ResponseVO>(msg, headers, HttpStatus.BAD_REQUEST);
			}
			
			
			int result = service.update(domain);
			
			if(result == CommonCode.EXCEPTION) {
				log.info("MariaRestController.controller not exists data : {}", domain);
				
				msg.setStatus(HttpStatus.BAD_REQUEST);
				msg.setMessage(ResponseMessage.NOT_EXISTS);
				msg.setData(null);
				
				return new ResponseEntity<ResponseVO>(msg, headers, HttpStatus.BAD_REQUEST);
			}
			else if(result == CommonCode.ERROR) {
				//쿼리 실패
				log.warn("MariaRestController.controller some interner error exists");
				
				msg.setStatus(HttpStatus.BAD_REQUEST);
				msg.setMessage(ResponseMessage.INTERNAL_ERROR);
				msg.setData(null);

				return new ResponseEntity<ResponseVO>(msg, headers, HttpStatus.BAD_REQUEST);
			}
			else {
				//성공
				log.info("MariaRestController.controller successfully updated data : {}", key);
				
				msg.setStatus(HttpStatus.OK);
				msg.setMessage(ResponseMessage.OK);
				msg.setData(domain);
				
				return new ResponseEntity<ResponseVO>(msg, headers, HttpStatus.OK);
			}
			
		}
		else if(method.equals("DELETE")) {
			log.info("MariaRestController.controller update data : {}", key);
			
			if(key == null) {
				log.warn("MariaRestController.controller required parameter not exists");
				
				msg.setStatus(HttpStatus.BAD_REQUEST);
				msg.setMessage(ResponseMessage.NOT_EXISTS_KEY);
				msg.setData(null);
				
				return new ResponseEntity<ResponseVO>(msg, headers, HttpStatus.BAD_REQUEST);
			}
			
			int result = service.delete(key);
			
			if(result == CommonCode.EXCEPTION) {
				log.warn("MariaRestController.controller not exists data : {}", key);
				
				msg.setStatus(HttpStatus.BAD_REQUEST);
				msg.setMessage(ResponseMessage.NOT_EXISTS);
				msg.setData(null);
				
				return new ResponseEntity<ResponseVO>(msg, headers, HttpStatus.BAD_REQUEST);
			}
			else if(result == CommonCode.ERROR) {
				log.warn("MariaRestController.controller some interner error exists");
				
				msg.setStatus(HttpStatus.BAD_REQUEST);
				msg.setMessage(ResponseMessage.INTERNAL_ERROR);
				msg.setData(null);
				
				return new ResponseEntity<ResponseVO>(msg, headers, HttpStatus.BAD_REQUEST);
			}
			else {
				//성공
				log.info("MariaRestController.controller successfully deleted data : {}", key);
				
				msg.setStatus(HttpStatus.OK);
				msg.setMessage(ResponseMessage.OK);
				msg.setData(null);
				
				return new ResponseEntity<ResponseVO>(msg, headers, HttpStatus.OK);
			}
			
		}
		
		//여기까지 올일은 사실상 없음.
		//그냥 return null 하기 싫어서 기재.
		msg.setStatus(HttpStatus.METHOD_NOT_ALLOWED);
		msg.setMessage(ResponseMessage.NOT_ALLOWED_METHD);
		msg.setData(null);
		return new ResponseEntity<ResponseVO>(msg, headers, HttpStatus.METHOD_NOT_ALLOWED);
	}
}

 

 

완료되었으니 이제 POSTMAN을 활용해 테스트를 수행해보자.

 

1) 등록

2) 수정

3) 조회

4) 삭제

전부 정상작동함을 확인할 수 있다.

728x90
반응형

'실습 > 리눅스 서버 + 스프링 부트' 카테고리의 다른 글

05. RestfulAPI_Redis CRUD  (0) 2021.05.23
04. RestfulAPI_MongoDB  (0) 2021.05.23
02. 윈도우 세팅 및 프로젝트 생성  (0) 2021.05.19
01. 리눅스 서버 세팅  (0) 2021.05.05
00. VB 및 리눅스 서버 설치  (0) 2021.05.05