@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();
}
}
SpringDataJPA中,对Web提供的支持的实现原理
于 2024-04-07 17:02:51 首次发布