昔者,有客临门,亟需自石墨文库中撷取卷帙若干。此等文册,非止一卷,乃累牍连篇,亟需批量转置。然吾辈虑及用户体验,当效东坡"腹有诗书气自华"之雅意,使操作如行云流水,遂定以条分缕析之法,列其要目于屏间,令观者一目了然,恰似"大江东去,浪淘尽"之畅达,去繁就简,存精去芜,使界面如清风明月,操作若庖丁解牛。具体之法,容后详叙…
上传流程介绍
石墨云台藏机杼,以链为引可通幽。昔者匠人剖玉,今人截链取牍,得十六位秘钥,若敦煌经卷之编号,暗藏玄机。其法非独单卷,亦通全册,或拓一室之藏,但添协作者于卷轴、函匣、书阁之间,如邀苏子瞻共游赤壁,许其同览文海。然需筑私邸于云中(私有化部署),方得启下载之门径,此间玄妙,非市井可窥。
进度条之艺,恰似东坡观潮:初见细浪如银线,渐涌为雪堆千叠,终成惊涛拍岸之势。其理有三:一曰分黍定寸(任务切分),二曰燃香计时(进度追踪),三曰墨染绢帛(界面渲染)。每完成一卷,则添一笔于素笺,恰似东坡夜游承天寺,见"庭下如积水空明",步步生辉。其间奥义,非止术数,更含天地运行之理,今且述其梗概,余者待诸君细参。
服务流程示意图
文枢流转之法,恰似东坡治水之道。用户执链如持竹简,录于云台(系统界面),此乃"大江初发昆仑源"之始。后端服务承此简牍,以密钥为符,协作者为印,启石墨秘库之门,如子瞻开赤壁石壁,得见卷帙浩繁。
所得文牍既至,当效东坡"腹中贮书一万卷"之法,分存于Redis玉匣。业务层为匠人,执进度之笔,于玉匣刻痕记数,初若"轻舟已过万重山"之速,渐成"千帆竞发争上游"之势,终显"百川东到海"之成。其间刻痕深浅,皆映下载之进度,恰似东坡观潮,见"素练横江,雪浪排空"之景。
Talk is easy show me the code
redis存储类实体类
public class RedisTaskProcess {@Schema(description = "消息id")private String taskId;@Schema(description = "业务类型,定义自己的任务类型xxxxx")private String businessType;@Schema(description = "处理进度的百分比")private BigDecimal processPercent;@Schema(description = "任务状态, processing|completed|error|cancel")private String status = "processing";@Schema(description = "消息描述, 异常时或者特殊场景会指定消息")private String msg;@Schema(description = "用户编码,用于获取任务Key")private String userCode;@Schema(description = "任务标题(文件名)")private String title;@Schema(description = "创建时间")private Long createTime;/*** 启动一个长任务处理流程,并返回任务处理响应对象。* * @param businessType 业务类型,用于标识任务的业务场景。* @param userCode 用户代码,标识发起任务的用户。* @param title 任务标题,用于描述任务内容。* @param redisTemplate Redis模板对象,用于将任务信息存储到Redis中。* @return LongTaskProcessResponse 返回长任务处理响应对象,包含任务ID、状态、进度等信息。*/
public static RedisTaskProcess commonStart(String businessType, String userCode, String title, RedisTemplate<String, Object> redisTemplate) {// 初始化长任务处理响应对象RedisTaskProcess res = new RedisTaskProcess();// 设置任务ID、业务类型、状态、消息、标题、进度、用户代码和创建时间res.setTaskId(IdUtil.getSnowflakeNextIdStr());res.setBusinessType(businessType);res.setStatus("processing");res.setMsg("开始处理");res.setTitle(title);res.setProcessPercent(new BigDecimal(1));res.setUserCode(userCode);res.setCreateTime(System.currentTimeMillis());// 将任务信息存储到Redis中,并设置过期时间为1天redisTemplate.opsForValue().set(res.findTaskCacheKey(), res, 1, TimeUnit.DAYS);return res;
}/*** 完成任务的通用方法,用于设置任务状态为“已完成”,并更新相关信息到Redis缓存中。** @param completeMsg 任务完成时的消息内容,用于设置任务的msg字段。* @param redisTemplate Redis操作模板,用于将任务信息存储到Redis缓存中。*/
public void commonComplete(String completeMsg, RedisTemplate<String, Object> redisTemplate) {// 设置任务状态为“已完成”this.setStatus("completed");// 设置任务完成消息this.setMsg(completeMsg);// 设置任务进度为100%this.setProcessPercent(new BigDecimal(100));// 设置任务创建时间为当前时间this.setCreateTime(System.currentTimeMillis());// 将任务信息存储到Redis缓存中,并设置过期时间为1天redisTemplate.opsForValue().set(this.findTaskCacheKey(), this, 1, TimeUnit.DAYS);
}/*** 执行通用的更新操作,并调用重载的 `commonUpdate` 方法。** @param status 当前状态信息,通常用于表示操作的状态。* @param msg 更新操作的消息或描述信息。* @param addPercent 需要增加的百分比值,通常用于表示进度或比例的增加。* @param redisTemplate Redis 操作模板,用于与 Redis 进行交互。*/
public void commonUpdate(String status, String msg, Integer addPercent, RedisTemplate<String, Object> redisTemplate) {this.commonUpdate(status, msg, addPercent, null, redisTemplate);
}/*** 更新任务状态信息,并将更新后的任务信息存储到Redis中。** @param status 任务状态,用于设置当前任务的状态。* @param msg 任务消息,用于设置当前任务的消息内容。* @param addPercent 增加的进度百分比,用于计算当前任务的进度。* @param title 任务标题,如果非空则更新任务的标题。* @param redisTemplate Redis模板对象,用于将任务信息存储到Redis中。*/
public void commonUpdate(String status, String msg, Integer addPercent, String title, RedisTemplate<String, Object> redisTemplate) {// 设置任务状态和消息this.setStatus(status);this.setMsg(msg);// 如果提供了任务标题,则更新标题if (title != null) {this.setTitle(title);}// 计算并更新任务进度,确保进度不超过99%BigDecimal calRes = this.getProcessPercent().add(new BigDecimal(addPercent));this.setProcessPercent(calRes.min(new BigDecimal(99)));// 设置任务的创建时间this.setCreateTime(System.currentTimeMillis());// 将更新后的任务信息存储到Redis中,并设置过期时间为1天redisTemplate.opsForValue().set(this.findTaskCacheKey(), this, 1, TimeUnit.DAYS);
}/*** 处理通用失败情况,并将失败信息存储到Redis中。** 该方法将当前对象的状态设置为"error",并设置失败信息。同时,记录当前时间作为创建时间,* 并将整个对象存储到Redis中,缓存时间为1天。** @param failMsg 失败信息,用于描述失败的原因或详情。* @param redisTemplate Redis操作模板,用于与Redis进行交互。*/
public void commonFailure(String failMsg, RedisTemplate<String, Object> redisTemplate) {// 设置状态为"error",表示任务失败this.setStatus("error");// 设置失败信息this.setMsg(failMsg);// 记录当前时间作为创建时间this.setCreateTime(System.currentTimeMillis());// 将当前对象存储到Redis中,缓存时间为1天redisTemplate.opsForValue().set(this.findTaskCacheKey(), this, 1, TimeUnit.DAYS);
}/*** 生成任务缓存的唯一键。** 该函数通过将任务处理前缀、用户代码和任务ID拼接成一个字符串,生成一个唯一的缓存键。* 该键通常用于在缓存系统中标识和存储与特定任务相关的数据。** @return 返回一个格式化的字符串,表示任务缓存的唯一键。格式为:"任务处理前缀:用户代码:任务ID"。*/
public String findTaskCacheKey() {return String.format("%s:%s:%s", TASK_PROCESS_PREFIX_KEY, this.userCode, this.taskId);
}}
上传服务伪代码
public void updatexxxx{try{// 业务测文件集合List fileIdList = new ArrayList();// 业务代码填充xxxxxxx// 初始化进度响应对象RedisTaskProcess redisTaskProcess = RedisTaskProcess.commonStart("业务代码","业务代码","业务代码");// 计算文件进度int documentationProgress = 99 / fileIdList.size();// 指定上传逻辑伪代码fileIdList.forEach(fileId -> {// 业务代码逻辑xxxxxx// 更新文件进度redisTaskProcess..commonUpdate("processing", "正在处理文件: " + save.getFileName(), progressIncrement, redisTemplate);})// 完成长传逻辑commonComplete("文档下载完成", redisTemplate);} catch {log.error("文档下载处理失败", e);redisTaskProcess.commonFailure("文档下载处理失败: " + e.getMessage(), redisTemplate);throw new RuntimeException(e);}}
昔者东坡治水,知"急流须用缓沙堤"之理。今以Redis玉匣存进度,虽得"轻舟已过万重山"之速,然遇千帆竞渡之时,犹恐"惊涛拍岸卷千堆雪"。盖因弦歌未绝,已有新篙入水,玉匣刻痕易为后浪所湮,此乃"前度刘郎今又来"之困也。
欲解此困,当效东坡"庐山烟雨浙江潮"之禅机:或借WATCH法眼观潮,察毫厘之变;或运Lua神笔,绘原子之章。其间妙理,非止于术,更在"不识庐山真面目"之破局——使进度刻痕如西子湖心月,任尔千帆过尽,自有清辉长明。然此中三昧,且待下回分说,恰似"欲把西湖比西子"之未尽余韵…