SpringDataJPA中,对Web提供的支持的实现原理

@Import({EnableSpringDataWebSupport.SpringDataWebConfigurationImportSelector.class, EnableSpringDataWebSupport.QuerydslActivator.class})
class EnableSpringDataWebSupport {
    class SpringDataWebConfigurationImportSelector {

    }
}

// Spring的自动配置
@Configuration
public class SpringDataWebConfiguration implements WebMvcConfigurer, BeanClassLoaderAware {

    private final ApplicationContext context;
    // 类型转换器
    private final ObjectFactory<ConversionService> conversionService;
    // JPA中对Pageable参数解析器
    private @Autowired
    Optional<PageableHandlerMethodArgumentResolverCustomizer> pageableResolverCustomizer;
    // JPA中对Sort参数解析器
    private @Autowired
    Optional<SortHandlerMethodArgumentResolverCustomizer> sortResolverCustomizer;

    public SpringDataWebConfiguration(ApplicationContext context, @Qualifier("mvcConversionService") ObjectFactory<ConversionService> conversionService) {
        this.context = context;
        this.conversionService = conversionService;
    }

    @Bean
    public PageableHandlerMethodArgumentResolver pageableResolver() {
        // 创建PageableHandlerMethodArgumentResolver,用于解析Pageable参数
        PageableHandlerMethodArgumentResolver pageableResolver = new PageableHandlerMethodArgumentResolver(sortResolver());
        // 自定义配置
        customizePageableResolver(pageableResolver);
        return pageableResolver;
    }

    @Bean
    public SortHandlerMethodArgumentResolver sortResolver() {
        // 创建SortHandlerMethodArgumentResolver,用于解析Sort参数
        SortHandlerMethodArgumentResolver sortResolver = new SortHandlerMethodArgumentResolver();
        // 自定义配置
        customizeSortResolver(sortResolver);
        return sortResolver;
    }

    // WebMvcConfigurer,添加类型转换器
    @Override
    public void addFormatters(FormatterRegistry registry) {
        // 添加类型转换器
        registry.addFormatter(DistanceFormatter.INSTANCE);
        registry.addFormatter(PointFormatter.INSTANCE);
        if (!(registry instanceof FormattingConversionService)) {
            return;
        }
        FormattingConversionService conversionService = (FormattingConversionService) registry;
        // 添加DomainClassConverter,对JPA实体类的转换
        DomainClassConverter<FormattingConversionService> converter = new DomainClassConverter<>(conversionService);
        converter.setApplicationContext(context);
    }

    // WebMvcConfigurer,添加参数解析器
    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {

        // 添加排序的解析器
        argumentResolvers.add(sortResolver());
        // 添加分页的解析器
        argumentResolvers.add(pageableResolver());
        // 创建一个处理代理的参数处理器,处理@ProjectedPayload,该类继承ModelAttributeMethodProcessor
        // 可以处理使用接口作为参数的接受对象
        /**
         * <pre>
         *     @PostMapping("/")
         *     public UserInterface userInterface(@RequestBody UserInterface userInterface) {
         *         return userInterface;
         *     }
         *
         *     @ProjectedPayload
         *     interface UserInterface{
         *         @JsonPath("$.age")
         *         Integer getAge();
         *
         *         @JsonPath("$.name")
         *         String getName();
         *     }
         * </pre>
         */
        ProxyingHandlerMethodArgumentResolver resolver = new ProxyingHandlerMethodArgumentResolver(conversionService, true);
        argumentResolvers.add(resolver);
    }


    @Override
    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        // 添加JSON的转换器
        if (ClassUtils.isPresent("com.jayway.jsonpath.DocumentContext", context.getClassLoader()) && ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper", context.getClassLoader())) {
            ObjectMapper mapper = getUniqueBean(ObjectMapper.class, context, ObjectMapper::new);
            // 用于解析ProjectedPayload注解的消息处理器
            // 该消息只可读取请求参数,不支持write响应
            ProjectingJackson2HttpMessageConverter converter = new ProjectingJackson2HttpMessageConverter(mapper);
            converters.add(0, converter);
        }
        // 添加XML的转换器
        if (ClassUtils.isPresent("org.xmlbeam.XBProjector", context.getClassLoader())) {
            converters.add(0, xmlBeamHttpMessageConverter.orElseGet(() -> new XmlBeamHttpMessageConverter()));
        }
    }

}

