스프링으로 CRUD기능을 한 번 만들어보자.
Repository를 이용할 것이다.
public interface Repository <T, ID>{
}
를 만들고 DataRepository도 만든다.
package com.example.demo.db;
public interface DataRepository <T, ID> extends Repository <T, ID> {
}
여기서 public interface DataRepository <T, ID> extends Repository <T, ID>는
'엔티티, 즉 데이터의 타입을 받을 것이고 각 고유한 ID를 받을 것이다. 그리고 인터페이스를 상속한다.' 라는 의미다.
DataRepository는 CRUD 기능을 인터페이스로 가지도록 할 것 이다.
Optional<T> findById(ID id)
이건 CRUD 중 Read에 해당한다.
리턴시키는 것은 당연히 method인데 data가 있을 수도 있고 없을 수도 있기 때문에 Optional을 사용한다.
findById는 Data의 ID를 통해서 Data를 return하는 method이다. 즉 ID type의 id를 받아서 return시킬 것이다.
List<T> findAll();
여기서 findById는 한 건을 return하는 것이니 List로 return해주는 FindAll이라는 method를 하나 만들 것이다.
T save(T data);
이건 CRUD 중 Create, Update에 해당한다.
특정한 data를 가지고 들어올 것이다. 이 data(id)가 여기서 있으면 id를 Update 시키고 없으면 save시킬것이다.
void delete(ID id);
이건 CRUD 중 Delete에 해당한다.
Delete는 data가 삭제됐기 때문에 return할 게 없고 ID통해서 Delete시키기만 한다.
이제 이러한 DB에 들어가는 data를 정의하는 Entity를 만들어보자.
우선 PrimaryKey라는 interface를 만든다. Id data는 많을 것이니 Long Type을 가질 것이다.
public interface PrimaryKey {
void setId(Long id);
Long getId();
}
이를 상속 받는 엔티티 클래스를 만든다.
public abstract class Entity implements PrimaryKey {
@Getter
@Setter
private Long id;
}
추상 클래스를 만들어서 이를 상속받는 것들이 구현을 해도 되고 안 해도 되는 형태로 만들자.
자신만의 저장 공간을 두도록 하는 코드를 만들어보자.
abstract public class SimpleDataRepository<T, ID> implements DataRepository<T, ID>{
private List<T> dataList = new ArrayList<T>();
private static long index = 0;
}
이제는 unique하게 id를 지정해줘야한다.
data에 setId를 통해서 id를 넣어줘야 되는데, 이 data가 Generic type이기 때문에 id를 setId를 해줄 수 없는 상황이다.
extends 키워드를 통해서 type을 어느정도 제한을 줄 수 있다.
Entity를 상속받은 ID만 이 type에다가 지정할 수 있다 라고 할 수 있다.
ID에 대한 type은 반드시 Long type으로 제한을 하겠다고 지정해줘야한다.
abstract public class SimpleDataRepository<T extends Entity, ID extends Long> implements DataRepository<T, ID>{
아까 만들었던 entity는 long타입의 변수를 갖고있기 때문에 여기서 T는 entity라고 보면 된다.
그렇기 때문에 data에 setId가 가능해진다.
data에 index를 지정해주고 unique id를 딸 수 있게 된다.
index++ 을 해서 항상 이 index가 unique하게 올라갈 수 있도록 만들어준다.
data.setId(index);
dataList.add(data);
index++;
null일 경우의 예외도 작성해준다.
if(Objects.isNull(data)){
throw new RuntimeException("Data is null");
}
여기도 CRUD 구조로 작성해준다.
Create, Update 부터, data list에 이미 data가 있으면 Update를 하고, 없으면 새로 save를 할 것이다.
그래서 사전에 DB에 이미 있는가를 볼 수 있는 작업을 할 것 이다. 현재 들어있는 data의 getId와 object, 즉 data가 가지고 있는 id가 동일한 경우 findFirst로 찾도록 하자.
var prevData = dataList.stream()
.filter(it->{
return it.getId().equals(data.getId());
})
.findFirst();
이제는 사전 data가 있는 경우 없는 경우를 작성해주자. 있는 경우에는 업데이트를 할 건데 기존 데이터를 remove하고 새 데이터를 add하는 방식으로 작성한다.
없는 경우는 index++ 해서 들어가고자 하는데다가 set하자.
if(prevData.isPresent()){
dataList.remove(prevData);
dataList.add(data);
}else{
data.setId(index);
dataList.add(data);
index++;
}
return data;
}
이제 Read 부분을 작성하자
아까처럼 id를 읽어오고 전체를 list로 읽어오는 것을 작성한다.
@Override
public Optional<T> findById(ID id){
return dataList.stream()
.filter(it->{
return (it.getId().equals(id));
})
.findFirst();
}
sort를 이용해서 전체 리스트를 받아와보자
private Comparator<T> sort = new Comparator<T>() {
@Override
public int compare(T o1, T o2) {
return Long.compare(o1.getId(), o2.getId());
}
};
``
```java
@Override
public List<T> findAll(){
return dataList
.stream()
.sorted(sort)
.collect(Collectors.toList());
}
Delete는 isPresent로 데이터가 있는 경우 삭제하도록 하자
@Override
public void delete(ID id){
var deleteEntity = dataList.stream()
.filter(it->{
return (it.getId().equals(id));
})
.findFirst();
if (deleteEntity.isPresent()){
dataList.remove(deleteEntity);
}
}
}
이제 CRUD 추상 클래스로 구현체까지 다 만들었다.
DataRepository
import java.util.List;
import java.util.Optional;
public interface DataRepository <T, ID> extends Repository <T, ID> {
T save(T data);
Optional<T> findById(ID id);
List<T> findAll();
void delete(ID id);
}
Repository
public interface Repository <T, ID>{
}
SimpleDataRepository
import com.example.demo.entity.Entity;
import java.util.*;
import java.util.stream.Collectors;
abstract public class SimpleDataRepository<T extends Entity, ID extends Long> implements DataRepository<T, ID>{
private List<T> dataList = new ArrayList<T>();
private static long index = 0;
private Comparator<T> sort = new Comparator<T>() {
@Override
public int compare(T o1, T o2) {
return Long.compare(o1.getId(), o2.getId());
}
};
@Override
public T save(T data){
if(Objects.isNull(data)){
throw new RuntimeException("Data is null");
}
var prevData = dataList.stream()
.filter(it->{
return it.getId().equals(data.getId());
})
.findFirst();
if(prevData.isPresent()){
dataList.remove(prevData);
dataList.add(data);
}else{
data.setId(index);
dataList.add(data);
index++;
}
return data;
}
@Override
public Optional<T> findById(ID id){
return dataList.stream()
.filter(it->{
return (it.getId().equals(id));
})
.findFirst();
}
@Override
public List<T> findAll(){
return dataList
.stream()
.sorted(sort)
.collect(Collectors.toList());
}
@Override
public void delete(ID id){
var deleteEntity = dataList.stream()
.filter(it->{
return (it.getId().equals(id));
})
.findFirst();
if (deleteEntity.isPresent()){
dataList.remove(deleteEntity);
}
}
}
PrimaryKey
public interface PrimaryKey {
void setId(Long id);
Long getId();
}
Entity
public abstract class Entity implements PrimaryKey {
@Getter
@Setter
private Long id;
}