Category: Spring

0

Spring Boot @RequestMapping

목차 Spring MVC - ArgumentResolver Spring MVC - HttpMessageConverter Spring Boot Http 응답 - HTTP API, Message Body에 직접 입력 Spring Boot 응답 - 정적 리소스, 뷰 템플릿 Spring Boot 요청 메시지 - JSON Spring Boot 요청 메시지 - Text Spring Boot 쿼리 파라미터, HTML Form Spring Boot 기본 헤더 조회 Spring Boot API 예시 Spring Boot @RequestMapping Spring Boot Logging Spring Boot @RequestMapping 사용자 요청 받기RequestMapping 어노테이션을 사용해 해당 URL로 들어오는 사용자 요청을 처리할 수 있다. 이때, method를 명시하지 않을 경우 GET, POST, PUT, PATCH, DELETE 모든 method를 사용해 접근이 가능하므로, 특정 method에서만 요청을 받고 싶을 경우 method를 명시해줘야 한다. @RequestMapping(value = "/hello-basic")public String helloBasic(){ log.info("helloBasic"); return "ok";} @RequestMapping(value = "/mapping-get-v1", method = RequestMethod.GET)public String mappingGetV1(){ log.info("helloBasic"); return "ok";} GetMapping 어노테이션 사용하기@GetMapping(value = "/mapping-get-v2")public String mappingGetV2(){ log.info("helloBasic"); return "ok";}

0

Spring MVC Request Life Cycle - ViewResolver

목차 Spring MVC - ArgumentResolver Spring MVC Request Life Cycle - ViewResolver Spring MVC Request Life Cycle - HandlerAdapter Spring MVC Request Life Cycle - HandlerMapping Spring MVC Request Life Cycle - DispatcherServlet Spring MVC Request Life Cycle - Interceptor Spring MVC Request Life Cycle - Filter Spring MVC Request Life Cycle - ViewResolver 핸들러 어뎁터 호출 ViewResolver 호출 spring.mvc.view.prefix=/WEB-INF/views/spring.mvc.view.suffix=.jsp ViewResolver.java public interface ViewResolver { @Nullable View resolveViewName(String viewName, Locale locale) throws Exception;} 스프링 부투에서는 InternalResourceViewResolver 를 등록할때 spring.mvc.view.prefix, spring.mvc.view.suffix 설정 정보를 갖고와 등록해준다. public InternalResourceViewResolver(String prefix, String suffix) { this(); setPrefix(prefix); setSuffix(suffix);}

0

Spring MVC Request Life Cycle - HandlerAdapter

