精华内容
下载资源
问答
  • 01大家好,上一期我们学习了常见参数检验单样本t检验,今天我们继续学习一种新的参数...在应用t检验进行两样本均数比较时,要求数据满足三个条件:正态性、方差齐性、独立性。其中独立性和方差齐性对数据影...

    01

    大家好,上一期我们学习了常见参数检验中的单样本t检验,今天我们继续学习一种新的参数检验——两独立样本t检验。两独立样本t检验同样是t检验的一种,又叫做成组设计两样本均数的比较,其基本原理与单样本t检验实际上是非常相似的。

    02

    但是这里我们需要引入一个概念,即两独立样本t检验的适用条件。在应用t检验进行两样本均数的比较时,要求数据满足三个条件:正态性、方差齐性、独立性。其中独立性和方差齐性对数据影响较大,而t检验对于资料的正态性有一定的耐受能力。

    例题

    现希望评价两位老师的教学质量,试比较其分别任教的甲、乙两班考试后的成绩是否存在差异?(设甲、乙两班原成绩相近,不存在差别)

    班级成绩
    甲班85738682779468839088
    76858774858082889093
    乙班75906298737575768366
    65788068877464687280


    数据录入时1=甲班,2=乙班

    操作如下

    83c7c0659358c1a8be0ce681431aa682.png

    983782c53888f287a8bdf54f8b5f0246.png

    98d9b29476b60229cc5c8beafae5dc92.png

    987aefeec1c9e49c31389900150fd3dd.png

    结果

    在结果的表格里,我们需要注意方差齐性检验,即方差方程的Levene检验。F=0.733,P=0.397>0.05,所以不拒绝原假设,即可以认为两样本方差是齐的。所以我们关注第一排的t值,t=3.056,P=0.004<0.05,所以两位老师执教班级成绩的均数是存在显著差异的,且差异具有统计学意义。

    (如果是方差不齐,我们需要看第二排的t值,这个时候是进行的t'检验,与t检验不同。)

    步骤

    1、录入数据;

    2、分析→比较均值→两独立样本样本t检验;

    3、成绩选入检验变量,班级选入分组变量,在定义组里进行如图的定义;

    4、确定,得出结果。

    展开全文
  • 后根据三个实例分析了采用七参数进行高程转换精度,得到结论: GPS 七参数的高程转换在一定测区内可以达到五等水准精度; 检验合格后,GPS 七参数转换高程数据可以满足图根控制精度的要求。本文为分享帖。
  • 3.计量经济学模型的检验包括哪几方面?其具体含义是什么?答:(1)经济意义检验,即根据拟定符号、大小、关系,对参数估计结果可靠性进行判断(2)统计检验,由数理统计理论决定。包括:拟合优度检验、总体显著性...

    3.计量经济学模型的检验包括哪几个方面?其具体含义是什么?

    答:(1)经济意义检验,即根据拟定的符号、大小、关系,对参数估计结果的可靠性进行判断(2)统计检验,由数理统计理论决定。包括:拟合优度检验、总体显著性检验。(3)计量经济学检验,由计量经济学理论决定。包括:异方差性检验、序列相关性检验、多重共线性检验。(4)模型预测检验,由模型应用要求决定。包括:稳定性检验:扩大样本重新估计;预测性能检验:对样本外一点进行实际预测。

    4.计量经济学方法与一般经济数学方法有什么区别?

    答:计量经济学揭示经济活动中各因素之间的定量关系,用随机性的数学方程加以描述;一般经济数学方法揭示经济活动中各因素之间的理论关系,用确定性的数学方程加以描述。

    5.计量经济学模型研究的经济关系有那两个基本特征?

    答:一是随机关系,二是因果关系

    6.计量经济学研究的对象和核心内容是什么?

    答:计量经济学的研究对象是经济现象,是研究经济现象中的具体数量规律。计量经济学的核心内容包括两个方面:一是方法论,即计量经济学方法或者理论计量经济学。二是应用,即应用计量经济学。无论是理论计量经济学还是应用计量经济学,都包括理论、方法和数据三种要素。

    7.计量经济学中应用的数据类型怎样?举例解释其中三种数据类型的结构。

    答:计量经济模型:WAGE=f(EDU,EXP,GEND,μ)

    1)时间序列数据是按时间周期收集的数据,如年度或季度的国民生产总值。

    2)横截面数据是在同一时间点手机的不同个体的数据。如世界各国某年国民生产总值。

    3)混合数据是兼有时间序列和横截面成分的数据,如1985—2010世界各国GDP数据。

    8.建立与应用计量经济学模型的主要步骤有哪些?

    (1)理论模型的设计(2)样本数据的收集(3)模型参数的估计(4)模型的检验

    9.用OLS建立多元线性回归模型,有哪些基本假设?

    1、回归模型是线性的,模型设定无误且含有误差项 2、误差项总体均值为零 3、所有解释变量与误差项都不相关 4、误差项互不相关(不存在序列相关性)5、误差项具有同方差 6、任何一个解释变量都不是其他解释变量的完全线性函数 7、误差项服从正态分布。

    10.随机误差项包含哪些因素影响?

    在解释变量中被忽略的因素的影响(影响不显著的因素、未知的影响因素、无法获得数据的因素);变量观测值的观测误差的影响;模型关系的设定误差的影响;其它随机因素的影响。

    11.为什么要计算调整后的可决系数?

    在应用过程中发现,如果在模型中增加一个解释变量, 往往增大。这是因为残差平方和往往随着解释变量的增加而减少,至少不会增加。这就给人一个错觉:要使得模型拟合得好,只要增加解释变量即可。但是,现实情况往往是,由增加解释变量个数引起的的增大与拟合好坏无关,需调整。=0.89表示被解释变量Y的变异性的89%能用估计的回归方程解释。

    12.叙述多重共线性的概念、后果和补救措施。

    概念:如果两个或多于两个解释变量之间出现了相关性,则称模型存在多重共线性。

    后果:1、估计量仍然是无偏的 2、参数估计量的方差和标准差增大 3、置信区间变宽 4、t统计量会变小 5、估计量对模型设定的变化及其敏感 6、对方程的整体拟合程度几乎没有影响 7、回归系数符号有误

    补救措施:1、什么都不做 2、去掉多余的变量 3、增大样本容量

    13.叙述异方差性的概念、后果和补救措施。

    概念:对于不同的样本点,随机干扰项的方差不再是常数,而是互不相同,则认为出现了异方差性。

    后果:参数估计非有效,变量的显著性检验失去意义,模型的预测失效

    补救措施:1、加权最小二乘法(WLS)(对原模型加权,使之变成一个新的不存在异方差性的模型,然后采用OLS估计其参数)。2、异方差稳健标准误法。

    14.叙述序列相关的概念、后果和补救措施。

    概念:在正确设定的函数中,如果随机干扰项序列的协方差不为0,则存在序列相关性。

    后果:参数估计非有效,变量的显著性检验失去意义,模型的预测失效

    补救措施:1、广义最小二乘法(消除一阶纯序列相关,回复估计量为最小方差性质的方法)2、Newey-West标准差法(在不改变估计值本身的前提下,修正存在序列相关性的标准差)。

    15.写出用White检验进行异方差的检验过程。

    1.假设回归模型

    2.对模型做普通最小二乘回归,得到残差 做辅助回归

    3.求辅助回归方程的R2,在原假设:不存在异方差下,nR2服从X2(df)

    4.自由度df等于辅助回归方程中解释变量的个数。如果拒绝原假设,有证据表明存在异方差。

    16.写出用方差膨胀因子检验多重共线性的检验过程。

    对于模型:

    第一步:计算下面辅助方程的决定系数。

    第二步:计算参数估计值的方差膨胀因子。

    如果VIF(βj)>5则存在严重的多重共线性。

    17.写出用杜宾-沃森DW方法检验序列相关的检验过程。

    (1)计算DW统计量

    (2)确定临界值:dL、dU

    (3)提出假设:H0:ρ=0,H1:ρ≠0,

    若0

    若dU

    若dL

    18.在所有的计量经济问题中,以方差性似乎是最难理解的,用自己的语言来解释异方差性,用图示法说明。

    概念:对于不同的样本点,随机干扰项的方差不再是常数,而是互不相同,则认为出现了异方差性。在异方差的情况下,σI2已不是常数,它随着X的变化而变化,即σI2=f(Xi)异方差一般可以归结为三种类型:(1)同方差性(2)单调递增型(3)单调递减型(4)复杂型

    19.当多远线性回归模型的回归系数符号与预期不一致时,应该检查什么?

    1)检验是否有无关变量 2)检验是否有相关变量的遗漏 3)检验函数形式是否设定偏误。

    20.在所建立的回归模型中,你遇到过哪些计量经济学问题?

    1)即使所有的经典假设都满足,得到的估计结果也会与“实际”有偏误。

    2)经济理论并未告知变量之间的具体关系应当是什么样的,比如说应该包括多少个解释变量,模型应该选线性形式还是双对数线性形式等。

    3)对于自回归模型,随机干扰项的自相关问题始终是存在的。

    21.回归模型中引入虚拟变量的作用?有哪几种基本引入方式?

    一些影响经济变量的因素无法定量度量,如:职业、性别对收入的影响,战争、自然灾害对GDP的影响,季节对某些产品(如冷饮)销售的影响等等。为了在模型中能够反应这些因素的影响,并提高模型的精度,需要将它们“量化”。这种“量化”通常是通过引入“虚拟变量”来完成的。虚拟变量做为解释变量引入模型有两种基本方式:加法方式(截距虚拟变量)和乘法方式(斜率虚拟变量)

    22.滞后变量模型有哪几种类型?分布滞后模型使用OLS存在哪些问题?

    滞后变量模型有两种类型,一是分布滞后模型,二是自回归模型存在的问题:

    1)对无线分布滞后模型,由于样本观测值得有限性,无法直接对其进行估计。

    2)对有限分布滞后模型,没有先验准则确定滞后期长度,若滞后期较长,样本容量有限,自由度减少,同名变量滞后值之间可能存在高度线性相关。

    23.在对联立方程模型进行估计之前我们先做些什么工作?为什么?

    24.简述两个阶段最小乘法估计方法的思路。

    第一阶段:将要估计的方程中作为解释变量的每一个内生变量对联立方程系统中全部前定变量回归(即估计简化式方程—用普通最小二乘法),然后计算这些内生变量的估计值。

    第二阶段:用第一阶段得出的内生变量的估计值代替方程右端的内生变量(即用它们作为这些内生变量的工具变量),对原方程应用OLS法,以得到结构参数的估计值。

    25.平稳时间序列应满足什么条件?

    1)均值E(Yt)=μ,是与时间t无关的常数;

    2)方差Var(Yt)=σ2是与时间t无关的常数;

    3)协方差Cov(Yt,Yt+k)=γK是只与时期间隔k有关,与时间t无关的常数

    26.什么是时间序列的单整性?举例说明。

    随机游走序列的一阶差分序列△Yt=Yt - Yt -1是平稳序列。在这种情况下,我们说原非平稳序列Yt是“一阶单整的”,表示为I(1)。若非平稳序列必须取二阶差分(△2 Yt=△Yt—△Yt -1)才变为平稳序列,则原序列是“二阶单整的”,表示为I(2)。一般地,若一个非平稳序列必须取d阶差分才变为平稳序列,则原序列是“d阶单整的”,表示为I(d)。

    27.对非平稳变量直接建立ARMA模型可以吗?为什么?写出ARIMA(1,1,1)模型。

    可以,一个非平稳的随机时间序列通常可以通过差分的方法将它变换为平稳的,对差分后平稳的时间序列也可找出对应的平稳随机过程或模型。如果我们将一个非平稳时间序列通过d次差分,将它变为平稳的,然后用一个平稳的ARMA(p,q)模型作为它的生成模型,则我们就说该原始时间序列是一个自回归单整移动平均时间序列,记为ARIMA(p,d.q)。

    ARIMA(1,1,1)模型

    28.解释相关关系与因果关系的区别与联系。

    相关关系是指两个以上的变量的样本观测值序列之间表现出来的随机数学关系,用相关系数来衡量。因果关系是指两个或两个以上变量在行为机制上的依赖性,作为结果的变量是由作为原因的变量来决定的,原因变量的变化引起结果变量的变化。因果关系有单向因果关系和互为因果关系之分。具有因果关系的变量之间一定具有数学上的相关关系。而具有相关关系的变量之间并不一定具有因果关系。

    29.什么是协整?

    如果变量之间有着长期的稳定关系,即它们之间是协整的,则是可以使用经典回归模型方法建立回归模型的。假设X与Y间的长期“均衡关系”由式描述:Yt=α0+α1Xt+μt该均衡关系意味着:给定X的一个值,Y相应的均衡值也随之确定为α0+α1X(d,d)阶协整是一类非常重要的协整关系,它的经济意义在于:两个变量,虽然它们具有各自的长期波动规律,但是如果它们是(d,d)阶协整的,则它们之间存在着一个长期稳定的比例关系。

    30.简述建立误差校正模型的步骤。

    首先对变量进行协整分析,以发现变量之间的协整关系,即长期均衡关系,并以这种关系构成误差修正项。然后建立短期模型,将误差修正项看作一个解释变量,连同其他反映短期波动的解释变量一起,建立短期模型,即误差修正模型。

    31.简述建立误差校正模型(ECM)的基本思路。

    由协整与误差修正模型的关系,可以得到误差修正模型建立的E-G两步法:第一步,进行协整回归(OLS法),检验变量之间的协整关系,估计协整向量(长期均衡关系参数);第二步,若协整性存在,则以第一步求到的残差作为非均衡误差项加入到误差修正模型中,并用OLS法估计相应参数。

    经管世界成立专门团队独家收集整理等信息,并在公众号第一时间推送,更多相关整理后的资讯请在公众号回复关键字 征文获取。

    展开全文
  • 在慕课网学习时候遇到了这样一Java编程练习题,正好对所学习Java基础知识检验一下: 请根据所学知识,编写一Java程序,实现输出考试成绩要求: 1考试成绩已保存在数组scores中,数组元素依次为89...

           在慕课网学习的时候遇到了这样一个Java编程练习题,正好对所学习的Java基础知识检验一下:

    请根据所学知识,编写一个Java程序,实现输出考试成绩的前三名
    
    要求:
    1考试成绩已保存在数组scores中,数组元素依次为89 , -23 , 64 , 91 , 119 , 52 , 73
    
    2要求通过自定义方法来实现成绩排名并输出操作,将成绩数组作为参数传入
    
    3要求判断成绩的有效性( 0—100 ),如果成绩无效,则忽略此成绩

           我自己分析了一下这个程序的过程:

           (1)首先是定义一个包含整型数组参数的方法,用来接收成绩数组,进行成绩排序并输出前三名

           具体的步骤是:

           A在方法中使用Arrays类的sort( )方法对数组进行排序,默认按升序排列,注意Arrays类的使用需要导入;

    //引入数组类
    import java.util.Arrays;

           B由于只需要输出考试成绩的前三名,所以定义一个变量,统计有效成绩的前三名的数量;

           C使用 for 循环遍历数组中的元素,由于要输出的是前三名成绩,所以从后往前遍历,即倒序遍历;

    for(int i = scores.length - 1; i >= 0; i-- ) {
    	
    }

           D在for循环中判断成绩的有效性,如果成绩小于 0 或大于 100 ,则使用continue忽略此成绩;

           E如果成绩有效,则有效成绩数加1。判断有效成绩的个数,如果有效成绩数等于3 ,则结束循环,只输出成绩的

    前三名;

           (2)完成 main 方法

           A定义一个成绩数组 scores ,保存预定的考试成绩89 , -23 , 64 , 91 , 119 , 52 , 73;

           B调用自定义方法,传入成绩数组,完成成绩的输出;

          具体实现的代码为:

    //引入数组类
    import java.util.Arrays;
    public class Test {
        
        //完成 main 方法
        public static void main(String[] args) {
           //创建HelloWorld类的实例对象
           Test test=new Test();
    	   //定义一个整型数组
           int[] scores={89,-23,64,91,119,52,73,-45,78,168};
           System.out.println("考试成绩的前三名为:");
    	   //调用类的方法,输出结果
           test.result(scores);
            
        }
        
        //定义方法完成成绩排序并输出前三名的功能
        public void result(int[] scores){
    		//使用数组的sort()方法进行排序
            Arrays.sort(scores);
    		//初始化变量
            int count=0;
            for(int i=scores.length-1;i>=0;i--){
    			//若进入循环不是有效的成绩时,跳过这个成绩
                if(scores[i]<0||scores[i]>100){
                    continue;
                }
                count++;
                System.out.println(scores[i]);
    			//累计输出的分数个数为3时,中止循环
                if(count==3){
                    break;
                }
            }
        } 
    }
    
            输出的结果:







    展开全文
  • SpringBoot招组合拳,手把手教你打出优雅后端接口前言所需依赖包参数校验业务层校验Validator + BindResult进行校验Validator + 自动抛出异常全局异常处理基本使用自定义异常数据统一响应自定义统一响应体响应码...


    以项目驱动学习,以实践检验真知

    前言

    一个后端接口大致分为四个部分组成:接口地址(url)、接口请求方式(get、post等)、请求数据(request)、响应数据(response)。如何构建这几个部分每个公司要求都不同,没有什么“一定是最好的”标准,但一个优秀的后端接口和一个糟糕的后端接口对比起来差异还是蛮大的,其中最重要的关键点就是看是否规范!

    本文就一步一步演示如何构建起一个优秀的后端接口体系,体系构建好了自然就有了规范,同时再构建新的后端接口也会十分轻松。

    在文章末尾贴上了项目演示的github地址,clone下来即可运行,并且我将每一次的优化记录都分别做了代码提交,你可以清晰的看到项目的改进过程!

    所需依赖包

    这里用的是SpringBoot配置项目,本文讲解的重点是后端接口,所以只需要导入一个spring-boot-starter-web包就可以了:

    <!--web依赖包,web应用必备-->
    <dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    

    本文还用了swagger来生成API文档,lombok来简化类,不过这两者不是必须的,可用可不用。

    参数校验

    一个接口一般对参数(请求数据)都会进行安全校验,参数校验的重要性自然不必多说,那么如何对参数进行校验就有讲究了。

    业务层校验

    首先我们来看一下最常见的做法,就是在业务层进行参数校验:

    public String addUser(User user) {
         if (user == null || user.getId() == null || user.getAccount() == null || user.getPassword() == null || user.getEmail() == null) {
             return "对象或者对象字段不能为空";
         }
         if (StringUtils.isEmpty(user.getAccount()) || StringUtils.isEmpty(user.getPassword()) || StringUtils.isEmpty(user.getEmail())) {
             return "不能输入空字符串";
         }
         if (user.getAccount().length() < 6 || user.getAccount().length() > 11) {
             return "账号长度必须是6-11个字符";
         }
         if (user.getPassword().length() < 6 || user.getPassword().length() > 16) {
             return "密码长度必须是6-16个字符";
         }
         if (!Pattern.matches("^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)+$", user.getEmail())) {
             return "邮箱格式不正确";
         }
         // 参数校验完毕后这里就写上业务逻辑
         return "success";
     }
    

    这样做当然是没有什么错的,而且格式排版整齐也一目了然,不过这样太繁琐了,这还没有进行业务操作呢光是一个参数校验就已经这么多行代码,实在不够优雅。

    我们来改进一下,使用Spring Validator和Hibernate Validator这两套Validator来进行方便的参数校验!这两套Validator依赖包已经包含在前面所说的web依赖包里了,所以可以直接使用。

    Validator + BindResult进行校验

    Validator可以非常方便的制定校验规则,并自动帮你完成校验。首先在入参里需要校验的字段加上注解,每个注解对应不同的校验规则,并可制定校验失败后的信息:

    @Data
    public class User {
        @NotNull(message = "用户id不能为空")
        private Long id;
    
        @NotNull(message = "用户账号不能为空")
        @Size(min = 6, max = 11, message = "账号长度必须是6-11个字符")
        private String account;
    
        @NotNull(message = "用户密码不能为空")
        @Size(min = 6, max = 11, message = "密码长度必须是6-16个字符")
        private String password;
    
        @NotNull(message = "用户邮箱不能为空")
        @Email(message = "邮箱格式不正确")
        private String email;
    }
    

    校验规则和错误提示信息配置完毕后,接下来只需要在接口需要校验的参数上加上@Valid注解,并添加BindResult参数即可方便完成验证:

    @RestController
    @RequestMapping("user")
    public class UserController {
        @Autowired
        private UserService userService;
    
        @PostMapping("/addUser")
        public String addUser(@RequestBody @Valid User user, BindingResult bindingResult) {
            // 如果有参数校验失败,会将错误信息封装成对象组装在BindingResult里
            for (ObjectError error : bindingResult.getAllErrors()) {
                return error.getDefaultMessage();
            }
            return userService.addUser(user);
        }
    }
    

    这样当请求数据传递到接口的时候Validator就自动完成校验了,校验的结果就会封装到BindingResult中去,如果有错误信息我们就直接返回给前端,业务逻辑代码也根本没有执行下去。

    此时,业务层里的校验代码就已经不需要了:

    public String addUser(User user) {
         // 直接编写业务逻辑
         return "success";
     }
    

    现在可以看一下参数校验效果。我们故意给这个接口传递一个不符合校验规则的参数,先传递一个错误数据给接口,故意将password这个字段不满足校验条件:

    {
        "account": "12345678",
        "email": "123@qq.com",
        "id": 0,
        "password": "123"
    }
    

    再来看一下接口的响应数据:

    在这里插入图片描述
    这样是不是方便很多?不难看出使用Validator校验有如下几个好处:

    • 简化代码,之前业务层那么一大段校验代码都被省略掉了。

    • 使用方便,那么多校验规则可以轻而易举的实现,比如邮箱格式验证,之前自己手写正则表达式要写那么一长串,还容易出错,用Validator直接一个注解搞定。(还有更多校验规则注解,可以自行去了解哦)

    • 减少耦合度,使用Validator能够让业务层只关注业务逻辑,从基本的参数校验逻辑中脱离出来。

    使用Validator+ BindingResult已经是非常方便实用的参数校验方式了,在实际开发中也有很多项目就是这么做的,不过这样还是不太方便,因为你每写一个接口都要添加一个BindingResult参数,然后再提取错误信息返回给前端。

    这样有点麻烦,并且重复代码很多(尽管可以将这个重复代码封装成方法)。我们能否去掉BindingResult这一步呢?当然是可以的!

    Validator + 自动抛出异常

    我们完全可以将BindingResult这一步给去掉:

    @PostMapping("/addUser")
    public String addUser(@RequestBody @Valid User user) {
        return userService.addUser(user);
    }
    

    去掉之后会发生什么事情呢?直接来试验一下,还是按照之前一样故意传递一个不符合校验规则的参数给接口。此时我们观察控制台可以发现接口已经引发MethodArgumentNotValidException异常了:
    在这里插入图片描述
    其实这样就已经达到我们想要的效果了,参数校验不通过自然就不执行接下来的业务逻辑,去掉BindingResult后会自动引发异常,异常发生了自然而然就不会执行业务逻辑。也就是说,我们完全没必要添加相关BindingResult相关操作嘛。

    不过事情还没有完,异常是引发了,可我们并没有编写返回错误信息的代码呀,那参数校验失败了会响应什么数据给前端呢?

    我们来看一下刚才异常发生后接口响应的数据:
    在这里插入图片描述
    没错,是直接将整个错误对象相关信息都响应给前端了!这样就很难受,不过解决这个问题也很简单,就是我们接下来要讲的全局异常处理!

    全局异常处理

    参数校验失败会自动引发异常,我们当然不可能再去手动捕捉异常进行处理,不然还不如用之前BindingResult方式呢。又不想手动捕捉这个异常,又要对这个异常进行处理,那正好使用SpringBoot全局异常处理来达到一劳永逸的效果!

    基本使用

    首先,我们需要新建一个类,在这个类上加上@ControllerAdvice或@RestControllerAdvice注解,这个类就配置成全局处理类了。(这个根据你的Controller层用的是@Controller还是@RestController来决定)

    然后在类中新建方法,在方法上加上@ExceptionHandler注解并指定你想处理的异常类型,接着在方法内编写对该异常的操作逻辑,就完成了对该异常的全局处理!

    我们现在就来演示一下对参数校验失败抛出的MethodArgumentNotValidException全局处理:

    @RestControllerAdvice
    public class ExceptionControllerAdvice {
    
        @ExceptionHandler(MethodArgumentNotValidException.class)
        public String MethodArgumentNotValidExceptionHandler(MethodArgumentNotValidException e) {
            // 从异常对象中拿到ObjectError对象
            ObjectError objectError = e.getBindingResult().getAllErrors().get(0);
            // 然后提取错误提示信息进行返回
            return objectError.getDefaultMessage();
        }
    
    }
    

    我们再来看下这次校验失败后的响应数据:
    在这里插入图片描述
    没错,这次返回的就是我们制定的错误提示信息!我们通过全局异常处理优雅的实现了我们想要的功能!以后我们再想写接口参数校验,就只需要在入参的成员变量上加上Validator校验规则注解,然后在参数上加上@Valid注解即可完成校验,校验失败会自动返回错误提示信息,无需任何其他代码!更多的校验思路:SpringBoot实现通用的接口参数校验

    自定义异常

    全局处理当然不会只能处理一种异常,用途也不仅仅是对一个参数校验方式进行优化。在实际开发中,如何对异常处理其实是一个很麻烦的事情。传统处理异常一般有以下烦恼:

    • 是捕获异常(try…catch)还是抛出异常(throws)

    • 是在controller层做处理还是在service层处理又或是在dao层做处理

    • 处理异常的方式是啥也不做,还是返回特定数据,如果返回又返回什么数据

    • 不是所有异常我们都能预先进行捕捉,如果发生了没有捕捉到的异常该怎么办?

    以上这些问题都可以用全局异常处理来解决,全局异常处理也叫统一异常处理,全局和统一处理代表什么?代表规范!规范有了,很多问题就会迎刃而解!

    全局异常处理的基本使用方式大家都已经知道了,我们接下来更进一步的规范项目中的异常处理方式:自定义异常。

    在很多情况下,我们需要手动抛出异常,比如在业务层当有些条件并不符合业务逻辑,我这时候就可以手动抛出异常从而触发事务回滚。那手动抛出异常最简单的方式就是throw new RuntimeException("异常信息")了,不过使用自定义会更好一些:

    • 自定义异常可以携带更多的信息,不像这样只能携带一个字符串。

    • 项目开发中经常是很多人负责不同的模块,使用自定义异常可以统一了对外异常展示的方式。

    • 自定义异常语义更加清晰明了,一看就知道是项目中手动抛出的异常。

    我们现在就来开始写一个自定义异常:

    @Getter //只要getter方法,无需setter
    public class APIException extends RuntimeException {
        private int code;
        private String msg;
    
        public APIException() {
            this(1001, "接口错误");
        }
    
        public APIException(String msg) {
            this(1001, msg);
        }
    
        public APIException(int code, String msg) {
            super(msg);
            this.code = code;
            this.msg = msg;
        }
    }
    

    在刚才的全局异常处理类中记得添加对我们自定义异常的处理:

    @ExceptionHandler(APIException.class)
    public String APIExceptionHandler(APIException e) {
        return e.getMsg();
    }
    

    这样就对异常的处理就比较规范了,当然还可以添加对Exception的处理,这样无论发生什么异常我们都能屏蔽掉然后响应数据给前端,不过建议最后项目上线时这样做,能够屏蔽掉错误信息暴露给前端,在开发中为了方便调试还是不要这样做。

    现在全局异常处理和自定义异常已经弄好了,不知道大家有没有发现一个问题,就是当我们抛出自定义异常的时候全局异常处理只响应了异常中的错误信息msg给前端,并没有将错误代码code返回。这就要引申出我们接下来要讲的东西了:数据统一响应

    数据统一响应

    现在我们规范好了参数校验方式和异常处理方式,然而还没有规范响应数据!比如我要获取一个分页信息数据,获取成功了呢自然就返回的数据列表,获取失败了后台就会响应异常信息,即一个字符串,就是说前端开发者压根就不知道后端响应过来的数据会是啥样的!所以,统一响应数据是前后端规范中必须要做的!

    自定义统一响应体

    统一数据响应第一步肯定要做的就是我们自己自定义一个响应体类,无论后台是运行正常还是发生异常,响应给前端的数据格式是不变的!那么如何定义响应体呢?关于异常的设计:如何更优雅的设计异常

    可以参考我们自定义异常类,也来一个响应信息代码code和响应信息说明msg:

    @Getter
    public class ResultVO<T> {
        /**
         * 状态码,比如1000代表响应成功
         */
        private int code;
        /**
         * 响应信息,用来说明响应情况
         */
        private String msg;
        /**
         * 响应的具体数据
         */
        private T data;
    
        public ResultVO(T data) {
            this(1000, "success", data);
        }
    
        public ResultVO(int code, String msg, T data) {
            this.code = code;
            this.msg = msg;
            this.data = data;
        }
    }
    

    然后我们修改一下全局异常处理那的返回值:

    @ExceptionHandler(APIException.class)
    public ResultVO<String> APIExceptionHandler(APIException e) {
        // 注意哦,这里返回类型是自定义响应体
        return new ResultVO<>(e.getCode(), "响应失败", e.getMsg());
    }
    
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResultVO<String> MethodArgumentNotValidExceptionHandler(MethodArgumentNotValidException e) {
        ObjectError objectError = e.getBindingResult().getAllErrors().get(0);
        // 注意哦,这里返回类型是自定义响应体
        return new ResultVO<>(1001, "参数校验失败", objectError.getDefaultMessage());
    }
    

    我们再来看一下此时如果发生异常了会响应什么数据给前端:
    在这里插入图片描述
    OK,这个异常信息响应就非常好了,状态码和响应说明还有错误提示数据都返给了前端,并且是所有异常都会返回相同的格式!异常这里搞定了,别忘了我们到接口那也要修改返回类型,我们新增一个接口好来看看效果:

    @GetMapping("/getUser")
    public ResultVO<User> getUser() {
        User user = new User();
        user.setId(1L);
        user.setAccount("12345678");
        user.setPassword("12345678");
        user.setEmail("123@qq.com");
    
        return new ResultVO<>(user);
    }
    

    看一下如果响应正确返回的是什么效果:
    在这里插入图片描述
    这样无论是正确响应还是发生异常,响应数据的格式都是统一的,十分规范!

    数据格式是规范了,不过响应码code和响应信息msg还没有规范呀!大家发现没有,无论是正确响应,还是异常响应,响应码和响应信息是想怎么设置就怎么设置,要是10个开发人员对同一个类型的响应写10个不同的响应码,那这个统一响应体的格式规范就毫无意义!所以,必须要将响应码和响应信息给规范起来。

    响应码枚举

    要规范响应体中的响应码和响应信息用枚举简直再恰当不过了,我们现在就来创建一个响应码枚举类:

    @Getter
    public enum ResultCode {
    
        SUCCESS(1000, "操作成功"),
    
        FAILED(1001, "响应失败"),
    
        VALIDATE_FAILED(1002, "参数校验失败"),
    
        ERROR(5000, "未知错误");
    
        private int code;
        private String msg;
    
        ResultCode(int code, String msg) {
            this.code = code;
            this.msg = msg;
        }
    
    }
    

    然后修改响应体的构造方法,让其只准接受响应码枚举来设置响应码和响应信息:

    public ResultVO(T data) {
        this(ResultCode.SUCCESS, data);
    }
    
    public ResultVO(ResultCode resultCode, T data) {
        this.code = resultCode.getCode();
        this.msg = resultCode.getMsg();
        this.data = data;
    }
    

    然后同时修改全局异常处理的响应码设置方式:

    @ExceptionHandler(APIException.class)
    public ResultVO<String> APIExceptionHandler(APIException e) {
        // 注意哦,这里传递的响应码枚举
        return new ResultVO<>(ResultCode.FAILED, e.getMsg());
    }
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResultVO<String> MethodArgumentNotValidExceptionHandler(MethodArgumentNotValidException e) {
        ObjectError objectError = e.getBindingResult().getAllErrors().get(0);
        // 注意哦,这里传递的响应码枚举
        return new ResultVO<>(ResultCode.VALIDATE_FAILED, objectError.getDefaultMessage());
    }
    

    这样响应码和响应信息只能是枚举规定的那几个,就真正做到了响应数据格式、响应码和响应信息规范化、统一化!

    全局处理响应数据

    接口返回统一响应体 + 异常也返回统一响应体,其实这样已经很好了,但还是有可以优化的地方。要知道一个项目下来定义的接口搞个几百个太正常不过了,要是每一个接口返回数据时都要用响应体来包装一下好像有点麻烦,有没有办法省去这个包装过程呢?当然是有滴,还是要用到全局处理。

    首先,先创建一个类加上注解使其成为全局处理类。然后继承ResponseBodyAdvice接口重写其中的方法,即可对我们的controller进行增强操作,具体看代码和注释:

    @RestControllerAdvice(basePackages = {"com.rudecrab.demo.controller"}) // 注意哦,这里要加上需要扫描的包
    public class ResponseControllerAdvice implements ResponseBodyAdvice<Object> {
        @Override
        public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> aClass) {
            // 如果接口返回的类型本身就是ResultVO那就没有必要进行额外的操作,返回false
            return !returnType.getGenericParameterType().equals(ResultVO.class);
        }
    
        @Override
        public Object beforeBodyWrite(Object data, MethodParameter returnType, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest request, ServerHttpResponse response) {
            // String类型不能直接包装,所以要进行些特别的处理
            if (returnType.getGenericParameterType().equals(String.class)) {
                ObjectMapper objectMapper = new ObjectMapper();
                try {
                    // 将数据包装在ResultVO里后,再转换为json字符串响应给前端
                    return objectMapper.writeValueAsString(new ResultVO<>(data));
                } catch (JsonProcessingException e) {
                    throw new APIException("返回String类型错误");
                }
            }
            // 将原本的数据包装在ResultVO里
            return new ResultVO<>(data);
        }
    }
    

    重写的这两个方法是用来在controller将数据进行返回前进行增强操作,supports方法要返回为true才会执行beforeBodyWrite方法,所以如果有些情况不需要进行增强操作可以在supports方法里进行判断。对返回数据进行真正的操作还是在beforeBodyWrite方法中,我们可以直接在该方法里包装数据,这样就不需要每个接口都进行数据包装了,省去了很多麻烦。

    我们可以现在去掉接口的数据包装来看下效果:

    @GetMapping("/getUser")
    public User getUser() {
        User user = new User();
        user.setId(1L);
        user.setAccount("12345678");
        user.setPassword("12345678");
        user.setEmail("123@qq.com");
        // 注意哦,这里是直接返回的User类型,并没有用ResultVO进行包装
        return user;
    }
    

    然后我们来看下响应数据:
    在这里插入图片描述
    成功对数据进行了包装!


    注意:beforeBodyWrite方法里包装数据无法对String类型的数据直接进行强转,所以要进行特殊处理,这里不讲过多的细节,有兴趣可以自行深入了解。


    总结

    自此整个后端接口基本体系就构建完毕了

    • 通过Validator + 自动抛出异常来完成了方便的参数校验

    • 通过全局异常处理 + 自定义异常完成了异常操作的规范

    • 通过数据统一响应完成了响应数据的规范

    • 多个方面组装非常优雅的完成了后端接口的协调,让开发人员有更多的经历注重业务逻辑代码,轻松构建后端接口

    再次强调,项目体系该怎么构建、后端接口该怎么写都没有一个绝对统一的标准,不是说一定要按照本文的来才是最好的,你怎样都可以,本文每一个环节你都可以按照自己的想法来进行编码,我只是提供了一个思路!

    END
    展开全文
  • 你必须知道495C语言问题

    千次下载 热门讨论 2015-05-08 11:09:25
    5.16 考虑到有关空指针所有这些困惑,要求它们内部表示都必须为0不是更简单吗? 5.17 说真,真有机器用非零空指针吗,或者不同类型用不同表示? 地址0上到底有什么? 5.18 运行时整数值0转换为指针...
  • 《你必须知道495C语言问题》

    热门讨论 2010-03-20 16:41:18
    5.16 考虑到有关空指针所有这些困惑,要求它们内部表示都必须为0不是更简单吗? 60 5.17 说真,真有机器用非零空指针吗,或者不同类型用不同表示? 61 地址0 上到底有什么? 61 5.18 运行时整数值0...
  • 5.16 考虑到有关空指针所有这些困惑,要求它们内部表示都必须为0不是更简单吗? 60 5.17 说真,真有机器用非零空指针吗,或者不同类型用不同表示? 61 地址0 上到底有什么? 61 5.18 运行时整数值0...
  • 你必须知道495C语言问题(PDF)

    热门讨论 2009-09-15 10:25:47
    3.12 我需要根据条件把一复杂表达式赋值给两变量中。可以用下边这样代码吗? ((condition) ? a : b) = complicated expression; . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 目录iii ...
  • 经过工艺优化后,研制出宽光谱增透膜在要求的3.5-4.0 mm,6.3-7.6 mm,10.3-11.3 mm三个通道平均透射率均大于96%,而11.5-12.5 mm通道平均透射率大于94%。膜层能够经受住浸泡、高温高湿等一系列环模试验的检验,...
  • 针对单混沌系统因计算机有限精度效应产生混沌退化问题,提出了一种多级混沌映射交替变参数的伪...生成序列通过仿真表明,符合Golomb三个随机性公设要求及局部随机性统计检验要求,可作为密钥流序列应用到加密体制中。
  • 摘要:给出了一种单片同与PC进行通信低成本接口设计方法,并给出了其中关键参数,通过在实践中检验证明:该接口在对成本和体积有严格要求的系统中有着广泛应用。  关键词:单片机 PC 接口 通信  在...
  • Java开发技术大全(500源代码).

    热门讨论 2012-12-02 19:55:48
    HelloWorldApp.java 第一用Java开发应用程序。 firstApplet.java 第一用Java开发Applet小程序。 firstApplet.htm 用来装载Applet网页文件 第2章 示例描述:本章介绍开发Java基础语法知识。 ...
  • 、结论用短时傅立叶信号和余弦信号进行噪声对消性能测试,通过分别使用单一BP算法和混合算法作比较发现遗传算法具有很强处理能力和优化能力,用它优化BP神经网络权值,与原有单一BP算法相比,可以节省大量...
  • excel使用

    2012-11-25 17:06:01
    Excel自定义格式使用下面通用模型:正数格式,负数格式,零格式,文本格式,在这个通用模型中,包含三个数字段和一个文本段:大于零数据使用正数格式;小于零数据使用负数格式;等于零数据使用零格式;...
  • 2.5.4 面向Web应用的三层和n层体系结构 32 2.6 数据库管理系统的分类 33 2.7 小结 35 复习题 36 练习题 36 选读文献 37 第3章 使用实体-联系(ER)模型的数据建模 38 3.1 使用高级概念数据模型...
  • 我们一般会在文献统计方法部分看到这样描述: 对于数值变量,首先进行...四分位数(Quartile)是统计学中分位数一种,即把所有数值由小到大排列并分成四等份,处于三个分割点位置数值就是四分位数。 ...
  • LINGO软件学习

    2009-08-08 22:36:50
    LINGO生成了三个父集所有组合共八组作为allowed集成员。列表如下: 编号 成员 1 (A,M,1) 2 (A,M,2) 3 (A,N,1) 4 (A,N,2) 5 (B,M,1) 6 (B,M,2) 7 (B,N,1) 8 (B,N,2) 成员列表被忽略时,派生集成员由父集...
  • Stata 9 很好统计软件

    热门讨论 2008-11-24 11:45:14
     数值变量资料一般分析:参数估计,t检验,单因素和多因素方差分析,协方差分析,交互效应模型,平衡和非平衡设计,嵌套设计,随机效应,多均数两两比较,缺项数据处理,方差齐性检验,正态性检验,变量...
  • 外键约束是保证一或两表之间参照完整性,外键是构建于一字段或是两字段之间参照关系。 也就是说从表外键值必须在主表中能找到或者为空。 当主表记录被从表参照时,主表记录将不...
  • 通过洞口测量得到的多的三维坐标拟合出洞口的圆心坐标、洞口半径以及洞口平面的法向量等参数,最后通过拟合得到的这些参数与设计数据进行对比,检验隧道的施工误差是否满足设计的限差要求。 小博参考李英硕等人...
  • 全书共分三个部分:第一部分阐释了数据库基本概念,讲解了数据库建模语言;第二部分展示了从概念建模到在 sql server 2008上真正实现数据库过程;第三部分深入探讨了 sql server若干方面技术细节,如数据保护...
  • 全书共分三个部分:第一部分阐释了数据库基本概念,讲解了数据库建模语言;第二部分展示了从概念建模到在 sql server 2008上真正实现数据库过程;第三部分深入探讨了 sql server若干方面技术细节,如数据保护...

空空如也

空空如也

1 2 3 4 5 ... 7
收藏数 127
精华内容 50
关键字:

参数检验的三个要求