|
1 |
| -# 异步 Controller |
| 1 | +# RespVo |
2 | 2 |
|
3 |
| -## 使用场景 |
| 3 | +## Introduction |
4 | 4 |
|
5 |
| -大文件上传及上传后进行语音识别的应用场景 |
| 5 | +为了方便开发者返回数据,tio-boot 提供了统一的数据返回类 RespVo |
| 6 | +`RespVo` 是一个用于构造和管理响应对象的工具类,它提供了一种标准化的方式来表示操作的结果(成功、失败或未知)、消息、数据和业务编码。这个类非常适合在后端服务中使用,尤其是在需要对前端返回标准化的响应结构时。 |
6 | 7 |
|
7 |
| -- 大文件上传: 企业员工上传完整的会议录音或录像文件 |
8 |
| -- 上传后进行语音识别: 对会议内容进行自动转写,生成会议纪要,便于后续查阅和分析讨论点 |
| 8 | +## RespVo 使用示例 |
9 | 9 |
|
10 |
| -如果上传完成后不采用异步任务对文件进行语音识别,可能会出现以下问题: |
| 10 | +```java |
| 11 | +import com.litongjava.tio.http.server.annotation.RequestPath; |
| 12 | +import com.litongjava.tio.utils.resp.RespVo; |
| 13 | + |
| 14 | +@RequestPath("/resp-vo") |
| 15 | +public class RespVoController { |
11 | 16 |
|
12 |
| -- 响应延迟: 语音识别是一个计算密集型的操作,特别是当处理大文件时。如果在同一请求中直接进行语音识别,服务器响应时间将大幅增加,导致用户体验变差。 |
13 |
| -- 超时错误: 许多 Web 服务器和 HTTP 客户端都有请求超时的限制。长时间的同步处理可能导致请求超时,从而使得语音识别任务失败。 |
14 |
| -- 资源占用: 大量的同步语音识别任务可能会占用大量服务器资源,包括 CPU 和内存,影响服务器处理其他请求的能力,降低整体服务的可用性和稳定性。 |
15 |
| -- 用户界面冻结: 对于基于 Web 的应用,如果在前端直接等待语音识别的结果,可能导致用户界面冻结,无法进行其他操作,影响用户体验。 |
| 17 | + public RespVo success() { |
| 18 | + return RespVo.ok("success"); |
| 19 | + } |
16 | 20 |
|
17 |
| -目前比较通用的做法是采用异步任务 |
| 21 | + public RespVo fail() { |
| 22 | + return RespVo.fail("fail"); |
| 23 | + } |
| 24 | +} |
| 25 | +``` |
18 | 26 |
|
19 |
| -1. 文件上传 |
| 27 | +### 成功响应 |
20 | 28 |
|
21 |
| -- 用户通过客户端(如 Web 页面、移动应用)上传文件。 |
22 |
| -- 服务器接收到文件后,存储在服务器上或云存储服务中,并立即返回一个响应告诉用户文件已成功上传。 |
| 29 | +- **方法**: `success()` |
| 30 | +- **类型**: GET |
| 31 | +- **路径**: `/resp-vo/success` |
| 32 | +- **返回数据示例**: |
23 | 33 |
|
24 |
| -2. 异步任务创建 |
| 34 | +```json |
| 35 | +{ |
| 36 | + "data": "success", |
| 37 | + "code": 1, |
| 38 | + "ok": true, |
| 39 | + "msg": null |
| 40 | +} |
| 41 | +``` |
25 | 42 |
|
26 |
| -- 在文件上传成功后,服务器不直接进行语音识别处理,而是创建一个异步任务。 |
27 |
| -- 这个任务被发送到消息队列中,这样可以在系统资源允许的情况下按顺序或并行处理。 |
| 43 | +**说明**: |
28 | 44 |
|
29 |
| -3. 任务处理 |
| 45 | +- `data` 字段表示业务数据,此处为字符串 "success"。 |
| 46 | +- `code` 字段为业务编码,`1` 表示操作成功。 |
| 47 | +- `ok` 字段表明响应状态,`true` 表示成功。 |
| 48 | +- `msg` 字段通常用于传递额外信息,此处为 `null` 因为操作成功不需要额外消息。 |
30 | 49 |
|
31 |
| -- 后台工作进程监听消息队列。一旦发现新任务,就开始处理该任务。 |
32 |
| -- 在处理过程中,工作进程执行语音识别操作,将音频文件转写为文本。 |
| 50 | +### 失败响应 |
33 | 51 |
|
34 |
| -4. 更新状态和通知 |
| 52 | +- **方法**: `fail()` |
| 53 | +- **类型**: GET |
| 54 | +- **路径**: `/resp-vo/fail` |
| 55 | +- **返回数据示例**: |
35 | 56 |
|
36 |
| -- 一旦异步任务完成,系统会更新任务的状态(例如,从“处理中”变为“已完成”)。 |
37 |
| -- 系统可以通过不同的方式通知用户任务已完成,比如电子邮件通知、短信、应用内通知等。 |
38 |
| -- 用户可以通过客户端查询任务状态,或者直接获取任务结果(如转写好的文本)。 |
| 57 | +```json |
| 58 | +{ |
| 59 | + "data": null, |
| 60 | + "code": 0, |
| 61 | + "ok": false, |
| 62 | + "msg": "fail" |
| 63 | +} |
| 64 | +``` |
39 | 65 |
|
40 |
| -## tio-boot 实现异步 |
| 66 | +**说明**: |
41 | 67 |
|
42 |
| -- tio-boot 内置了线程池工具类 com.litongjava.tio.utils.thread.ThreadUtils |
| 68 | +- `data` 字段在失败响应中通常为空,因为没有业务数据要返回。 |
| 69 | +- `code` 字段为业务编码,`0` 表示操作失败。 |
| 70 | +- `ok` 字段表明响应状态,`false` 表示失败。 |
| 71 | +- `msg` 字段用于提供失败的具体原因,此处为字符串 "fail"。 |
43 | 72 |
|
44 |
| -配置线程池 |
| 73 | +## RespVo 使用文档 |
45 | 74 |
|
| 75 | +### 成功响应 |
| 76 | + |
| 77 | +要创建一个表示成功的响应,可以使用 `RespVo.ok()` 方法。这个方法可以被重载,以便于传递与操作成功相关的数据。 |
| 78 | + |
| 79 | +- **无数据成功响应**: |
| 80 | + |
| 81 | +```java |
| 82 | +RespVo response = RespVo.ok(); |
46 | 83 | ```
|
47 |
| -package com.litongjava.apps.asrgpt.config; |
48 | 84 |
|
49 |
| -import java.util.concurrent.ExecutorService; |
| 85 | +- **带数据的成功响应**: |
50 | 86 |
|
51 |
| -import com.litongjava.jfinal.aop.annotation.AConfiguration; |
52 |
| -import com.litongjava.jfinal.aop.annotation.AInitialization; |
53 |
| -import com.litongjava.tio.boot.server.TioBootServer; |
54 |
| -import com.litongjava.tio.utils.thread.ThreadUtils; |
| 87 | +```java |
| 88 | +RespVo response = RespVo.ok(someData); |
| 89 | +``` |
55 | 90 |
|
56 |
| -@AConfiguration |
57 |
| -public class ExecutorServiceConfig { |
| 91 | +在这里,`someData` 可以是任何类型的对象,表示与操作成功相关的业务数据。 |
58 | 92 |
|
59 |
| - @AInitialization |
60 |
| - public void config() { |
61 |
| - // 创建包含10个线程的线程池 |
62 |
| - ExecutorService executor = ThreadUtils.newFixedThreadPool(10); |
| 93 | +### 失败响应 |
63 | 94 |
|
64 |
| - // 项目关闭时,关闭线程池 |
65 |
| - TioBootServer.me().addDestroyMethod(() -> { |
66 |
| - if (executor != null && !executor.isShutdown()) { |
67 |
| - executor.shutdown(); |
68 |
| - } |
69 |
| - }); |
| 95 | +要创建一个表示失败的响应,可以使用 `RespVo.fail()` 方法。这个方法也可以被重载,以便于传递表示失败原因的消息。 |
70 | 96 |
|
71 |
| - } |
72 |
| -} |
| 97 | +- **无消息的失败响应**: |
73 | 98 |
|
| 99 | +```java |
| 100 | +RespVo response = RespVo.fail(); |
74 | 101 | ```
|
75 | 102 |
|
76 |
| -在 Controller 中使用线程池,开启异步任务 |
| 103 | +- **带消息的失败响应**: |
77 | 104 |
|
| 105 | +```java |
| 106 | +RespVo response = RespVo.fail("失败的原因"); |
78 | 107 | ```
|
79 |
| -import com.litongjava.apps.asrgpt.services.AsrSubmitService; |
80 |
| -import com.litongjava.apps.asrgpt.validator.AsrSubmitValidator; |
81 |
| -import com.litongjava.jfinal.aop.Aop; |
82 |
| -import com.litongjava.tio.http.common.HttpRequest; |
83 |
| -import com.litongjava.tio.http.common.HttpResponse; |
84 |
| -import com.litongjava.tio.http.common.UploadFile; |
85 |
| -import com.litongjava.tio.http.server.util.Resps; |
86 |
| -import com.litongjava.tio.utils.resp.RespVo; |
87 |
| -import com.litongjava.tio.utils.thread.ThreadUtils; |
88 |
| -
|
89 |
| -import lombok.extern.slf4j.Slf4j; |
90 |
| -
|
91 |
| -@Slf4j |
92 |
| -public class AsrSubmitController { |
93 |
| -
|
94 |
| - public HttpResponse submit(HttpRequest request) { |
95 |
| - UploadFile uploadFile = request.getUploadFile("file"); |
96 |
| - String email = request.getParam("email"); |
97 |
| - log.info("upload file size:{}", uploadFile.getData().length); |
98 |
| - log.info("email:{}", email); |
99 |
| -
|
100 |
| - //validator |
101 |
| - RespVo respVo = Aop.get(AsrSubmitValidator.class).submit(email); |
102 |
| - if (respVo != null) { |
103 |
| - return Resps.json(request, respVo); |
104 |
| - } |
105 |
| -
|
106 |
| - // 使用ExecutorService异步执行任务 |
107 |
| - ThreadUtils.getFixedThreadPool().submit(() -> { |
108 |
| - try { |
109 |
| - RespVo result = Aop.get(AsrSubmitService.class).submit(uploadFile, email); |
110 |
| - // 在这里处理异步操作的结果,例如更新数据库或发送通知等 |
111 |
| - log.info("异步任务执行完成, 结果: {}", result); |
112 |
| - } catch (Exception e) { |
113 |
| - log.error("异步任务执行异常", e); |
114 |
| - } |
115 |
| - }); |
116 |
| -
|
117 |
| - // 立即响应客户端,表示文件上传请求已接收,正在处理中 |
118 |
| - RespVo ok = RespVo.ok(); |
119 |
| - ok.setMsg("文件上传成功,正在处理中..."); |
120 |
| - return Resps.json(request, ok); |
121 |
| - } |
| 108 | + |
| 109 | +### 设置额外属性 |
| 110 | + |
| 111 | +除了基本的成功或失败状态,`RespVo` 还允许你设置额外的属性,如消息(`msg`)、业务编码(`code`)和业务数据(`data`)。 |
| 112 | + |
| 113 | +- **设置消息**: |
| 114 | + |
| 115 | +```java |
| 116 | +response.msg("操作成功的附加信息"); |
| 117 | +``` |
| 118 | + |
| 119 | +- **设置业务编码**: |
| 120 | + |
| 121 | +```java |
| 122 | +response.code(1001); // 1001 为示例业务编码 |
| 123 | +``` |
| 124 | + |
| 125 | +- **设置业务数据**: |
| 126 | + |
| 127 | +```java |
| 128 | +response.data(someData); |
| 129 | +``` |
| 130 | + |
| 131 | +## 响应格式 |
| 132 | + |
| 133 | +使用 `RespVo` 构造的响应对象通常包含以下几个字段: |
| 134 | + |
| 135 | +- `code`:业务编码,用于表示操作的具体结果。 |
| 136 | +- `ok`:布尔值,表示操作是成功(`true`)还是失败(`false`)。 |
| 137 | +- `msg`:字符串,用于提供关于操作结果的额外信息或失败原因。 |
| 138 | +- `data`:对象,携带与操作成功相关的业务数据。 |
| 139 | + |
| 140 | +### 示例 |
| 141 | + |
| 142 | +以下是一个完整的示例,展示了如何使用 `RespVo` 来构造一个带有成功消息、业务编码和业务数据的成功响应: |
| 143 | + |
| 144 | +```java |
| 145 | +public RespVo createSuccessResponse() { |
| 146 | + Object someData = ...; // 从业务逻辑获取数据 |
| 147 | + return RespVo.ok(someData) |
| 148 | + .msg("操作成功完成") |
| 149 | + .code(200); // 使用自定义的成功业务编码 |
122 | 150 | }
|
| 151 | +``` |
123 | 152 |
|
| 153 | +相应地,下面是一个失败响应的示例: |
| 154 | + |
| 155 | +```java |
| 156 | +public RespVo createFailResponse() { |
| 157 | + return RespVo.fail("无法完成操作,因为...") |
| 158 | + .code(400); // 使用自定义的失败业务编码 |
| 159 | +} |
124 | 160 | ```
|
0 commit comments