로깅 (Logging)
운영 시스템에서는 System.out.println() 보다는 별도의 로깅 라이브러리를 사용해 로그를 출력한다.
로그 선언 방법 (3가지)
private Logger log = LoggerFactory.getLogger(getClass());
private static final Logger log = LoggerFactory.getLogger(Xxx.class)
@Slf4j //Lombok 사용
로그 호출 방법
log.info("hello")
log.info("info log={}", name);
로그 사용시 장점
- 쓰레드 정보, 클래스 이름 같은 부가 정보를 함께 볼 수 있고, 출력 모양을 조정할 수 있다.
- 로그 레벨에 따라 개발 서버에서는 모든 로그를 출력하고, 운영서버에서는 출력하지 않는 등 로그를 상황에 맞게 조절할 수 있다.
- 시스템 아웃 콘솔에만 출력하는 것이 아니라, 파일이나 네트워크 등 로그를 별도의 위치에 남길 수 있다.
* 특히 파일로 남길 때는 일별, 특정 용량에 따라 로그를 분할하는 것도 가능하다.
- 성능도 일반 System.out보다 좋다. (내부 버퍼링, 멀티 쓰레드 등) / 실무에서는 꼭 로그를 사용해야 한다.
요청 매핑 (RequestMapping)
package hello.springmvc.basic.requestmapping;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.*;
@RestController
public class MappingController {
private Logger log = LoggerFactory.getLogger(getClass());
/**
* 기본 요청
* 둘다 허용 /hello-basic, /hello-basic/
* HTTP 메서드 모두 허용 GET, HEAD, POST, PUT, PATCH, DELETE
*/
@RequestMapping("/hello-basic")
public String helloBasic() {
log.info("helloBasic");
return "ok";
}
}
@RestController
- @Controller는 반환 값이 String이면 뷰 이름으로 인식한다. 따라서 뷰를 찾고 뷰가 랜더링 된다.
- @RestController는 반환 값으로 뷰를 찾는 것이 아니라, HTTP 메시지 바디에 바로 입력한다.
☞ 따라서 실행 결과 'ok' 메시지를 받을 수 있다.
@RequestMapping("/hello-basic")
- /hello-basic URL 호출이 오면 이 메서드가 실행되도록 매핑한다.
- 대부분의 속성을 배열[]로 제공하므로 다중 설정이 가능하다. ex) {"/hello-basic", "/hello-go"}
HTTP 메서드
- @RequestMapping에 method 속성으로 HTTP 메서드를 지정하지 않으면 HTTP 메서드와 무관하게 호출된다.
- GET, HEAD, POST, PUT, PATCH, DELETE 모두 허용
/**
* method 특정 HTTP 메서드 요청만 허용
* GET, HEAD, POST, PUT, PATCH, DELETE
*/
@RequestMapping(value = "/mapping-get-v1", method = RequestMethod.GET)
public String mappingGetV1() {
log.info("mappingGetV1");
return "ok";
}
HTTP 메서드 매핑 축약 (@GetMapping을 이용한 모습)
/**
* 편리한 축약 애노테이션 (코드보기) * @GetMapping
* @PostMapping
* @PutMapping
* @DeleteMapping
* @PatchMapping
*/
@GetMapping(value = "/mapping-get-v2")
public String mappingGetV2() {
log.info("mapping-get-v2");
return "ok";
}
PathVariable(경로 변수) 사용
/**
* PathVariable 사용
* 변수명이 같으면 생략 가능
* @PathVariable("userId") String userId -> @PathVariable userId
*/
@GetMapping("/mapping/{userId}")
public String mappingPath(@PathVariable("userId") String data) {
log.info("mappingPath userId={}", data);
return "ok";
}
요청 매핑 - API 예시
ex) 회원 관리를 HTTP API로 만든다 생각하고 매핑
- 회원 목록 조회: GET /users
- 회원 등록: POST /users
- 회원 조회: GET /users/{userId}
- 회원 수정: PATCH /users/{userId}
- 회원 삭제: DELETE /users/{userId}
package hello.springmvc.basic.requestmapping;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/mapping/users")
public class MappingClassController {
/**
* GET /mapping/users
*/
@GetMapping
public String users() {
return "get users";
}
/**
* POST /mapping/users
*/
@PostMapping
public String addUser() {
return "post user";
}
/**
* GET /mapping/users/{userId}
*/
@GetMapping("/{userId}")
public String findUser(@PathVariable String userId) {
return "get userId=" + userId;
}
/**
* PATCH /mapping/users/{userId}
*/
@PatchMapping("/{userId}")
public String updateUser(@PathVariable String userId) {
return "update userId=" + userId;
}
/**
* DELETE /mapping/users/{userId}
*/
@DeleteMapping("/{userId}")
public String deleteUser(@PathVariable String userId) {
return "delete userId=" + userId;
}
}
HTTP 요청 파라미터 - 쿼리 파라미터, HTML Form
클라이언트에서 서버로 요청 데이터를 전달할 때 사용하는 방법
GET 쿼리 파라미터
- /url?username=hello&age=20
- 메시지 바디 없이, URL의 쿼리 파라미터에 데이터를 포함해서 전달
- ex) 검색, 필터, 페이징 등에서 많이 사용하는 방식
package hello.springmvc.basic.request;
import hello.springmvc.basic.HelloData;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Map;
@Slf4j
@Controller
public class RequestParamController {
/**
* 반환 타입이 없으면서 이렇게 응답에 값을 직접 집어넣으면, view 조회X
*/
@RequestMapping("/request-param-v1")
public void requestParamV1(HttpServletRequest request, HttpServletResponse response) throws IOException {
String username = request.getParameter("username");
int age = Integer.parseInt(request.getParameter("age"));
log.info("username={}, age={}", username, age);
response.getWriter().write("ok");
}
}
request.getParameter()를 이용하여 요청 파라미터 조회
POST - HTML Form
- content-type: application/x-www-form-urlencoded
- 메시지 바디에 쿼리 파라미터 형식으로 전달 username=hello&age=20
- ex) 회원 가입, 상품 주문, HTML Form 사용
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/request-param-v1" method="post">
username: <input type="text" name="username" />
age: <input type="text" name="age" /> <button type="submit">전송</button>
</form>
</body>
</html>
HTTP message body에 데이터를 직접 담아서 요청
- HTTP API에서 주로 사용 JSON, XML, TEXT
- 데이터 형식은 주로 JSON 사용
- POST, PUT, PATCH
/**
* @RequestParam 사용
* - 파라미터 이름으로 바인딩
* @ResponseBody 추가
* - View 조회를 무시하고, HTTP message body에 직접 해당 내용 입력 */
@ResponseBody
@RequestMapping("/request-param-v2")
public String requestParamV2(@RequestParam("username") String memberName, @RequestParam("age") int memberAge) {
log.info("username={}, age={}", memberName, memberAge);
return "ok";
}
- @RequestParam: 파라미터 이름으로 바인딩
- @ResponseBody: View 조회를 무시하고, HTTP message body에 직접 해당 내용 입력
@RequestParam("username") String memberName = request.getParameter("username)
- String, int, Integer 등의 단순 타입이라면 @RequestParam 생략 가능 (웬만하면 그냥 작성하는 편이 나음)
HTTP 요청 파라미터 - @ModelAttribute
/**
* @ModelAttribute 사용
*/
@ResponseBody
@RequestMapping("/model-attribute-v1")
public String modelAttributeV1(@ModelAttribute HelloData helloData) {
log.info("username={}, age={}", helloData.getUsername(),
helloData.getAge());
return "ok";
}
- HelloData 객체를 생성한다.
- 요청 파라미터의 이름으로 HelloData 객체의 프로퍼티를 찾고, 해당 프로퍼티의 setter를 호출해서 파라미터의 값을 입력(바인딩)한다.
* 프로퍼티: 객체에 getUsername(), setUsername() 메서드가 있으면, 이 객체는 username이라는 프로퍼티를 가지고 있다.
HTTP 요청 메시지 - 단순 텍스트 / JSON
HTTP message body에 데이터를 직접 담아서 요청
- HTTP API에서 주로 사용 JSON, XML, TEXT
- 데이터 형식은 주로 JSON 사용
- POST, PUT, PATCH
스프링 MVC가 지원하는 파라미터
- HttpEntity: HTTP header, body 정보를 편리하게 조회
1. 메시지 바디를 직접 조회
2. 요청 파라미터를 조회하는 기능과 관계 없음 @RequestParam X, @ModelAttribute X
- HttpEntity는 응답에도 사용 가능
1. 메시지 바디 정보 직접 반환
2. 헤더 정보 포함 가능
3. view 조회 X
HTTP 응답 - 정적 리소스, 뷰 템플릿
정적 리소스: 웹 브라우저에 정적인 HTML, css, js를 제공할 때 사용한다
- 정적 리소스 경로: src/main/resources/static
- src/main/resources/static/basic/hello-form.html 이라는 파일이 들어있을 경우
→ localhost:8080/basic/hello-form.html
- 정적 리소스는 해당 파일을 변경 없이 그대로 서비스 하는 것이다.
뷰 템플릿 사용: 웹 브라우저에 동적인 HTML을 제공할 때 사용한다.
- 뷰 템플릿 경로: src/main/resources/templates
<src/main/resources/templates/response/hello.html 생성>
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<p th:text="${data}">empty</p>
</body>
</html>
<뷰 템플릿을 호출하는 컨트롤러>
package hello.springmvc.basic.response;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
@Controller
public class ResponseViewController {
@RequestMapping("/response-view-v1")
public ModelAndView responseViewV1() {
ModelAndView mav = new ModelAndView("response/hello").addObject("data", "hello!");
return mav;
}
@RequestMapping("/response-view-v2")
public String responseViewV2(Model model) {
model.addAttribute("data", "hello!!");
return "response/hello";
}
@RequestMapping("/response/hello")
public void responseViewV3(Model model) {
model.addAttribute("data", "hello!!");
}
}
- String을 반환하는 경우 - View or HTTP 메시지
1. @ResponseBody가 없으면 response/hello로 뷰 리졸버가 실행되어 뷰를 찾고, 렌더링 한다.
2. @ResponseBody가 있으면 뷰 리졸버를 실행하지 않고, HTTP 메시지 바디에 직접 문자가 입력된다.
- Void를 반환하는 경우
@Controller를 사용하고 HttpServletResponse, OutputStream(Writer) 같은 HTTP 메시지 바디를 처리하는 파라미터가 없으면 요청 URL을 참고해서 논리 뷰 이름으로 사용
- HTTP 메시지 사용
HTTP API를 제공하는 경우 HTML이 아닌 데이터를 전달해야 하므로, HTTP 메시지 바디에 JSON 같은 형식으로 데이터를 실어 보낸다.
'Spring Study > MVC 패턴' 카테고리의 다른 글
[MVC 패턴] 타임리프 (Thymeleaf) - 스프링 통합과 폼 (0) | 2023.08.18 |
---|---|
[MVC 패턴] 타임리프 (Thymeleaf) (0) | 2023.08.16 |
[MVC 패턴] MVC 구조 (0) | 2023.08.14 |
[MVC 패턴] MVC 프레임워크 만들기 (0) | 2023.08.12 |
[MVC 패턴] JSP / MVC 패턴 (0) | 2023.08.09 |
댓글