목차 Spring MVC - ArgumentResolver Spring MVC Request Life Cycle - ViewResolver Spring MVC Request Life Cycle - HandlerAdapter Spring MVC Request Life Cycle - HandlerMapping Spring MVC Request Life Cycle - DispatcherServlet Spring MVC Request Life Cycle - Interceptor Spring MVC Request Life Cycle - Filter HandlerAdapter 살펴보기 HandlerAdapter 는 HandlerMapping 통해 찾은 Handler를 이용해 사용자 요청(Request)를 처리하는 역할을 한다. public interface HandlerAdapter { // supports 메소드를 통해 HandlerAdapter 가 인자로 받은 handler를 지원하는지 확인한다. 보통 Handler에는 HandlerAdapter를 갖는다. boolean supports(Object handler); // handler를 이용해 사용자 Request를 처리한다. @Nullable ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception; @Deprecated long getLastModified(HttpServletRequest request, Object handler);} HandlerAdapter 구현체 AbstractHandlerMethodAdapter RequestMappingHandlerAdapter HandlerAdapter 지원 여부 확인하기 supports 메소드를 이용해 HandlerAdapter가 전달받은 Handler를 지원하는지 확인한다.

0

Spring MVC Request Life Cycle - HandlerMapping

목차 Spring MVC - ArgumentResolver Spring MVC Request Life Cycle - ViewResolver Spring MVC Request Life Cycle - HandlerAdapter Spring MVC Request Life Cycle - HandlerMapping Spring MVC Request Life Cycle - DispatcherServlet Spring MVC Request Life Cycle - Interceptor Spring MVC Request Life Cycle - Filter Spring MVC Request Life Cycle - HandlerMapping RequestMapping 어노테이션을 처리하는 Handler, Handler Adapter는 RequestMappingHandlerMapping, RequestMappingHandlerAdapter다 HandlerMapping 살펴보기 Request(요청)와 Request를 처리하기 위한 Handler의 Mapping 정보를 관리한다. HttpServletRequest 객체 Attribute에서 Handler의 정보를 가져올 수 있다. BEST_MATCHING_HANDLER_ATTRIBUTE 요청 URL과 가장 많이 일치하는 Handler를 가져온다. PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE 요청을 처리하기 위한 Handler의 URL을 가져온다. BEST_MATCHING_PATTERN_ATTRIBUTE 요청 URL과 가장 많이 일치하는 Handler Pattern(URL)을 가져온다. INTROSPECT_TYPE_LEVEL_MAPPING URI_TEMPLATE_VARIABLES_ATTRIBUTE 요청 URL에 포함된 PathVariable 정보를 가져온다. MATRIX_VARIABLES_ATTRIBUTE 요청 URL에 포함된 MATRIX 변수 정보를 가져온다. Matrix 변수를 사용하기 위해서는 WebMvcConfigurer 를 이용해 설정해줘야 한다. 반환 값은 MultiValueMap 형태의 데이터다. PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE HttpServletRequest 객체내 Attribute에서 Handler가 반환하는 Media Type 정보를 가져온다.

0

Spring MVC Request Life Cycle - DispatcherServlet

목차 Spring MVC - ArgumentResolver Spring MVC Request Life Cycle - ViewResolver Spring MVC Request Life Cycle - HandlerAdapter Spring MVC Request Life Cycle - HandlerMapping Spring MVC Request Life Cycle - DispatcherServlet Spring MVC Request Life Cycle - Interceptor Spring MVC Request Life Cycle - Filter DispatcherServlet 이란 사용자의 요청을 제일 먼저 받는 Front Controller, 스프링 MVC는 Front Controller 패턴 으로 구현돼 있다.DispatcherServlet도 HttpServlet을 상속 받고 Servlet으로 동작한다. 스프링 부트는 DispatcherServlet을 Servlet으로 자동으로 등록하면서 모든 경로(urlpattern = “/“) 에 대해 매핑한다. 사용자로 부터 들어오는 모든 요청을 제일 먼저 받아 적절한 Handler(Controller) 를 찾아 호출한다. 모든 요청은 DispatcherServlet을 거치기 때문에 모든 요청에 공통적인 작업 이 가능한다. 요청 흐름 서블릿이 호출 되면 HttpServlet에서 제공하는 service 메소드가 호출된다. 스프링 MVC는 DispatcherServlet의 부모인 FrameworkServlet 에서 service를 오버라이드 했다. FrameworkServlet service를 시작으로 여러 메소드를 호출되면서 DispatcherServlet의 doDispatch 메소드가 호출된다. DispatcherServlet 동작 과정 살펴보기

0

Spring MVC - ArgumentResolver

목차 Spring MVC - ArgumentResolver Spring MVC - HttpMessageConverter Spring Boot Http 응답 - HTTP API, Message Body에 직접 입력 Spring Boot 응답 - 정적 리소스, 뷰 템플릿 Spring Boot 요청 메시지 - JSON Spring Boot 요청 메시지 - Text Spring Boot 쿼리 파라미터, HTML Form Spring Boot 기본 헤더 조회 Spring Boot API 예시 Spring Boot @RequestMapping Spring Boot Logging 참고 https://docs.spring.io/spring-framework/docs/current/reference/html/web.html#mvc-ann-%20arguments Spring Boot ArgumentResolver ArgumentResolver 를 통해 Spring 에서는 어노테이션 기반 Controller에 다양한 파라미터를 사용할 수 있다. 스프링에서 컨트롤러를 생성할 때 메소드 매게변수로 다양한 파라미터들을 넣을 수 있다. 메소드에 다양한 파라미터를 넣을 수 있도록 도움을 주는 게 바로 ArgumentResolver 다. HandlerMethodArgumentResolver.java HandlerMethodArgumentResolver 인터페이스를 구현함으로서 Controller 에서 넘어오는 Parameter 를 초기화 할 수 있다. supportsParameter 메소드를 통해 전달 받은 파라미터를 지원하는지 확인한 후 해당 파라미터를 지원하면 resolveArgument 를 통해 전달 받은 파리미터에 해당하는 객체를 생성한 후 Controller에 넘겨준다.

0

Spring Boot 응답 - 정적 리소스, 뷰 템플릿

목차 Spring MVC - ArgumentResolver Spring MVC - HttpMessageConverter Spring Boot Http 응답 - HTTP API, Message Body에 직접 입력 Spring Boot 응답 - 정적 리소스, 뷰 템플릿 Spring Boot 요청 메시지 - JSON Spring Boot 요청 메시지 - Text Spring Boot 쿼리 파라미터, HTML Form Spring Boot 기본 헤더 조회 Spring Boot API 예시 Spring Boot @RequestMapping Spring Boot Logging Spring Boot 응답 - 정적 리소스, 뷰 템플릿@RequestMapping("/response-view-v1")public ModelAndView responseViewV1(){ ModelAndView mav = new ModelAndView("response/hello") .addObject("data", "hello"); return mav;} String을 반환하는 경우뷰 리졸버를 통해 반환되는 문자열에 해당되는 뷰를 찾아 렌더링 해준다. @RequestMapping("/response-view-v2")public String responseViewV2(Model model){ model.addAttribute("data", "hello!"); return "response/hello";} void를 반환하는 경우@RequestMapping("/response/hello")public void responseViewV3(Model model){ model.addAttribute("data", "hello!");}

0

Spring Boot Http 응답 - HTTP API, Message Body에 직접 입력

목차 Spring MVC - ArgumentResolver Spring MVC - HttpMessageConverter Spring Boot Http 응답 - HTTP API, Message Body에 직접 입력 Spring Boot 응답 - 정적 리소스, 뷰 템플릿 Spring Boot 요청 메시지 - JSON Spring Boot 요청 메시지 - Text Spring Boot 쿼리 파라미터, HTML Form Spring Boot 기본 헤더 조회 Spring Boot API 예시 Spring Boot @RequestMapping Spring Boot Logging Spring Boot Http 응답 - HTTP API, Message Body에 직접 입력@GetMapping("/response-body-string-v1")public void responseBodyV1(HttpServletResponse response) throws IOException { response.getWriter().write("ok");} @GetMapping("/response-body-string-v2")public ResponseEntity<String> responseBodyV2(HttpServletResponse response) { return new ResponseEntity<>("ok", HttpStatus.OK);} @ResponseBody@GetMapping("/response-body-string-v3")public String responseBodyV3(HttpServletResponse response) { return "ok";} @GetMapping("/response-body-json-v1")public ResponseEntity<HelloData> responseBodyJsonV1() { HelloData helloData = new HelloData(); helloData.setUsername("userA"); helloData.setAge(20); return new ResponseEntity<>(helloData, HttpStatus.OK);} @ResponseBody@ResponseStatus(HttpStatus.OK)@GetMapping("/response-body-json-v1")public HelloData responseBodyJsonV2() { HelloData helloData = new HelloData(); helloData.setUsername("userA"); helloData.setAge(20); return helloData;}

0

Spring MVC - HttpMessageConverter

목차 Spring MVC - ArgumentResolver Spring MVC - HttpMessageConverter Spring Boot Http 응답 - HTTP API, Message Body에 직접 입력 Spring Boot 응답 - 정적 리소스, 뷰 템플릿 Spring Boot 요청 메시지 - JSON Spring Boot 요청 메시지 - Text Spring Boot 쿼리 파라미터, HTML Form Spring Boot 기본 헤더 조회 Spring Boot API 예시 Spring Boot @RequestMapping Spring Boot Logging Spring MVC - HttpMessageConverterHttpMessageConverter 는 HTTP 요청, 응답 둘다 사용된다. canRead, canWrite : 메시지 컨버터가 해당 클래스, 미디어 타입을 지원하는지 확인한다. read, write : 메시지 컨버터를 통해 메시지르 읽고 쓰는 기능 public interface HttpMessageConverter<T> { boolean canRead(Class<?> clazz, @Nullable MediaType mediaType); boolean canWrite(Class<?> clazz, @Nullable MediaType mediaType); List<MediaType> getSupportedMediaTypes(); default List<MediaType> getSupportedMediaTypes(Class<?> clazz) { return (canRead(clazz, null) || canWrite(clazz, null) ? getSupportedMediaTypes() : Collections.emptyList()); } T read(Class<? extends T> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException; void write(T t, @Nullable MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException;} 스프링 부트 기본 메시지 컨버터 ByteArrayHttpMessageConverter StringHttpMessageConverter MappingJackson2HttpMessageConverter 스프링 부트는 다양한 메시지 컨버터를 제공하는데, 대상 클래스 타입과 미디어 타입 둘을 체크해 사용여부를 결정한다. 만약 해당되지 않으면 다음 메시지 컨버터로 넘어간다. ByteArrayHttpMessageConverter

0

Spring Boot RequestMappingHandlerAdapter

목차 Spring MVC - ArgumentResolver Spring MVC - HttpMessageConverter Spring Boot Http 응답 - HTTP API, Message Body에 직접 입력 Spring Boot 응답 - 정적 리소스, 뷰 템플릿 Spring Boot 요청 메시지 - JSON Spring Boot 요청 메시지 - Text Spring Boot 쿼리 파라미터, HTML Form Spring Boot 기본 헤더 조회 Spring Boot API 예시 Spring Boot @RequestMapping Spring Boot Logging public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter implements BeanFactoryAware, InitializingBean { private static final boolean shouldIgnoreXml = SpringProperties.getFlag("spring.xml.ignore"); public static final MethodFilter INIT_BINDER_METHODS = (method) -> { return AnnotatedElementUtils.hasAnnotation(method, InitBinder.class); }; public static final MethodFilter MODEL_ATTRIBUTE_METHODS = (method) -> { return !AnnotatedElementUtils.hasAnnotation(method, RequestMapping.class) && AnnotatedElementUtils.hasAnnotation(method, ModelAttribute.class); }; @Nullable private List<HandlerMethodArgumentResolver> customArgumentResolvers; @Nullable private HandlerMethodArgumentResolverComposite argumentResolvers; @Nullable private HandlerMethodArgumentResolverComposite initBinderArgumentResolvers; @Nullable private List<HandlerMethodReturnValueHandler> customReturnValueHandlers; @Nullable private HandlerMethodReturnValueHandlerComposite returnValueHandlers; @Nullable private List<ModelAndViewResolver> modelAndViewResolvers; private ContentNegotiationManager contentNegotiationManager = new ContentNegotiationManager(); private List<HttpMessageConverter<?>> messageConverters = new ArrayList(4); private final List<Object> requestResponseBodyAdvice = new ArrayList(); @Nullable private WebBindingInitializer webBindingInitializer; private AsyncTaskExecutor taskExecutor = new SimpleAsyncTaskExecutor("MvcAsync"); @Nullable private Long asyncRequestTimeout; private CallableProcessingInterceptor[] callableInterceptors = new CallableProcessingInterceptor[0]; private DeferredResultProcessingInterceptor[] deferredResultInterceptors = new DeferredResultProcessingInterceptor[0]; private ReactiveAdapterRegistry reactiveAdapterRegistry = ReactiveAdapterRegistry.getSharedInstance(); private boolean ignoreDefaultModelOnRedirect = false; private int cacheSecondsForSessionAttributeHandlers = 0; private boolean synchronizeOnSession = false; private SessionAttributeStore sessionAttributeStore = new DefaultSessionAttributeStore(); private ParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer(); @Nullable private ConfigurableBeanFactory beanFactory; private final Map<Class<?>, SessionAttributesHandler> sessionAttributesHandlerCache = new ConcurrentHashMap(64); private final Map<Class<?>, Set<Method>> initBinderCache = new ConcurrentHashMap(64); private final Map<ControllerAdviceBean, Set<Method>> initBinderAdviceCache = new LinkedHashMap(); private final Map<Class<?>, Set<Method>> modelAttributeCache = new ConcurrentHashMap(64); private final Map<ControllerAdviceBean, Set<Method>> modelAttributeAdviceCache = new LinkedHashMap(); public RequestMappingHandlerAdapter() { this.messageConverters.add(new ByteArrayHttpMessageConverter()); this.messageConverters.add(new StringHttpMessageConverter()); if (!shouldIgnoreXml) { try { this.messageConverters.add(new SourceHttpMessageConverter()); } catch (Error var2) { } } this.messageConverters.add(new AllEncompassingFormHttpMessageConverter()); } public void setCustomArgumentResolvers(@Nullable List<HandlerMethodArgumentResolver> argumentResolvers) { this.customArgumentResolvers = argumentResolvers; } @Nullable public List<HandlerMethodArgumentResolver> getCustomArgumentResolvers() { return this.customArgumentResolvers; } public void setArgumentResolvers(@Nullable List<HandlerMethodArgumentResolver> argumentResolvers) { if (argumentResolvers == null) { this.argumentResolvers = null; } else { this.argumentResolvers = new HandlerMethodArgumentResolverComposite(); this.argumentResolvers.addResolvers(argumentResolvers); } } @Nullable public List<HandlerMethodArgumentResolver> getArgumentResolvers() { return this.argumentResolvers != null ? this.argumentResolvers.getResolvers() : null; } public void setInitBinderArgumentResolvers(@Nullable List<HandlerMethodArgumentResolver> argumentResolvers) { if (argumentResolvers == null) { this.initBinderArgumentResolvers = null; } else { this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite(); this.initBinderArgumentResolvers.addResolvers(argumentResolvers); } } @Nullable public List<HandlerMethodArgumentResolver> getInitBinderArgumentResolvers() { return this.initBinderArgumentResolvers != null ? this.initBinderArgumentResolvers.getResolvers() : null; } public void setCustomReturnValueHandlers(@Nullable List<HandlerMethodReturnValueHandler> returnValueHandlers) { this.customReturnValueHandlers = returnValueHandlers; } @Nullable public List<HandlerMethodReturnValueHandler> getCustomReturnValueHandlers() { return this.customReturnValueHandlers; } public void setReturnValueHandlers(@Nullable List<HandlerMethodReturnValueHandler> returnValueHandlers) { if (returnValueHandlers == null) { this.returnValueHandlers = null; } else { this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite(); this.returnValueHandlers.addHandlers(returnValueHandlers); } } @Nullable public List<HandlerMethodReturnValueHandler> getReturnValueHandlers() { return this.returnValueHandlers != null ? this.returnValueHandlers.getHandlers() : null; } public void setModelAndViewResolvers(@Nullable List<ModelAndViewResolver> modelAndViewResolvers) { this.modelAndViewResolvers = modelAndViewResolvers; } @Nullable public List<ModelAndViewResolver> getModelAndViewResolvers() { return this.modelAndViewResolvers; } public void setContentNegotiationManager(ContentNegotiationManager contentNegotiationManager) { this.contentNegotiationManager = contentNegotiationManager; } public void setMessageConverters(List<HttpMessageConverter<?>> messageConverters) { this.messageConverters = messageConverters; } public List<HttpMessageConverter<?>> getMessageConverters() { return this.messageConverters; } public void setRequestBodyAdvice(@Nullable List<RequestBodyAdvice> requestBodyAdvice) { if (requestBodyAdvice != null) { this.requestResponseBodyAdvice.addAll(requestBodyAdvice); } } public void setResponseBodyAdvice(@Nullable List<ResponseBodyAdvice<?>> responseBodyAdvice) { if (responseBodyAdvice != null) { this.requestResponseBodyAdvice.addAll(responseBodyAdvice); } } public void setWebBindingInitializer(@Nullable WebBindingInitializer webBindingInitializer) { this.webBindingInitializer = webBindingInitializer; } @Nullable public WebBindingInitializer getWebBindingInitializer() { return this.webBindingInitializer; } public void setTaskExecutor(AsyncTaskExecutor taskExecutor) { this.taskExecutor = taskExecutor; } public void setAsyncRequestTimeout(long timeout) { this.asyncRequestTimeout = timeout; } public void setCallableInterceptors(List<CallableProcessingInterceptor> interceptors) { this.callableInterceptors = (CallableProcessingInterceptor[])interceptors.toArray(new CallableProcessingInterceptor[0]); } public void setDeferredResultInterceptors(List<DeferredResultProcessingInterceptor> interceptors) { this.deferredResultInterceptors = (DeferredResultProcessingInterceptor[])interceptors.toArray(new DeferredResultProcessingInterceptor[0]); } public void setReactiveAdapterRegistry(ReactiveAdapterRegistry reactiveAdapterRegistry) { this.reactiveAdapterRegistry = reactiveAdapterRegistry; } public ReactiveAdapterRegistry getReactiveAdapterRegistry() { return this.reactiveAdapterRegistry; } public void setIgnoreDefaultModelOnRedirect(boolean ignoreDefaultModelOnRedirect) { this.ignoreDefaultModelOnRedirect = ignoreDefaultModelOnRedirect; } public void setSessionAttributeStore(SessionAttributeStore sessionAttributeStore) { this.sessionAttributeStore = sessionAttributeStore; } public void setCacheSecondsForSessionAttributeHandlers(int cacheSecondsForSessionAttributeHandlers) { this.cacheSecondsForSessionAttributeHandlers = cacheSecondsForSessionAttributeHandlers; } public void setSynchronizeOnSession(boolean synchronizeOnSession) { this.synchronizeOnSession = synchronizeOnSession; } public void setParameterNameDiscoverer(ParameterNameDiscoverer parameterNameDiscoverer) { this.parameterNameDiscoverer = parameterNameDiscoverer; } public void setBeanFactory(BeanFactory beanFactory) { if (beanFactory instanceof ConfigurableBeanFactory) { this.beanFactory = (ConfigurableBeanFactory)beanFactory; } } @Nullable protected ConfigurableBeanFactory getBeanFactory() { return this.beanFactory; } public void afterPropertiesSet() { this.initControllerAdviceCache(); List handlers; if (this.argumentResolvers == null) { handlers = this.getDefaultArgumentResolvers(); this.argumentResolvers = (new HandlerMethodArgumentResolverComposite()).addResolvers(handlers); } if (this.initBinderArgumentResolvers == null) { handlers = this.getDefaultInitBinderArgumentResolvers(); this.initBinderArgumentResolvers = (new HandlerMethodArgumentResolverComposite()).addResolvers(handlers); } if (this.returnValueHandlers == null) { handlers = this.getDefaultReturnValueHandlers(); this.returnValueHandlers = (new HandlerMethodReturnValueHandlerComposite()).addHandlers(handlers); } } private void initControllerAdviceCache() { if (this.getApplicationContext() != null) { List<ControllerAdviceBean> adviceBeans = ControllerAdviceBean.findAnnotatedBeans(this.getApplicationContext()); List<Object> requestResponseBodyAdviceBeans = new ArrayList(); Iterator var3 = adviceBeans.iterator(); while(var3.hasNext()) { ControllerAdviceBean adviceBean = (ControllerAdviceBean)var3.next(); Class<?> beanType = adviceBean.getBeanType(); if (beanType == null) { throw new IllegalStateException("Unresolvable type for ControllerAdviceBean: " + adviceBean); } Set<Method> attrMethods = MethodIntrospector.selectMethods(beanType, MODEL_ATTRIBUTE_METHODS); if (!attrMethods.isEmpty()) { this.modelAttributeAdviceCache.put(adviceBean, attrMethods); } Set<Method> binderMethods = MethodIntrospector.selectMethods(beanType, INIT_BINDER_METHODS); if (!binderMethods.isEmpty()) { this.initBinderAdviceCache.put(adviceBean, binderMethods); } if (RequestBodyAdvice.class.isAssignableFrom(beanType) || ResponseBodyAdvice.class.isAssignableFrom(beanType)) { requestResponseBodyAdviceBeans.add(adviceBean); } } if (!requestResponseBodyAdviceBeans.isEmpty()) { this.requestResponseBodyAdvice.addAll(0, requestResponseBodyAdviceBeans); } if (this.logger.isDebugEnabled()) { int modelSize = this.modelAttributeAdviceCache.size(); int binderSize = this.initBinderAdviceCache.size(); int reqCount = this.getBodyAdviceCount(RequestBodyAdvice.class); int resCount = this.getBodyAdviceCount(ResponseBodyAdvice.class); if (modelSize == 0 && binderSize == 0 && reqCount == 0 && resCount == 0) { this.logger.debug("ControllerAdvice beans: none"); } else { this.logger.debug("ControllerAdvice beans: " + modelSize + " @ModelAttribute, " + binderSize + " @InitBinder, " + reqCount + " RequestBodyAdvice, " + resCount + " ResponseBodyAdvice"); } } } } private int getBodyAdviceCount(Class<?> adviceType) { List<Object> advice = this.requestResponseBodyAdvice; return RequestBodyAdvice.class.isAssignableFrom(adviceType) ? RequestResponseBodyAdviceChain.getAdviceByType(advice, RequestBodyAdvice.class).size() : RequestResponseBodyAdviceChain.getAdviceByType(advice, ResponseBodyAdvice.class).size(); } private List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() { List<HandlerMethodArgumentResolver> resolvers = new ArrayList(30); resolvers.add(new RequestParamMethodArgumentResolver(this.getBeanFactory(), false)); resolvers.add(new RequestParamMapMethodArgumentResolver()); resolvers.add(new PathVariableMethodArgumentResolver()); resolvers.add(new PathVariableMapMethodArgumentResolver()); resolvers.add(new MatrixVariableMethodArgumentResolver()); resolvers.add(new MatrixVariableMapMethodArgumentResolver()); resolvers.add(new ServletModelAttributeMethodProcessor(false)); resolvers.add(new RequestResponseBodyMethodProcessor(this.getMessageConverters(), this.requestResponseBodyAdvice)); resolvers.add(new RequestPartMethodArgumentResolver(this.getMessageConverters(), this.requestResponseBodyAdvice)); resolvers.add(new RequestHeaderMethodArgumentResolver(this.getBeanFactory())); resolvers.add(new RequestHeaderMapMethodArgumentResolver()); resolvers.add(new ServletCookieValueMethodArgumentResolver(this.getBeanFactory())); resolvers.add(new ExpressionValueMethodArgumentResolver(this.getBeanFactory())); resolvers.add(new SessionAttributeMethodArgumentResolver()); resolvers.add(new RequestAttributeMethodArgumentResolver()); resolvers.add(new ServletRequestMethodArgumentResolver()); resolvers.add(new ServletResponseMethodArgumentResolver()); resolvers.add(new HttpEntityMethodProcessor(this.getMessageConverters(), this.requestResponseBodyAdvice)); resolvers.add(new RedirectAttributesMethodArgumentResolver()); resolvers.add(new ModelMethodProcessor()); resolvers.add(new MapMethodProcessor()); resolvers.add(new ErrorsMethodArgumentResolver()); resolvers.add(new SessionStatusMethodArgumentResolver()); resolvers.add(new UriComponentsBuilderMethodArgumentResolver()); if (KotlinDetector.isKotlinPresent()) { resolvers.add(new ContinuationHandlerMethodArgumentResolver()); } if (this.getCustomArgumentResolvers() != null) { resolvers.addAll(this.getCustomArgumentResolvers()); } resolvers.add(new PrincipalMethodArgumentResolver()); resolvers.add(new RequestParamMethodArgumentResolver(this.getBeanFactory(), true)); resolvers.add(new ServletModelAttributeMethodProcessor(true)); return resolvers; } private List<HandlerMethodArgumentResolver> getDefaultInitBinderArgumentResolvers() { List<HandlerMethodArgumentResolver> resolvers = new ArrayList(20); resolvers.add(new RequestParamMethodArgumentResolver(this.getBeanFactory(), false)); resolvers.add(new RequestParamMapMethodArgumentResolver()); resolvers.add(new PathVariableMethodArgumentResolver()); resolvers.add(new PathVariableMapMethodArgumentResolver()); resolvers.add(new MatrixVariableMethodArgumentResolver()); resolvers.add(new MatrixVariableMapMethodArgumentResolver()); resolvers.add(new ExpressionValueMethodArgumentResolver(this.getBeanFactory())); resolvers.add(new SessionAttributeMethodArgumentResolver()); resolvers.add(new RequestAttributeMethodArgumentResolver()); resolvers.add(new ServletRequestMethodArgumentResolver()); resolvers.add(new ServletResponseMethodArgumentResolver()); if (this.getCustomArgumentResolvers() != null) { resolvers.addAll(this.getCustomArgumentResolvers()); } resolvers.add(new PrincipalMethodArgumentResolver()); resolvers.add(new RequestParamMethodArgumentResolver(this.getBeanFactory(), true)); return resolvers; } private List<HandlerMethodReturnValueHandler> getDefaultReturnValueHandlers() { List<HandlerMethodReturnValueHandler> handlers = new ArrayList(20); handlers.add(new ModelAndViewMethodReturnValueHandler()); handlers.add(new ModelMethodProcessor()); handlers.add(new ViewMethodReturnValueHandler()); handlers.add(new ResponseBodyEmitterReturnValueHandler(this.getMessageConverters(), this.reactiveAdapterRegistry, this.taskExecutor, this.contentNegotiationManager)); handlers.add(new StreamingResponseBodyReturnValueHandler()); handlers.add(new HttpEntityMethodProcessor(this.getMessageConverters(), this.contentNegotiationManager, this.requestResponseBodyAdvice)); handlers.add(new HttpHeadersReturnValueHandler()); handlers.add(new CallableMethodReturnValueHandler()); handlers.add(new DeferredResultMethodReturnValueHandler()); handlers.add(new AsyncTaskMethodReturnValueHandler(this.beanFactory)); handlers.add(new ServletModelAttributeMethodProcessor(false)); handlers.add(new RequestResponseBodyMethodProcessor(this.getMessageConverters(), this.contentNegotiationManager, this.requestResponseBodyAdvice)); handlers.add(new ViewNameMethodReturnValueHandler()); handlers.add(new MapMethodProcessor()); if (this.getCustomReturnValueHandlers() != null) { handlers.addAll(this.getCustomReturnValueHandlers()); } if (!CollectionUtils.isEmpty(this.getModelAndViewResolvers())) { handlers.add(new ModelAndViewResolverMethodReturnValueHandler(this.getModelAndViewResolvers())); } else { handlers.add(new ServletModelAttributeMethodProcessor(true)); } return handlers; } protected boolean supportsInternal(HandlerMethod handlerMethod) { return true; } protected ModelAndView handleInternal(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception { this.checkRequest(request); ModelAndView mav; if (this.synchronizeOnSession) { HttpSession session = request.getSession(false); if (session != null) { Object mutex = WebUtils.getSessionMutex(session); synchronized(mutex) { mav = this.invokeHandlerMethod(request, response, handlerMethod); } } else { mav = this.invokeHandlerMethod(request, response, handlerMethod); } } else { mav = this.invokeHandlerMethod(request, response, handlerMethod); } if (!response.containsHeader("Cache-Control")) { if (this.getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) { this.applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers); } else { this.prepareResponse(response); } } return mav; } protected long getLastModifiedInternal(HttpServletRequest request, HandlerMethod handlerMethod) { return -1L; } private SessionAttributesHandler getSessionAttributesHandler(HandlerMethod handlerMethod) { return (SessionAttributesHandler)this.sessionAttributesHandlerCache.computeIfAbsent(handlerMethod.getBeanType(), (type) -> { return new SessionAttributesHandler(type, this.sessionAttributeStore); }); } @Nullable protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception { ServletWebRequest webRequest = new ServletWebRequest(request, response); Object result; try { WebDataBinderFactory binderFactory = this.getDataBinderFactory(handlerMethod); ModelFactory modelFactory = this.getModelFactory(handlerMethod, binderFactory); ServletInvocableHandlerMethod invocableMethod = this.createInvocableHandlerMethod(handlerMethod); if (this.argumentResolvers != null) { invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers); } if (this.returnValueHandlers != null) { invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers); } invocableMethod.setDataBinderFactory(binderFactory); invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer); ModelAndViewContainer mavContainer = new ModelAndViewContainer(); mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request)); modelFactory.initModel(webRequest, mavContainer, invocableMethod); mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect); AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response); asyncWebRequest.setTimeout(this.asyncRequestTimeout); WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); asyncManager.setTaskExecutor(this.taskExecutor); asyncManager.setAsyncWebRequest(asyncWebRequest); asyncManager.registerCallableInterceptors(this.callableInterceptors); asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors); if (asyncManager.hasConcurrentResult()) { result = asyncManager.getConcurrentResult(); mavContainer = (ModelAndViewContainer)asyncManager.getConcurrentResultContext()[0]; asyncManager.clearConcurrentResult(); LogFormatUtils.traceDebug(this.logger, (traceOn) -> { String formatted = LogFormatUtils.formatValue(result, !traceOn); return "Resume with async result [" + formatted + "]"; }); invocableMethod = invocableMethod.wrapConcurrentResult(result); } invocableMethod.invokeAndHandle(webRequest, mavContainer, new Object[0]); if (!asyncManager.isConcurrentHandlingStarted()) { ModelAndView var15 = this.getModelAndView(mavContainer, modelFactory, webRequest); return var15; } result = null; } finally { webRequest.requestCompleted(); } return (ModelAndView)result; } protected ServletInvocableHandlerMethod createInvocableHandlerMethod(HandlerMethod handlerMethod) { return new ServletInvocableHandlerMethod(handlerMethod); } private ModelFactory getModelFactory(HandlerMethod handlerMethod, WebDataBinderFactory binderFactory) { SessionAttributesHandler sessionAttrHandler = this.getSessionAttributesHandler(handlerMethod); Class<?> handlerType = handlerMethod.getBeanType(); Set<Method> methods = (Set)this.modelAttributeCache.get(handlerType); if (methods == null) { methods = MethodIntrospector.selectMethods(handlerType, MODEL_ATTRIBUTE_METHODS); this.modelAttributeCache.put(handlerType, methods); } List<InvocableHandlerMethod> attrMethods = new ArrayList(); this.modelAttributeAdviceCache.forEach((controllerAdviceBean, methodSet) -> { if (controllerAdviceBean.isApplicableToBeanType(handlerType)) { Object bean = controllerAdviceBean.resolveBean(); Iterator var7 = methodSet.iterator(); while(var7.hasNext()) { Method method = (Method)var7.next(); attrMethods.add(this.createModelAttributeMethod(binderFactory, bean, method)); } } }); Iterator var7 = methods.iterator(); while(var7.hasNext()) { Method method = (Method)var7.next(); Object bean = handlerMethod.getBean(); attrMethods.add(this.createModelAttributeMethod(binderFactory, bean, method)); } return new ModelFactory(attrMethods, binderFactory, sessionAttrHandler); } private InvocableHandlerMethod createModelAttributeMethod(WebDataBinderFactory factory, Object bean, Method method) { InvocableHandlerMethod attrMethod = new InvocableHandlerMethod(bean, method); if (this.argumentResolvers != null) { attrMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers); } attrMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer); attrMethod.setDataBinderFactory(factory); return attrMethod; } private WebDataBinderFactory getDataBinderFactory(HandlerMethod handlerMethod) throws Exception { Class<?> handlerType = handlerMethod.getBeanType(); Set<Method> methods = (Set)this.initBinderCache.get(handlerType); if (methods == null) { methods = MethodIntrospector.selectMethods(handlerType, INIT_BINDER_METHODS); this.initBinderCache.put(handlerType, methods); } List<InvocableHandlerMethod> initBinderMethods = new ArrayList(); this.initBinderAdviceCache.forEach((controllerAdviceBean, methodSet) -> { if (controllerAdviceBean.isApplicableToBeanType(handlerType)) { Object bean = controllerAdviceBean.resolveBean(); Iterator var6 = methodSet.iterator(); while(var6.hasNext()) { Method method = (Method)var6.next(); initBinderMethods.add(this.createInitBinderMethod(bean, method)); } } }); Iterator var5 = methods.iterator(); while(var5.hasNext()) { Method method = (Method)var5.next(); Object bean = handlerMethod.getBean(); initBinderMethods.add(this.createInitBinderMethod(bean, method)); } return this.createDataBinderFactory(initBinderMethods); } private InvocableHandlerMethod createInitBinderMethod(Object bean, Method method) { InvocableHandlerMethod binderMethod = new InvocableHandlerMethod(bean, method); if (this.initBinderArgumentResolvers != null) { binderMethod.setHandlerMethodArgumentResolvers(this.initBinderArgumentResolvers); } binderMethod.setDataBinderFactory(new DefaultDataBinderFactory(this.webBindingInitializer)); binderMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer); return binderMethod; } protected InitBinderDataBinderFactory createDataBinderFactory(List<InvocableHandlerMethod> binderMethods) throws Exception { return new ServletRequestDataBinderFactory(binderMethods, this.getWebBindingInitializer()); } @Nullable private ModelAndView getModelAndView(ModelAndViewContainer mavContainer, ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception { modelFactory.updateModel(webRequest, mavContainer); if (mavContainer.isRequestHandled()) { return null; } else { ModelMap model = mavContainer.getModel(); ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model, mavContainer.getStatus()); if (!mavContainer.isViewReference()) { mav.setView((View)mavContainer.getView()); } if (model instanceof RedirectAttributes) { Map<String, ?> flashAttributes = ((RedirectAttributes)model).getFlashAttributes(); HttpServletRequest request = (HttpServletRequest)webRequest.getNativeRequest(HttpServletRequest.class); if (request != null) { RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes); } } return mav; } }}

