第四阶段05- 关于响应结果JsonResult对象,枚举,Spring MVC的统一处理异常机制

news/2024/5/14 21:45:18/文章来源:https://blog.csdn.net/aiheshuicxy/article/details/129255202

23. 关于响应结果

目前,当成功的添加相册后,服务器端响应的结果是:

添加相册成功!

如果相册名称已经被占用,服务器端响应的结果是:

添加相册失败,相册名称已经被占用!

以上的响应结果是不合适的,因为客户端不便于通过以上结果判断本次请求是否被成功的处理了,或是处理结果是失败。

如果服务器端改为使用数字作为响应结果,与客户端协商不同的数字所表示的意义,例如使用1表示成功,使用0表示失败,这种做法更利于客户端判断操作成功与否,但是,却需要客户端自行组织后续的文本,以在界面上显示相关提示,而客户端自行组织文本也是不适合的,特别是操作失败时,仍应该是“谁抛出,谁描述”,客户端不一定能准确的、统一的组织这些文本,所以,仍应该是由服务器端响应操作失败的描述文本!

所以,服务器端响应的结果中应该既包含数字这类标志着成功与失败的数据,还应该包含描述文本!

由于服务器端响应的结果中包含多个部分(目前是2个部分:数字标志、描述文本),应该将这多个部分使用JSON格式组织起来,则客户端收到后,可以从中取出任何所需的部分的数据:

{ "state": "1", "message": "添加相册成功!""
}

在Spring MVC框架中,当需要向客户端响应JSON格式的数据时,需要:

  • 处理请求的方法必须是响应正文

    • 在方法上添加@ResponseBody / 在控制器类上添加@ResponseBody / 在控制器类上添加@RestController
  • 开启注解驱动

    • 如果是使用XML配置的Spring MVC项目,需要在XML配置文件中添加<annotation-driven/>
    • 如果是使用注解配置的Spring MVC项目,需要在配置类上添加@EnableWebMvc
    • 如果是Spring Boot项目,不需要添加任何配置
  • 添加jackson-databind依赖项

    • spring-boot-starter-web依赖项中包含此依赖项:

请添加图片描述

  • 使用自定义的数据类型作为处理请求的方法的返回值类型

则在项目的根包下创建web.JsonResult类(类名是完全自定义的),并在类中声明需要响应到客户端的数据属性,也可以理解为声明期望响应的JSON数据中的属性:

@Data
public class JsonResult implements Serializable {private Integer state;private String message;
}

然后,将处理请求的方法的返回值类型改为JsonResult,并调整内部实现,处理完请求后返回此类型的对象:

@PostMapping("/add-new")
public JsonResult addNew(AlbumAddNewDTO albumAddNewDTO) {try {albumService.addNew(albumAddNewDTO);JsonResult jsonResult = new JsonResult();jsonResult.setState(1);jsonResult.setMessage("添加相册成功!");return jsonResult;} catch (ServiceException e) {JsonResult jsonResult = new JsonResult();jsonResult.setState(0);jsonResult.setMessage(e.getMessage());return jsonResult;}
}

完成后,重启项目,再次通过API文档调试访问,当添加相册成功时,响应结果为:

{"state": 1,"message": "添加相册成功!"
}

当相册名称已经被占用,导致添加失败时,响应结果为:

{"state": 0,"message": "添加相册失败,相册名称已经被占用!"
}

24. 使用静态方法创建JsonResult对象

在处理响应时,每次都需要创建对象、为属性赋值、返回对象,使用了较多语句实现此效果,在语法上过于繁琐,应该简化此类代码!

可以在JsonResult类中添加全参数构造方法(在类上添加@AllArgsConstructor注解,出于规范性,也添加@NoArgsConstructor),以简化相关代码,例如:

@Data
@NoArgsConstructor
@AllArgsConstructor
public class JsonResult implements Serializable {private Integer state;private String message;}

则处理请求的响应代码可以简化:

@PostMapping("/add-new")
public JsonResult addNew(AlbumAddNewDTO albumAddNewDTO) {try {albumService.addNew(albumAddNewDTO);return new JsonResult(1, "添加相册成功!");} catch (ServiceException e) {return new JsonResult(0, e.getMessage());}
}

