Spring注解⾯⾯通之@RequestPart参数绑定源码解析
  Spring MVC中使⽤HandlerMethodArgumentResolver策略接⼝来定义处理器⽅法参数解析器,@RequestPart使⽤的
是RequestPartMethodArgumentResolver,@RequestParam使⽤的是RequestParamMethodArgumentResolver,,接下来⼀起来深⼊了解⼀下其源码实现。
  类结构
  类解析
  HandlerMethodArgumentResolver和AbstractNamedValueMethodArgumentResolver是解析策略的上层定义和抽象,关于这两个类可以参照中的解析。
  RequestPartMethodArgumentResolver和RequestParamMethodArgumentResolver针对不同的注解,
RequestPartMethodArgumentResolver针对@RequestPart注释的⽅法参数,RequestParamMethodArgumentResolver针对@RequestParam注释的⽅法参数。
  1) RequestPartMethodArgumentResolver实现了HandlerMethodArgumentResolver的supportsParameter(...)和resolveArgument(...)⽅法。
  RequestHeaderMapMethodArgumentResolver,在某些条件成⽴的情况下才会使⽤此类进⾏解析:
  ① ⽅法参数由@RequestPart注解注释。
  ② ⽅法参数不可由@RequestParam注解注释。
  ③ ⽅法参数类型为org.springframework.web.multipart.MultipartFile、org.springframework.web.multipart.MultipartFile集
