Spring mvc获取请求参数以及返回执行结果是由RequestMappingHandlerAdapter类处理的,该类的customArgumentResolvers和customReturnValueHandlers是请求参数和返回结果参数的自定义处理扩展点。本篇文章将带大家由浅入深来介绍自定义数据处理的实现方法。
1. 理解RequestMappingHandlerAdapter的初始化
Spring boot使用WebMvcAutoConfiguration.EnableWebMvcConfiguration类自动配置方式对HandlerAdapter进行实例化Bean。初始化代码如下:
@Bean
@Override
public RequestMappingHandlerAdapter requestMappingHandlerAdapter() {
RequestMappingHandlerAdapter adapter = super.requestMappingHandlerAdapter();
adapter.setIgnoreDefaultModelOnRedirect(
this.mvcProperties == null || this.mvcProperties.isIgnoreDefaultModelOnRedirect());
return adapter;
}
EnableWebMvcConfiguration类图如下
image.png
执行流程图如下
image.png
2. 自定义数据处理
自定义请求参数的步骤包括:
1 )自定义注解@JoeParam
2 ) 实现HandlerMethodArgumentResolver接口
3 ) 定义一个Config类且实现WebMvcConfigurer接口,并用@Configuration标注在类上。
下面提一下具体实现代码,自定义注解源码
package com.joe.code.common.annotations;
import java.lang.annotation.*;
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface JoeParam {
String name();
boolean required() default false;
}
在控制器上增加注解
@GetMapping("/list")
public ResultObject<List<SysProjectRsp>> selectListByPage(@JoeParam(name = "page") Integer page,
@JoeParam(name="limit") Integer limit,
@JoeParam(name="sysName1") String sysName){
Page page1 = new Page<>(page, limit);
List<SysProjectRsp> list = sysProjectService.getBaseMapper().selectByPage(page1, sysName);
return ResultStatusEnum.SUCCESS.ok(list, page1.getTotal());
}
1.1 定义加载
package com.joe.code.common.configuration;
import com.joe.code.common.component.TestResolver;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.List;
// 注册resolver
@Configuration
public class WebConfiguration implements WebMvcConfigurer {
@Autowired
private ApplicationContext context;
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
resolvers.add(new TestResolver(true));
}
}
1.2 定义处理器
package com.joe.code.common.component;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.core.MethodParameter;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.TypeDescriptor;
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.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.ValueConstants;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver;
import org.springframework.web.method.annotation.RequestParamMethodArgumentResolver;
import org.springframework.web.method.support.UriComponentsContributor;
import org.springframework.web.multipart.MultipartException;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartRequest;
import org.springframework.web.multipart.support.MissingServletRequestPartException;
import org.springframework.web.multipart.support.MultipartResolutionDelegate;
import org.springframework.web.util.UriComponentsBuilder;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.Part;
import java.util.Collection;
import java.util.List;
import java.util.Map;
@Slf4j
public class TestResolver extends AbstractNamedValueMethodArgumentResolver implements UriComponentsContributor {
private static final TypeDescriptor STRING_TYPE_DESCRIPTOR = TypeDescriptor.valueOf(String.class);
private final boolean useDefaultResolution;
/**
* Create a new {@link RequestParamMethodArgumentResolver} instance.
* @param useDefaultResolution in default resolution mode a method argument
* that is a simple type, as defined in {@link BeanUtils#isSimpleProperty},
* is treated as a request parameter even if it isn't annotated, the
* request parameter name is derived from the method parameter name.
*/
public TestResolver(boolean useDefaultResolution) {
this.useDefaultResolution = useDefaultResolution;
}
/**
* Create a new {@link RequestParamMethodArgumentResolver} instance.
* @param beanFactory a bean factory used for resolving ${...} placeholder
* and #{...} SpEL expressions in default values, or {@code null} if default
* values are not expected to contain expressions
* @param useDefaultResolution in default resolution mode a method argument
* that is a simple type, as defined in {@link BeanUtils#isSimpleProperty},
* is treated as a request parameter even if it isn't annotated, the
* request parameter name is derived from the method parameter name.
*/
public TestResolver(@Nullable ConfigurableBeanFactory beanFactory,
boolean useDefaultResolution) {
super(beanFactory);
this.useDefaultResolution = useDefaultResolution;
}
@Override
public boolean supportsParameter(MethodParameter parameter) {
log.info("判断是否是支持的请求注解 。。。。。。");
if (parameter.hasParameterAnnotation(RequestParam.class)) {
if (Map.class.isAssignableFrom(parameter.nestedIfOptional().getNestedParameterType())) {
RequestParam requestParam = parameter.getParameterAnnotation(RequestParam.class);
return (requestParam != null && StringUtils.hasText(requestParam.name()));
}
else {
return true;
}
}
else {
if (parameter.hasParameterAnnotation(RequestPart.class)) {
return false;
}
parameter = parameter.nestedIfOptional();
if (MultipartResolutionDelegate.isMultipartArgument(parameter)) {
return true;
}
else if (this.useDefaultResolution) {
return BeanUtils.isSimpleProperty(parameter.getNestedParameterType());
}
else {
return false;
}
}
}
@Override
protected NamedValueInfo createNamedValueInfo(MethodParameter parameter) {
log.info("获取请求参数。。。。。。");
RequestParam ann = parameter.getParameterAnnotation(RequestParam.class);
return (ann != null ? new TestResolver.RequestParamNamedValueInfo(ann) : new TestResolver.RequestParamNamedValueInfo());
}
@Override
@Nullable
protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest request) throws Exception {
HttpServletRequest servletRequest = request.getNativeRequest(HttpServletRequest.class);
if (servletRequest != null) {
Object mpArg = MultipartResolutionDelegate.resolveMultipartArgument(name, parameter, servletRequest);
if (mpArg != MultipartResolutionDelegate.UNRESOLVABLE) {
return mpArg;
}
}
Object arg = null;
MultipartRequest multipartRequest = request.getNativeRequest(MultipartRequest.class);
if (multipartRequest != null) {
List<MultipartFile> files = multipartRequest.getFiles(name);
if (!files.isEmpty()) {
arg = (files.size() == 1 ? files.get(0) : files);
}
}
if (arg == null) {
String[] paramValues = request.getParameterValues(name);
if (paramValues != null) {
arg = (paramValues.length == 1 ? paramValues[0] : paramValues);
}
}
return arg;
}
@Override
protected void handleMissingValue(String name, MethodParameter parameter, NativeWebRequest request)
throws Exception {
HttpServletRequest servletRequest = request.getNativeRequest(HttpServletRequest.class);
if (MultipartResolutionDelegate.isMultipartArgument(parameter)) {
if (servletRequest == null || !MultipartResolutionDelegate.isMultipartRequest(servletRequest)) {
throw new MultipartException("Current request is not a multipart request");
}
else {
throw new MissingServletRequestPartException(name);
}
}
else {
throw new MissingServletRequestParameterException(name,
parameter.getNestedParameterType().getSimpleName());
}
}
@Override
public void contributeMethodArgument(MethodParameter parameter, @Nullable Object value,
UriComponentsBuilder builder, Map<String, Object> uriVariables, ConversionService conversionService) {
Class<?> paramType = parameter.getNestedParameterType();
if (Map.class.isAssignableFrom(paramType) || MultipartFile.class == paramType || Part.class == paramType) {
return;
}
RequestParam requestParam = parameter.getParameterAnnotation(RequestParam.class);
String name = (requestParam != null && StringUtils.hasLength(requestParam.name()) ?
requestParam.name() : parameter.getParameterName());
Assert.state(name != null, "Unresolvable parameter name");
if (value == null) {
if (requestParam != null &&
(!requestParam.required() || !requestParam.defaultValue().equals(ValueConstants.DEFAULT_NONE))) {
return;
}
builder.queryParam(name);
}
else if (value instanceof Collection) {
for (Object element : (Collection<?>) value) {
element = formatUriValue(conversionService, TypeDescriptor.nested(parameter, 1), element);
builder.queryParam(name, element);
}
}
else {
builder.queryParam(name, formatUriValue(conversionService, new TypeDescriptor(parameter), value));
}
}
@Nullable
protected String formatUriValue(
@Nullable ConversionService cs, @Nullable TypeDescriptor sourceType, @Nullable Object value) {
if (value == null) {
return null;
}
else if (value instanceof String) {
return (String) value;
}
else if (cs != null) {
return (String) cs.convert(value, sourceType, STRING_TYPE_DESCRIPTOR);
}
else {
return value.toString();
}
}
private static class RequestParamNamedValueInfo extends NamedValueInfo {
public RequestParamNamedValueInfo() {
super("", false, ValueConstants.DEFAULT_NONE);
}
public RequestParamNamedValueInfo(RequestParam annotation) {
super(annotation.name(), annotation.required(), annotation.defaultValue());
}
}
}
参考:https://blog.csdn.net/fgszdgbzdb/article/details/93519752
网友评论