Backend/spring

Spring Boot+JPA REST API 서버 만들기

에토 2017. 5. 3. 10:32

Spring Boot + Gradle + JPA


Spring Boot로 REST API 서버를 만들어보자


클라이언트는 ios, android, web으로 가정한다.


ide : IntelliJ IDEA  2017.1.2

spring boot : 1.5.3.RELEASE

build : gradle


github : https://github.com/kkashio/springboot-rest-server.git


디렉토리 구조





Gradle

dependencies {
compile('org.springframework.boot:spring-boot-starter-data-jpa')
compile('org.springframework.boot:spring-boot-starter-web')
runtime('com.h2database:h2')
compileOnly('org.projectlombok:lombok')
testCompile('org.springframework.boot:spring-boot-starter-test')
}


JPA를 사용하기 위해 간단하게 나마 DB 모델링을 해야한다.



게시판과 멤버 테이블을 간단히 모델링 해보았다.

위에 모델링을 참고하여 domain class를 만들어보자



Member.java


@Entity(name = "MEMBER")
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Member {
@Id
@Column(name = "EMAIL")
private String email;

@Column(name = "PASSWORD")
private String password;

@Column(name = "NICKNAME")
private String nickname;

@Column(name = "REG_DATE")
private Date regDate;
}

@Entity - 해당 클래스를 엔티티로 정의

@Data - lombok의 getter/setter

@AllArgsConstructor, @NoArgsConstructor - 자동 생성자

@Id - PK 지정



Board.java


@Entity(name = "BOARD")
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Board {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "BOARD_ID")
private long id;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "EMAIL")
private Member member;

@Column(name = "TITLE")
private String title;

@Column(name = "CONTENT")
private String content;

@Column(name = "REG_DATE")
private Date regDate;

@Column(name = "MODIFY_DATE")
private Date modifyDate;

@Column(name = "DEL_FLAG")
private boolean delFlag;
}


@GeneratedValue - 아이디 값 자동 할당

strategy 값으로 

- AUTO (기본값) : 데이터베이스에 따라 자동으로 선택

- IDENTITY : 기본키 생성을 DB에 위임하는 방법 (MySql, PostgresSQL, SQL Server, DB2)

- SEQUENCE : DB 시퀀스를 사용해 기본 키를 할당하는 방법 (Oracle, PostgresSQL, DB2, H2)

- TABLE : 키 생성 테이블을 사용하는 방법



이제 JpaRepository를 상속받은 repository interface를 구현해보자



BoardRepository

public interface BoardRepository extends JpaRepository<Board, Long>{
Stream<Board> findByMember(String email);
}

기본적으로 JpaRepository만 상속 받으면 기본적인 CRUD를 사용할 수 있다. JpaRepository 클래스를 좀 더 상세히보면 CrudRepository를 상속받고 있어 기본적인 findAll, findOne, save 등 CRUD를 할 수 있다.


또한 Query Method를 이용해 원하는 데이터값을 불러 올 수 있다.

위의 경우 findByMember로 Board 엔티티의 멤버를 이용해 게시목록을 얻어오는 기능이다.



MemberRepository

public interface MemberRepository extends JpaRepository<Member, String>{
List<Member> findByNickname(String nickname);
}


findByNickname : Member 엔티티에서 닉네임으로 유저목록을 가지고 오는 기능이다.

게시판의 경우 자바8의 Stream 형태로 리턴받고, 밑은 일반적으로 많이 쓰는 List로 리턴받는다.


간단한 비지니스 로직을 추가하기 위해 Service단을 만들어보자.



BoardService

public interface BoardService {
List<Board> findByWriter(String email);
}


먼저 인터페이스로 필요한 메서드를 정의하고



BoardServiceImpl

@Service
public class BoardServiceImpl implements BoardService {

@Autowired
BoardRepository boardRepository;

@Override
@Transactional
public List<Board> findByWriter(String email) {
return boardRepository.findByMember(email).collect(Collectors.toList());
}
}


@Service - BoardService를 Bean에 등록해준다.

@Autowired - 등록된 Bean을 사용

@Transactional - 메서드 트랙잭션 설정 ( 이 기능은 사용하지 않아도 무방하나 추후 따로 설명을 하겠습니다. - 영속성 관련 )


구현 클래스에서 BoardService를 구현한다.

findByWriter은 글쓴이로 게시목록을 찾는 기능이다.

boardRepository의 findByMember의 기능을 이용하였고 Stream으로 리턴받은 값을 List로 바꾸어 리턴해주었다. ( Stream은 기능은 따로 정리 하겠습니다 ) 



MemberService

public interface MemberService {
List<Member> findAll();
}



MemberServiceImpl

@Service
public class MemberServiceImpl implements MemberService {

@Autowired
MemberRepository memberRepository;

@Override
public List<Member> findAll() {
return memberRepository.findAll();
}
}


여기선 JpaRepository의 기본기능인 findAll 사용함



BoardController

@RestController
@RequestMapping("/board")
public class BoardController {

@Autowired
BoardService boardService;

@GetMapping("/writer/{email}")
public List<Board> findByWriter(@PathVariable String email){
return boardService.findByWriter(email);
}
}

@RestController - 해당 클래스를 RestController로 만듬 ( 다음 요청을 리턴은 body에 데이터를 실어 리턴 )

@RequestMapping - 맵핑되는 url

@GetMapping - Type이 GET인 맵핑

@PathVariable - url에 { } 에 들어간 값을 파싱해온다. 변수 이름과 파싱해올 데이터 이름이 다르면 따로 선언해주어야한다.


BASE_URL + /board/writer/{email} 로 요청을 하면 해당 메서드가 실행된다.


MemberController

@RestController
@RequestMapping("/member")
public class MemberController {

@Autowired
MemberService memberService;

public List<Member> findAll(){
return memberService.findAll();
}
}


BASE_URL+/member 


DB에 등록된 모든 member를 불러온다.