@RequestParam
defaultValue: 사용자의 입력값이 없거나("") request의 parameter 키 값과 일치 않는 매개변수일 때 사용하고 싶은 값을 default값으로 설정 가능
name: request parameter의 키 값과 다른 매개변수 명을 사용하고 싶을 때 request parameter의 키 값을 작성(@Requestparam 어노테이션 생략 가능)
use
@PostMapping("modify")
public String modify(
Model model,
@RequestParam(defaultValue = "디폴트", name = "name") String name,
@RequestParam(defaultValue = "0") int modifyPrice
) {
String message = name + " has modified to " + modifyPrice;
System.out.println(modifyPrice);
model.addAttribute("message", message);
return "first/messagePrinter";
}
Command Object: 핸들러 메소드의 매개변수에 POJO 클래스를 스프링이 객체로 만들며 내부적으로 setter를 활용해 값도 주입해줌
@ModelAttribute 어노테이션에는 어트리뷰트 키 값을 지정 가능 (키 값이 없을 땐 타입을 활용 가능)
use
@PostMapping("search")
public String search(@ModelAttribute("menu") MenuDTO menu) {
System.out.println("menu = " + menu);
return "searchResult";
}
@PostMapping("login")
public String sessionLogin(HttpSession session, @RequestParam String id) {
session.setAttribute("id", id);
return "loginResult";
}
@GetMapping("logout")
public String logout(HttpSession session) {
session.invalidate();
return "login";
}
@Controller
@SessionAttributes("id")
public class FirstController {
...
@PostMapping("login")
public String sessionLogin(Model model, @RequestParam String id) {
model.addAttribute("id", id);
return "loginResult";
}
// 설명. @SessionAttribute 방식으로 session에 담긴 값은 SessionStatus 에서 제공하는 setComplete으로 만료시킨다.
@GetMapping("logout")
public String logout(SessionStatus sessionStatus) {
sessionStatus.setComplete();
return "loginResult";
}
}
@Controller
public class MainController {
@RequestMapping(value= {"/", "/main"})
public String main() {
return "main";
}
}
Model
ModelAndView
RedirectAttributes
flashAttribute
@GetMapping("string-redirect-attr")
public String stringRedirectionFlashAttribute(RedirectAttributes rttr) {
rttr.addFlashAttribute("flashMessage1", "리다이렉트 attr 사용하여 redirect...");
return "redirect:/";
}
@GetMapping("modelandview")
public ModelAndView modelAndViewTest(ModelAndView mv) {
mv.addObject("message2", "ModelAndView를 이용한 forward");
mv.setViewName("result");
return mv;
}
@GetMapping("modelandview-redirect")
public ModelAndView modelAndViewRedirectTest(ModelAndView mv) {
mv.addObject("message2", "ModelAndView를 이용한 redirect");
mv.setViewName("redirect:/");
return mv;
}
@GetMapping("modelandview-redirect-attr")
public ModelAndView modelAndViewRedirectFlashAttribute(ModelAndView mv, RedirectAttributes rttr) {
rttr.addFlashAttribute("flashMessage2", "ModelAndView를 이용한 redirect attribute");
mv.setViewName("redirect:/");
return mv;
}
@Configuration
public class RootConfiguration {
@Bean
public SimpleMappingExceptionResolver simpleMappingExceptionResolver() {
SimpleMappingExceptionResolver exceptionResolver = new SimpleMappingExceptionResolver();
Properties props = new Properties();
props.setProperty("java.lang.NullPointerException", "error/nullPointer");
exceptionResolver.setExceptionMappings(props);
exceptionResolver.setDefaultErrorView("error/default");
exceptionResolver.setExceptionAttribute("exceptionMessage");
return exceptionResolver;
}
}
@ExceptionHandler(NullPointerException.class)
public String nullPointerExceptionHandler() {
System.out.println("이 Controller에서 NullPointerException 발생 시 logging");
return "error/nullPointer";
}
handler method로 가기 전에 bean들에 대한 접근 가능하게 하는 도구
-> 따라서 특정 작업의 (handler method의) 전/후처리 가능
ex. 관리자는 controller를 진행하지 않고, service에 접근하는 등 여러 작업 가능 - db에서 권한 데이터를 먼저 가져오는 등
흐름이 어지럽혀지지 않는 범위 내에서 다양하게 활용 가능
use. 요청 시간 측정
// 설명. Interceptor 설정
@Configuration
public class StopwatchInterceptor implements HandlerInterceptor {
private final MenuService menuService;
@Autowired
public StopwatchInterceptor(MenuService menuService) {
this.menuService = menuService;
}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
menuService.method();
System.out.println("preHandle() 호출함...(핸들러 메소드 이전)");
long startTime = System.currentTimeMillis();
request.setAttribute("startTime", startTime);
// 설명. 반환형을 false로 하면 특정 조건에 의해 이후 핸들러 메소드가 실행되지 않게 할 수도 있다.
// return false;
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("PostHandler 호출함...(핸들러 메소드 이후)");
long startTime = (long) request.getAttribute("startTime");
long endTime = System.currentTimeMillis();
modelAndView.addObject("interval", (endTime - startTime));
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
}
}
// 설명. Interceptor 의존성 주입
// 설명. Interceptor 추가 및 static 리소스 호출 경로 등록 설정
@Configuration
public class WebConfiguration implements WebMvcConfigurer {
private StopwatchInterceptor stopwatchInterceptor;
@Autowired
public WebConfiguration(StopwatchInterceptor stopwatchInterceptor) {
this.stopwatchInterceptor = stopwatchInterceptor;
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(stopwatchInterceptor);
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/css/**")
.addResourceLocations("/classpath:/static/css/")
.setCachePeriod(50);
}
}
// 설명. 컨트롤러
@Controller
public class InterceptorTestController {
@GetMapping("stopwatch")
public String handlerMethod() throws InterruptedException {
System.out.println("핸들러 메소드 호출됨..");
Thread.sleep(1000);
return "result";
}
}
@Controller
public class FileUploadController {
private ResourceLoader resourceLoader;
@Autowired
public FileUploadController(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
}
@PostMapping("single-file")
public String singleFileUpload(
@RequestParam MultipartFile singleFile,
@RequestParam String singleFileDescription,
RedirectAttributes rttr
) throws IOException {
Resource resource = resourceLoader.getResource("classpath:static/uploadFiles/img/single");
String filePath = resource.getFile().getAbsolutePath();
String originalFileName = singleFile.getOriginalFilename();
String ext = originalFileName.substring(originalFileName.lastIndexOf("."));
String saveName = UUID.randomUUID().toString().replace("-", "") + ext;
try {
singleFile.transferTo(new File(filePath + "/" + saveName));
// BusinessLogic이 성공하면 redirect 된 페이지를 값을 넘기기 위해 RedirectAttributes로 담는다. (flashAttribute)
rttr.addFlashAttribute("message", "파일 업로드 성공!");
rttr.addFlashAttribute("img", "uploadFiles/img/single/" + saveName);
rttr.addFlashAttribute("singleFileDescription", singleFileDescription);
} catch (Exception e) {
e.printStackTrace();
new File(filePath + "/" + saveName).delete();
}
return "redirect:/result";
}
}
@Controller
public class FileUploadController {
private ResourceLoader resourceLoader;
@Autowired
public FileUploadController(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
}
@PostMapping("/multi-file")
public String multiFileUpload(@RequestParam List<MultipartFile> multiFiles
, @RequestParam String multiFileDescription
, RedirectAttributes rttr) throws IOException {
String filePath = resourceLoader.getResource("classpath:static/uploadFiles/img/multi")
.getFile()
.getAbsolutePath();
List<Map<String, String>> files = new ArrayList<>();
List<String> saveFiles = new ArrayList<>();
try {
for (int i = 0; i < multiFiles.size(); i++) {
String originFileName = multiFiles.get(i).getOriginalFilename();
String ext = originFileName.substring(originFileName.lastIndexOf("."));
String saveName = UUID.randomUUID().toString().replace("-", "") + ext;
Map<String, String> file = new HashMap<>();
file.put("originFileName", originFileName);
file.put("saveName", saveName);
file.put("filePath", filePath);
file.put("multiFileDescription", multiFileDescription);
files.add(file);
multiFiles.get(i).transferTo(new File(filePath + "/" + saveName));
saveFiles.add("uploadFiles/img/multi/" + saveName);
}
rttr.addFlashAttribute("message", "다중 파일 업로드 성공!");
rttr.addFlashAttribute("imgs", saveFiles);
rttr.addFlashAttribute("multiFileDescription", multiFileDescription);
} catch (Exception e) {
// 설명. 전체 파일 업로드가 아닌 일부 파일 업로드 시 올라간 파일 삭제
for(int i = 0; i < saveFiles.size(); i++) {
Map<String, String> file = files.get(i);
new File(filePath + "/" + file.get("saveName")).delete();
}
rttr.addFlashAttribute("message", "다중 파일 업로드 실패");
}
return "redirect:/result";
}
}