우리는 특정 uri로 요청을 보내면 Controller에서 어떠한 방식으로 처리할지 정의를 한다.
이때 들어온 요청을 특정 메서드와 매핑하기 위해 사용하는 것이 @RequestMapping이다.
@RequestMapping에서 가장 많이사용하는 부분은 value와 method이다.
예시
@RequestMapping(method = RequestMetho.GET, value = "/api/v1/main")
method는 어떤 요청으로 받을지 정의하게 된다.(GET, POST, PUT, DELETE 등)
예시
@RestController
@RequestMapping("/api/v1/main")
public class HelloController {
@GetMapping("/hi")
public String helloGetHi(...) {
...
}
}
httpentity를 상속받는, 결과 데이터와 HTTP 상태 코드를 직접 제어할 수 있는 클래스이다.
ResponseEntity에는 사용자의 HttpRequest에 대한 응답 데이터가 포함된다.
에러 코드와 같은 HTTP상태 코드를 전송하고 싶은 데이터와 함께 전송할 수 있기 때문에 좀 더 세밀한 제어가 필요한 경우 사용한다고 합니다.
ResponseEntity는 HttpEntity를 상속받고 사용자의 응답 데이터가 포함된 클래스이기 때문에 HttpStatus, HttpHeaders, HttpBody를 포함한다.
ResponseEntity 클래스를 사용하면, 결과값! 상태코드! 헤더값!을 모두 프론트에 넘겨줄 수 있고, 에러코드 또한 섬세하게 설정해서 보내줄 수 있다는 장점이 있다!
참고자료
ResponseEntity에 대해
HttpEntity
HttpEntity클래스는 HTTP요청또는 응답에 해당하는 HttpHeader와 HttpBody를 포함하는 클래스다.
따라서 이 클래스는 다음과같은 생성자와 필드를 갖는다.public class HttpEntity<T> { public static final HttpEntity<?> EMPTY = new HttpEntity(); private final HttpHeaders headers; private final T body; ... }
HttpEntity 클래스를 상속받아 구현한 클래스가 RequestEntity, ResponseEntity 클래스이다.
상태코드에 따른 데이터를 보내기 위해 만들어준다.
package com.example.hr1.domain.temp;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api/v1/temp")
public class TempCotrollerApiV1 {
@GetMapping("/200")
public ResponseEntity<?> get200(){ // ?는 어떤 값이 들어가도 상관없음
return new ResponseEntity<>("성공", HttpStatus.OK); // body는 생략가능
}
}
결과값 안보낼꺼니까 논으로 해서 get방식으로 send한다.
400에러도 만들어준다.
@GetMapping("400")
public ResponseEntity<?> get400(){ // ?는 어떤 값이 들어가도 상관없음
return new ResponseEntity<>("잘못된 요청", HttpStatus.BAD_REQUEST); // body는 생략가능
}
실행하면 잘나온다.
다른 에러도 만들어 본다.
// 다른 것도 만들어보기
// 401
@GetMapping("401")
public ResponseEntity<?> get401() { // ?는 어떤 값이 들어가도 상관없음
return new ResponseEntity<>("권한 없음", HttpStatus.UNAUTHORIZED); // body는 생략가능
}
// 403
@GetMapping("403")
public ResponseEntity<?> get403() { // ?는 어떤 값이 들어가도 상관없음
return new ResponseEntity<>("금지됨", HttpStatus.FORBIDDEN); // body는 생략가능
}
// 404
@GetMapping("404")
public ResponseEntity<?> get404() { // ?는 어떤 값이 들어가도 상관없음
return new ResponseEntity<>("찾을 수 없음", HttpStatus.NOT_FOUND); // body는 생략가능
}
// 405
@GetMapping("405")
public ResponseEntity<?> get405() { // ?는 어떤 값이 들어가도 상관없음
return new ResponseEntity<>("허용되지 않은 메소드", HttpStatus.METHOD_NOT_ALLOWED); // body는 생략가능
}
// 500
@GetMapping("500")
public ResponseEntity<?> get500() { // ?는 어떤 값이 들어가도 상관없음
return new ResponseEntity<>("내부 서버 오류", HttpStatus.INTERNAL_SERVER_ERROR); // body는 생략가능
}
실행화면들이다.
Stateful : 이어져 있는 상태
Stateless : 이어져 있지 않는 상태
HTTP는 기본적으로 Stateful상태이다.
session은 서버에서 내 정보를 저장하는 공간
HTTP는 stateless인데 session을 사용해서 임시 stateful로 만드는 것이다.!
(저장되어 있는 거지 연결되어 있지는 않다!)
ex) 로그인
참고자료
위에 간단히 정리한 것 아래를 보면 자세히 설명되어 있음
Stateful과 Stateless의 대해
session을 이용하기 위해 만들어준다.
public ModelAndView mainPage(HttpServletRequest request){
HttpSession session = request.getSession();
session.setAttribute("name", "hong");
HttpServletRequest
- http프로토콜의 request정보를 서블릿에게 전달하기 위해 사용
- 헤더정보, 파라미터, 쿠키, URI, URL 등의 정보를 읽어 들이는 메소드 포함
- Body의 Stream을 읽어 들이는 메소드 포함
실행해서 콘솔창을 보면 hong이 들어간 것을 볼 수 있다.
f12를 눌려 cookies에 가면 session이 들어가 잇는 걸 볼 수 있다.
톰캣 컨테이너에서 세션을 유지하기 위해 발급하는 키.
HTTP 프로토콜은 stateless하다. 요청시마다 새로운 연결이 생성되고 응답후 연결은 끈히게 되므로 상태를 유지할 수 없다.
따라서 상태를 저장하기 위해서 톰캣은 JSESSIONID 쿠키를 클라이언트에게 발급해주고 이 값을 통해 세션을 유지할 수 있도록 한다.
1. 브라우저에 최초 접근 시 톰캣은 Response 헤더에 다음과 같이 JSESSIONID값이 발급된다.
- Set-Cookie :
2. 브라우저 재요청시 Response를 통해 받은 JSESSIONID를 Request 헤더의 쿠키에 값을 넣어 서버에 요청한다.
쿠키를 통해 JSESSIONID 값을 전달받게 되면 서버는 새로운 JSESSIONID 값을 Response 헤더에 발급받지 않는다.
3. 클라이언트로부터 전달받은 JSESSIONID값을 기준으로 서버에서는 세션 메모리 영역에 상태를 유지할 값들을 저장할 수 있게 된다.
(HttpSession 등)
참고자료
JSESSIONID
public ModelAndView updatePage(@PathVariable Integer regionsId, HttpServletRequest request){
HttpSession session = request.getSession();
System.out.println(session.getAttribute("name"));
적고 실행해서 f12눌려서 cookie를 보면 jsession이 발급되어있는 걸 볼 수 있다.
유저의 정보가 아닌 유저의 주소만 담겨져있는거
DBeaver에 들어가 테스트를 위해 기존의 있던 post와 user테이블을 삭제한다.
생성하기 위해 yml파일에 들어가서 아래의 코드를 넣어준다.
hibernate:
ddl-auto: create # create-drop, update, validate, none
실행하면 생성된다.
테이블에 컬럼을 만들어준다.
컬럼은 다 작성한 테이블에서 DDL을 클릭해 열서어 만들어진 쿼리문을 복사해온다.
(마찬가지로 post테이블도 같이 해준다.)
복사한 것을 여기에 다 넣어준다.
CREATE TABLE `user` (
`idx` int(11) NOT NULL AUTO_INCREMENT,
`id` varchar(255) NOT NULL,
`password` varchar(255) NOT NULL,
PRIMARY KEY (`idx`)
);
CREATE TABLE `post` (
`idx` int(11) NOT NULL AUTO_INCREMENT,
`user_idx` int(11) NOT NULL,
`content` varchar(255) NOT NULL,
`title` varchar(255) NOT NULL,
PRIMARY KEY (`idx`),
KEY `FK8fepup8sn6kmveiiffdcab7sc` (`user_idx`),
CONSTRAINT `FK8fepup8sn6kmveiiffdcab7sc` FOREIGN KEY (`user_idx`) REFERENCES `user` (`idx`)
);
파일구조
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "idx", nullable = false, unique = true)
private Integer idx;
@Column(name = "id", nullable = false)
private String id;
@Column(name = "password", nullable = false)
private String password;
@OneToMany(mappedBy = "userEntity")
private List<PostEntity> postEntityList;
@Override
public String toString() {
return "UserEntity [idx=" + idx + ", id=" + id + ", password=" + password + "]";
}
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY) //폴인키
@Column(name = "idx", nullable = false, unique = true)
private Integer idx;
@Column(name = "title", nullable = false)
private String title;
@Column(name = "content", nullable = false)
private String content;
@ManyToOne
@JoinColumn(name = "user_idx", referencedColumnName = "idx", nullable = false) // 폴인키
private UserEntity userEntity;
create를 none으로 변경해준다.
hibernate:
ddl-auto: none
경로를 설정해준다.
sql:
init:
encoding: UTF-8
schema-locations: classpath:sql/schema.sql # bin폴더 안에 main폴더
mode: always
넣어준다.
DROP TABLE IF EXISTS `post`;
DROP TABLE IF EXISTS `user`;
테이블에서 우클릭해 insert문을 가져온다.
위에서 가져온걸 조금 수정했다.
INSERT INTO site.`user`(idx, id, password)
VALUES(1, 'temp', '123'),
(2, 'sample', '123');
INSERT INTO post (idx, title, content, user_idx)
VALUES (1, '첫번째', '안녕하세요', 1),
(2, '두번째', '안녕하세요', 1),
(3, '세번째', '뉴비입니다', 2);
실행하면 이렇게 들어가는 것을 볼 수 있다.
ddl-auto를 create로 하고 엔티티 먼저 만들어서 테이블만들어지면 ddl-auto를 none으로 해야한다.
디비버에서 ddl수정해서 테이블 삭제 후 쿼리 날린다.
바꾸지 않고 create로 하게 되면 테스트시 데이터를 항상 같은 조건으로 두고 싶은데 데이터가 계속 쌓여서 직접 지운 뒤에 다시 테스트 해야한다.
sample 아이디 만들어서 테스트 했는데 db에서 삭제한 다음에 다시 만들어야 하는데 귀찮았다.
좋은 글 감사합니다. 자주 올게요 :)