본문 바로가기
Spring boot 프로젝트 기록/1. 백엔드 개발

서비스 개발(1) - 글을 추가하는 기능

by 으노으뇨 2021. 11. 26.
728x90
반응형
SMALL

서비스 개발에 앞서 , 로깅 하는것을 간단하게 익히고가자, 로깅없이 디버깅하는 것은 코와 입을 막고 숨을 쉬는

것과 같다고한다.

시중에는 로그 라이브러리가 많이 나와있지만 그중 SL4J를 사용하겠다.

package com.unoSpringBoot.study.service;

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

import com.unoSpringBoot.study.model.TodoEntity;
import com.unoSpringBoot.study.persistence.TodoRepository;

import lombok.extern.slf4j.Slf4j;
@Slf4j //<-- 추가된 어노테이션
@Service
public class TodoService {

	@Autowired
	private TodoRepository todoRepository;

	public String testService() {
		TodoEntity todoEntity = TodoEntity.builder().title("하위~").userId("KimEunHo").build();
		todoRepository.save(todoEntity);
		TodoEntity saveEntity = todoRepository.findById(todoEntity.getId()).get();
		return saveEntity.getUserId();
	}
	
}

테스팅을 위해 서비스 클래스에 추가를 해주었다.


Create Todo 구현

Todo 아이템을 생성하는 리포지터리, 서비스 컨트롤러 등을 알아보고 구현해야한다.

새로운 서비스를 추가하기 위해 Todo서비스 클래스에 create매서드를 작성하자.

	public List<TodoEntity> createTodo(final TodoEntity entity) {
		if (entity == null) {
			log.warn("Entity cannot be null!!!");
			throw new RuntimeException("엔티티에 널값이..ㅠ");
		}
		if (entity.getUserId() == null) {
			log.warn("해당하는 아이디가 없음!");
			throw new RuntimeException("해당하는 값이없다.");
		}
		todoRepository.save(entity);
		return todoRepository.findByUserId(entity.getUserId());
	}

중간중간 유효성검사를 위해 if문과 로그를 넣어주었다. 널값일때 갑자기 프로그램이 뻗어버리는걸 막기위해서다.

또는 어떤 값들이 들어오는지 알수있기위해서다.

코드리팩토링

검증 부분은 다른 매서드에서도 계속 쓰일 예정이므로, private method로 리팩토링한다.

	public List<TodoEntity> createTodo(final TodoEntity entity) {
		checkValidate(entity);
		todoRepository.save(entity);
		log.info("entity id : {} is saved", entity.getId());
		return todoRepository.findByUserId(entity.getUserId());
	}

	private void checkValidate(final TodoEntity entity) {
		if (entity == null) {
			log.warn("엔티티값이 널값임");
			throw new RuntimeException("엔티티에 널값이..ㅠ");
		}
		if (entity.getUserId() == null) {
			log.warn("해당하는 값이없다.");
			throw new RuntimeException("해당하는 값이없다.");
		}
	}

앞으로 해당 아이디값을 통해야한다면 위의 매서드를 가져다쓰면된다.

근데 나는 따로 라이브러리처럼 만드는걸 좋아해서 (어짜피 계속 반복되고 사용할테니)

package com.unoSpringBoot.study.UnoDOC;

import com.unoSpringBoot.study.model.TodoEntity;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class Validate {
	public static void checkValidate(final TodoEntity entity) {
		if (entity == null) {
			log.warn("엔티티값이 널값임");
			throw new RuntimeException("엔티티에 널값이..ㅠ");
		}
		if (entity.getUserId() == null) {
			log.warn("해당하는 값이없다.");
			throw new RuntimeException("해당하는 값이없다.");
		}
	}
}

클래스를 따로뺴주었다. 스태틱 상태를 주어서 켜짐과동시 해당 DOC은 서버에 올라가고 그것들을 어디에서나 쓸수있게된다.

그럼 해당 코드처럼 이 메서드가 그게 뭘하는지 간단하게 알수있다. 어떤 로직을 통해찾는지는

그 해당 로직을 고치거나 변경이있지않는이상 보지않아도된다.

그리고 이제 컨트롤러 구현을 해보자.

TodoDTO에 DTO를 엔티티 로 변환하려면 toEntity매서드가 필요하다.

	public static TodoEntity toEntity(final TodoDTO dto) {
		return TodoEntity.builder().id(dto.getId())
				.title(dto.getTitle()).done(dto.isDone())
				.build();
	}

추가해주었다. 

디티오를 매개변수로 받아 엔티티에 셋팅하고 반환해주는 간단한 메서드이다.

이제 이것을 이용해서 컨트롤클래스에 create할수 있는 기능을 구현해주자.

	@PostMapping
	public ResponseEntity<?> createTodo(@RequestBody TodoDTO dto) {
		try {
			String temporartUserId = "김은호";
			TodoEntity todoEntity = TodoDTO.toEntity(dto);
			todoEntity.setId(null);
			todoEntity.setUserId(temporartUserId);
			List<TodoEntity> entities = service.createTodo(todoEntity);
			List<TodoDTO> outDTO = entities.stream().map(TodoDTO::new).collect(Collectors.toList());
			ResponseDTO<TodoDTO> response = ResponseDTO.<TodoDTO>builder().data(outDTO).build();

			return ResponseEntity.ok().body(response);
		} catch (Exception e) {
			// TODO: handle exception
			ResponseDTO<TodoDTO> response = ResponseDTO.<TodoDTO>builder().error("오류").build();
			return ResponseEntity.badRequest().body(response);
		}
	}