0

Spring Boot ReturnValueHandler

목차 Spring MVC - ArgumentResolver Spring MVC - HttpMessageConverter Spring Boot Http 응답 - HTTP API, Message Body에 직접 입력 Spring Boot 응답 - 정적 리소스, 뷰 템플릿 Spring Boot 요청 메시지 - JSON Spring Boot 요청 메시지 - Text Spring Boot 쿼리 파라미터, HTML Form Spring Boot 기본 헤더 조회 Spring Boot API 예시 Spring Boot @RequestMapping Spring Boot Logging Spring Boot ReturnValueHandlerpublic interface HandlerMethodReturnValueHandler { boolean supportsReturnType(MethodParameter returnType); void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception;}

0

Spring MVC Request Life Cycle - Filter

목차 Spring MVC - ArgumentResolver Spring MVC Request Life Cycle - ViewResolver Spring MVC Request Life Cycle - HandlerAdapter Spring MVC Request Life Cycle - HandlerMapping Spring MVC Request Life Cycle - DispatcherServlet Spring MVC Request Life Cycle - Interceptor Spring MVC Request Life Cycle - Filter Filter Filter는 Spring Context 이전에 실행되기 때문에 Spring자체와는 무관하며 Web Application에 등록이 된다. 요청이 DispatcherServlet에 도착하기 전에 처리를 하거나 요청이 끝나고 응답할 때 마지막으로 처리를 하는 역할을 한다. 주로 인코딩, 요청에 대한 인증, 권한 체크 와 같은 요청에 대한 전역적인 처리를 할 때 사용한다. Filter 인터페이스 init 필터 인스턴스 초기화 doFilter 실제 로직 처리(Filter Chain을 따라 다을 Filter로 움직인다.) destroy 필터 인스턴스 종료 public interface Filter { public default void init(FilterConfig filterConfig) throws ServletException {} public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException; public default void destroy() {}} Filter Chain Filter는 Client와 Servlet사이에 존재해 Client가 보내는 요청정보를 가공해 Servlet으로 보내고 Servelt이 보내는 응답정보를 가공해 Client에게 전달하는 역할을 한다. Filter는 일반적인 경우 1개가 존재하지만 여러개의 필터를 모아 Filter Chain을 형성할 수 있다.

