본문으로 바로가기

스프링 잡학사전

category Spring & JPA 2020. 5. 25. 17:47

REST API  

-웹브라우저에서 실행되는 javascript로 개발한 앱을 위한 서버를 개발할 때, REST API 서비스를 제공하는 서버를 구현한다.  REST API 서비스라는 것은 클라이언트의 URL요청에 대해서 JSON형태의 데이터를 출력하는 서버의 메소드를 말한다.

 

Single-Valued Association

- 두 개의 테이블  ex) employee와 department에서  외래키(employee 테이블의 departmentId)가 포함된

employee 객체에 department 멤버 변수를 구하는 것이 기본이다.(필수)

@Entity
public class Employees {
   .... 생략 ...
    @ManyToOne
    @JoinColumn(name ="departmentId")
    Department department;

직원(employee) 여러 명이 부서(department) 한개에 소속되어 있으므로
직원은 여러개, 부서는 한개 즉 @ManyToOne

*정리 : 외래키인 departmentId 멤버 변수를 Employee에 만들지 않고, department 멤버 변수를 만들어야 한다.

Collection-Valued Association

-department와 employee 관계를 구현할 때 , @OneToMany 관계에서  One에 해당하는 department 객체에 그 부서 소속 직원들의 목록에 해당하는 List<Employee> employee 멤버 변수를 구할 수 있다.

 

- Collection-Valued Association은 필수가 아니고 선택이다. Department객체로부터 , 소속직원인 Employee목록을 구하고 싶을때만 구현

 

@Entity
public class Department {
     ...생략...
     @OneToMany(mappedBy = "department")
     List<Employee> employees;

*mappedBy = "department"의 department  는 Employee 엔티티 클래스에서 @JoinColumn 어노테이션이 붙은 멤버 변수를 가르킨다.

*department  테이블에는 employee레코드를 가르키는 외래키가 없다. employee 테이블에 departmentId외래키가 있을뿐이다.

 


JSON(Javascript Object Notation)

-서버와 클라이언트 사이에 데이터를 주고 받을 때 흔히 사용되는 포멧.

-JSON 포맷은 javascript 언어의 객체나 배열의 문법과 동일하다.

객체
{ id: 1, name : "전우치" , age: 24}

int 배열
{1,2,3,4}

객체배열
[{ id:1, name : "홍길동" , age:18} , {id:2, name:"김달섭", age:25}]

 

@RestController

-Spring MVC 프레임웍에서 REST API 서비스를 구현할 때, 컨트롤러에 @RestController 어노테이션을 붙인다.

-RestController의 액션 메소드는, 데이터를 클라이언트에 전송하기 때문에 뷰(view)가 필요 없다.

정리: @Controller의 주 용도는 view(화면)을 리턴하는 것이고, @RestController는 데이터를 리턴하는 것.

 

@ResponseBody

-컨트롤러의 액션메소드 앞에 @ResponseBody 어노테이션을 붙이면, 이 액션 메소드가 리턴하는 java 객체는 자동으로 JSON 포멧으로 변환되어 클라이언트에 전송된다.

-단, @Controller 대신 @RestController 어노테이션을 붙인다면 @ResponseBody를 생략해도 상관없다.

 

 

@RequestBody

-RestController의 액션 메소드가 액션 메소드를 호출할 때 전송하는 request parameter 데이터를 받을 액션 메소드의 파라미터 변수에는

@RequestBody 어노테이션을 붙여주어야 한다.

 

 

Request Methods

-클라이언트가 서버에 요청(request)을 전달하는 방식을 request method라고 한다.

-가장 많이 알려진 request method는 GET, POST 인데, REST API 서비스를 구현할 때, request method들을 전부 활용해야 한다.

1. 서버에 데이터를 요청할 때 : GET 방식

2. 서버에 저장할 새 데이터를 전송할 때 : POST방식

3. 서버의 기존 데이터를 수정하기 위해 전송할 때 : PUT 방식

4. 서버의 데이터 삭제를 요청할 때 : DELETE

 

 

REST API URL 패턴

1. REST API 서비스의 URL에 query string를 사용하지 않는 것이 관례이다.

  -http://localhost:8080/server/api/student?id=3   (X)

  -http://localhost:8080/server/api/student/3  (O)

 

2.REST API 서비스의 URL에 동사를 사용하지 않는 것이 관례이다.

 -http://localhost:8080/server/studentDelete?id=3  (X)