// 接口参数类型解析器
class ProxyingHandlerMethodArgumentResolver extends ModelAttributeMethodProcessor {
    public boolean supportsParameter(MethodParameter parameter) {
        // 先调用ModelAttributeMethodProcessor的校验
        if (!super.supportsParameter(parameter)) {
            return false;
        }
        // 获取参数类型
        Class<?> type = parameter.getParameterType();
        // 如果不是接口,不处理
        if (!type.isInterface()) {
            return false;
        }
        // 获取接口上的ProjectedPayload注解
        // 如果存在,表示可以处理
        if (parameter.getParameterAnnotation(ProjectedPayload.class) != null) {
            return true;
        }
        // 找继承类中的ProjectedPayload注解
        if (AnnotatedElementUtils.findMergedAnnotation(type, ProjectedPayload.class) != null) {
            return true;
        }
        // 如果不存在该注解,获取接口的包名
        String packageName = ClassUtils.getPackageName(type);
        // 如果不是被忽略的包名(java,org.springframework),也可以
        return !IGNORED_PACKAGES.stream().anyMatch(it -> packageName.startsWith(it));
    }

    // 解析参数
    public final Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {

        // 获取参数名
        String name = ModelFactory.getNameForParameter(parameter);
        // 是否存在ModelAttribute注解
        ModelAttribute ann = parameter.getParameterAnnotation(ModelAttribute.class);
        // 如果存在该注解
        if (ann != null) {
            // 设置是否可以绑定
            mavContainer.setBinding(name, ann.binding());
        }
        // 属性值
        Object attribute = null;
        // 绑定结果
        BindingResult bindingResult = null;
        // 如果容器的Model中已经存在该属性
        if (mavContainer.containsAttribute(name)) {
            // 直接获取Model中的属性值
            attribute = mavContainer.getModel().get(name);
        } else {
            // 否则创建该属性对象并绑定属性值
            try {
                attribute = createAttribute(name, parameter, binderFactory, webRequest);
            } catch (BindException ex) {
                // 绑定异常,获取到绑定的异常信息
                if (parameter.getParameterType() == Optional.class) {
                    attribute = Optional.empty();
                }
                bindingResult = ex.getBindingResult();
            }
        }
        // 如果不存在绑定异常
        if (bindingResult == null) {
            // 创建WebDataBinder类型转换器
            WebDataBinder binder = binderFactory.createBinder(webRequest, attribute, name);
            // 获取目标对象
            if (binder.getTarget() != null) {
                // 如果可以绑定
                if (!mavContainer.isBindingDisabled(name)) {
                    // 绑定请求参数,在ProxyingHandlerMethodArgumentResolver,无需绑定请求参数
                    bindRequestParameters(binder, webRequest);
                }
                // 校验参数并绑定
                validateIfApplicable(binder, parameter);
                // 如果存在绑定异常
                if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) {
                    // 抛出异常
                    throw new BindException(binder.getBindingResult());
                }
            }
            // 如果参数不是目标需要的参数类型
            if (!parameter.getParameterType().isInstance(attribute)) {
                // 进行类型转换
                attribute = binder.convertIfNecessary(binder.getTarget(), parameter.getParameterType(), parameter);
            }
            // 获取到绑定的结果
            bindingResult = binder.getBindingResult();
        }
        // 获取绑定的数据
        Map<String, Object> bindingResultModel = bindingResult.getModel();
        // 移除之前给定的bindingResultModel中的数据
        mavContainer.removeAttributes(bindingResultModel);
        // 再重新添加
        mavContainer.addAllAttributes(bindingResultModel);
        // 返回处理好的属性值
        return attribute;
    }

    // 创建属性对象
    protected Object createAttribute(String attributeName, MethodParameter parameter, WebDataBinderFactory binderFactory, NativeWebRequest request) throws Exception {

        // 使用Map的数据绑定器
        MapDataBinder binder = new MapDataBinder(parameter.getParameterType(), conversionService.getObject());
        // 获取所有的请求参数进行绑定
        binder.bind(new MutablePropertyValues(request.getParameterMap()));
        // 创建属性对象的代理对象
        return proxyFactory.createProjection(parameter.getParameterType(), binder.getTarget()) {
            // 如果参数类型就是目标类型,直接返回
            if (projectionType.isInstance(source)) {
                return (T) source;
            }
            // 创建代理工厂
            ProxyFactory factory = new ProxyFactory();
            // 设置目标对象
            factory.setTarget(source);
            factory.setOpaque(true);
            // 设置需要实现的接口
            factory.setInterfaces(projectionType, TargetAware.class);
            // 添加几个拦截器,执行接口默认方法的拦截器
            factory.addAdvice(new DefaultMethodInvokingMethodInterceptor());
            factory.addAdvice(new TargetAwareMethodInterceptor(source.getClass()));
            factory.addAdvice(getMethodInterceptor(source, projectionType));
            // 返回代理对象
            return (T) factory.getProxy(classLoader == null ? ClassUtils.getDefaultClassLoader() : classLoader);
        }
    }

}