그리고 포스트맨을 통해 확인해보자

값이 정상적으로 나온다.


이것은 좀 다른얘기지만

벌써 뭔가 코드가 길어지고 어지럽다...

todo기능, 해당 매핑에 대한 개별적 서비스들. 즉 하나하나 원자화를 해주는것이다.

그래서 Service Object 해서 SO로 해당 기능만을 또 따로 뺴주어서 지금의 떼껄쓰 코드가아닌

기능별로 또 나누어서 관리될수 있도록 쪼개주자.

즉 컨트롤러의 기능은 유효하나, 컨트롤러하나에는 하나또는 두개의 기능만 남긴다는 의미이다.

package com.unoSpringBoot.study.SO;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.unoSpringBoot.study.Controller.TodoController;
import com.unoSpringBoot.study.Controller.TodoCreaeteCO;
import com.unoSpringBoot.study.DTO.TodoDTO;

@RestController
@RequestMapping("todo")
public class TodoSO {

	@Autowired
	TodoController todoController;

	@GetMapping("/badConnect")
	public ResponseEntity<?> testControllerResponseEntity() {
		return todoController.testControllerResponseEntity();
	}

	@Autowired
	TodoCreaeteCO todoCreateCO;

	@PostMapping("/CreateTodo")
	public ResponseEntity<?> createTodo(@RequestBody TodoDTO dto) {
		return todoCreateCO.createTodo(dto);
	}
}

이렇게 만들었다. 

SO는 매서드와 리턴값만 보여주고 관리한다. 즉 매핑만 해주고 기능적인 부분은없다.

package com.unoSpringBoot.study.Controller;

import java.util.List;
import java.util.stream.Collectors;

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

import com.unoSpringBoot.study.DTO.ResponseDTO;
import com.unoSpringBoot.study.DTO.TodoDTO;
import com.unoSpringBoot.study.model.TodoEntity;
import com.unoSpringBoot.study.service.TodoService;

@Service
public class TodoCreaeteCO {

	@Autowired
	private TodoService service;

	public ResponseEntity<?> createTodo(TodoDTO dto) {
		try {
			String temporartUserId = "김은호";
			TodoEntity todoEntity = TodoDTO.toEntity(dto);
			todoEntity.setId(null);
			todoEntity.setUserId(temporartUserId);
			List<TodoEntity> entities = service.createTodo(todoEntity);
			List<TodoDTO> outDTO = entities.stream().map(TodoDTO::new).collect(Collectors.toList());
			ResponseDTO<TodoDTO> response = ResponseDTO.<TodoDTO>builder().data(outDTO).build();

			return ResponseEntity.ok().body(response);
		} catch (Exception e) {
			// TODO: handle exception
			ResponseDTO<TodoDTO> response = ResponseDTO.<TodoDTO>builder().error("오류").build();
			return ResponseEntity.badRequest().body(response);
		}
	}
}

그럼 해당 주소값이라던가 REST방식을 통해 메서드로 진입하게된다.

그리고 그 메서드인 컨트롤러 , 실직적인 로직을 구현한다.

package com.unoSpringBoot.study.Controller;

import java.util.List;
import java.util.stream.Collectors;

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

import com.unoSpringBoot.study.DTO.ResponseDTO;
import com.unoSpringBoot.study.DTO.TodoDTO;
import com.unoSpringBoot.study.model.TodoEntity;
import com.unoSpringBoot.study.service.TodoService;

@Service
public class TodoCreaeteCO {

	@Autowired
	private TodoService service;

	public ResponseEntity<?> createTodo(TodoDTO dto) {
		try {
			String temporartUserId = "김은호";
			TodoEntity todoEntity = TodoDTO.toEntity(dto);
			todoEntity.setId(null);
			todoEntity.setUserId(temporartUserId);
			List<TodoEntity> entities = service.createTodo(todoEntity);
			List<TodoDTO> outDTO = entities.stream().map(TodoDTO::new).collect(Collectors.toList());
			ResponseDTO<TodoDTO> response = ResponseDTO.<TodoDTO>builder().data(outDTO).build();

			return ResponseEntity.ok().body(response);
		} catch (Exception e) {
			// TODO: handle exception
			ResponseDTO<TodoDTO> response = ResponseDTO.<TodoDTO>builder().error("오류").build();
			return ResponseEntity.badRequest().body(response);
		}
	}
}

독립적으로 기능을 수행한다.

그리고 데이터처리는 

서비스패키지 Service클래스에서 수행된다. 여기서 엔티티의 값 유효성검사를 하고, 조건이 만족되면 엔티티와 짝짝꿍이되고 

다시 CO로 돌아온다. 그리고 여기서 데이터 정제라던가 값들을 옮겨받고 나누고 등등 작업을 통해 결과를 SO로 보낸다.

그럼 SO는 최종단계 역할만하고 종료된다.

728x90
반응형
LIST

댓글