问题遇到的现象和发生背景
我的项目是一个API网关项目,使用的spring-cloud-gateway,之前使用的springboot2.2版本,并在项目中自定义了错误异常处理,其中使用到一个类ResourceProperties,但是当我升级到springboot2.7.1后,该类被移除了,但是有一个类WebProperties的内部静态类Resources好像是ResourceProperties的代替者,但是我使用的过程中总是报错,还没找到如何使用。
问题相关代码,请勿粘贴截图
就是如下两个类使用到了ResourceProperties,在springboot2.7.1缺失
package com.cosmosource.core.exception;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.condition.SearchStrategy;
import org.springframework.boot.autoconfigure.web.ResourceProperties;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.autoconfigure.web.reactive.WebFluxAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.reactive.error.DefaultErrorAttributes;
import org.springframework.boot.web.reactive.error.ErrorAttributes;
import org.springframework.boot.web.reactive.error.ErrorWebExceptionHandler;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.http.codec.ServerCodecConfigurer;
import org.springframework.web.reactive.config.WebFluxConfigurer;
import org.springframework.web.reactive.result.view.ViewResolver;
import java.util.List;
import java.util.stream.Collectors;
@Configuration
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
@ConditionalOnClass(WebFluxConfigurer.class)
@AutoConfigureBefore(WebFluxAutoConfiguration.class)
@EnableConfigurationProperties({ServerProperties.class, ResourceProperties.class})
public class CustomErrorWebFluxAutoConfiguration {
private final ServerProperties serverProperties;
private final ApplicationContext applicationContext;
private final ResourceProperties resourceProperties;
private final List<ViewResolver> viewResolvers;
private final ServerCodecConfigurer serverCodecConfigurer;
public CustomErrorWebFluxAutoConfiguration(ServerProperties serverProperties,
ResourceProperties resourceProperties, // 就这个类缺失了
ObjectProvider<ViewResolver> viewResolversProvider,
ServerCodecConfigurer serverCodecConfigurer,
ApplicationContext applicationContext) {
this.serverProperties = serverProperties;
this.applicationContext = applicationContext;
this.resourceProperties = resourceProperties;
this.viewResolvers = viewResolversProvider.orderedStream()
.collect(Collectors.toList());
this.serverCodecConfigurer = serverCodecConfigurer;
}
@Bean
@ConditionalOnMissingBean(value = ErrorWebExceptionHandler.class,
search = SearchStrategy.CURRENT)
@Order(-1)
public ErrorWebExceptionHandler errorWebExceptionHandler(ErrorAttributes errorAttributes) {
JsonErrorWebExceptionHandler exceptionHandler = new JsonErrorWebExceptionHandler(
errorAttributes,
resourceProperties,
this.serverProperties.getError(),
applicationContext);
exceptionHandler.setViewResolvers(this.viewResolvers);
exceptionHandler.setMessageWriters(this.serverCodecConfigurer.getWriters());
exceptionHandler.setMessageReaders(this.serverCodecConfigurer.getReaders());
return exceptionHandler;
}
@Bean
@ConditionalOnMissingBean(value = ErrorAttributes.class, search = SearchStrategy.CURRENT)
public DefaultErrorAttributes errorAttributes() {
return new DefaultErrorAttributes(this.serverProperties.getError().isIncludeException());
}
}
package com.cosmosource.core.exception;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.web.ErrorProperties;
import org.springframework.boot.autoconfigure.web.ResourceProperties;
import org.springframework.boot.autoconfigure.web.reactive.error.DefaultErrorWebExceptionHandler;
import org.springframework.boot.web.reactive.error.ErrorAttributes;
import org.springframework.context.ApplicationContext;
import org.springframework.http.HttpStatus;
import org.springframework.web.reactive.function.server.*;
import java.net.UnknownHostException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* @author liaoyuanyuan@cosmosource.com
* @date 2022/5/5 19:27
**/
@Slf4j
public class JsonErrorWebExceptionHandler extends DefaultErrorWebExceptionHandler {
public JsonErrorWebExceptionHandler(ErrorAttributes errorAttributes,
ResourceProperties resourceProperties,
ErrorProperties errorProperties,
ApplicationContext applicationContext) {
super(errorAttributes, resourceProperties, errorProperties, applicationContext);
}
@Override
protected Map<String, Object> getErrorAttributes(ServerRequest request, boolean includeStackTrace) {
//定制化逻辑
Throwable error = super.getError(request);
Map<String, Object> errorAttributes = new LinkedHashMap<>(8);
if (error instanceof UnknownHostException) {
errorAttributes.put("message", StrUtil.contains(error.getMessage(), "未知的名称或服务")
? error.getMessage() : error.getMessage() + " 未知的名称或服务");
} else {
errorAttributes.put("message", error.getMessage());
}
errorAttributes.put("timestamp", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
errorAttributes.put("status", HttpStatus.INTERNAL_SERVER_ERROR.value());
errorAttributes.put("method", request.methodName());
errorAttributes.put("path", request.path());
errorAttributes.put("requestId", request.exchange().getRequest().getId());
log.error("全局异常处理:" + JSON.toJSONString(errorAttributes));
return errorAttributes;
}
@Override
protected RouterFunction<ServerResponse> getRoutingFunction(ErrorAttributes errorAttributes) {
return RouterFunctions.route(RequestPredicates.all(), this::renderErrorResponse);
}
@Override
protected int getHttpStatus(Map<String, Object> errorAttributes) {
// 这里其实可以根据errorAttributes里面的属性定制HTTP响应码
return HttpStatus.INTERNAL_SERVER_ERROR.value();
}
}
运行结果及报错内容
我将ResourceProperties替换成了WebProperties,但是启动报错:
java.lang.IllegalStateException: No ConfigurationProperties annotation found on 'org.springframework.boot.autoconfigure.web.WebProperties$Resources'.
at org.springframework.util.Assert.state(Assert.java:97) ~[spring-core-5.3.21.jar:5.3.21]
at org.springframework.boot.context.properties.ConfigurationPropertiesBeanRegistrar.registerBeanDefinition(ConfigurationPropertiesBeanRegistrar.java:86) ~[spring-boot-2.7.1.jar:2.7.1]
at org.springframework.boot.context.properties.ConfigurationPropertiesBeanRegistrar.register(ConfigurationPropertiesBeanRegistrar.java:60) ~[spring-boot-2.7.1.jar:2.7.1]
at org.springframework.boot.context.properties.ConfigurationPropertiesBeanRegistrar.register(ConfigurationPropertiesBeanRegistrar.java:54) ~[spring-boot-2.7.1.jar:2.7.1]
at java.lang.Iterable.forEach(Iterable.java:75) ~[na:1.8.0_321]
at org.springframework.boot.context.properties.EnableConfigurationPropertiesRegistrar.registerBeanDefinitions(EnableConfigurationPropertiesRegistrar.java:49) ~[spring-boot-2.7.1.jar:2.7.1]
at org.springframework.context.annotation.ImportBeanDefinitionRegistrar.registerBeanDefinitions(ImportBeanDefinitionRegistrar.java:86) ~[spring-context-5.3.21.jar:5.3.21]
at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.lambda$loadBeanDefinitionsFromRegistrars$1(ConfigurationClassBeanDefinitionReader.java:396) ~[spring-context-5.3.21.jar:5.3.21]
at java.util.LinkedHashMap.forEach(LinkedHashMap.java:684) ~[na:1.8.0_321]
at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsFromRegistrars(ConfigurationClassBeanDefinitionReader.java:395) ~[spring-context-5.3.21.jar:5.3.21]
at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsForConfigurationClass(ConfigurationClassBeanDefinitionReader.java:157) ~[spring-context-5.3.21.jar:5.3.21]
at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitions(ConfigurationClassBeanDefinitionReader.java:129) ~[spring-context-5.3.21.jar:5.3.21]
at org.springframework.context.annotation.ConfigurationClassPostProcessor.processConfigBeanDefinitions(ConfigurationClassPostProcessor.java:343) ~[spring-context-5.3.21.jar:5.3.21]
at org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(ConfigurationClassPostProcessor.java:247) ~[spring-context-5.3.21.jar:5.3.21]
at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanDefinitionRegistryPostProcessors(PostProcessorRegistrationDelegate.java:311) ~[spring-context-5.3.21.jar:5.3.21]
at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:112) ~[spring-context-5.3.21.jar:5.3.21]
at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:746) ~[spring-context-5.3.21.jar:5.3.21]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:564) ~[spring-context-5.3.21.jar:5.3.21]
at org.springframework.boot.web.reactive.context.ReactiveWebServerApplicationContext.refresh(ReactiveWebServerApplicationContext.java:66) ~[spring-boot-2.7.1.jar:2.7.1]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:734) [spring-boot-2.7.1.jar:2.7.1]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:408) [spring-boot-2.7.1.jar:2.7.1]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:308) [spring-boot-2.7.1.jar:2.7.1]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1306) [spring-boot-2.7.1.jar:2.7.1]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1295) [spring-boot-2.7.1.jar:2.7.1]
at com.cosmosource.PlatformWebApplication.main(PlatformWebApplication.java:20) [classes/:na]
我的解答思路和尝试过的方法
我找到了WebProperties的内部类Resource可以作为替代者,但是不知道如何使用,简单的使用总是报错
我想要达到的结果
我想知道该如何使用WebProperties来代替我之前的ResourceProperties