 -http://loclhost:8080/server/api/student/3 (O)

 

 

@PathVriable

-요청된 URL이 만약 http://localhost:8080/jpa/api/student/3 이라면, URL에 들어있는 id값 3을 받기 위한 액션 메소드는

@RequestMapping("api/student/{id}")
public Student student(@PathVariable("id") int id)

@Entity

-JPA Entity 클래스 앞에 @Entity를 붙이자.

 

@Id

-기본키에 해당하는 멤버 변수에 @Id 어노테이션을 붙여야 한다.

 

@GeneratedValue(stategy= GenerationType.IDENTITY)

-기본키가 AI(Auto Increment) 이거나 Identity 필드인 경우에 이 어노테이션을 붙여야 한다.

 


@Data (롬복)

		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<scope>provided</scope>
		</dependency>

pom.xml에 추가 후 ,

import lombok.Data;


Single-Valued Association

-department 테이블과 employee 테이블이 존재한다고 가정했을 때, 두 테이블 관계의 구현은 외래키(departmentId)가 포함된

employee 객체에 department 멤버 변수를 구현하는 것이 기본이다.

 

ex) 직원(employee) 여러 명이 부서(department) 한개에 소속된다. 즉 Employee는 여러 개 Department는 한개이다.

따라서 Employee 입장에서는 다대일 , 즉 @ManyToOne 어노테이션을 붙여줘야 한다.

여기서 주의할 점은 외래키를 포함하는 엔티티 클래스(Employee) 에  @ManyToOne 어노테이션을 사용해야 한다.

 

 

Collection-Valued Association

-collection-Valued Association 은 필수 구현 조건이 아니다.

-department 와 employee 관계를 구현할 때, 1대 다의 관계에서 1에 해당하는 department 객체에 그 부서(department)에 소속된 직원인 employee 목록을 구할 필요가 있을 때 구현한다.

 

 

@JsonIgnor

-객체를 JSON 포멧으로 변환할 때, 변환하지 않고 무시해야할 멤버 변수에 @JsonIgnor 를 붙인다.

 

 

@Column

- DB table 컬럼명과 JPA entity 클래스의 변수명을 다르게 설정 할 경우 @Column 어노테이션을 붙인다.

-course라는 테이블이 있다는 가정하에 , 컬럼명이 courseName인데 entity 클래스에서는 name으로 변수를 설정하고 싶을때 사용

@Column(name = "courseName")
String name;

 

@Table

- DB테이블명과 entity클래스명이 다를경우 @Table 어노테이션을 붙인다.

@Table(name = "register")
public class Registration {
 ....
}

@Embeddable   ,@Embedded(변수)

-Entity에 속해있는 객체(dto)라는 것을 명시

 

@Min, @Max

-최대/최소 값 지정

 

 

JPQL 예시

   1. @Query(value ="select person from Person person where person.birthday.monthOfBirthday = ?1 and person.birthday.dayOfBirthday =?2")
   2. @Query(value ="select person from Person person where person.birthday.monthOfBirthday = :monthOfBirthday and person.birthday.dayOfBirthday = :dayOfBirthday")
   3. @Query(value ="select * from person where month_of_birthday = :monthOfBirthday and day_of_birthday =:dayOfBirthday", nativeQuery = true)
    
    List<Person> findByMonthOfBirthday(@Param("monthOfBirthday") int monthOfBirthday, @Param("dayOfBirthday") int dayOfBirthday);

 

1,2,3 모두 동일한 실행 결과

 

 

@Vaild 

-유효성 검사 / 객체검증

import javax.validation.Valid;
@Size(max=10, min=2, message=”errMsg”)
@Email(message=”errMsg”)
@NotEmpty(message=”errMsg”)


form 태그에서 put과 delete방식으로 전달하기

-form 태그의 메서드는 get과 post방식만 지원하기 때문에, put과 delete 방식으로 전달을 하지 못한다.

<form name="question" method="post" action="/users/{{id}}">
<input type="hidden" name="_method" value="put"/>

위 방법으로 put과 delete 방식으로도 전달할 수 있다.


#에러

Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured.
Reason: Failed to determine a suitable driver class

위 에러는, 스프링 부트를 처음 실행했을 때 연결한 DB가 없다는 에러로 DB연결 설정을 해주거나, 나중에 설정할 계획이라면

 

src/main/java - ~~~Application.java에

@EnableAutoConfiguration(exclude={DataSourceAutoConfiguration.class})  어노테이션을 추가해주면 정상적으로 서버가 동작한다.

 


@Controller

  • 요청을 받아서 view를 리턴

@RestController

  • @Controller에 @ResponseBody가 포함되어 있다.

@ResponseBody

  • view가 아닌 json 데이터를 클라이언트에 보낸다. Map을 반환하면 자동으로 Map 정보가 json 객체로 변환되어 전송

@RequestMapping

  • 요청과 컨트롤러 메서드를 맵핑하기 위한 애너테이션
  • @GetMapping 등을 사용해서 좀 더 편하게 사용할 수 있다.

@RequestBody

  • 컨트롤러로 전송된 정보가 자동으로 Map으로 변환되어 해당 변수에 저장된다.
  • json으로 데이터가 넘어오는 post 요청에 객체로 맵핑할 때 주로 사용된다.

@RequestParam

@PathVariable

@ModelAttribute

  • @ModelAttribute가 붙은 객체는 HTTP로 넘어온 값들을 자동으로 바인딩한다.
  • 바인딩된 객체는 자동으로 Model 객체에 추가되고 뷰단까지 전달이 된다.

ResponseEntity

