Database Design

이전에 설계한 API Design 을 기반으로 간단하게 Database 설계 및 sample data 를 추가해보자.

CREATE DATABASE  IF NOT EXISTS `employee_directory`;
USE `employee_directory`;
 
--
-- Table structure for table `employee`
--
 
DROP TABLE IF EXISTS `employee`;
 
CREATE TABLE `employee` (
  `id` int NOT NULL AUTO_INCREMENT,
  `first_name` varchar(45) DEFAULT NULL,
  `last_name` varchar(45) DEFAULT NULL,
  `email` varchar(45) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1;
 
--
-- Data for table `employee`
--
 
INSERT INTO `employee` VALUES 
	(1,'Leslie','Andrews','leslie@luv2code.com'),
	(2,'Emma','Baumgarten','emma@luv2code.com'),
	(3,'Avani','Gupta','avani@luv2code.com'),
	(4,'Yuri','Petrov','yuri@luv2code.com'),
	(5,'Juan','Vega','juan@luv2code.com');
Create Project

Dependency 를 위와 같이 포함시킨 뒤, project 를 generate 하자.

Development Process

Development Process 는 우선 다음 단계를 따라서 진행한다.

  1. Update DB configs in application.properties
  2. Create Employee entity (entity class)
  3. Create DAO interface
  4. Create DAO implementation
  5. Create REST controller to use DAO

처음에는 아래와 같은 Architecture 로 구성된다.

이전에 DAO 를 처음 다뤘을 때와 같이, DAO 를 Controller 에서 직접 injection 받아서 사용하는 구조이다. 이제 Development Process 에 있는 단계들을 하나씩 구현해보자.

우선 Database configuration 을 다음과 같이 application.properties 에 update 한다.

# JDBC properties
spring.datasource.url=jdbc:mysql://localhost:3306/employee_directory  
spring.datasource.username=username  
spring.datasource.password=password

그리고 Database Design 한 것을 기반으로 Entity Class 를 작성한다. Employee.java 에 다음과 같이 작성한다.

@Entity  
@Table(name="employee")  
public class Employee {  
  
    // define fields  
    @Id  
    @GeneratedValue(strategy = GenerationType.IDENTITY)  
    @Column(name="id")  
    private int id;  
  
    @Column(name="first_name")  
    private String firstName;  
  
    @Column(name="last_name")  
    private String lastName;  
  
    @Column(name="email")  
    private String email;
 
	// define constructors
	...
	// define getter/setter
	...
	// define toString
	...
}

이렇게 @Entity 를 사용하여 JPA 가 알아서 실제 DB 의 employee table 및 각 field 와 mapping 을 수행하도록 하면 entity class 설정은 끝났다. 이제는 DAO 를 위한 Interface 와 그에 대한 Implementation 을 만들자.

이쯤에서 다시 Boss 가 요청한 API Requirements 를 확인해보자.

Create a RET API for the Employee Directory

REST clients should be able to

  • get a list of employees
  • get a single employee by id
  • add a new employee
  • update an employee
  • delete an employee

requirements 의 첫 번째 사항부터 하나씩 구현하는 식으로 진행하면 좋을 것 같다. 다시 DAO 로 돌아와서, 모든 employee 의 list 를 return 할 수 있는 method 부터 declare 하고, define 하면 될 것 같다.

EmployeeDAO.java interface 에는 다음과 같이 작성하고,

public interface EmployeeDAO {   
    List<Employee> findAll();  
}

이를 implement 하는 EmployeeDAOImpl.java 에는 다음과 같이 작성하면 될 것이다.

@Repository  
public class EmployeeDAOImpl implements EmployeeDAO {  
  
    // define field for entity manager  
    private EntityManager entityManager;  
  
    // set up constructor injection  
    public EmployeeDAOImpl(EntityManager entityManager) {  
        this.entityManager = entityManager;  
    }  
  
    @Override  
    public List<Employee> findAll() {  
  
        // create a query  
        TypedQuery<Employee> theQuery = entityManager.createQuery("from Employee", Employee.class);  
  
        return theQuery.getResultList();  
    }  
}

마지막으로, 해당 DAO 를 Injection 받아 사용하는 REST Controller 를 작성하면 requirement 하나의 Development Process 가 끝이 난다. EmployeeRestController.java 에는 다음과 같이 작성한다.

@RestController  
@RequestMapping("/api")  
public class EmployeeRestController {  
  
    private EmployeeDAO employeeDAO;  
  
    // quick and dirty: inject employee dao using constructor injection  
    public EmployeeRestController(EmployeeDAO employeeDAO) {  
        this.employeeDAO = employeeDAO;  
    }  
  
    // expose "/employees" and return a list of employees  
    @GetMapping("/employees")  
    public List<Employee> findAll() {  
        return employeeDAO.findAll();  
    }  
}
Potential Problem

그러나 잠재적인 문제점이 보이는 것 같다. 만약에 Buiness logic 이 조금 더 복잡해져서 하나의 method 에 여러개의 DAO 가 사용되고, logic 이 복잡해지면 Controller 내부의 code 가 무한히 늘어나 유지보수에 어려움이 생길 것이다.

그렇다면 Controller 와 Buisness logic 을 분리시킬 필요가 있을 것 같다.