合、org.springframework.web.multipart.MultipartFile数组、javax.servlet.http.Part、javax.servlet.http.Part集合或javax.servlet.http.Part数组。package org.springframework.web.hod.annotation;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import MethodParameter;
import org.springframework.http.HttpInputMessage;
import org.verter.HttpMessageConverter;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.t.request.NativeWebRequest;
import org.hod.support.ModelAndViewContainer;
import org.springframework.web.multipart.MultipartException;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.support.MissingServletRequestPartException;
import org.springframework.web.multipart.support.MultipartResolutionDelegate;
import org.springframework.web.multipart.support.RequestPartServletServerHttpRequest;
/**
* 解析以下⽅法参数:
*  @RequestPart注释的参数.
*  类型为MultipartFile,结合Spring的MultipartResolver抽象.
*  类型javax.servlet.http.Part与Servlet 3.0多部分请求结合使⽤.
*
* 当⼀个参数⽤@RequestPart注释时,该部分的内容将通过HttpMessageConverter传递,
*  以便在记住请求部分的"Content-Type"的情况下解析⽅法参数.
* 这类似于RequestBody根据常规请求的内容解析参数.
*
* 如果参数未注释或未指定部件的名称,则从⽅法参数的名称派⽣.
*
*
* 如果参数⽤@javax.validation.Valid注释,则可以应⽤⾃动验证.
* 在验证失败的情况下,如果配置了org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver, *  则引发MethodArgumentNotValidException并返回400响应状态代码.
*/
public class RequestPartMethodArgumentResolver extends AbstractMessageConverterMethodArgumentResolver {
/**
* Constructor.
*/
public RequestPartMethodArgumentResolver(List<HttpMessageConverter<?>> messageConverters){
super(messageConverters);
}
/**
* Constructor.
*/
public RequestPartMethodArgumentResolver(List<HttpMessageConverter<?>> messageConverters,
List<Object> requestResponseBodyAdvice){
super(messageConverters, requestResponseBodyAdvice);
}
/**
* ⽅法参数检查.
*  @RequestPart注释的参数.
*  类型为MultipartFile,结合Spring的MultipartResolver抽象.
*  类型javax.servlet.http.Part与Servlet 3.0多部分请求结合使⽤.
springmvc的注解有哪些*/
@Override
public boolean supportsParameter(MethodParameter parameter){
if(parameter.hasParameterAnnotation(RequestPart.class)){
return true;
}
else{
if(parameter.hasParameterAnnotation(RequestParam.class)){
return false;
}
return MultipartResolutionDelegate.stedIfOptional());
}
}
/**
* 解析⽅法参数值.
*/
@Override
@Nullable
public Object resolveArgument(MethodParameter parameter,@Nullable ModelAndViewContainer mavContainer,
NativeWebRequest request,@Nullable WebDataBinderFactory binderFactory)throws Exception {
HttpServletRequest servletRequest = NativeRequest(HttpServletRequest.class);
Assert.state(servletRequest != null,"No HttpServletRequest");
// 获取⽅法参数@RequestPart注解.
RequestPart requestPart = ParameterAnnotation(RequestPart.class);
boolean isRequired =((requestPart == null || quired())&&!parameter.isOptional());
// 获取多部分名称.
String name =getPartName(parameter, requestPart);
parameter = stedIfOptional();
Object arg = null;
// 解析多部分参数值.
Object mpArg = solveMultipartArgument(name, parameter, servletRequest);
if(mpArg != MultipartResolutionDelegate.UNRESOLVABLE){
arg = mpArg;
}
else{
try{
// 从整体请求中解析多部分参数值.
// 从整体请求中解析多部分参数值.
HttpInputMessage inputMessage =new RequestPartServletServerHttpRequest(servletRequest, name);
arg =readWithMessageConverters(inputMessage, parameter, NestedGenericParameterType());
// 对WebDataBinder进⾏处理.
if(binderFactory != null){
WebDataBinder binder = ateBinder(request, arg, name);
if(arg != null){
validateIfApplicable(binder, parameter);
BindingResult().hasErrors()&&isBindExceptionRequired(binder, parameter)){
throw new MethodArgumentNotValidException(parameter, BindingResult());
}
}
if(mavContainer != null){
mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX + name, BindingResult());
}
}
}
catch(MissingServletRequestPartException | MultipartException ex){
if(isRequired){
throw ex;
}
}
}
// 处理required属性.
if(arg == null && isRequired){
if(!MultipartResolutionDelegate.isMultipartRequest(servletRequest)){
throw new MultipartException("Current request is not a multipart request");
}
else{
throw new MissingServletRequestPartException(name);
}
}
return adaptArgumentIfNecessary(arg, parameter);
}
/**
* 获取多部分名称.
*/
private String getPartName(MethodParameter methodParam,@Nullable RequestPart requestPart){
String partName =(requestPart != null ? requestPart.name():"");
if(partName.isEmpty()){
partName = ParameterName();
if(partName == null){
throw new IllegalArgumentException("Request part name for argument type ["+
"] not specified, and parameter name information not found in class file either.");
}
}
return partName;
}
}
  2) RequestParamMethodArgumentResolver继承⾃抽象AbstractNamedValueMethodArgumentResolver(可以参照)。
  RequestParamMethodArgumentResolver除了能处理@RequestPart注解外,还可以处理@RequestParam注解:
  当处理@RequestPart注解时,需在某些条件成⽴的情况下才会使⽤此类进⾏解析:
  ① ⽅法参数不可由@RequestPart注解注释。
  ② ⽅法参数类型为org.springframework.web.multipart.MultipartFile、org.springframework.web.multipart.MultipartFile集
合、org.springframework.web.multipart.MultipartFile数组、javax.servlet.http.Part、javax.servlet.http.Part集合或javax.servlet.http.Part数组。
  ③ ⼀个简单类型的⽅法参数,包
括:boolean、byte、char、short、int、long、float、double、Enum.class、CharSequence.class、Number.class、Date.class、URI. class、URL.class、Locale.class或Class.class。
  当处理@RequestParam注解时,需在某些条件成⽴的情况下才会使⽤此类进⾏解析:
  ① ⽅法参数由@RequestParam注解注释。
  ② ⽅法参数若是Map类型时,@RequestParam的name属性不能为空。
  ③ ⽅法参数若不是Map类型时,都可以处理。