// 对JPA实体类的转换器
// 作用,将Path中的Id变量或者Request中的ID参数值直接转换成实体对象注册到接口参数中
class DomainClassConverter {
    public void setApplicationContext(ApplicationContext context) {
        // 保存JpaRepositoryFactoryBean的信息,内部就可以知道Repository和实现类信息
        this.repositories = new Repositories(context);
        // 将参数转换为实体的类型转换器
        this.toEntityConverter = Optional.of(new ToEntityConverter(this.repositories, this.conversionService));
        this.toEntityConverter.ifPresent(it -> this.conversionService.addConverter(it));
        // 将参数转换为ID的转换器
        this.toIdConverter = Optional.of(new ToIdConverter());
        this.toIdConverter.ifPresent(it -> this.conversionService.addConverter(it));
    }

    // 匹配哪些转换器可以用
    public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
        // 获取当前配置的转换器进行匹配
        return getConverter(targetType).map(it -> it.matches(sourceType, targetType)).orElse(false);
    }

    // 获取目标实体类型的转换器
    private Optional<? extends ConditionalGenericConverter> getConverter(TypeDescriptor targetType) {
        // 如果实体类型参数存在对应的Repository,返回实体转换器,否则返回ID转换器
        return repositories.hasRepositoryFor(targetType.getType()) ? toEntityConverter : toIdConverter;
    }

    // 获取参数中的ID,调用实体对象Repository接口的findById方法,然后返回查询的Entity对象
    class ToEntityConverter implements ConditionalGenericConverter {
        // 转换类型为Object -> Object
        public Set<ConvertiblePair> getConvertibleTypes() {
            return Collections.singleton(new ConvertiblePair(Object.class, Object.class));
        }

        // 匹配类型
        public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
            // 类型一致,不需要转换
            if (sourceType.isAssignableTo(targetType)) {
                return false;
            }
            // 获取实体类型
            Class<?> domainType = targetType.getType();
            // 如果实体没有对应的Repository接口,不转换
            if (!repositories.hasRepositoryFor(domainType)) {
                return false;
            }
            // 获取Repository接口信息
            Optional<RepositoryInformation> repositoryInformation = repositories.getRepositoryInformationFor(domainType);
            // 返回是否可以转换
            return repositoryInformation.map(it -> {
                // 获取ID类型
                Class<?> rawIdType = it.getIdType();
                // 是否可以转换,将参数转换为实体的ID类型
                return sourceType.equals(TypeDescriptor.valueOf(rawIdType)) || conversionService.canConvert(sourceType.getType(), rawIdType);

            }).orElseThrow(() -> new IllegalStateException(String.format("Couldn't find RepositoryInformation for %s!", domainType)));
        }

        // 类型转换
        public Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
            // 如果需要转换的类型就目标类型,直接返回
            if (sourceType.equals(targetType)) {
                return source;
            }
            // 获取实体类型信息
            Class<?> domainType = targetType.getType();
            // 获取Repository的执行器
            RepositoryInvoker invoker = repositoryInvokerFactory.getInvokerFor(domainType);
            // 获取当前实体对应的Repository接口信息
            RepositoryInformation information = repositories.getRequiredRepositoryInformation(domainType);
            // 类型转换,获取到实体ID
            Object id = conversionService.convert(source, information.getIdType());
            // 执行Repository接口的findById方法,返回查询出来的实体对象
            return id == null ? null : invoker.invokeFindById(id).orElse(null);
        }

    }

    // 获取参数中的ID,转换为默认的实体对象,并设置ID
    class ToIdConverter implements ConditionalGenericConverter {

        // 转换类型为Object -> Object
        public Set<ConvertiblePair> getConvertibleTypes() {
            return Collections.singleton(new ConvertiblePair(Object.class, Object.class));
        }

        @Override
        public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
            // 类型一致,不需要转换
            if (sourceType.isAssignableTo(targetType)) {
                return false;
            }
            // 获取实体类型
            Class<?> domainType = sourceType.getType();
            // 如果不存在实体的Repository,不处理
            if (!repositories.hasRepositoryFor(domainType)) {
                return false;
            }
            // 获取Repository接口信息
            Optional<RepositoryInformation> information = repositories.getRepositoryInformationFor(domainType);
            return information.map(it -> {
                // 获取ID类型
                Class<?> rawIdType = it.getIdType();
                // 是否可以转换,将参数转换为实体的ID类型
                return targetType.equals(TypeDescriptor.valueOf(rawIdType)) || conversionService.canConvert(rawIdType, targetType.getType());
            }).orElseThrow(() -> new IllegalStateException(String.format("Couldn't find RepositoryInformation for %s!", domainType)));
        }

        // 类型转换
        public Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
            // 如果类型一样,直接返回需要转换的对象
            if (sourceType.equals(targetType)) {
                return source;
            }
            // 获取实体类型
            Class<?> domainType = sourceType.getType();
            // 获取实体信息
            EntityInformation<Object, ?> entityInformation = repositories.getEntityInformationFor(domainType);
            // 获取到实体对象,并且设置实体ID
            return conversionService.convert(entityInformation.getId(source), targetType.getType());
        }

    }

}