0

Spring Boot 요청 메시지 - JSON

목차 Spring MVC - ArgumentResolver Spring MVC - HttpMessageConverter Spring Boot Http 응답 - HTTP API, Message Body에 직접 입력 Spring Boot 응답 - 정적 리소스, 뷰 템플릿 Spring Boot 요청 메시지 - JSON Spring Boot 요청 메시지 - Text Spring Boot 쿼리 파라미터, HTML Form Spring Boot 기본 헤더 조회 Spring Boot API 예시 Spring Boot @RequestMapping Spring Boot Logging Spring Boot 요청 메시지 - JSON@PostMapping("/request-body-json-v1")public void requestBodyJsonV1(HttpServletRequest request, HttpServletResponse response) throws IOException { ServletInputStream inputStream = request.getInputStream(); String messageBody = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8); log.info("messageBody={}", messageBody); HelloData helloData = objectMapper.readValue(messageBody, HelloData.class); log.info("username={}, age={}", helloData.getUsername(), helloData.getAge()); response.getWriter().write("ok");} RequestBody 어노테이션 사용하기RequestParam 어노테이션과 다르게 RequestBody 어노테이션은 생략하면 안된다. @ResponseBody@PostMapping("/request-body-json-v2")public String requestBodyJsonV2(@RequestBody String messageBody) throws IOException { log.info("messageBody={}", messageBody); HelloData helloData = objectMapper.readValue(messageBody, HelloData.class); log.info("username={}, age={}", helloData.getUsername(), helloData.getAge()); return "ok";} DTO 사용하기@ResponseBody@PostMapping("/request-body-json-v3")public String requestBodyJsonV3(@RequestBody HelloData helloData) throws IOException { log.info("username={}, age={}", helloData.getUsername(), helloData.getAge()); return "ok";} @ResponseBody@PostMapping("/request-body-json-v4")public String requestBodyJsonV4(HttpEntity<HelloData> data) throws IOException { HelloData body = data.getBody(); log.info("username={}, age={}", body.getUsername(), body.getAge()); return "ok";}

