Home

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 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 요청 메시지 - 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 요청 메시지 - 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 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"; }}

0

Spring Boot API 예시

목차 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 API 예시@RestController@RequestMapping("/mapping/users")public class MappingClassController { @GetMapping public String user(){ return "get users"; } @PostMapping public String addUser(){ return "post user"; } @GetMapping("/{userId}") public String findUser(@PathVariable String userId){ return "get suerId = " + userId; } @PatchMapping("/{userId}") public String updateUser(@PathVariable String userId){ return "update userId = " + userId; } @DeleteMapping("/{userId}") public String deleteUser(@PathVariable String userId){ return "delete userId = " + userId; }}

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 기본 헤더 조회Controller 사용 가능한 파리미터 목록 @Slf4j@RestControllerpublic class RequestHeaderController { @RequestMapping("/headers") public String headers(HttpServletRequest request, HttpServletResponse response, HttpMethod httpMethod, Locale locale, @RequestHeader MultiValueMap<String, String> headerMap, @RequestHeader("host") String host, @CookieValue(value = "myCookie", required = false) String cookie) { log.info("request={}", request); log.info("response={}", response); log.info("httpMethod={}", httpMethod); log.info("locale={}", locale); log.info("headerMap={}", headerMap); log.info("header host={}", host); log.info("myCookie={}", cookie); return "ok"; }}

0

Spring Boot 쿼리 파라미터, HTML Form

목차 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 쿼리 파라미터, 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> HttpServletRequest 객체 내 메소드 사용하기@Slf4j@RestControllerpublic class RequestParamController { @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"); }} RequestParam 어노테이션 사용하기@RequestMapping("/request-param-v2")@ResponseBodypublic String requestParamV2( @RequestParam("username") String memberName, @RequestParam("age") int memberAge) { log.info("username={}, age={}", memberName, memberAge); return "ok";} @RequestMapping("/request-param-v3")@ResponseBodypublic String requestParamV3( @RequestParam String username, @RequestParam int age) { log.info("username={}, age={}", username, age ); return "ok";} @RequestMapping("/request-param-v4")@ResponseBodypublic String requestParamV4(String username, int age) { log.info("username={}, age={}", username, age ); return "ok";}

0

Spring Security - AuthenticationProvider

목차 Spring Security 권한 계층 사용하기 - @RoleHierarcy Spring Security - DelegateFilterProxy Spring Security - Remember Me와 관련된 인증 API - RememberMeConfigurer Spring Security - RembmerMeAuthenticationFilter Spring Security - SessionManagementFilter & ConcurrentSessionFilter Spring Security - 인가 API ExpressionUrlAuthorizationConfigurer Spring Security - Security 설정을 위한 WebSecurityConfigurerAdatper Spring Security - AuthenticationProvider Spring Security - AuthenticationManager Spring Security - UsernamePasswordAuthenticationFilter & AbstractAuthenticationProcessingFilter Spring Security - SecurityContextHolder 와 SecurityContext Spring Security - Authentication 객체 참고 https://spring.io/guides/topicals/spring-security-architecture Spring Security - AuthenticationProviderAuthenticationProvider.java AuthenticationManager로 부터 인증을 위임받아 실제로 인증을 진행하는 객체, AuthenticationProvider의 구현체로는 AbstractUserDetailsAuthenticationProvider 와 DaoAuthenticationProvider 가 존재한다. AuthenticationProvider 의 인증 과정 전달받는 authentication 에서 username을 가져온 뒤 DB에서 해당 하는 유저 정보를 가져온다. 인증을 진행하기 전 DB로부터 가져온 UserDetails 객체에 대한 유효성 검사를 진행한다. 전달 받은 Authentication 객체내의 Credential 정보와 UserDetails 객체의 Password와 값이 일치하는지 확인한다. username에 대한하는 UserDetails 객체를 못 찾을 경우 UsernameNotFoundException 예외를 던지고 Credentials가 Password와 다를 경우 BadCredentialsException 예외를 던진다. 인증 후 다시한번 UserDetails 객체의 유효성 검사를 진행하고, 캐시에 UserDetails 객체를 저장한다. 새로운 Authentication 객체를 만들어 반환한다.

0

Spring Security - AuthenticationManager

목차 Spring Security 권한 계층 사용하기 - @RoleHierarcy Spring Security - DelegateFilterProxy Spring Security - Remember Me와 관련된 인증 API - RememberMeConfigurer Spring Security - RembmerMeAuthenticationFilter Spring Security - SessionManagementFilter & ConcurrentSessionFilter Spring Security - 인가 API ExpressionUrlAuthorizationConfigurer Spring Security - Security 설정을 위한 WebSecurityConfigurerAdatper Spring Security - AuthenticationProvider Spring Security - AuthenticationManager Spring Security - UsernamePasswordAuthenticationFilter & AbstractAuthenticationProcessingFilter Spring Security - SecurityContextHolder 와 SecurityContext Spring Security - Authentication 객체 참고 https://spring.io/guides/topicals/spring-security-architecture Spring Security - AuthenticationManager AuthenticationManager 는 인증을 진행하는 AuthenticationProvider 객체들을 관리하는 객체다. AuthenticationManager 는 AuthenticationProvider 에 인증을 위임하는 형태로 인증을 진행한다. public interface AuthenticationManager { Authentication authenticate(Authentication authentication) throws AuthenticationException;} ProviderManager AuthenticationManager의 가장 대표적인 구현체