// 解析Pageable参数的参数解析器
class PageableHandlerMethodArgumentResolver {

    // 排序的Sort接口方法默认的参数解析器
    private static final SortHandlerMethodArgumentResolver DEFAULT_SORT_RESOLVER = new SortHandlerMethodArgumentResolver();
    // Sort参数解析器
    private SortHandlerMethodArgumentResolver sortResolver;

    // 只处理Pageable参数
    public boolean supportsParameter(MethodParameter parameter) {
        return Pageable.class.equals(parameter.getParameterType());
    }

    // 解析参数
    public Pageable resolveArgument(MethodParameter methodParameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) {
        // private static final String DEFAULT_PAGE_PARAMETER = "page";
        // private static final String DEFAULT_SIZE_PARAMETER = "size";
        String pageParameterName = getPageParameterName();
        String sizeParameterName = getSizeParameterName();
        // 获取page的参数值
        String page = webRequest.getParameter(getParameterNameToUse(pageParameterName, methodParameter));
        // 获取size的参数值
        String pageSize = webRequest.getParameter(getParameterNameToUse(sizeParameterName, methodParameter));
        // 使用排序参数解析器解析到Sort对象
        Sort sort = sortResolver.resolveArgument(methodParameter, mavContainer, webRequest, binderFactory);
        // 获取分页参数
        Pageable pageable = getPageable(methodParameter, page, pageSize);
        // 如果需要排序,Pageable转换为需要排序的PageRequest
        if (sort.isSorted()) {
            return PageRequest.of(pageable.getPageNumber(), pageable.getPageSize(), sort);
        }
        return pageable;
    }

    // 从注解中获取默认的分页参数
    private Pageable getDefaultFromAnnotationOrFallback(MethodParameter methodParameter) {
        // 获取PageableDefault注解
        PageableDefault defaults = methodParameter.getParameterAnnotation(PageableDefault.class);
        // 如果不为空,从注解中获取默认值
        if (defaults != null) {
            return getDefaultPageRequestFrom(methodParameter, defaults);
        }
        // 否则返回null
        return fallbackPageable;
    }

