【Java项目-企悦抽】05-搭建项目+自定义状态码/自定义异常+统一返回结果

发布时间:2026/7/6 3:39:34

【Java项目-企悦抽】05-搭建项目+自定义状态码/自定义异常+统一返回结果 ✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨你正在阅读「Java项目-企悦抽」系列文章✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨弹简特 个人主页❄️个人专栏直通车接口测试从入门到跑路☕一个后端的 JavaEE 续命指南网络原理续命手册☕Java项目-轻聊✨靠热爱去书写自己靠勇敢去书写生活✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨ 博主简介:文章目录一、前言二、项目搭建1、创建工程2、分层3、创建对应的层三、状态码和异常1、自定义状态码2、自定义异常类四、统一返回结果1、为什么封装统一返回结果2、代码解释2.1 属性2.2 成功的静态方法2.3 失败的静态方法第一种写法第二种写法2.4 对断言代码的解释1). 这行代码的作用2). 拆解每一部分① Assert.isTrue(条件, 错误信息)② !GlobalErrorCodeConstants.SUCCESS.getCode().equals(code)③ 合起来的逻辑3). 为什么要写这行4). 运行效果举例正确调用断言通过错误调用断言报错5). 总结一、前言兄弟们我们前面完成了对于该项目的文档性内容那么有了文档的参考从本期开始我们就可以正式的进入项目实战环节了本期将会带你搭建环境、自定义状态码自定义异常最后封装统一返回结果二、项目搭建1、创建工程pom.xml文件?xml version1.0 encodingUTF-8?projectxmlnshttp://maven.apache.org/POM/4.0.0xmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsdmodelVersion4.0.0/modelVersionparentgroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-parent/artifactIdversion3.2.6/versionrelativePath//parentgroupIdcom.zhongge/groupIdartifactIdlottery-system/artifactIdversion0.0.1-SNAPSHOT/versionnamelottery-system/namedescriptionlottery-system/descriptionpropertiesjava.version17/java.version/propertiesdependencies!-- RabbitMQ --dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-amqp/artifactId/dependency!-- redis 服务 --dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-data-redis/artifactId/dependency!--spring web依赖包--dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId/dependency!-- mysql驱动包 --dependencygroupIdcom.mysql/groupIdartifactIdmysql-connector-j/artifactIdscoperuntime/scope/dependency!--lombok依赖包--dependencygroupIdorg.projectlombok/groupIdartifactIdlombok/artifactIdoptionaltrue/optional/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-test/artifactIdscopetest/scope/dependencydependencygroupIdorg.springframework.amqp/groupIdartifactIdspring-rabbit-test/artifactIdscopetest/scope/dependency/dependenciesbuildpluginsplugingroupIdorg.springframework.boot/groupIdartifactIdspring-boot-maven-plugin/artifactIdconfigurationexcludesexcludegroupIdorg.projectlombok/groupIdartifactIdlombok/artifactId/exclude/excludes/configuration/plugin/plugins/build/project2、分层3、创建对应的层三、状态码和异常1、自定义状态码为什么咱们要自定义一些异常状态码呢第1点它的明确性我们有这些以数字为基础的错误码它就可以明确的表示当前的一个错误状态可以更好的避免我们一些问题的所在总比我们返回一堆错误描述好多。第2点就是对客户端友好我们作为调用方我们呢是希望人家给我们返回的是可以针对这些错误码去进行一些判断。第3点是维护性我们这样定一些错误码的话我们可以更好的去维护系统。第4点是错误分类。就是对于我们的系统来说我们是对系统进行分层的那么我们可以对每一层进行一个错误的分层处理那这样的话哪一层错误我们就可以直接就处理到了。第5点就是容易检索因为你容易检索我们定义这样的错误码它的明确性很高我们也可以容易检索是什么问题因为你每一层有啥错误就很容易检索。那么这些错误码类我们写在哪一层我们肯定是写在这个common层因为呢这个错误码它可以是控制层的错误码也可以是服务层的错误码也可以是持久层的错误码所以我们写在那个common通用业务层这样就可以兼顾控制层、服务层、持久层。那我们这个错误码类里面应该有哪些信息呢首先是有一个错误码是整型然后再有一个描述(String类型的描述)。就是一个错误码对应的一个错误描述。代码DatapublicclassErrorCode{/** * 错误码 */privatefinalIntegercode;/** * 错误描述 */privatefinalStringmessage;//构造方法publicErrorCode(Integercode,Stringmessage){this.codecode;this.messagemessage;}}那定义完错误码之后我们接下来就需要给我们当前的系统去进行一个错误的分类比如说我们对分层进行分类我们有哪些层呢有控制层、服务层和持久层原则上我们要对这三层进行错误的定义。不过实际上我们对持久层dao不定义错误码为什么呢因为我们的持久层它可能是sql报错它有许多的错误码我们定义不过来。因此我们要在service层把dao层的错误给它包住故这一点可体现我们是必须要在服务层里面去定义这个错误码的。好有了以上条件我们就可以定一个controller和一个service控制层和服务层的两层的错误码。那除此之外我们还要定义一个全局的错误码就是它不包含控制层也不包含服务层就是其他未知错误我们可以把它定义成个全局的错误码。首先我们定义控制层的错误码类publicinterfaceControllerErrorCodeConstants{//TODO 具体有哪一些错误码 我们写到对应代码的时候再说//------人员模块的错误码--------//------活动模块的错误码--------//------奖品模块的错误码--------//------抽奖的错误码--------}其次是定义服务层的错误码类publicinterfaceServiceErrorCodeConstants{//TODO 具体有哪一些错误码 我们写到对应代码的时候再说//------人员模块的错误码--------//------活动模块的错误码--------//------奖品模块的错误码--------//------抽奖的错误码--------}最后定义未知错误码类publicinterfaceGlobalErrorCodeConstants{// 成功的错误码ErrorCodeSUCCESSnewErrorCode(200,成功! );//系统异常500ErrorCodeINTERNAL_SYSTEM_ERRORnewErrorCode(500,系统异常! );//未知异常ErrorCodeUNKNOWNnewErrorCode(999,未知错误! );}2、自定义异常类我们定义异常类的策略是根据分层来定义的。比如我们的看controller层去定一个统一的异常类对它进行抓取我们的service层我们去另外统一的搞一个异常类对service进行抓取。所以我们开始吧先创建一个包exception控制层的异常抓取类。DataEqualsAndHashCode(callSupertrue)publicclassControllerExceptionextendsRuntimeException{/** * 异常码 * see com.zhongge.lotterysystem.common.errorcode.ControllerErrorCodeConstants //参考 */privateIntegercode;/** * 异常信息 */privateStringmessage;//无参构造 是为了 序列化的publicControllerException(){}publicControllerException(Integercode,Stringmessage){this.codecode;this.messagemessage;}publicControllerException(ErrorCodeerrorCode){this.codeerrorCode.getCode();this.messageerrorCode.getMessage();}}服务层异常抓取类DataEqualsAndHashCode(callSupertrue)publicclassServiceExceptionextendsRuntimeException{/** * 异常码 * see com.zhongge.lotterysystem.common.errorcode.ServiceErrorCodeConstants //参考 */privateIntegercode;/** * 异常信息 */privateStringmessage;//无参构造 是为了 序列化的publicServiceException(){}publicServiceException(Integercode,Stringmessage){this.codecode;this.messagemessage;}publicServiceException(ErrorCodeerrorCode){this.codeerrorCode.getCode();this.messageerrorCode.getMessage();}}注意OK到此我们的异常类就结束了四、统一返回结果1、为什么封装统一返回结果我们接收参数的那一层也就是我们的控制层同时也是和我们前端打交道那层我们要控制层去封装一个统一的返回结果。这里我们是使用一个泛型使用泛型的话它是允许我们返回任何一个类型。为什么我们要统一封装一个http请求接口调用的返回结果呢比如有一个testA接口返回的是AResult类型。还有一个testB接口访问的是BResult类的型这两个接口本身是没有问题的a返回a的b的b的互不影响但是它对前端的处理有问题。什么问题呢由于我们一般前端拿到结果之后先判断本次调用是否成功。那是如何判断呢一般前端拿到一个结果之后他会先判断每次调用是否成功对于testA()接口来说他会拿到aResult简写为a, 然后拿到a里面的状态码code来代表本次调用的结果如果是code是200就代表成功如果不是200就表示不成功。那对于testB()来说如果返回值bResult里面封装的不是code的字段而是b.errorcode那对于前端来说他要判断a的code。也要判断b的errorcode这样会比较麻烦此时对于前端来说如果他们有一个统一的行为来管理后端的结构到底是成功还是失败所以对于前端来说他肯定是希望我们后端无论调什么接口都给他一个统一的反馈结果。比如说一个统一的叫做commonResult.code。然后使用commonResult.date来获取统一的数据这样的话我们的前端就会方便操作很多因此我们才会设置泛型让我们后端任意返回我们的数据类型。说明白之后我们来写一下这个统一的返回类型怎么写Data//因为我们是进行http进行传输的因此我们可能需要进行一些序列化。所以我们暂时让它实现一下Serializable。publicclasscommonResultTimplementsSerializable{//code表示调用是否成功 返回的错误码privateIntegercode;//数据 正常返回的数据privateTdata;//消息 错误码描述privateStringmessage;}返回成功我们希望封装哪些数据呢返回失败我们希望封装那些数据呢所以我们上述的代码还需要加两个静态方法。其实返回统计结果它是有那个格式规则也就是公式就是属性加两个静态方法一个成功一个失败一般是这两种。Data//因为我们是进行http进行传输的因此我们可能需要进行一些序列化。所以我们暂时让它实现一下Serializable。publicclasscommonResultTimplementsSerializable{//code表示调用是否成功 返回的错误码privateIntegercode;//数据 正常返回的数据privateTdata;//消息 错误码描述privateStringmessage;//静态方法返回成功的时候publicstaticTcommonResultTsuccess(Tdata){commonResultTresultnewcommonResult();result.codeGlobalErrorCodeConstants.SUCCESS.getCode();result.datadata;result.message;//或者 GlobalErrorCodeConstants.SUCCESS.getMessage()returnresult;}//静态方法返回失败的时候publicstaticTcommonResultTerror(Integercode,Stringmessage){//断言一下 如果传递进来的code是200 即 success 那么就没必要往下走了这一步是为了做充分的判断Assert.isTrue(!GlobalErrorCodeConstants.SUCCESS.getCode().equals(code),code 不是错误的异常);//查询走到这里 说明是错误的codecommonResultTresultnewcommonResult();result.codecode;//result.data null;//由于是错误的 所以我们就没有必要往这个code里面去塞数据了默认就是nullresult.messagemessage;returnresult;}//静态方法返回失败的时候:通过我们之前返回的ErrorCodepublicstaticTcommonResultTerror(ErrorCodeerrorCode){returnerror(errorCode.getCode(),errorCode.getMessage());}}2、代码解释2.1 属性2.2 成功的静态方法2.3 失败的静态方法第一种写法第二种写法第二种写法 就似乎直接传递我们的状态码对象 然后调用一下第一种写法的方法即可2.4 对断言代码的解释Assert.isTrue(!GlobalErrorCodeConstants.SUCCESS.getCode().equals(code),code 不是错误的状态码);1). 这行代码的作用一句话总结强制检查你传入的 code 绝对不能是成功码比如 200。如果传了成功码程序直接报错停止避免逻辑出错。2). 拆解每一部分①Assert.isTrue(条件, 错误信息)这是 Spring 框架提供的断言工具。作用如果条件为 true→ 什么都不做继续往下走如果条件为 false→直接抛出异常并显示后面的错误信息简单说我断言这个条件一定成立不成立就报错②!GlobalErrorCodeConstants.SUCCESS.getCode().equals(code)拆成两部分GlobalErrorCodeConstants.SUCCESS.getCode()→ 拿到成功状态码比如 200!→ 取反不是整句意思传入的 code 不是成功码200③ 合起来的逻辑Assert.isTrue(传入的code不是成功码,code 不是错误的状态码);翻译成人话我要求你调用 error() 方法时必须传错误码。如果你不小心传了 200成功码我就直接报错提醒你3). 为什么要写这行因为你的方法叫error()它的功能是创建一个“失败响应”逻辑上失败响应 → 状态码绝对不能是 200200 是成功不是失败如果有人不小心写commonResult.error(200,操作成功);这就逻辑矛盾了这行断言就是为了提前拦截这种低级错误避免bug藏在代码里。4). 运行效果举例正确调用断言通过commonResult.error(500,服务器异常);500 ≠ 200 → 条件成立 → 正常执行错误调用断言报错commonResult.error(200,成功了);200 200 → 条件不成立 →直接抛异常提示信息code 不是错误的状态码5). 总结Assert.isTrue(你必须满足的条件,不满足时报错的消息);你这行的意思调用错误方法时状态码不能是成功码否则报错朋友们我们本期就到这里吧下一期我们会完成序列化、日志以及加密等等工作如果有用的老铁点赞关注或者评论区逛一逛您的支持是我创作的最大动力咱们下一期见啦~~

相关新闻