  • @ResponseBody와 기능적으론 같지만, 그 구현 방법이 다르다.
  • 일반적인 API는 반환하는 리소스에 Value만 있지 않다.
  • 상태코드, 응답 메세지 등이 포함될 수 있는 데 그럴 때 사용된다.
  • spring framework에서 제공하는 HttpEntity를 상속받음으로써 HttpHeader와 body를 가질 수 있다.
  • Header 값을 통해 조금 더 견고한 API를 개발하고 싶을 때 사용하자.

RESTful이란?

  • REST는 Representational State Transfer라는 용어의 약자로서 웹의 장점을 최대한 활용할 수 있는 아키텍처
  • 최근의 서버 프로그램은 다양한 브라우저와 안드로이폰, 아이폰과 같은 모바일 디바이스에서도 통신을 할 수 있어야 한다.
  • REST 아키텍처는 Hypermedia API의 기본을 충실히 지키면서 범용성을 보장한다.

DI(Dependency Injection)

  • 의존성 주입

DIP(Dependency Inversion Principle)

  • 의존 역전 원칙, 변하기 쉬운 클래스에 의존하지 않는 것

IOC(Inversion Of Control)

  • 제어의 역전

DTO(Data Transfer Object)

  • 계층간 데이터 교환을 위한 객체
  • DB에서 데이터를 얻어 Service나 Controller 등으터 보낼 때 사용하는 객체
  • 로직을 갖고있지 않은 순수한 데이터 객체, getter/setter만 가진다.
  • setter를 활용하기 보단 생성자를 통해 값을 변경한다.
  • Domain Model을 아무리 잘 설계했다고 해도 각 View 내에서 Domain Model의 getter만을 이용해서 원하는 정보를 표시하기가 어려운 경우가 종종 있다. 이런 경우 Domain Model 내에 Presentation을 위한 필드나 로직을 추가하게 되는데, 이러한 방식이 모델링의 순수성을 깨고 Domain Model 객체를 망가뜨리게 된다. 또한 Domain Model을 복잡하게 조합한 형태의 Presentation 요구사항들이 있기 때문에 Domain Model을 직접 사용하는 것은 어렵다.
  • 즉 DTO는 Domain Model을 복사한 형태로, 다양한 View를 각각 DTO에 각자의 Presentation Logic을 생성자에 추가한 정도로 사용하며 Domain Model 객체는 Persistent(지속성)만을 위해서 사용한다.

Entity

  • 식별성을 가져야 한다.
  • 동일하다는 것이 무엇을 의미하는지 정의해야 한다.
  • 실제 DB테이블과 매칭될 클래스
  • 최대한 외부에서 Entity 클래스의 getter method를 사용하지 않도록 해당 클래스 안에서 필요한 로직 method을 구현한다.
    • 단, Domain Logic만 가지고 있어야 하고 Presentation Logic을 가지고 있어서는 안된다.
    • 여기서 구현한 method는 주로 Service Layer에서 사용한다.

DTO와 Entity를 분리하는 이유

  • View Layer와 DB Layer의 역할을 철저히 분리하기 위해
  • View와 통신하는 DTO는 자주 분리되기 때문에 분리해야 한다.

 

@RequestBody

이 어노테이션이 붙은 파라미터에는 HTTP 요청의 본문 body 부분이 그대로 전달된다. RequestMappingHandlerAdapter에는 HttpMessageConverter 타입의 메시지 변환기(message converter)가 여러 개 등록되어 있다. @RequestBody가 붙은 파라미터가 있으면 HTTP 요청의 미디어 타입과 파라미터의 타입을 먼저 확인한다. (dispatcher-servlet.xml 에서 확인) 메시지 변환기 중에서 해당 미디어 타입과 파라미터 타입을 처리할 수 있다면, HTTP 요청의 본문 부분을 통째로 변환해서 지정된 메소드 파라미터로 전달해준다.

 

쉽게 말하자면 @RequestBody 어노테이션을 이용하면 HTTP 요청 Body를 자바 객체로 전달받을 수 있다.

 

 

@RequestBody 어노테이션은 요청에서 Body부분을 살펴 요청된 데이터를 추출하여 파라미터로 변환해주는데, ‘GET’ 메소드 요청의 경우에는 HTTP Body에 요청이 전달되는 것이 아니라, URL의 파라미터로 전달 (ex: http://localhost:8080/test?id=admin&name=hanq…) 형식으로 전달되기 때문에 @RequestBody로 받으려고 해도 서로 다른 곳을 보며 데이터가 없다는 결과를 던질 수 밖에 없다.

 

@ResponseBody

@ResponseBody는 @RequestBody와 비슷한 방식으로 동작한다. @ResponseBody가 메서드 레벨에서 부여되면 메서드가 리턴하는 오브젝트는 뷰를 통해 결과를 만들어내는 모델로 사용하는 대신, 메시지 컨버터를 통해 바로 HTTP 응답의 메시지 본문으로 변환된다.

 

 

간단히 이야기 하자면, 요청한 형태에 맞춰서 메시지 변환기를 통해 결과값을 반환한다. @ResponseBody는 @RequestBody가 선택한 형식으로 결과값을 변환하여 반환한다고 보면 된다. 또한 @ResponseBody을 이용하면 자바 객체를 HTTP 응답 body로 전송할 수 있다.