mirror of
https://gitee.com/yudaocode/SpringBoot-Labs.git
synced 2026-09-03 05:53:54 +08:00
spring webflux 实现全局统一返回
This commit is contained in:
32
lab-27/lab-27-webflux-02/pom.xml
Normal file
32
lab-27/lab-27-webflux-02/pom.xml
Normal file
@@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>2.2.1.RELEASE</version>
|
||||
<relativePath/> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>lab-27-webflux-02</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<!-- 实现对 Spring WebFlux 的自动化配置 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-webflux</artifactId>
|
||||
<version>2.2.1.RELEASE</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 方便等会写单元测试 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,29 @@
|
||||
package cn.iocoder.springboot.lab27.springwebflux;
|
||||
|
||||
import cn.iocoder.springboot.lab27.springwebflux.core.web.GlobalResponseBodyHandler;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.http.codec.ServerCodecConfigurer;
|
||||
import org.springframework.web.reactive.accept.RequestedContentTypeResolver;
|
||||
|
||||
@SpringBootApplication
|
||||
public class Application {
|
||||
|
||||
@Autowired
|
||||
ServerCodecConfigurer serverCodecConfigurer;
|
||||
@Autowired
|
||||
RequestedContentTypeResolver requestedContentTypeResolver;
|
||||
|
||||
@Bean
|
||||
public GlobalResponseBodyHandler responseWrapper() {
|
||||
return new GlobalResponseBodyHandler(serverCodecConfigurer
|
||||
.getWriters(), requestedContentTypeResolver);
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(Application.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
package cn.iocoder.springboot.lab27.springwebflux.controller;
|
||||
|
||||
import cn.iocoder.springboot.lab27.springwebflux.core.vo.CommonResult;
|
||||
import cn.iocoder.springboot.lab27.springwebflux.vo.UserVO;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 用户 Controller
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/users")
|
||||
public class UserController {
|
||||
|
||||
/**
|
||||
* 查询用户列表
|
||||
*
|
||||
* @return 用户列表
|
||||
*/
|
||||
@GetMapping("/list")
|
||||
public Flux<UserVO> list() {
|
||||
// 查询列表
|
||||
List<UserVO> result = new ArrayList<>();
|
||||
result.add(new UserVO().setId(1).setUsername("yudaoyuanma"));
|
||||
result.add(new UserVO().setId(2).setUsername("woshiyutou"));
|
||||
result.add(new UserVO().setId(3).setUsername("chifanshuijiao"));
|
||||
// 返回列表
|
||||
return Flux.fromIterable(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得指定用户编号的用户
|
||||
*
|
||||
* @param id 用户编号
|
||||
* @return 用户
|
||||
*/
|
||||
@GetMapping("/get")
|
||||
public Mono<UserVO> get(@RequestParam("id") Integer id) {
|
||||
// 查询用户
|
||||
UserVO user = new UserVO().setId(id).setUsername("username:" + id);
|
||||
// 返回
|
||||
return Mono.just(user);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得指定用户编号的用户
|
||||
*
|
||||
* @param id 用户编号
|
||||
* @return 用户
|
||||
*/
|
||||
@GetMapping("/get2")
|
||||
public Mono<CommonResult<UserVO>> get2(@RequestParam("id") Integer id) {
|
||||
// 查询用户
|
||||
UserVO user = new UserVO().setId(id).setUsername("username:" + id);
|
||||
// 返回
|
||||
return Mono.just(CommonResult.success(user));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得指定用户编号的用户
|
||||
*
|
||||
* @param id 用户编号
|
||||
* @return 用户
|
||||
*/
|
||||
@GetMapping("/get3")
|
||||
public UserVO get3(@RequestParam("id") Integer id) {
|
||||
// 查询用户
|
||||
UserVO user = new UserVO().setId(id).setUsername("username:" + id);
|
||||
// 返回
|
||||
return user;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得指定用户编号的用户
|
||||
*
|
||||
* @param id 用户编号
|
||||
* @return 用户
|
||||
*/
|
||||
@GetMapping("/get4")
|
||||
public CommonResult<UserVO> get4(@RequestParam("id") Integer id) {
|
||||
// 查询用户
|
||||
UserVO user = new UserVO().setId(id).setUsername("username:" + id);
|
||||
// 返回
|
||||
return CommonResult.success(user);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package cn.iocoder.springboot.lab27.springwebflux.controller;
|
||||
|
||||
import cn.iocoder.springboot.lab27.springwebflux.vo.UserVO;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.reactive.function.server.*;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import static org.springframework.web.reactive.function.server.RequestPredicates.*;
|
||||
import static org.springframework.web.reactive.function.server.RouterFunctions.*;
|
||||
import static org.springframework.web.reactive.function.server.ServerResponse.*;
|
||||
|
||||
/**
|
||||
* 用户 Router
|
||||
*/
|
||||
@Configuration
|
||||
public class UserRouter {
|
||||
|
||||
@Bean
|
||||
public RouterFunction<ServerResponse> userListRouterFunction() {
|
||||
return RouterFunctions.route(RequestPredicates.GET("/users2/list"),
|
||||
new HandlerFunction<ServerResponse>() {
|
||||
|
||||
@Override
|
||||
public Mono<ServerResponse> handle(ServerRequest request) {
|
||||
// 查询列表
|
||||
List<UserVO> result = new ArrayList<>();
|
||||
result.add(new UserVO().setId(1).setUsername("yudaoyuanma"));
|
||||
result.add(new UserVO().setId(2).setUsername("woshiyutou"));
|
||||
result.add(new UserVO().setId(3).setUsername("chifanshuijiao"));
|
||||
// 返回列表
|
||||
return ServerResponse.ok().bodyValue(result);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
@Bean
|
||||
public RouterFunction<ServerResponse> userGetRouterFunction() {
|
||||
return RouterFunctions.route(RequestPredicates.GET("/users2/get"),
|
||||
new HandlerFunction<ServerResponse>() {
|
||||
|
||||
@Override
|
||||
public Mono<ServerResponse> handle(ServerRequest request) {
|
||||
// 获得编号
|
||||
Integer id = request.queryParam("id")
|
||||
.map(s -> StringUtils.isEmpty(s) ? null : Integer.valueOf(s)).get();
|
||||
// 查询用户
|
||||
UserVO user = new UserVO().setId(id).setUsername(UUID.randomUUID().toString());
|
||||
// 返回列表
|
||||
return ServerResponse.ok().bodyValue(user);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
@Bean
|
||||
public RouterFunction<ServerResponse> demoRouterFunction() {
|
||||
return route(GET("/users2/demo"), request -> ok().bodyValue("demo"));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* 提供核心封装
|
||||
*/
|
||||
package cn.iocoder.springboot.lab27.springwebflux.core;
|
||||
@@ -0,0 +1,102 @@
|
||||
package cn.iocoder.springboot.lab27.springwebflux.core.vo;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 通用返回结果
|
||||
*
|
||||
* @param <T> 结果泛型
|
||||
*/
|
||||
public class CommonResult<T> implements Serializable {
|
||||
|
||||
public static Integer CODE_SUCCESS = 0;
|
||||
|
||||
/**
|
||||
* 错误码
|
||||
*/
|
||||
private Integer code;
|
||||
/**
|
||||
* 错误提示
|
||||
*/
|
||||
private String message;
|
||||
/**
|
||||
* 返回数据
|
||||
*/
|
||||
private T data;
|
||||
|
||||
/**
|
||||
* 将传入的 result 对象,转换成另外一个泛型结果的对象
|
||||
*
|
||||
* 因为 A 方法返回的 CommonResult 对象,不满足调用其的 B 方法的返回,所以需要进行转换。
|
||||
*
|
||||
* @param result 传入的 result 对象
|
||||
* @param <T> 返回的泛型
|
||||
* @return 新的 CommonResult 对象
|
||||
*/
|
||||
public static <T> CommonResult<T> error(CommonResult<?> result) {
|
||||
return error(result.getCode(), result.getMessage());
|
||||
}
|
||||
|
||||
public static <T> CommonResult<T> error(Integer code, String message) {
|
||||
Assert.isTrue(!CODE_SUCCESS.equals(code), "code 必须是错误的!");
|
||||
CommonResult<T> result = new CommonResult<>();
|
||||
result.code = code;
|
||||
result.message = message;
|
||||
return result;
|
||||
}
|
||||
|
||||
public static <T> CommonResult<T> success(T data) {
|
||||
CommonResult<T> result = new CommonResult<>();
|
||||
result.code = CODE_SUCCESS;
|
||||
result.data = data;
|
||||
result.message = "";
|
||||
return result;
|
||||
}
|
||||
|
||||
public Integer getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public void setCode(Integer code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public void setMessage(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public T getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public void setData(T data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
public boolean isSuccess() {
|
||||
return CODE_SUCCESS.equals(code);
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
public boolean isError() {
|
||||
return !isSuccess();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "CommonResult{" +
|
||||
"code=" + code +
|
||||
", message='" + message + '\'' +
|
||||
", data=" + data +
|
||||
'}';
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package cn.iocoder.springboot.lab27.springwebflux.core.web;
|
||||
|
||||
import org.springframework.web.bind.annotation.ControllerAdvice;
|
||||
|
||||
@ControllerAdvice(basePackages = "cn.iocoder.springboot.lab23.springmvc.controller")
|
||||
public class GlobalExceptionHandler {
|
||||
|
||||
// private Logger logger = LoggerFactory.getLogger(getClass());
|
||||
//
|
||||
// /**
|
||||
// * 处理 ServiceException 异常
|
||||
// */
|
||||
// @ResponseBody
|
||||
// @ExceptionHandler(value = ServiceException.class)
|
||||
// public CommonResult serviceExceptionHandler(HttpServletRequest req, ServiceException ex) {
|
||||
// logger.debug("[serviceExceptionHandler]", ex);
|
||||
// // 包装 CommonResult 结果
|
||||
// return CommonResult.error(ex.getCode(), ex.getMessage());
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 处理 MissingServletRequestParameterException 异常
|
||||
// *
|
||||
// * SpringMVC 参数不正确
|
||||
// */
|
||||
// @ResponseBody
|
||||
// @ExceptionHandler(value = MissingServletRequestParameterException.class)
|
||||
// public CommonResult missingServletRequestParameterExceptionHandler(HttpServletRequest req, MissingServletRequestParameterException ex) {
|
||||
// logger.debug("[missingServletRequestParameterExceptionHandler]", ex);
|
||||
// // 包装 CommonResult 结果
|
||||
// return CommonResult.error(ServiceExceptionEnum.MISSING_REQUEST_PARAM_ERROR.getCode(),
|
||||
// ServiceExceptionEnum.MISSING_REQUEST_PARAM_ERROR.getMessage());
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 处理其它 Exception 异常
|
||||
// */
|
||||
// @ResponseBody
|
||||
// @ExceptionHandler(value = Exception.class)
|
||||
// public CommonResult exceptionHandler(HttpServletRequest req, Exception e) {
|
||||
// // 记录异常日志
|
||||
// logger.error("[exceptionHandler]", e);
|
||||
// // 返回 ERROR CommonResult
|
||||
// return CommonResult.error(ServiceExceptionEnum.SYS_ERROR.getCode(),
|
||||
// ServiceExceptionEnum.SYS_ERROR.getMessage());
|
||||
// }
|
||||
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package cn.iocoder.springboot.lab27.springwebflux.core.web;
|
||||
|
||||
import cn.iocoder.springboot.lab27.springwebflux.core.vo.CommonResult;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.core.ReactiveAdapterRegistry;
|
||||
import org.springframework.http.codec.HttpMessageWriter;
|
||||
import org.springframework.web.reactive.HandlerResult;
|
||||
import org.springframework.web.reactive.accept.RequestedContentTypeResolver;
|
||||
import org.springframework.web.reactive.result.method.annotation.ResponseBodyResultHandler;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class GlobalResponseBodyHandler extends ResponseBodyResultHandler {
|
||||
|
||||
private static Logger LOGGER = LoggerFactory.getLogger(GlobalResponseBodyHandler.class);
|
||||
|
||||
private static MethodParameter METHOD_PARAMETER_MONO_COMMON_RESULT;
|
||||
|
||||
private static final CommonResult COMMON_RESULT_SUCCESS = CommonResult.success(null);
|
||||
|
||||
static {
|
||||
try {
|
||||
// 获得 METHOD_PARAMETER_MONO_COMMON_RESULT 。其中 -1 表示 `#methodForParams()` 方法的返回值
|
||||
METHOD_PARAMETER_MONO_COMMON_RESULT = new MethodParameter(
|
||||
GlobalResponseBodyHandler.class.getDeclaredMethod("methodForParams"), -1);
|
||||
} catch (NoSuchMethodException e) {
|
||||
LOGGER.error("[static][获取 METHOD_PARAMETER_MONO_COMMON_RESULT 时,找不都方法");
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public GlobalResponseBodyHandler(List<HttpMessageWriter<?>> writers, RequestedContentTypeResolver resolver) {
|
||||
super(writers, resolver);
|
||||
}
|
||||
|
||||
public GlobalResponseBodyHandler(List<HttpMessageWriter<?>> writers, RequestedContentTypeResolver resolver, ReactiveAdapterRegistry registry) {
|
||||
super(writers, resolver, registry);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public Mono<Void> handleResult(ServerWebExchange exchange, HandlerResult result) {
|
||||
Object returnValue = result.getReturnValue();
|
||||
Object body = null;
|
||||
if (returnValue instanceof Mono) {
|
||||
body = ((Mono<Object>) result.getReturnValue())
|
||||
.map((Function<Object, Object>) GlobalResponseBodyHandler::wrapCommonResult)
|
||||
.defaultIfEmpty(COMMON_RESULT_SUCCESS);
|
||||
} else if (returnValue instanceof Flux) {
|
||||
body = ((Flux<Object>) result.getReturnValue())
|
||||
.collectList()
|
||||
.map((Function<Object, Object>) GlobalResponseBodyHandler::wrapCommonResult)
|
||||
.defaultIfEmpty(COMMON_RESULT_SUCCESS);
|
||||
} else {
|
||||
body = wrapCommonResult(returnValue);
|
||||
}
|
||||
return writeBody(body, METHOD_PARAMETER_MONO_COMMON_RESULT, exchange);
|
||||
}
|
||||
|
||||
private static Mono<CommonResult> methodForParams() {
|
||||
return null;
|
||||
}
|
||||
|
||||
private static CommonResult<?> wrapCommonResult(Object body) {
|
||||
// 如果已经是 CommonResult 类型,则直接返回
|
||||
if (body instanceof CommonResult) {
|
||||
return (CommonResult<?>) body;
|
||||
}
|
||||
// 如果不是,则包装成 CommonResult 类型
|
||||
return CommonResult.success(body);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package cn.iocoder.springboot.lab27.springwebflux.vo;
|
||||
|
||||
/**
|
||||
* 用户 VO
|
||||
*/
|
||||
public class UserVO {
|
||||
|
||||
/**
|
||||
* 编号
|
||||
*/
|
||||
private Integer id;
|
||||
/**
|
||||
* 账号
|
||||
*/
|
||||
private String username;
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public UserVO setId(Integer id) {
|
||||
this.id = id;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public UserVO setUsername(String username) {
|
||||
this.username = username;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
@@ -13,6 +13,7 @@
|
||||
<packaging>pom</packaging>
|
||||
<modules>
|
||||
<module>lab-27-webflux-01</module>
|
||||
<module>lab-27-webflux-02</module>
|
||||
</modules>
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user