0

Spring Boot 요청 메시지 - Text

목차 Spring MVC - ArgumentResolver Spring MVC - HttpMessageConverter Spring Boot Http 응답 - HTTP API, Message Body에 직접 입력 Spring Boot 응답 - 정적 리소스, 뷰 템플릿 Spring Boot 요청 메시지 - JSON Spring Boot 요청 메시지 - Text Spring Boot 쿼리 파라미터, HTML Form Spring Boot 기본 헤더 조회 Spring Boot API 예시 Spring Boot @RequestMapping Spring Boot Logging Spring Boot 요청 메시지@PostMapping("/request-body-string-v1")public void requestBodyString(HttpServletRequest request, HttpServletResponse response) throws IOException { ServletInputStream inputStream = request.getInputStream(); String messageBody = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8); log.info("messageBody = {}", messageBody); response.getWriter().write("ok");} @PostMapping("/request-body-string-v2")public void requestBodyStringV2(InputStream inputStream, Writer responseWriter) throws IOException { String messageBody = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8); log.info("messageBody = {}", messageBody); responseWriter.write("ok");} HttpEntity 사용하기@PostMapping("/request-body-string-v3")public HttpEntity<String> requestBodyStringV3(HttpEntity<String> httpEntity) throws IOException { String messageBody = httpEntity.getBody(); log.info("messageBody = {}", messageBody); return new HttpEntity<>("ok");} RequestBody, ResponseBody 어노테이션 사용하기@ResponseBody@PostMapping("/request-body-string-v4")public String requestBodyStringV4(@RequestBody String messageBody) throws IOException { log.info("messageBody = {}", messageBody); return "ok";}