package org.hod.annotation;
import java.beans.PropertyEditor;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.Part;
import org.springframework.beans.BeanUtils;
import org.springframework.fig.ConfigurableBeanFactory;
import MethodParameter;
import onvert.ConversionService;
import onvert.TypeDescriptor;
import verter.Converter;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.ValueConstants;
import org.t.request.NativeWebRequest;
import org.hod.support.UriComponentsContributor;
import org.springframework.web.multipart.MultipartException;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.multipart.MultipartResolver;
import org.springframework.web.multipart.support.MissingServletRequestPartException;
import org.springframework.web.multipart.support.MultipartResolutionDelegate;
import org.springframework.web.util.UriComponentsBuilder;
/**
* 解析⽤@RequestParam注释的⽅法参数,MultipartFile类型的参数与
*  Spring的{@link MultipartResolver}抽象结合使⽤,以及AAA类型的参数与Servlet 3.0多部分请求⼀起使⽤.
* 这个解析器也可以在默认的解析模式下创建,在这种模式下,没有⽤RequestParam注释的简单类型(int、long等)也被视为请求参数,参数名从参数名派⽣. *
* 如果⽅法参数类型是Map,则使⽤注释中指定的名称来解析请求参数字符串值.
* 然后通过类型转换将该值转换为Map,假设已经注册了合适的Converter或PropertyEditor.
* 或者,如果没有指定请求参数名,则使⽤RequestParamMapMethodArgumentResolver以映射的形式提供对所有请求参数的访问.
*
* 调⽤@WebDataBinder将类型转换应⽤于尚未与⽅法参数类型匹配的已解析请求头值.
*/
public class RequestParamMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver
implements UriComponentsContributor {
/**
* String 类型描述符.
*/
private static final TypeDescriptor STRING_TYPE_DESCRIPTOR = TypeDescriptor.valueOf(String.class);
private final boolean useDefaultResolution;
/**
/**
* @param useDefaultResolution 在默认解析模式下,⼀个简单类型的⽅法参数,
*  如BeanUtils.isSimpleProperty中定义的那样,被视为⼀个请求参数,
*  即使它没有被注释,请求参数名是从⽅法参数名派⽣的.
*/
public RequestParamMethodArgumentResolver(boolean useDefaultResolution){
this.useDefaultResolution = useDefaultResolution;
}
/**
* @param beanFactory ⼀个Bean⼯⼚,⽤于解析默认值中的${…}占位符和#{…}SpEL表达式,如果
默认值不包含表达式,则为null.  * @param useDefaultResolution 在默认解析模式下,⼀个简单类型的⽅法参数,
*  如BeanUtils.isSimpleProperty中定义的那样,被视为⼀个请求参数,
*  即使它没有被注释,请求参数名是从⽅法参数名派⽣的.
*/
public RequestParamMethodArgumentResolver(@Nullable ConfigurableBeanFactory beanFactory,
boolean useDefaultResolution){
super(beanFactory);
this.useDefaultResolution = useDefaultResolution;
}
/**
* ⽅法参数检查:
* ⽅法参数由@RequestParam注释,且@RequestParam的name属性为空.
* ⽅法参数类型为Map类型.
* ⽅法参数不可由@RequestPart注释.
*/
@Override
public boolean supportsParameter(MethodParameter parameter){
// 处理@RequestParam注解.
if(parameter.hasParameterAnnotation(RequestParam.class)){
if(Map.class.stedIfOptional().getNestedParameterType())){
RequestParam requestParam = ParameterAnnotation(RequestParam.class);
return(requestParam != null && StringUtils.hasText(requestParam.name()));
}
else{
return true;
}
}
// 处理@RequestPart注解.
else{
if(parameter.hasParameterAnnotation(RequestPart.class)){
return false;
}
parameter = stedIfOptional();
if(MultipartResolutionDelegate.isMultipartArgument(parameter)){
return true;
}
else if(this.useDefaultResolution){
return BeanUtils.NestedParameterType());
}
else{
return false;
}
}
}
/
**
* 创建NamedValueInfo.
*/
@Override
protected NamedValueInfo createNamedValueInfo(MethodParameter parameter){
RequestParam ann = ParameterAnnotation(RequestParam.class);
return(ann != null ?new RequestParamNamedValueInfo(ann):new RequestParamNamedValueInfo());
}

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。