当前位置: 首页 > article >正文

IntelliJ+SpringBoot项目实战(十)--常量类、自定义错误页、全局异常处理

一、常量类

       在项目开发中,经常需要约定一些常量,比如接口返回响应请求指定状态码、异常类型、默认页数等,为了增加代码的可阅读性以及开发团队中规范一些常量的使用,可开发一些常量类。下面有3个常量类示例,代码位于openjweb-common的org/openjweb/common/constant路径:

下面是接口调用返回的状态码常量类ResponseConst.java:

package org.openjweb.common.constant;

public class ResponseConst {

    //按HTTP返回码定义的常量
    public static final int STATE_HTTP_SUCCESS = 200;

    //有的项目设置0为调用成功的返回值
    public static final int STATE_SUCCESS = 0;

    //有的项目设置-1为默认的请求失败返回的错误码
    public static final int STATE_FAIL = -1;

}

 下面是异常提示信息常量类ExceptionConst.java:

/**
 * 异常相关常量
 */
public class ExceptionConst {

    public static final String UNKNOWN_ERROR_MSG = "数据加载失败,请稍后重试";
    public static final String SQL_ERROR_MSG = "数据异常,请稍后重试";
    public static final String CONNECT_ERROR_MSG = "连接异常,请稍后重试";
    public static final String LOGIN_ERROR_MSG = "用户名或密码错误";
    public static final String CLICK_HOUSE_ERROR_MSG = "clickhouse查询异常";
    public static final String UPLOAD_FILE_ERROR_MSG = "上传文件失败";
    public static final String DELETE_FILE_ERROR_MSG = "删除文件失败";
    public static final String XCX_ERROR_MSG = "小程序维护中,请稍后再试";
}

下面是公共常量类CommonConst.java:

package org.openjweb.common.constant;

/**
 * 公共常量
 
 */
public class CommonConst {

    /**
     * 默认显示页数20
     */
    public static final int DEFAULT_PAGE_SIZE = 20;

    /**
     * 数据量大时,分页查询数据条数
     */
    public static final int DEFAULT_SEARCH_PAGE_SIZE = 500;

    /**
     * 微信支付access-token
     */
    public static final String WX_ACCESS_TOKEN = "wx_access_token";

    /**
     * 默认排序
     */
    public static final int DEFAULT_SORT = 1;

    /**
     * 状态:0-禁用;1-启用
     */
    public static final int IS_ENABLE_0 = 0;
    public static final int IS_ENABLE_1 = 1;
}

在项目开发中还可以定义更多的常量类。

二、自定义错误页面

      大家在SpringBoot开发过程中,对下面这个页面应该是很熟悉:

    

       如果我们访问一个不存在的资源的时候,就会显示这个页面。这个页面不太友好,我们如何自定义这个默认的错误页呢?

      现在在openjweb-sys的resources目录下建一个static目录,然后在这个目录下建一个error-404.html页面(特别注意:经测试,如果页面命名为404.html是有问题的,所以不能用404.html文件名):

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>404</title>
</head>
<body>
<div class="text" style=" text-align:center;">
    页面出错了!!
</div>
</body></html>

     然后在openjweb-sys的org/openjweb/sys/config下面建一个错位页配置类ErrorPageConfig.java:

package org.openjweb.sys.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.web.server.ConfigurableWebServerFactory;
import org.springframework.boot.web.server.ErrorPage;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;

@Configuration
@Slf4j
public class ErrorPageConfig {

    @Bean
    public WebServerFactoryCustomizer<ConfigurableWebServerFactory> webServerFactoryCustomizer() {
        return new WebServerFactoryCustomizer<ConfigurableWebServerFactory>() {
            @Override
            public void customize(ConfigurableWebServerFactory factory) {

                log.info("重新指定404页面................");
                ErrorPage err404Page = new ErrorPage(HttpStatus.NOT_FOUND, "/error-404.html");//不能直接命名404.html
                //ErrorPage err500Page = new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR, "/error/error-500.html");//
                //ttpStatus.BAD_REQUEST:400,ttpStatus.INTERNAL_SERVER_ERROR 500
                factory.addErrorPages(err404Page);
                //factory.addErrorPages(err404Page,err500Page);
            }
        };
    }
}

        注意在上面的代码中,仅示例了出现404(HttpStatus.NOT_FOUND)的时候跳转到error-404.html,另外这个类只是演示了替代默认的错误处理,并没有根据不同的HttpStatus指定不同的错误处理页。现在重启动SpringBoot,访问一个不存在的链接:http://localhost:8001/demo/api/redis/se1

