提交 4a8d57db 编写于 作者: 如梦技术's avatar 如梦技术 🐛

完成对 webflux 的支持

上级 5692ed7f
## mica(云母)
[![Mica Maven](https://img.shields.io/maven-central/v/net.dreamlu/mica-bom.svg?style=flat-square)](https://mvnrepository.com/artifact/net.dreamlu/mica-bom)
`Mica`,Spring Cloud 微服务开发核心包,基于 `Spring boot 2.x`暂不支持 `webflux`
`Mica`,Spring Cloud 微服务开发核心包,基于 `Spring boot 2.x`支持 `web` `webflux`
想要了解更多可加入【如梦技术】QQ群:`479710041`
......@@ -25,6 +25,7 @@
- spi 扩展
### mica-boot
- 支持 `Spring boot web``Spring boot webflux`
- 异步配置。
- 异常处理,未知异常发送 Event 事件,方便监听收集。
- swagger自动化配置,加入jar包即可。
......
VERSION=0.0.1-RC3
VERSION=0.0.1-RC4
GROUPID=net.dreamlu
NEXUS_OSS_USER_NAME=***
......
......@@ -4,6 +4,7 @@ dependencies {
api "org.springframework.boot:spring-boot-starter-aop"
compileOnly "org.springframework.cloud:spring-cloud-context"
implementation "io.springfox:springfox-swagger2:${swaggerVersion}"
implementation "org.springframework.boot:spring-boot-starter-webflux"
implementation("org.springframework.boot:spring-boot-starter-web") {
exclude group: "org.springframework.boot", module: "spring-boot-starter-tomcat"
}
......
/*
* Copyright (c) 2019-2029, Dreamlu 卢春梦 (596392912@qq.com & www.dreamlu.net).
* <p>
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.dreamlu.mica.common.error;
import net.dreamlu.mica.core.result.R;
import net.dreamlu.mica.core.result.SystemCode;
import org.hibernate.validator.internal.engine.path.PathImpl;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import javax.validation.ConstraintViolation;
import java.util.Set;
/**
* 抽取共性 通用部分代码
*
* @author L.cm
*/
public abstract class BaseExceptionTranslator {
/**
* 处理 BindingResult
* @param result BindingResult
* @return R
*/
protected R<Object> handleError(BindingResult result) {
FieldError error = result.getFieldError();
String message = String.format("%s:%s", error.getField(), error.getDefaultMessage());
return R.fail(SystemCode.PARAM_BIND_ERROR, message);
}
/**
* 处理 ConstraintViolation
* @param violations 校验结果
* @return R
*/
protected R<Object> handleError(Set<ConstraintViolation<?>> violations) {
ConstraintViolation<?> violation = violations.iterator().next();
String path = ((PathImpl) violation.getPropertyPath()).getLeafNode().getName();
String message = String.format("%s:%s", path, violation.getMessage());
return R.fail(SystemCode.PARAM_VALID_ERROR, message);
}
}
......@@ -14,10 +14,11 @@
* limitations under the License.
*/
package net.dreamlu.mica.error;
package net.dreamlu.mica.common.error;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import org.springframework.lang.Nullable;
import java.time.LocalDateTime;
......@@ -29,6 +30,7 @@ import java.time.LocalDateTime;
*/
@Getter
@Setter
@ToString
public class MicaErrorEvent {
/**
* 应用名
......
......@@ -16,7 +16,7 @@
@NonNullApi
@NonNullFields
package net.dreamlu.mica.error;
package net.dreamlu.mica.common.error;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.NonNullFields;
......@@ -14,7 +14,7 @@
* limitations under the License.
*/
package net.dreamlu.mica.version;
package net.dreamlu.mica.common.version;
import lombok.Getter;
import org.springframework.http.MediaType;
......
......@@ -16,7 +16,7 @@
@NonNullApi
@NonNullFields
package net.dreamlu.mica.version;
package net.dreamlu.mica.common.version;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.NonNullFields;
......@@ -14,7 +14,7 @@
* limitations under the License.
*/
package net.dreamlu.mica.async;
package net.dreamlu.mica.config;
import lombok.AllArgsConstructor;
import net.dreamlu.mica.props.MicaAsyncProperties;
......
/*
* Copyright (c) 2019-2029, Dreamlu 卢春梦 (596392912@qq.com & www.dreamlu.net).
* <p>
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.dreamlu.mica.reactive.config;
import net.dreamlu.mica.core.convert.EnumToStringConverter;
import net.dreamlu.mica.core.convert.StringToEnumConverter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.context.annotation.Configuration;
import org.springframework.format.FormatterRegistry;
import org.springframework.web.reactive.config.WebFluxConfigurer;
/**
* mica enum 《-》 String 转换配置
*
* @author L.cm
*/
@Configuration
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
public class MicaConverterConfiguration implements WebFluxConfigurer {
@Override
public void addFormatters(FormatterRegistry registry) {
registry.addConverter(new EnumToStringConverter());
registry.addConverter(new StringToEnumConverter());
}
}
......@@ -14,26 +14,25 @@
* limitations under the License.
*/
package net.dreamlu.mica.version;
package net.dreamlu.mica.reactive.config;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.web.servlet.WebMvcRegistrations;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.codec.ServerCodecConfigurer;
import org.springframework.web.reactive.config.WebFluxConfigurer;
/**
* url版本号处理
* <p>
* 参考:https://gitee.com/lianqu1990/spring-boot-starter-version-mapping
* 消息转换器
*
* @author L.cm
*/
@Configuration
@ConditionalOnWebApplication
public class VersionMappingAutoConfiguration {
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
public class MicaMessageConfiguration implements WebFluxConfigurer {
@Bean
public WebMvcRegistrations webMvcRegistrations() {
return new MicaWebMvcRegistrations();
@Override
public void configureHttpMessageCodecs(ServerCodecConfigurer configurer) {
// TODO L.cm json 将 null 转为 空,需求暂时不支持
}
}
/*
* Copyright (c) 2019-2029, Dreamlu 卢春梦 (596392912@qq.com & www.dreamlu.net).
* <p>
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.dreamlu.mica.reactive.config;
import lombok.AllArgsConstructor;
import net.dreamlu.mica.props.MicaUploadProperties;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.config.ResourceHandlerRegistry;
import org.springframework.web.reactive.config.WebFluxConfigurer;
/**
* 文件上传配置
*
* @author L.cm
*/
@Configuration
@AllArgsConstructor
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
public class MicaUploadConfigurtion implements WebFluxConfigurer {
private final MicaUploadProperties properties;
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
String path = properties.getSavePath();
registry.addResourceHandler(properties.getUploadPathPattern())
.addResourceLocations("file:" + path + "/upload/");
}
}
/*
* Copyright (c) 2019-2029, Dreamlu 卢春梦 (596392912@qq.com & www.dreamlu.net).
* <p>
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.dreamlu.mica.reactive.config;
import net.dreamlu.mica.reactive.version.MicaRequestMappingHandlerMapping;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.web.reactive.WebFluxRegistrations;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.result.method.annotation.RequestMappingHandlerMapping;
/**
* webflux 配置 注入
*
* @author L.cm
*/
@Configuration
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
public class MicaWebFluxRegistrations implements WebFluxRegistrations {
@Override
public RequestMappingHandlerMapping getRequestMappingHandlerMapping() {
return new MicaRequestMappingHandlerMapping();
}
}
/*
* Copyright (c) 2019-2029, Dreamlu 卢春梦 (596392912@qq.com & www.dreamlu.net).
* <p>
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@NonNullApi
@NonNullFields
package net.dreamlu.mica.reactive.config;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.NonNullFields;
/*
* Copyright (c) 2019-2029, Dreamlu 卢春梦 (596392912@qq.com & www.dreamlu.net).
* <p>
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.dreamlu.mica.reactive.error;
import lombok.RequiredArgsConstructor;
import net.dreamlu.mica.servlet.error.MicaErrorAttributes;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.web.ResourceProperties;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.autoconfigure.web.reactive.error.ErrorWebFluxAutoConfiguration;
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.result.view.ViewResolver;
import java.util.List;
/**
* ExceptionTranslator 只支持控制器中的异常
*
* @see ErrorWebFluxAutoConfiguration
* @author L.cm
*/
@Configuration
@RequiredArgsConstructor
@AutoConfigureBefore(ErrorWebFluxAutoConfiguration.class)
@EnableConfigurationProperties({ ServerProperties.class, ResourceProperties.class })
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
public class MicaErrorAutoConfiguration {
private final ServerProperties serverProperties;
private final ApplicationContext applicationContext;
private final ResourceProperties resourceProperties;
private final ServerCodecConfigurer serverCodecConfigurer;
@Bean
@Order(-1)
public ErrorWebExceptionHandler errorWebExceptionHandler(ErrorAttributes errorAttributes) {
MicaErrorWebExceptionHandler exceptionHandler = new MicaErrorWebExceptionHandler(
errorAttributes, this.resourceProperties, this.serverProperties.getError(), this.applicationContext);
exceptionHandler.setMessageWriters(this.serverCodecConfigurer.getWriters());
exceptionHandler.setMessageReaders(this.serverCodecConfigurer.getReaders());
return exceptionHandler;
}
}
/*
* Copyright (c) 2019-2029, Dreamlu 卢春梦 (596392912@qq.com & www.dreamlu.net).
* <p>
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.dreamlu.mica.reactive.error;
import lombok.extern.slf4j.Slf4j;
import net.dreamlu.mica.core.result.R;
import net.dreamlu.mica.core.result.SystemCode;
import net.dreamlu.mica.core.utils.BeanUtil;
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.core.annotation.AnnotatedElementUtils;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.support.WebExchangeBindException;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.server.*;
import org.springframework.web.server.ResponseStatusException;
import reactor.core.publisher.Mono;
import java.util.Map;
/**
* webflux 异常处理
*
* @author L.cm
*/
@Slf4j
public class MicaErrorWebExceptionHandler extends DefaultErrorWebExceptionHandler {
public MicaErrorWebExceptionHandler(ErrorAttributes attributes, ResourceProperties properties,
ErrorProperties errorProperties, ApplicationContext applicationContext) {
super(attributes, properties, errorProperties, applicationContext);
}
@Override
protected RouterFunction<ServerResponse> getRoutingFunction(ErrorAttributes errorAttributes) {
return RouterFunctions.route(RequestPredicates.all(), this::renderErrorResponse);
}
/**
* Render the error information as a JSON payload.
* @param request the current request
* @return a {@code Publisher} of the HTTP response
*/
@Override
protected Mono<ServerResponse> renderErrorResponse(ServerRequest request) {
Throwable error = this.getError(request);
HttpStatus status = determineHttpStatus(error);
// 返回消息
String message = status.value() + ":" + status.getReasonPhrase();
R<Object> result = R.fail(SystemCode.FAILURE, message);
return ServerResponse.status(status)
.contentType(MediaType.APPLICATION_JSON_UTF8)
.body(BodyInserters.fromObject(result));
}
private HttpStatus determineHttpStatus(Throwable error) {
if (error instanceof ResponseStatusException) {
return ((ResponseStatusException)error).getStatus();
} else {
ResponseStatus responseStatus = AnnotatedElementUtils.findMergedAnnotation(error.getClass(), ResponseStatus.class);
return responseStatus != null ? responseStatus.code() : HttpStatus.INTERNAL_SERVER_ERROR;
}
}
}
package net.dreamlu.mica.reactive.error;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import net.dreamlu.mica.core.exception.ServiceException;
import net.dreamlu.mica.core.result.R;
import net.dreamlu.mica.core.result.SystemCode;
import net.dreamlu.mica.core.utils.Exceptions;
import net.dreamlu.mica.core.utils.ObjectUtil;
import net.dreamlu.mica.reactive.filter.ReactiveRequestContextHolder;
import net.dreamlu.mica.common.error.MicaErrorEvent;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import reactor.core.publisher.Mono;
import java.time.LocalDateTime;
/**
* mica 未知异常转译和发送,方便监听,对未知异常统一处理。Order 排序优先级低
*
* @author L.cm
*/
@Slf4j
@Order
@Configuration
@RestControllerAdvice
@AllArgsConstructor
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
public class MicaExceptionTranslator {
private final ApplicationEventPublisher publisher;
@ExceptionHandler(ServiceException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Mono<R<Object>> handleError(ServiceException e) {
log.error("业务异常", e);
R<Object> result = e.getResult();
if (result != null) {
return Mono.just(result);
}
// 发送:未知异常异常事件
return ReactiveRequestContextHolder.getRequest()
.doOnSuccess(r -> publishEvent(r, e))
.flatMap(r -> Mono.just(R.fail(SystemCode.FAILURE, e.getMessage())));
}
@ExceptionHandler(Throwable.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Mono<?> handleError(Throwable e) {
log.error("未知异常", e);
// 发送:未知异常异常事件
return ReactiveRequestContextHolder.getRequest()
.doOnSuccess(r -> publishEvent(r, e))
.flatMap(r -> Mono.just(R.fail(SystemCode.FAILURE)));
}
private void publishEvent(ServerHttpRequest request, Throwable error) {
String requestUrl = request.getPath().pathWithinApplication().value();
MicaErrorEvent event = new MicaErrorEvent();
event.setRequestUrl(requestUrl);
event.setStackTrace(Exceptions.getStackTraceAsString(error));
event.setExceptionName(error.getClass().getName());
event.setMessage(error.getMessage());
event.setCreatedAt(LocalDateTime.now());
StackTraceElement[] elements = error.getStackTrace();
if (ObjectUtil.isNotEmpty(elements)) {
StackTraceElement element = elements[0];
event.setClassName(element.getClassName());
event.setFileName(element.getFileName());
event.setMethodName(element.getMethodName());
event.setLineNumber(element.getLineNumber());
}
// 发布事件
publisher.publishEvent(event);
}
}
/*
* Copyright (c) 2019-2029, Dreamlu 卢春梦 (596392912@qq.com & www.dreamlu.net).
* <p>
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.dreamlu.mica.reactive.error;
import lombok.extern.slf4j.Slf4j;
import net.dreamlu.mica.common.error.BaseExceptionTranslator;
import net.dreamlu.mica.core.result.R;
import net.dreamlu.mica.core.result.SystemCode;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.MethodParameter;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.BindException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.bind.support.WebExchangeBindException;
import org.springframework.web.server.ResponseStatusException;
import org.springframework.web.server.ServerWebInputException;
import reactor.core.publisher.Mono;
import javax.validation.ConstraintViolationException;
/**
* 异常信息处理
*/
@Slf4j
@Order(Ordered.HIGHEST_PRECEDENCE)
@Configuration
@RestControllerAdvice
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
public class RestExceptionTranslator extends BaseExceptionTranslator {
@ExceptionHandler(ServerWebInputException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public Mono<R<Object>> handleError(ServerWebInputException e) {
log.error("缺少请求参数:{}", e.getMessage());
MethodParameter parameter = e.getMethodParameter();
String message = String.format("缺少必要的请求参数: %s", parameter.getParameterName());
return Mono.just(R.fail(SystemCode.PARAM_MISS, message));
}
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public Mono<R<Object>> handleError(MethodArgumentNotValidException e) {
log.error("参数验证失败:{}", e.getMessage());
return Mono.just(handleError(e.getBindingResult()));
}
@ExceptionHandler(BindException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public Mono<R<Object>> handleError(BindException e) {
log.error("参数绑定失败:{}", e.getMessage());
return Mono.just(handleError(e.getBindingResult()));
}
@ExceptionHandler(WebExchangeBindException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public Mono<R<Object>> handleError(WebExchangeBindException e) {
log.error("参数绑定失败:{}", e.getMessage());
return Mono.just(handleError(e.getBindingResult()));
}
@ExceptionHandler(ConstraintViolationException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public Mono<R<Object>> handleError(ConstraintViolationException e) {
log.error("参数验证失败:{}", e.getMessage());
return Mono.just(handleError(e.getConstraintViolations()));
}
@ExceptionHandler(ResponseStatusException.class)
public Mono<ResponseEntity<R<Object>>> handleError(ResponseStatusException e) {
log.error("响应状态异常:{}", e.getMessage());
ResponseEntity<R<Object>> entity = ResponseEntity.status(e.getStatus())
.body(R.fail(SystemCode.REQ_REJECT, e.getMessage()));
return Mono.just(entity);
}
}
......@@ -16,7 +16,7 @@
@NonNullApi
@NonNullFields
package net.dreamlu.mica.support;
package net.dreamlu.mica.reactive.error;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.NonNullFields;
/*
* Copyright (c) 2019-2029, Dreamlu 卢春梦 (596392912@qq.com & www.dreamlu.net).
* <p>
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.dreamlu.mica.reactive.filter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;
/**
* ReactiveRequestContextFilter
*
* @author L.cm
*/
@Configuration
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
public class ReactiveRequestContextFilter implements WebFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
return chain.filter(exchange).subscriberContext(ctx -> ctx.put(ReactiveRequestContextHolder.CONTEXT_KEY, request));
}
}
/*
* Copyright (c) 2019-2029, Dreamlu 卢春梦 (596392912@qq.com & www.dreamlu.net).
* <p>
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.dreamlu.mica.reactive.filter;
import org.springframework.http.server.reactive.ServerHttpRequest;
import reactor.core.publisher.Mono;
import reactor.util.context.Context;
/**
* ReactiveRequestContextHolder
*
* @author L.cm
*/
public class ReactiveRequestContextHolder {
static final Class<?> CONTEXT_KEY = ServerHttpRequest.class;
/**
* Gets the {@code Mono<ServerHttpRequest>} from Reactor {@link Context}
* @return the {@code Mono<ServerHttpRequest>}
*/
public static Mono<ServerHttpRequest> getRequest() {
return Mono.subscriberContext()
.map(ctx -> ctx.get(CONTEXT_KEY))
.cast(ServerHttpRequest.class);
}
}
/*
* Copyright (c) 2019-2029, Dreamlu 卢春梦 (596392912@qq.com & www.dreamlu.net).
* <p>
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@NonNullApi
@NonNullFields
package net.dreamlu.mica.reactive.filter;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.NonNullFields;
/*
* Copyright (c) 2019-2029, Dreamlu 卢春梦 (596392912@qq.com & www.dreamlu.net).
* <p>
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.dreamlu.mica.reactive.version;
import net.dreamlu.mica.annotation.ApiVersion;
import net.dreamlu.mica.annotation.UrlVersion;
import net.dreamlu.mica.common.version.MicaMediaType;
import net.dreamlu.mica.core.utils.StringPool;
import net.dreamlu.mica.core.utils.StringUtil;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.lang.Nullable;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.reactive.result.method.RequestMappingInfo;
import org.springframework.web.reactive.result.method.annotation.RequestMappingHandlerMapping;
import java.lang.reflect.Method;
import java.util.Map;
/**
* url版本号处理
*
* @author L.cm
*/
public class MicaRequestMappingHandlerMapping extends RequestMappingHandlerMapping {
@Override
protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
RequestMappingInfo mappinginfo = super.getMappingForMethod(method, handlerType);
if (mappinginfo != null) {
RequestMappingInfo apiVersionMappingInfo = getApiVersionMappingInfo(method, handlerType);
return apiVersionMappingInfo == null ? mappinginfo : apiVersionMappingInfo.combine(mappinginfo);
}
return mappinginfo;
}
@Nullable
private RequestMappingInfo getApiVersionMappingInfo(Method method, Class<?> handlerType) {
// url 上的版本,优先获取方法上的版本
UrlVersion urlVersion = AnnotatedElementUtils.findMergedAnnotation(method, UrlVersion.class);
// 再次尝试类上的版本
if (urlVersion == null || StringUtil.isBlank(urlVersion.value())) {
urlVersion = AnnotatedElementUtils.findMergedAnnotation(handlerType, UrlVersion.class);
}
// Media Types 版本信息
ApiVersion apiVersion = AnnotatedElementUtils.findMergedAnnotation(method, ApiVersion.class);
// 再次尝试类上的版本
if (apiVersion == null || StringUtil.isBlank(apiVersion.value())) {
apiVersion = AnnotatedElementUtils.findMergedAnnotation(handlerType, ApiVersion.class);
}
boolean nonUrlVersion = urlVersion == null || StringUtil.isBlank(urlVersion.value());
boolean nonApiVersion = apiVersion == null || StringUtil.isBlank(apiVersion.value());
// 先判断同时不纯在
if (nonUrlVersion && nonApiVersion) {
return null;
}
// 如果 header 版本不存在
RequestMappingInfo.Builder mappingInfoBuilder;
if (nonApiVersion) {
mappingInfoBuilder = RequestMappingInfo.paths(urlVersion.value());
} else {
mappingInfoBuilder = RequestMappingInfo.paths(StringPool.EMPTY);
}
// 如果url版本不存在
if (nonUrlVersion) {
String vsersionMediaTypes = new MicaMediaType(apiVersion.value()).toString();
mappingInfoBuilder.produces(vsersionMediaTypes);
}
return mappingInfoBuilder.build();
}
@Override
protected void handlerMethodsInitialized(Map<RequestMappingInfo, HandlerMethod> handlerMethods) {
// 打印路由信息 spring boot 2.1 去掉了这个 日志的打印
if (logger.isInfoEnabled()) {
for (Map.Entry<RequestMappingInfo, HandlerMethod> entry : handlerMethods.entrySet()) {
RequestMappingInfo mapping = entry.getKey();
HandlerMethod handlerMethod = entry.getValue();
logger.info("Mapped \"" + mapping + "\" onto " + handlerMethod);
}
}
super.handlerMethodsInitialized(handlerMethods);
}
}
/*
* Copyright (c) 2019-2029, Dreamlu 卢春梦 (596392912@qq.com & www.dreamlu.net).
* <p>
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@NonNullApi
@NonNullFields
package net.dreamlu.mica.reactive.version;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.NonNullFields;
......@@ -14,10 +14,11 @@
* limitations under the License.
*/
package net.dreamlu.mica.config;
package net.dreamlu.mica.servlet.config;
import net.dreamlu.mica.core.convert.EnumToStringConverter;
import net.dreamlu.mica.core.convert.StringToEnumConverter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.context.annotation.Configuration;
import org.springframework.format.FormatterRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
......@@ -28,6 +29,7 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
* @author L.cm
*/
@Configuration
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
public class MicaConverterConfiguration implements WebMvcConfigurer {
@Override
......
......@@ -14,12 +14,13 @@
* limitations under the License.
*/
package net.dreamlu.mica.config;
package net.dreamlu.mica.servlet.config;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.AllArgsConstructor;
import net.dreamlu.mica.core.jackson.MappingApiJackson2HttpMessageConverter;
import net.dreamlu.mica.props.MicaJacksonProperties;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.*;
import org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter;
......@@ -36,6 +37,7 @@ import java.util.List;
*/
@Configuration
@AllArgsConstructor
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
public class MicaMessageConfiguration implements WebMvcConfigurer {
private final MicaJacksonProperties properties;
private final ObjectMapper objectMapper;
......
......@@ -14,10 +14,11 @@
* limitations under the License.
*/
package net.dreamlu.mica.config;
package net.dreamlu.mica.servlet.config;
import lombok.AllArgsConstructor;
import net.dreamlu.mica.props.MicaUploadProperties;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
......@@ -29,6 +30,7 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
*/
@Configuration
@AllArgsConstructor
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
public class MicaUploadConfigurtion implements WebMvcConfigurer {
private final MicaUploadProperties properties;
......
......@@ -14,11 +14,12 @@
* limitations under the License.
*/
package net.dreamlu.mica.version;
package net.dreamlu.mica.servlet.config;
import net.dreamlu.mica.servlet.version.MicaRequestMappingHandlerMapping;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.web.servlet.WebMvcRegistrations;
import org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
/**
......@@ -26,19 +27,13 @@ import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandl
*
* @author L.cm
*/
@Configuration
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
public class MicaWebMvcRegistrations implements WebMvcRegistrations {
@Override
public RequestMappingHandlerMapping getRequestMappingHandlerMapping() {
return new MicaRequestMappingHandlerMapping();
}
@Override
public RequestMappingHandlerAdapter getRequestMappingHandlerAdapter() {
return null;
}
@Override
public ExceptionHandlerExceptionResolver getExceptionHandlerExceptionResolver() {
return null;
}
}
/*
* Copyright (c) 2019-2029, Dreamlu 卢春梦 (596392912@qq.com & www.dreamlu.net).
* <p>
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@NonNullApi
@NonNullFields
package net.dreamlu.mica.servlet.config;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.NonNullFields;
......@@ -14,7 +14,7 @@
* limitations under the License.
*/
package net.dreamlu.mica.error;
package net.dreamlu.mica.servlet.error;
import lombok.extern.slf4j.Slf4j;
import net.dreamlu.mica.core.result.R;
......
......@@ -14,7 +14,7 @@
* limitations under the License.
*/
package net.dreamlu.mica.error;
package net.dreamlu.mica.servlet.error;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.AllArgsConstructor;
......@@ -41,10 +41,10 @@ import javax.servlet.Servlet;
* @author L.cm
*/
@Configuration
@ConditionalOnWebApplication
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class })
@AutoConfigureBefore(ErrorMvcAutoConfiguration.class)
@AllArgsConstructor
@AutoConfigureBefore(ErrorMvcAutoConfiguration.class)
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class })
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
public class MicaErrorAutoConfiguration {
private final ServerProperties serverProperties;
private final ObjectMapper objectMapper;
......
......@@ -14,7 +14,7 @@
* limitations under the License.
*/
package net.dreamlu.mica.error;
package net.dreamlu.mica.servlet.error;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.boot.autoconfigure.web.ErrorProperties;
......
package net.dreamlu.mica.error;
package net.dreamlu.mica.servlet.error;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import net.dreamlu.mica.common.error.MicaErrorEvent;
import net.dreamlu.mica.core.exception.ServiceException;
import net.dreamlu.mica.core.result.R;
import net.dreamlu.mica.core.result.SystemCode;
......@@ -31,18 +32,18 @@ import java.time.LocalDateTime;
@Slf4j
@Order
@Configuration
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class })
@RestControllerAdvice
@AllArgsConstructor
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class })
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
public class MicaExceptionTranslator {
private final ApplicationEventPublisher publisher;
@ExceptionHandler(ServiceException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public R handleError(ServiceException e) {
public R<Object> handleError(ServiceException e) {
log.error("业务异常", e);
R result = e.getResult();
R<Object> result = e.getResult();
if (result == null) {
// 发送:未知业务异常事件
result = R.fail(SystemCode.FAILURE, e.getMessage());
......@@ -53,7 +54,7 @@ public class MicaExceptionTranslator {
@ExceptionHandler(Throwable.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public R handleError(Throwable e) {
public R<Object> handleError(Throwable e) {
log.error("未知异常", e);
// 发送:未知异常异常事件
publishEvent(e);
......@@ -61,9 +62,10 @@ public class MicaExceptionTranslator {
}
private void publishEvent(Throwable error) {
HttpServletRequest request = WebUtil.getRequest();
MicaErrorEvent event = new MicaErrorEvent();
event.setRequestUrl(request.getRequestURI());
HttpServletRequest request = WebUtil.getRequest();
String requestUrl = request.getRequestURI() + "?" + request.getQueryString();
event.setRequestUrl(requestUrl);
event.setStackTrace(Exceptions.getStackTraceAsString(error));
event.setExceptionName(error.getClass().getName());
event.setMessage(error.getMessage());
......
......@@ -14,14 +14,13 @@
* limitations under the License.
*/
package net.dreamlu.mica.error;
package net.dreamlu.mica.servlet.error;
import lombok.extern.slf4j.Slf4j;
import net.dreamlu.mica.common.error.BaseExceptionTranslator;
import net.dreamlu.mica.core.result.R;
import net.dreamlu.mica.core.result.SystemCode;
import net.dreamlu.mica.core.utils.StringUtil;
import org.hibernate.validator.internal.engine.path.PathImpl;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
......@@ -29,8 +28,6 @@ import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
......@@ -40,13 +37,9 @@ import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.NoHandlerFoundException;
import javax.servlet.Servlet;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.Set;
/**
* 全局异常处理,处理可预见的异常,Order 排序优先级高
......@@ -60,89 +53,78 @@ import java.util.Set;
@Slf4j
@Order(Ordered.HIGHEST_PRECEDENCE)
@Configuration
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class })
@RestControllerAdvice
public class RestExceptionTranslator {
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
public class RestExceptionTranslator extends BaseExceptionTranslator {
@ExceptionHandler(MissingServletRequestParameterException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public R handleError(MissingServletRequestParameterException e) {
log.warn("缺少请求参数", e.getMessage());
public R<Object> handleError(MissingServletRequestParameterException e) {
log.warn("缺少请求参数:{}", e.getMessage());
String message = String.format("缺少必要的请求参数: %s", e.getParameterName());
return R.fail(SystemCode.PARAM_MISS, message);
}
@ExceptionHandler(MethodArgumentTypeMismatchException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public R handleError(MethodArgumentTypeMismatchException e) {
log.warn("请求参数格式错误", e.getMessage());
public R<Object> handleError(MethodArgumentTypeMismatchException e) {
log.warn("请求参数格式错误:{}", e.getMessage());
String message = String.format("请求参数格式错误: %s", e.getName());
return R.fail(SystemCode.PARAM_TYPE_ERROR, message);
}
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public R handleError(MethodArgumentNotValidException e) {
log.warn("参数验证失败", e.getMessage());
public R<Object> handleError(MethodArgumentNotValidException e) {
log.warn("参数验证失败:{}", e.getMessage());
return handleError(e.getBindingResult());
}
@ExceptionHandler(BindException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public R handleError(BindException e) {
log.warn("参数绑定失败", e.getMessage());
public R<Object> handleError(BindException e) {
log.warn("参数绑定失败:{}", e.getMessage());
return handleError(e.getBindingResult());
}
private R handleError(BindingResult result) {
FieldError error = result.getFieldError();
String message = String.format("%s:%s", error.getField(), error.getDefaultMessage());
return R.fail(SystemCode.PARAM_BIND_ERROR, message);
}
@ExceptionHandler(ConstraintViolationException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public R handleError(ConstraintViolationException e) {
log.warn("参数验证失败", e.getLocalizedMessage());
Set<ConstraintViolation<?>> violations = e.getConstraintViolations();
ConstraintViolation<?> violation = violations.iterator().next();
String path = ((PathImpl) violation.getPropertyPath()).getLeafNode().getName();
String message = String.format("%s:%s", path, violation.getMessage());
return R.fail(SystemCode.PARAM_VALID_ERROR, message);
public R<Object> handleError(ConstraintViolationException e) {
log.warn("参数验证失败:{}", e.getMessage());
return handleError(e.getConstraintViolations());
}
@ExceptionHandler(NoHandlerFoundException.class)
@ResponseStatus(HttpStatus.NOT_FOUND)
public R handleError(NoHandlerFoundException e) {
public R<Object> handleError(NoHandlerFoundException e) {
log.error("404没找到请求:{}", e.getMessage());
return R.fail(SystemCode.NOT_FOUND, e.getMessage());
}
@ExceptionHandler(HttpMessageNotReadableException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public R handleError(HttpMessageNotReadableException e) {
public R<Object> handleError(HttpMessageNotReadableException e) {
log.error("消息不能读取:{}", e.getMessage());
return R.fail(SystemCode.MSG_NOT_READABLE, e.getMessage());
}
@ExceptionHandler(HttpRequestMethodNotSupportedException.class)
@ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED)
public R handleError(HttpRequestMethodNotSupportedException e) {
public R<Object> handleError(HttpRequestMethodNotSupportedException e) {
log.error("不支持当前请求方法:{}", e.getMessage());
return R.fail(SystemCode.METHOD_NOT_SUPPORTED, e.getMessage());
}
@ExceptionHandler(HttpMediaTypeNotSupportedException.class)
@ResponseStatus(HttpStatus.UNSUPPORTED_MEDIA_TYPE)
public R handleError(HttpMediaTypeNotSupportedException e) {
public R<Object> handleError(HttpMediaTypeNotSupportedException e) {
log.error("不支持当前媒体类型:{}", e.getMessage());
return R.fail(SystemCode.MEDIA_TYPE_NOT_SUPPORTED, e.getMessage());
}
@ExceptionHandler(HttpMediaTypeNotAcceptableException.class)
@ResponseStatus(HttpStatus.UNSUPPORTED_MEDIA_TYPE)
public R handleError(HttpMediaTypeNotAcceptableException e) {
public R<Object> handleError(HttpMediaTypeNotAcceptableException e) {
String message = e.getMessage() + " " + StringUtil.join(e.getSupportedMediaTypes());
log.error("不接受的媒体类型:{}", message);
return R.fail(SystemCode.MEDIA_TYPE_NOT_SUPPORTED, message);
......
......@@ -16,7 +16,7 @@
@NonNullApi
@NonNullFields
package net.dreamlu.mica.async;
package net.dreamlu.mica.servlet.error;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.NonNullFields;
......@@ -14,7 +14,7 @@
* limitations under the License.
*/
package net.dreamlu.mica.support;
package net.dreamlu.mica.servlet.support;
import net.dreamlu.mica.core.result.IResultCode;
import net.dreamlu.mica.core.result.R;
......
/*
* Copyright (c) 2019-2029, Dreamlu 卢春梦 (596392912@qq.com & www.dreamlu.net).
* <p>
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@NonNullApi
@NonNullFields
package net.dreamlu.mica.servlet.support;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.NonNullFields;
......@@ -14,10 +14,11 @@
* limitations under the License.
*/
package net.dreamlu.mica.version;
package net.dreamlu.mica.servlet.version;
import net.dreamlu.mica.annotation.ApiVersion;
import net.dreamlu.mica.annotation.UrlVersion;
import net.dreamlu.mica.common.version.MicaMediaType;
import net.dreamlu.mica.core.utils.StringPool;
import net.dreamlu.mica.core.utils.StringUtil;
import org.springframework.core.annotation.AnnotatedElementUtils;
......@@ -75,7 +76,7 @@ public class MicaRequestMappingHandlerMapping extends RequestMappingHandlerMappi
return null;
}
// 如果 header 版本不存在
RequestMappingInfo.Builder mappingInfoBuilder = null;
RequestMappingInfo.Builder mappingInfoBuilder;
if (nonApiVersion) {
mappingInfoBuilder = RequestMappingInfo.paths(urlVersion.value());
} else {
......
/*
* Copyright (c) 2019-2029, Dreamlu 卢春梦 (596392912@qq.com & www.dreamlu.net).
* <p>
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@NonNullApi
@NonNullFields
package net.dreamlu.mica.servlet.version;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.NonNullFields;
......@@ -32,9 +32,9 @@ public class ServiceException extends RuntimeException {
@Getter
@Nullable
private final R result;
private final R<Object> result;
public ServiceException(R result) {
public ServiceException(R<Object> result) {
super(result.getMsg());
this.result = result;
}
......
......@@ -153,7 +153,7 @@ public class NumberUtil extends org.springframework.util.NumberUtils {
i = i / radix;
}
buf[charPos] = DIGITS[(int)(-i)];
return new String(buf, charPos, (65 - charPos));
return new String(buf, charPos, (65 - charPos), Charsets.UTF_8);
}
}
......@@ -322,7 +322,7 @@ public class StringUtil extends org.springframework.util.StringUtils {
formatUnsignedLong0(msb, buf, 12, 4);
formatUnsignedLong0(msb >>> 16, buf, 8, 4);
formatUnsignedLong0(msb >>> 32, buf, 0, 8);
return new String(buf);
return new String(buf, Charsets.UTF_8);
}
private static void formatUnsignedLong0(long val, byte[] buf, int offset, int len) {
......
......@@ -99,7 +99,7 @@ public class MicaApplication {
props.setProperty("mica.env", profile);
props.setProperty("mica.is-local", String.valueOf(isLocalDev));
props.setProperty("spring.application.name", appName);
props.setProperty("spring.banner.location", "classpath:mica_banner.txt");
props.setProperty("spring.banner.location", "classpath:banner.txt");
// 加载自定义组件
ServiceLoader<LauncherService> loader = ServiceLoader.load(LauncherService.class);
// 启动组件
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册