0

Spring Boot Logging

목차 Spring MVC - ArgumentResolver Spring MVC - HttpMessageConverter Spring Boot Http 응답 - HTTP API, Message Body에 직접 입력 Spring Boot 응답 - 정적 리소스, 뷰 템플릿 Spring Boot 요청 메시지 - JSON Spring Boot 요청 메시지 - Text Spring Boot 쿼리 파라미터, HTML Form Spring Boot 기본 헤더 조회 Spring Boot API 예시 Spring Boot @RequestMapping Spring Boot Logging Spring Boot Logging로그 선언 방법 private final Logger log = LoggerFactory.getLogger(getClass()); private static final Logger log = LoggerFactory.getLogger(xxx.class); @slf4j // Lombok에서 제공하는 Log 기능 사용 log.trace("info log = {}", name);log.debug("info log = {}", name);log.info("info log = {}", name);log.warn("info log = {}", name);log.error("info log = {}", name); logging.level.com.example.springmvc=trace @Slf4j@RestControllerpublic class LogTestController {// private final Logger log = LoggerFactory.getLogger(getClass()); @RequestMapping("/log-test") public String logTest(){ String name = "Spring"; System.out.println("name = " + name); log.trace("info log = {}", name); log.debug("info log = {}", name); log.info("info log = {}", name); log.warn("info log = {}", name); log.error("info log = {}", name); return "ok"; }}