界面显示: 这个就是我们定义的error-404.html的内容,已经不再显示SpringBoot默认的错误页了。不过在实际项目中,光做到这一步还是不够的。应该针对不同的错误返回不同的错误信息。

三、全局异常处理及升级错误处理页

       在实际开发中,需要做一个全局异常处理,以便通过框架自动处理异常,而不是在每个业务方法中手工处理产生的异常,这样开发效率很低。另外在错误处理页上,需要展示错误码、错误信息等。首先我们需要实现一个全局异常处理类,我们命名为GlobalException,放在openjweb-common的org/openjweb/common/exception下:

        

package org.openjweb.common.exception;

import org.openjweb.common.constant.ResponseConst;

public class GlobalException extends RuntimeException {

    private int code = ResponseConst.STATE_FAIL;//默认错误码

    private String appName;//异常产生的应用名称

    public GlobalException(String msg) {
        super(msg);
    }

    public GlobalException(String msg, int code) {
        super(msg);
        this.code = code;
    }

    public GlobalException(String message, String appName) {
        super(message);
        this.appName = appName;
    }

    public GlobalException(String message, int code, String appName) {
        super(message);
        this.code = code;
        this.appName = appName;
    }

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public String getAppName() {
        return this.appName;
    }

    public void setAppName(String appName) {
        this.appName = appName;
    }
}

        接下来我们在oopenjweb-common工程的org.openjweb.common.handler包下创建一个GlobalExceptionHandler类,在这个类中,我们指定GlobalException类的拦截处理以及指定错误视图:

package org.openjweb.common.handler;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import lombok.extern.slf4j.Slf4j;
import org.openjweb.common.exception.GlobalException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

@Slf4j
@ControllerAdvice(basePackages= {"org.openjweb"})
public class GlobalExceptionHandler {
    
    @ExceptionHandler({GlobalException.class})
    @ResponseBody
    public ModelAndView globalErrorHandler(HttpServletRequest request,HttpServletResponse response,Exception ex) throws Exception {
        ModelAndView mv = new ModelAndView();
        if(true) {
            log.info("自定义全局异常 GlobalException 异常处理........");
            GlobalException thisException = (GlobalException)ex;
            int errorCode = thisException.getCode();
            mv.addObject("errorCode", errorCode);
            mv.addObject("errorMessage","GlobalException处理异常:"+ex.getMessage());
            mv.addObject("requestUrl",request.getRequestURL().toString());
            mv.setViewName("errorPage");
        }
        return mv;

    }

}

        在上面的类中,通过增加了@ControllerAdvice注解,通过在方法中增加@ExceptionHandler(GlobalException.class)注解,则凡是在控制层中抛出GlobalException异常,则都会被此类拦截,并返回错误页视图errorPage。

       接下来我们定义一个errorPage错误处理页面,因为我们现在要使用thymeleaf解析视图里的页面错误信息,所以需要在openjweb-sys工程的resources/template目录下创建一个errorPage.html:

<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>error</title>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
</head>

<body>
<table> 
<tr>
<td>错误码:</td>
<td th:text="${errorCode}"></td>
</tr>
<tr>
<td>错误信息:</td>
<td th:text="${errorMessage}"></td> 
</tr>
<tr>
<td>请求地址:</td>
    <td th:text="${requestUrl}"></td>
</tr>
</table>
</body>
</html>

        在errorPage.html里显示错误码、错误信息、错误请求的URL。然后我们需要实现一个api测试类来演示下效果。在openjweb-sys的org.openjweb.sys.api下创建一个DefaultErrorApi.java:

package org.openjweb.sys.api;

import lombok.extern.slf4j.Slf4j;
import org.openjweb.common.exception.GlobalException;
import org.openjweb.sys.entity.CommUser;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * 测试:http://localhost:8001/demo/error/testError?flag=1
 * http://localhost:8001/demo/error/testError?flag=2
 *  *
 */
@RestController
@RequestMapping("/demo/error")
@Slf4j
public class DefaultErrorApi {