    // 从注解中获取默认的分页参数
    private static Pageable getDefaultPageRequestFrom(MethodParameter parameter, PageableDefault defaults) {
        // 获取注解中的默认page
        Integer defaultPageNumber = defaults.page();
        // 获取注解中的size
        Integer defaultPageSize = getSpecificPropertyOrDefaultFromValue(defaults, "size");
        // 如果page小于1,抛出异常
        if (defaultPageSize < 1) {
            Method annotatedMethod = parameter.getMethod();
            throw new IllegalStateException(String.format(INVALID_DEFAULT_PAGE_SIZE, annotatedMethod));
        }
        // 如果没有设置排序
        if (defaults.sort().length == 0) {
            // 直接返回Pageable对象
            return PageRequest.of(defaultPageNumber, defaultPageSize);
        }
        // 如果同时存在排序,则返回包含排序的Pageable对象
        return PageRequest.of(defaultPageNumber, defaultPageSize, defaults.direction(), defaults.sort());
    }

    // 获取排序参数,解析为Pageable对象
    protected Pageable getPageable(MethodParameter methodParameter, String pageString, String pageSizeString) {
        // 校验只能存在一个Pageable对象,否则抛出异常
        assertPageableUniqueness(methodParameter);
        // 获取分页的默认值
        Optional<Pageable> defaultOrFallback = getDefaultFromAnnotationOrFallback(methodParameter).toOptional();
        // 解析page和size的边界值,就是返回一个合法的参数值
        Optional<Integer> page = parseAndApplyBoundaries(pageString, Integer.MAX_VALUE, true);
        Optional<Integer> pageSize = parseAndApplyBoundaries(pageSizeString, maxPageSize, false);
        // 如果没有分页参数
        if (!(page.isPresent() && pageSize.isPresent()) && !defaultOrFallback.isPresent()) {
            // 不分页
            return Pageable.unpaged();
        }
        // 获取分页值
        int p = page.orElseGet(() -> defaultOrFallback.map(Pageable::getPageNumber).orElseThrow(IllegalStateException::new));
        // 获取分页大小值
        int ps = pageSize.orElseGet(() -> defaultOrFallback.map(Pageable::getPageSize).orElseThrow(IllegalStateException::new));

        // 校验pageSize的边界值
        ps = ps < 1 ? defaultOrFallback.map(Pageable::getPageSize).orElseThrow(IllegalStateException::new) : ps;
        ps = ps > maxPageSize ? maxPageSize : ps;
        // 返回分页信息
        return PageRequest.of(p, ps, defaultOrFallback.map(Pageable::getSort).orElseGet(Sort::unsorted));
    }

    /**
     * 获取page,size参数
     * 格式: prefix(默认为"") +  (Qualifier注解的值+"_" : 可选) + page或者size
     *
     * @param source page或者size
     */
    protected String getParameterNameToUse(String source, MethodParameter parameter) {
        // 参数前缀,默认为"",空
        StringBuilder builder = new StringBuilder(prefix);
        // 获取Qualifier注解
        Qualifier qualifier = parameter == null ? null : parameter.getParameterAnnotation(Qualifier.class);
        // 如果存在Qualifier注解
        if (qualifier != null) {
            // 保存Qualifier的值
            builder.append(qualifier.value());
            // 并且下划线
            builder.append(qualifierDelimiter);
        }
        // 再拼接参数名称
        return builder.append(source).toString();
    }

}

// 实际上就是SortHandlerMethodArgumentResolver
class SortHandlerMethodArgumentResolver implements SortArgumentResolver {
    // 只处理Sort参数
    public boolean supportsParameter(MethodParameter parameter) {
        return Sort.class.equals(parameter.getParameterType());
    }