关于JsonResult中的String message属性,其作用是避免客户端在描述“失败”时组织的文本不统一,或不准确,在“成功”时,其实并不需要此属性,因为在操作成功时,由客户端自行组织描述文本,通常不会出现歧义,甚至,在许多业务中,操作成功后,只需要让客户端的软件界面发生变化即可,并不需要提示一段信息!

同时,为了进一步更好的管理状态码,应该将这些状态码定义在专门的类型中,例如,在项目的根包下创建web.ServiceCode类,用于管理各个可能使用到的业务状态码:

public interface ServiceCode {Integer OK = 10000;Integer ERR = 20000;
}

**提示:**以上类型声明为接口,可以不必在每个常量上添加public static final这些修饰符。

JsonResult类中,可以定义一些静态方法,以快速的创建对象,并为属性赋值,例如:

@Data
public class JsonResult implements Serializable {private Integer state;private String message;public static JsonResult ok() {JsonResult jsonResult = new JsonResult();jsonResult.setState(ServiceCode.OK);return jsonResult;}public static JsonResult fail(Integer state, String message) {JsonResult jsonResult = new JsonResult();jsonResult.setState(state.getValue());jsonResult.setMessage(message);return jsonResult;}
}

**提示:**相比构造方法,以上静态方法的方法名是可以自由定义的,可以更好的表现代码的语义。

在控制器类中的代码则调整为:

@PostMapping("/add-new")
public JsonResult addNew(AlbumAddNewDTO albumAddNewDTO) {try {albumService.addNew(albumAddNewDTO);return JsonResult.ok();} catch (ServiceException e) {return JsonResult.fail(ServiceCode.ERR, e.getMessage());}
}

25. 使用枚举限制参数的传入

经过以上调整,各状态码可以集中的管理起来,控制器类中的语法也可以清晰的表现语义,但是,无法避免方法的调用者传值错误的问题,例如,在JsonResult类中的fail()方法的第1个参数仍是Integer类型的:

public static JsonResult fail(Integer state, String message) {JsonResult jsonResult = new JsonResult();jsonResult.setState(state);jsonResult.setMessage(message);return jsonResult;
}

方法的调用者可能不清楚“必须传入ServiceCode中的某个常量值”这样的约定,则可能错误的传入值,例如:

//                     ↓↓↓↓↓↓↓ 错误的传值
return JsonResult.fail(1234567, e.getMessage());

**提示:**枚举的本质是一种“穷举”,如果你认为某个数据的取值是相对有限的可能性,则可以考虑使用枚举。

可以将ServiceCode改为枚举类型,例如:

public enum ServiceCode {// 注意:每一个枚举值,其实都是当前枚举类型的对象// 注意:请将以下语法理解为“通过带参数的构造方法创建枚举类型的对象”// 注意:由于通过构造方法传入了值,所以,每个枚举类型的对象都带有一个数字值,后续可以getValue()取出OK(10000),ERR(20000);// 以下属性,表示每个枚举类型的对象都有一个Integer value属性,此属性的值将通过构造方法传入private Integer value;// 显式的声明枚举的带Integer参数的构造方法,用于创建枚举类型的对象时,为其Integer value属性赋值// 注意:枚举的构造方法的访问权限固定是私有的(Java语法特征)//      不写访问权限,并不表示“默认的”,而是“私有的”//      写public / protected是错误的//      写private是多余的ServiceCode(Integer value) {this.value = value;}// 用于通过枚举对象获取Integer value属性的值public Integer getValue() {return value;}}

并且,将fail()方法的参数设计为枚举类型:

//                            ↓↓↓↓↓↓↓↓↓↓↓ 由原本的Integer改为ServiceCode
public static JsonResult fail(ServiceCode serviceCode, String message) {// 暂不关心内部代码
}

则方法的调用者只能传入ServiceCode中的某个枚举值,不可以传入任意值!

ok()fail()方法的内部,可以调用枚举值的getValue()方法,得到各枚举值对应的数值:

public static JsonResult ok() {JsonResult jsonResult = new JsonResult();//                                ↓↓↓↓↓↓↓↓↓↓↓ 调用枚举对象的getValue()jsonResult.setState(ServiceCode.OK.getValue());return jsonResult;
}public static JsonResult fail(ServiceCode serviceCode, String message) {JsonResult jsonResult = new JsonResult();//                              ↓↓↓↓↓↓↓↓↓↓↓ 调用枚举对象的getValue()jsonResult.setState(serviceCode.getValue());jsonResult.setMessage(message);return jsonResult;
}

至此,既保证了响应的业务状态码(JsonResult中的state)是数值类型的,又保证了传入的值只能是限定的某个值(只能是ServiceCode中列举的某个值)。

26. 关于枚举值的状态码

各枚举值的状态码虽然是自由定义的,但强烈推荐是有一定规律的!

如果没有更合适的规律,可以参考HTTP状态,例如,在HTTP状态码中,200表示“成功”的意义,404表示“不存在”的意义,409表示“冲突”的意义,则可以将枚举值改为:

public enum ServiceCode {OK(20000),ERR_NOT_FOUND(40400),ERR_CONFLICT(40900);// 暂不关心此类型中的其它代码
}

27. 调整ServiceException

关于异常的描述文本,应该是“谁抛出,谁描述”,而业务状态码(JsonResult中的state,或,ServiceCode的值)也应该是“谁抛出,谁定值”,而不应该是由捕获异常的一方来决定业务状态码,而现有的代码是:

@PostMapping("/add-new")
public JsonResult addNew(AlbumAddNewDTO albumAddNewDTO) {try {albumService.addNew(albumAddNewDTO);return JsonResult.ok();} catch (ServiceException e) {//                     ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ 捕获异常时确定业务状态码,是“不合适”的return JsonResult.fail(ServiceCode.ERR_CONFLICT, e.getMessage());}
}

目前,抛出的异常对象中只包含“描述文本”,如果还要包含“业务状态码”,则应该调整异常类型的源代码:

public class ServiceException extends RuntimeException {private ServiceCode serviceCode;public ServiceException(ServiceCode serviceCode, String message) {super(message);this.serviceCode = serviceCode;}public ServiceCode getServiceCode() {return serviceCode;}}

以上调整的思路:

  • 在异常类型中声明ServiceCode属性,表示此类型的异常中将包含“业务状态码”
  • 调整现有的构造方法,添加ServiceCode类型的参数,表示强制要求传入此值,否则不允许创建此类型的异常对象
  • 为了便于后续获取到此类型的异常对象中通过构造方法传入的ServiceCode值,还需要添加Getter方法

完成后,当需要抛出异常时,必须通过以上的唯一的构造方法,例如在AlbumServiceImpladdNew()方法中调整:

if (countByName > 0) {String message = "添加相册失败,相册名称已经被占用!";log.warn(message);//                         ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ 创建异常对象时传入业务状态码throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
}

后续,当处理异常时,可以调用捕获到的异常对象的getServiceCode()方法得到业务状态码,例如在AlbumController中处理“添加相册”的请求时:

@PostMapping("/add-new")
public JsonResult addNew(AlbumAddNewDTO albumAddNewDTO) {try {albumService.addNew(albumAddNewDTO);return JsonResult.ok();} catch (ServiceException e) {//                     ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ 从异常对象中取出业务状态码return JsonResult.fail(e.getServiceCode(), e.getMessage());}
}

为了进一步简化JsonResult的调用,可以在JsonResult类中重载fail()方法:

public static JsonResult fail(ServiceException e) {// JsonResult jsonResult = new JsonResult();// jsonResult.setState(e.getServiceCode().getValue());// jsonResult.setMessage(e.getMessage());// return jsonResult;return fail(e.getServiceCode(), e.getMessage());
}

**提示:**原本的fail(ServiceCode serviceCode, String message)仍需要保留下来,后续出现其它异常时需要使用到。

当添加了以上新的fail()方法后,在AlbumController中捕获并处理异常的代码可以简化:

@PostMapping("/add-new")
public JsonResult addNew(AlbumAddNewDTO albumAddNewDTO) {try {albumService.addNew(albumAddNewDTO);return JsonResult.ok();} catch (ServiceException e) {//                     ↓ 只需要传入整个异常对象即可return JsonResult.fail(e);}
}

28. Spring MVC的统一处理异常机制

在Spring MVC中,存在统一处理异常的机制,具体表现为:无论是哪个处理请求的过程中出现异常,每种类型的异常只需要编写一段处理异常的代码即可!

统一处理异常的核心是定义处理异常的方法:

  • 返回值类型:可参考处理请求的方法
  • 方法名称:自定义
  • 参数列表:至少包含被处理的异常对象,另外,可按需添加HttpServletRequestHttpServletResponse等少量特定的参数,当存在多个参数时,各参数不区分先后顺序
  • 注解:必须添加@ExceptionHandler注解,表示此方法是处理异常的方法

例如:

@ExceptionHandler
public JsonResult handleServiceException(ServiceException e) {log.warn("程序运行过程中出现ServiceException,将统一处理!");log.warn("异常信息:{}", e.getMessage());return JsonResult.fail(e);
}

当客户端向服务器端提交请求,例如“添加相册”,如果服务器端的控制器中处理请求的方法中调用Service方法时出现异常,但是,处理请求的方法不必对此异常进行处理,例如:

@PostMapping("/add-new")
public JsonResult addNew(AlbumAddNewDTO albumAddNewDTO) {log.debug("开始处理【添加相册】的请求,参数:{}", albumAddNewDTO);albumService.addNew(albumAddNewDTO); // 此次调用可能出现异常,但并不需要try...catchreturn JsonResult.ok();
}

当处理请求的方法不使用try..catch...捕获异常,如果出现异常,相当于此处理请求的方法会抛出异常!

在Spring MVC框架中,处理请求的方法都是被框架所调用的,所以,处理请求的方法抛出的异常也都会被框架捕获到,则框架会自动的使用此异常对象来调用处理异常的方法!类似于:

try {框架.addNew(); // 框架调用了控制器类中处理异常的方法
} catch (ServiceException e) {框架.handleServiceException(e); // 框架调用了处理异常的方法
}

需要注意:如果将处理异常的方法定义在某个控制器类中,将只能作用于当前控制器类所有处理请求时出现的异常,并不能作用于其它控制器类中处理请求时出现的异常!

在使用Spring MVC框架时,可以在类上添加@RestControllerAdvice注解,此类中特定的方法(例如统一处理异常的方法)将可以作用于整个项目中任何处理请求的过程中!

在项目的根包下创建ex.handler.GlobalExceptionHandler类,作为当前项目的“全局异常处理器”类,将统一处理异常的代码编写在此类中(各控制器类中不再需要重复的处理异常的方法):

@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {@ExceptionHandlerpublic JsonResult handleServiceException(ServiceException e) {log.warn("程序运行过程中出现ServiceException,将统一处理!");log.warn("异常信息:{}", e.getMessage());return JsonResult.fail(e);}}

29. 关于响应结果中的null值

目前,服务器端处理完请求后,会向客户端响应JSON格式的结果,但是,某些情况下,会有一些属性的值为null,例如,当成功的添加相册后,响应的结果是:

{"state": 20000,"message": null
}

以上message属性是没有必要响应的,因为此属性的作用是“失败”时的提示文本,当操作成功时,此属性的值一定是null值,将此属性响应到客户端去是没有任何意义的!

可以在响应结果对应的属性上配置@JsonInclude注解,例如:

@Data
public class JsonResult implements Serializable {private Integer state;// @JsonInclude用于配置“此属性什么时候会包含在JSON结果中”// NON_NULL 表示 不为null的时候@JsonInclude(JsonInclude.Include.NON_NULL)private String message;}

也可以将此注解添加在类上,则类中每个属性都是此配置:

@Data
@JsonInclude(JsonInclude.Include.NON_NULL) // 在类上配置,每个属性都遵循此配置
public class JsonResult implements Serializable {private Integer state;private String message;}

或者,还可以在配置文件中通过spring.jackson.default-property-inclusion属性进行作用于整个项目的全局配置!例如,在application.yml中添加:

# Spring相关配置
spring:# jackson框架的相关配置jackson:# 服务器端响应JSON结果时,JSON结果中默认包含哪些属性default-property-inclusion: non_null

}


也可以将此注解添加在类上,则类中每个属性都是此配置:```java
@Data
@JsonInclude(JsonInclude.Include.NON_NULL) // 在类上配置,每个属性都遵循此配置
public class JsonResult implements Serializable {private Integer state;private String message;}

或者,还可以在配置文件中通过spring.jackson.default-property-inclusion属性进行作用于整个项目的全局配置!例如,在application.yml中添加:

# Spring相关配置
spring:# jackson框架的相关配置jackson:# 服务器端响应JSON结果时,JSON结果中默认包含哪些属性default-property-inclusion: non_null

**提示:**在配置文件中、在类上、在类的属性上,都可以配置“是否包含在JSON结果中”,通常只需要在主配置文件中配置即可,但是,如果在多处都配置了,以“作用域”更小的为准,例如,在类上和在类的属性上都配置了,但配置值不同,则以在类的属性上的配置为准!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_75866.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

机器学习100天(三十二):032 KD树的构造和搜索

机器学习100天,今天讲的是:KD树的构造和搜索! 《机器学习100天》完整目录:目录 在 K 近邻算法中,我们计算测试样本与所有训练样本的距离,类似于穷举法。如果数据量少的时候,算法运行时间没有大的影响,但是如果数据量很大,那么算法运行的时间就会很长。这在实际的应用…

4.排序算法之一:冒泡排序

排序算法稳定性假定在待排序的记录序列中&#xff0c;存在多个具有相同的关键字的记录&#xff0c;若经过排序&#xff0c;这些记录的相对次序保持不变&#xff0c;即在原序列中&#xff0c;r[i]r[j]&#xff0c;且r[i]在r[j]之前&#xff0c;而在排序后的序列中&#xff0c;r[…

柔性电路板的优点、分类和发展方向

柔性电路板是pcb电路板的一种&#xff0c;又称为软板、柔性印刷电路板&#xff0c;主要是由柔性基材制作而成的一种具有高可靠性、高可挠性的印刷电路板&#xff0c;具有厚度薄、可弯曲、配线密度高、重量轻、灵活度高等特点&#xff0c;主要用在手机、电脑、数码相机、家用电器…

二叉树——二叉树的最近公共祖先

二叉树的最近公共祖先 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。 百度百科中最近公共祖先的定义为&#xff1a;“对于有根树 T 的两个节点 p、q&#xff0c;最近公共祖先表示为一个节点 x&#xff0c;满足 x 是 p、q 的祖先且 x 的深度尽可能大&#xff08;一…

Guitar Pro8免费吉他曲谱mySongBook

每周都会发布新的谱子&#xff0c;目前已有有数千首歌曲可供选择&#xff0c;在谱库中&#xff0c;您能找到 Guns N Roses&#xff0c;Miles Davis&#xff0c;Ed Sheeran 等人的经典曲目。开头我们先做一个小实验&#xff1a;现在打开你电脑里存放曲谱的文件夹&#xff0c;里面…

[busybox] busybox生成一个最精简rootfs(上)

这篇文章是承接着[rootfs]用busybox做一个rootfs(根文件系统)来的&#xff0c;再回看这篇我很久之前写的文章的时候&#xff0c;有一个问题出现在我的脑海中&#xff0c;创建了这个文件那个文件&#xff0c;但确实是每个文件都是必需的吗&#xff1f; 这篇文章我们就来讨论下这…

【用Group整理目录结构 Objective-C语言】

一、接下来,我们看另外一个知识点,怎么用Group把这一堆乱七八糟的文件给它整理一下,也算是封装一下吧, 1.这一堆杂乱无章的文件: 那么,哪些类是属于模型呢,哪些类是属于视图呢,哪些类是属于控制器呢, 我们接下来通过Group的方式,来给它们分一下类, 这样看起来就好…

蓝海彤翔执行副总裁张加廷接受【联播苏州】独家专访

今年春节档&#xff0c;科幻类电影《流浪地球2》票房口碑双丰收&#xff0c;截至目前&#xff0c;累计票房已破 38 亿&#xff0c;淘票票评分 9.6 &#xff0c;影片的特效质感可以媲美国际顶尖水平。其中&#xff0c;蓝海彤翔为影片的后期制作提供了出色的渲染服务。2月21日&am…

招投标管理系统-适合于招标代理、政府采购、企业采购、工程交易等业务的企业

招投标管理系统-适合于招标代理、政府采购、企业采购、工程交易等业务的企业 招投标管理系统是一个用于内部业务项目管理的应用平台。以项目为主线&#xff0c;从项目立项&#xff0c;资格预审&#xff0c;标书编制审核&#xff0c;招标公告&#xff0c;项目开标&#xff0c;项…

[chapter 11][NR Physical Layer][Layer Mapping]

前言&#xff1a;这里参考Curious Being系列 &#xff0c;简单介绍一下NR 5G 物理层核心技术层映射.我们主要讲了一下what is layer Mapping, why need layer Mapping, how layer Mapping 参考文档&#xff1a;3GPP 38.211- 6.3.1.3 Layer mapping《5G NR Physical Layer | Cha…

js几种对象创建方式

适用于不确定对象内部数据方式一&#xff1a;var p new Object(); p.name TOM; p.age 12 p.setName function(name) {this.name name; }// 测试 p.setName(jack) console.log(p.name,p.age)方式二&#xff1a; 对象字面量模式套路&#xff1a;使用{}创建对象&#xff0c;同…

发现新大陆——原来软件开发根本不需要会编码(看我10分钟应用上线)

目录 一、前言 二、官网基础功能及搭建 三、体验过程 01、连接数据源 02、设计表单 03、流程设计 04、图表呈现 05、组织架构设置 五、效率评价 六、小结 一、前言 众所周知&#xff0c;每家公司在发展过程中都需要构建大量的内部系统&#xff0c; 如运营使用的用户…

cnpm adduser 报错 409 Conflict

今天遇到一个问题&#xff0c;cnpm adduser 一直失败&#xff0c;返回 409 Conflict。 我们先来看下报错信息 409 Conflict - PUT http://registry.cnpm.xxxx.com.cn/-/user/org.couchdb.user:mingyu6 - conflict第一步 分析 http 错误码 409 Conflict&#xff1a;请求与服务…

数据结构初阶 -- 顺序表

数据结构初阶 链表的讲解 目录 一. 线性表 1.1 定义 1.2 特点 二. 顺序表 2.1 定义 2.2 代码 2.3 功能需求 2.4 静态顺序表的特点以及缺点 2.5 动态的顺序表 2.6 动态顺序表接口的实现 三. 代码 头文件 主文件 一. 线性表 1.1 定义 线性表&#xff08;linear li…

代码随想录算法训练营第九届期第十四天 | 二叉树理论基础 、递归遍历 、迭代遍历 、统一迭代

打卡第十四天&#xff0c;今天学习二叉树。 今日任务 理论基础递归遍历迭代遍历统一迭代 理论基础 二叉树是一种基础数据结构 二叉树的种类 满二叉树&#xff1a;只有度为0和为2的结点&#xff0c;而且度为0 的结点都在最后一层。完全二叉树&#xff1a;结点按顺序从上到下&…

电脑没有回收站找回删除文件的2种方法

最近后台收到了这样的咨询&#xff1a;”在网吧上网&#xff0c;删除东西的时候不小心把我的文件给删除了&#xff0c;但是桌面上没有回收站&#xff0c;怎么才能找回我的文件&#xff1f;“——针对“电脑没有回收站删除的东西怎么恢复”这种疑问&#xff1f;不妨看看下面数据…

【计算机组成原理 - 第一章】计算机系统概论(完结)

本章参考王道考研相关课程&#xff1a; 【2021版】1.2.1_计算机硬件的基本组成_哔哩哔哩_bilibili 【2021版】1.2.2_认识各个硬件部件_哔哩哔哩_bilibili 【2021版】1.2.3_计算机系统的层次结构_哔哩哔哩_bilibili 【2021版】1.3_计算机的性能指标_哔哩哔哩_bilibili 目录 一、…

【记录问题】RuntimeError:working outside of application context. Flask使用SQLAlchemy数据库

前提&#xff1a;Flask使用SQLAlchemy数据库 本质&#xff1a;依赖包版本不匹配 问题1&#xff1a;报错RuntimeError&#xff1a;working outside of application context. 运行程序报错&#xff0c;如下错误&#xff1a; 原因&#xff1a;flask-sqlalchemy 版本过高导致&am…

手牵手教Docker部署Springboot+vue ,全过程十分详细,轻松完成项目部署(简单,高效,通用)

手把手教Docker部署Springbootvue &#xff0c;详细全过程&#xff0c;轻松完成项目部署&#xff08;简单&#xff0c;高效&#xff09; 上线前准备 腾讯云的服务器&#xff0c;服务器安装好docker 和docker-compose 最好事先了解技术 nginxdocker-compose 整体编排 后端部…

CCNP350-401学习笔记(易错题合集)

CCNP350-401学习笔记&#xff08;1-50题&#xff09;_殊彦_sy的博客-CSDN博客CCNP350-401学习笔记&#xff08;2023.2.17&#xff09;https://blog.csdn.net/shuyan1115/article/details/129088574?spm1001.2014.3001.5502CCNP350-401学习笔记&#xff08;51-100题&#xff09…