    @RequestMapping("testError")
    public CommUser testError(String flag){
        CommUser user = new CommUser();

        if("1".equals(flag)) {
            throw new GlobalException("演示全局异常", -1);
        }
        else {
            user.setRealName("张三");
            user.setLoginId("admin");
            return user;
        }
    }

}

       在上面的示例代码中,通过传递flag=1演示带自定义错误页的异常显示,传其他值为正常接口调用,访问 http://localhost:8001/demo/error/testError?flag=1 演示自定义错误页:

        

访问http://localhost:8001/demo/error/testError?flag=2为正常的接口调用:

       在实际开发中,控制层一种是返回API JSON数据,第二种就是返回视图,我们在调用数据请求接口时,希望异常时返回统一的错误信息JSON包,请求视图时,异常返回统一的错误视图,这种需求怎么实现?上面的示例是返回视图的异常。接下来我们再实现一个返回JSON的异常处理:

      (1)首先我们再加一个用于JSON处理的异常处理类,命名为GlobalJsonException,内容直接复制GlobalException,然后把构造方法修改下:

   

package org.openjweb.common.exception;

import org.openjweb.common.constant.ResponseConst;

/**
 * 用于API调用时统一处理错误异常
 */

public class GlobalJsonException extends RuntimeException {

    private int code = ResponseConst.STATE_FAIL;//默认错误码

    private String appName;//异常产生的应用名称

    public GlobalJsonException(String msg) {
        super(msg);
    }

    public GlobalJsonException(String msg, int code) {
        super(msg);
        this.code = code;
    }

    public GlobalJsonException(String message, String appName) {
        super(message);
        this.appName = appName;
    }

    public GlobalJsonException(String message, int code, String appName) {
        super(message);
        this.code = code;
        this.appName = appName;
    }

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public String getAppName() {
        return this.appName;
    }

    public void setAppName(String appName) {
        this.appName = appName;
    }
}

然后在GlobalExceptionHandler.java中增加一个新的方法:

    @ExceptionHandler({GlobalJsonException.class})
    @ResponseBody
    public JSONObject globalJsonErrorHandler(HttpServletRequest request, HttpServletResponse response, Exception ex) throws Exception {
        GlobalJsonException thisException = (GlobalJsonException)ex;
        JSONObject errJson = new JSONObject();
        errJson.put("code",thisException.getCode());
        errJson.put("msg",thisException.getMessage());
        return errJson;

    }

然后我们在defaultErrorApi中在增加一个方法演示JSON接口调用异常的拦截处理:

    @RequestMapping("testJsonError")
    public CommUser testJsonError(String flag){
        CommUser user = new CommUser();

        if("1".equals(flag)) {
            throw new GlobalJsonException("演示全局异常", -1);
        }
        else {
            user.setRealName("张三");
            user.setLoginId("admin");

        }
        return user;
    }

测试地址:http://localhost:8001/demo/error/testJsonError?flag=1

       这样我们就不需要在每个业务接口中专门针对异常来做JSON处理了。只需要在全局异常处理类中做处理即可,不过业务接口中,需要把code、message放到异常中。


http://www.kler.cn/a/407962.html

相关文章:

  • 3D超声重建技术
  • C#里怎么样检测文件的属性?
  • 《Spring Boot:快速构建应用的利器》
  • 【青牛科技】 GC2803:白色家电与安防领域的卓越驱动芯片可替代ULN2803
  • stm32如何接收舵机的控制信号(而不是控制舵机)
  • 【AI】kimi深度版的荣誉之战(fail)
  • 软件测试面试之重要的名词解释
  • 大模型上层Agent系统思考
  • Perforce《2024游戏技术现状报告》Part3:生成式AI、版本控制、CI/CD等游戏技术的未来趋势与应用
  • FreeSWITCH 简单图形化界面34 - 网络环境安全的情况下,进行任意SIP注册
  • 案例研究|阿特斯的JumpServer分布式部署和多组织管理实践
  • 摄像机视频分析软件下载LiteAIServer视频智能分析平台玩手机打电话检测算法技术的实现
  • P2TR(Taproot 交易)和Musig2
  • 51c深度学习~合集8
  • react-amap海量点优化
  • python 正则表达式re 模块的基本使用方法
  • Spark 中 RDD checkpoint 是通过启动两个独立的 Job 完成的。
  • Spring Boot驱动的高效OA解决方案
  • nc网络工具的使用
  • 《Python编程实训快速上手》第八天--组织文件