    // 解析参数
    public Sort resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) {
        // 获取所有的sort参数名称对应的值
        String[] directionParameter = webRequest.getParameterValues(getSortParameter(parameter));
        // 如果不存在sort参数值
        if (directionParameter == null) {
            // 获取注解提供的默认值
            return getDefaultFromAnnotationOrFallback(parameter);
        }
        // 如果只有一个存在sort参数值,并且值为空
        if (directionParameter.length == 1 && !StringUtils.hasText(directionParameter[0])) {
            // 获取注解提供的默认值
            return getDefaultFromAnnotationOrFallback(parameter);
        }
        // 将参数解析为Sort
        return parseParameterIntoSort(Arrays.asList(directionParameter), getPropertyDelimiter());
    }

    /**
     * 将参数解析为Sort
     * 格式为: sort = age,desc
     *
     * @param source    sort参数值
     * @param delimiter 分割符号,默认为","
     */
    public Sort parseParameterIntoSort(List<String> source, String delimiter) {
        // 格式为: sort = age,desc
        List<Order> allOrders = new ArrayList<>();
        // 遍历所有的sort值
        for (String part : source) {
            // 格式为: sort = age,desc
            // 使用,分割sort值,返回字段和方向的数组
            String[] elements = Arrays.stream(part.split(delimiter))
                    .filter(SortHandlerMethodArgumentResolver::notOnlyDots)
                    .toArray(String[]::new);
            // 解析排序方向
            Optional<Direction> direction = elements.length == 0 ? Optional.empty() : Direction.fromOptionalString(elements[elements.length - 1]);
            int lastIndex = direction.map(it -> elements.length - 1).orElseGet(() -> elements.length);
            /// 解析排序字段
            for (int i = 0; i < lastIndex; i++) {
                // 将排序字段转换为Order对象,并保存到allOrders中
                toOrder(elements[i], direction).ifPresent(allOrders::add);
            }
        }
        // 如果解析到了排序信息,返回Sort排序对象,否则返回不排序
        return allOrders.isEmpty() ? Sort.unsorted() : Sort.by(allOrders);
    }

    // 获取SortDefault或者SortDefaults注解提供的默认值
    protected Sort getDefaultFromAnnotationOrFallback(MethodParameter parameter) {
        // 获取注解信息
        SortDefaults annotatedDefaults = parameter.getParameterAnnotation(SortDefaults.class);
        SortDefault annotatedDefault = parameter.getParameterAnnotation(SortDefault.class);
        // 如果都不存在,抛出异常,表示有Sort参数,但是又没给定值
        if (annotatedDefault != null && annotatedDefaults != null) {
            throw new IllegalArgumentException(String.format("Cannot use both @%s and @%s on parameter %s! Move %s into %s to define sorting order!", SORT_DEFAULTS_NAME, SORT_DEFAULT_NAME, parameter.toString(), SORT_DEFAULT_NAME, SORT_DEFAULTS_NAME));
        }
        // 如果存在SortDefault注解
        if (annotatedDefault != null) {
            // 添加或者创建Sort对象
            return appendOrCreateSortTo(annotatedDefault, Sort.unsorted());
        }
        // 如果存在SortDefaults注解
        if (annotatedDefaults != null) {
            Sort sort = Sort.unsorted();
            // 遍历所在的SortDefault注解
            for (SortDefault currentAnnotatedDefault : annotatedDefaults.value()) {
                // 不断地追加排序规则
                sort = appendOrCreateSortTo(currentAnnotatedDefault, sort);
            }
            // 返回最终的排序信息
            return sort;
        }
        return fallbackSort;
    }

    // 添加或者创建Sort对象
    private Sort appendOrCreateSortTo(SortDefault sortDefault, Sort sortOrNull) {
        // 获取SortDefault注解的值
        String[] fields = SpringDataAnnotationUtils.getSpecificPropertyOrDefaultFromValue(sortDefault, "sort");
        // 如果没有设置
        if (fields.length == 0) {
            // 标记不排序
            return Sort.unsorted();
        }
        // 设置排序规则
        return sortOrNull.and(Sort.by(sortDefault.direction(), fields));
    }

    /**
     * 获取排序的参数名称
     * 格式: (Qualifier注解的值+"_" : 可选) + sort
     */
    protected String getSortParameter(MethodParameter parameter) {
        StringBuilder builder = new StringBuilder();
        // 是否存在Qualifier注解
        Qualifier qualifier = parameter != null ? parameter.getParameterAnnotation(Qualifier.class) : null;
        // 如果存在
        if (qualifier != null) {
            // 拼接 注解的值+"_"
            builder.append(qualifier.value()).append(qualifierDelimiter);
        }
        // 	private static final String DEFAULT_PARAMETER = "sort";
        // 最后拼接sort
        return builder.append(sortParameter).toString();
    }
}

  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值