美文网首页
Spring mvc实战应用-自定义数据处理

Spring mvc实战应用-自定义数据处理

作者: engineer_tang | 来源:发表于2020-10-01 22:26 被阅读0次

    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

    相关文章

      网友评论

          本文标题:Spring mvc实战应用-自定义数据处理

          本文链接:https://www.haomeiwen.com/subject/tlkvuktx.html