핸들러 메소드 - 2 (스프링 MVC - 6)
1. @SessionAttributes
- 모델 정보를 HTTP 세션에 저장해주는 애노테이션
- 이 애노테이션에 설정한 이름에 해당하는 모델 정보를 자동으로 세션에 넣어준다.
- @ModelAttribute는 세션에 있는 데이터도 바인딩한다.
- 여러 화면에서 사용해야 하는 객체를 공유할 때 사용함
ex) 회원 가입을 여러 창에 나누어서 할 때
- SessionStatus를 사용해서 세션 처리 완료를 알려줄 수 있다. (폼 처리가 끝나고 세션을 비울 때 사용)
2. @SessionAttribute
- 해당 컨트롤러 안에서 동작하는 @SessionAttributes와는 다르게 쓰임
-> @SessionAttribute는 컨트롤러 밖 (인터셉터 또는 필터 등)에서 만들어 준 세션 데이터에 접근할 때 사용함
- HTTP 세션에 들어있는 값 참조할 때 사용
세션을 사용해서 여러 폼에 걸쳐 데이터를 나눠 입력 받고 저장하기 (@SessionAttributes)
- 이벤트 이름 입력 -> 이벤트 아이디 입력 -> 이벤트 목록
사용자 최초 접근 시간을 핸들러 인터셉터로 구현하기 (@SessionAttribute)
1) 컨트롤러 작성
@Controller
@SessionAttributes("event")
public class SampleController {
private List<Event> eventList = new ArrayList<>();
@GetMapping("/events/form/name")
public String eventsFormName(Model model) {
model.addAttribute("event", new Event());
return "/events/form-name";
}
@PostMapping("/events/form/name")
public String eventsFromNameSumit(@Valid @ModelAttribute Event event,
BindingResult bindingResult) {
if(bindingResult.hasErrors()){
return "events/form-name";
}
return "redirect:/events/form/id";
}
@GetMapping("/events/form/id")
public String eventsFormId(@ModelAttribute Event event,
Model model) {
model.addAttribute(event);
return "/events/form-id";
}
@PostMapping("/events/form/id")
public String eventFormIdSubmit(@Valid @ModelAttribute Event event,
BindingResult bindingResult,
SessionStatus sessionStatus) {
if(bindingResult.hasErrors()){
return "/events/form-id";
}
// Store to Database
eventList.add(event);
sessionStatus.setComplete();
return "redirect:/events/list";
}
@GetMapping("/events/list")
public String showEvents(Model model, @SessionAttribute LocalDateTime visitTime) {
System.out.println(visitTime);
// Select from database
model.addAttribute(eventList);
return "/events/list";
}
}
2) 핸들러 인터셉터 작성 및 등록(등록은 생략)
public class VisitTimeInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
final HttpSession session = request.getSession();
if(session.getAttribute("visitTime") == null) {
session.setAttribute("visitTime", LocalDateTime.now());
}
return true;
}
}
3. RedirectAttributes
- 리다이렉트 할 때 기본적으로 Model에 들어있는 primitive type 데이터는 URI 쿼리 매개변수에 추가된다.
스프링 부트에서는 이 기능이 기본적으로 비활성화 되어 있다. (프로퍼티 추가하여 활성화)
- 원하는 값만 리다이렉트 할 때 전달하고 싶다면 RedirectAttributes에 명시적으로 추가 가능
- 리다이렉트 요청을 처리하는 곳에서 @RequestParam, @ModelAttribute (세션 사용 시 이름 같으면 안됨)로 받을 수 있음
- Event와 같은 객체 전달 불가능
4. Flash Attributes
- 주로 리다이렉트시에 데이터를 전달할 때 사용한다.
- 데이터가 URI에 노출되지 않는다
- 임의의 객체를 저장할 수 있다.
리다이렉트 하기 전에 데이터를 HTTP 세션에 저장하고 리다이렉트 요청을 처리 한 다음 그 즉시 제거한다.
redirectAttributes.addFlashAttribute(event);
리다이렉트를 받는 핸들러는 Model로 위의 객체를 받을 수 있음.
5. MultipartFile
- 파일 업로드 시 사용하는 메소드 아규먼트
- MultipartResolver 빈이 설정 되어 있어야 사용할 수 있다 (스프링 부트 자동 설정이 해줌)
- POST multipart/form-data 요청에 들어있는 파일 참조 가능
- List<MultipartFile> 아규먼트로 여러 파일을 참조할 수 있다.
1) 업로드 및 업로드 확인 페이지 작성
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8"></meta>
<title>Title</title>
</head>
<body>
<div th:if="${message}">
<h2 th:text="${message}">msg</h2>
</div>
<form method="POST" enctype="multipart/form-data" action="#" th:action="@{/file}">
<input type="file" name="file"></input>
<input type="submit" value="UPLOAD"></input>
</form>
</body>
</html>
2) FileController 작성
@Controller
public class FileController {
@GetMapping("/file")
public String fileForm(Model model) {
return "/files/index";
}
@PostMapping("/file")
public String fileUpload(@RequestParam MultipartFile file,
RedirectAttributes redirectAttributes) {
/*
save
local, cloud..에 저장
*/
String message = file.getOriginalFilename() + " is Uploaded";
redirectAttributes.addFlashAttribute("message", message);
return "redirect:/file";
}
}
6. 파일 다운로드
파일 리소스 읽어오는 방법
- 스프링 ResourceLoader 사용하기
파일의 종류(미디어 타입) 알아내는 방법
- 티카 의존성 추가 후 사용
ResponseEntity
- 응답 상태 코드
- 응답 헤더
- 응답 본문
@Controller
public class FileController {
@Autowired
ResourceLoader resourceLoader;
@GetMapping("/file/{filename}")
public ResponseEntity<Resource> fileDownload(@PathVariable String filename) throws IOException {
Resource resource = resourceLoader.getResource("classpath:" + filename);
File file = resource.getFile();
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION,
"attachment; filename=\"" + resource.getFilename() + "\"")
.header(HttpHeaders.CONTENT_TYPE, "text/plain")
.header(HttpHeaders.CONTENT_LENGTH, file.length() + "")
.body(resource);
}
}
7. @RequestBody & HttpEntity
@ReqeustBody
- 요청 본문(body)에 들어있는 데이터를 HttpMessageConverter를 통해 변환한 객체로 받아올 수 있음
- @Valid, @Validated 사용해서 검증 할 수 있음
- BindingResult 사용 가능 (바인딩 예외 발생 시 예외를 발생시키지 않고, 코드로 처리할 수 있음)
HttpEntity
- @RequestBody와 비슷하지만 추가적으로 요청 헤더 정보를 사용할 수 있다.
8. @ResponseBody & ResponseEntity
@ResponseBody
- 데이터를 HttpMessageConverter를 사용해 응답 본문 메시지로 보낼 때 사용함
- @RestController 사용 시 자동으로 모든 핸들러 메소드에 적용됨
ResponseEntity
- 응답 헤더 상태 코드 본문을 직접 다루고 싶은 경우에 사용함
-@JsonView, PushBuilder는 따로 공부할 것!
인프런 백기선님 '스프링 MVC’ 강의를 듣고 정리한 내용입니다.