0、前言

无论任何项目,都避免不了在运行期间出现的一些异常,并伴随着因业务逻辑的需要而给出相应的提示,使得系统变得更加友好,这类提示处理,我们统称为异常处理(exceptiona handling)。

在项目中异常处理所抛出的异常码、异常提示 ,都需要进行一定的封装,以确保异常的统一,提高程序的可维护性。而不是随心所欲的来进行异常提醒,如:一些硬编码异常信息(throw new Exception("系统处理异常")),随着想项目的变大、开发人员的不同,这些异常码可能会五花八门,没有统一标准,给用户提示、给开发很容易带来些许的困惑。

本文不是讲解如何正确使用try、catch、finally等进行异常捕获,而是就异常码、异常信息进行封装,通过配置文件进行集中化定义,来统一异常处理,让异常处理变得更标准化、统一化,方便维护、管理。

1、异常处理

异常处理,又称为错误处理,提供了处理程序运行时出现的任何意外或异常情况的方法。异常处理使用 try、catch 和 finally 关键字来尝试可能未成功的操作,处理失败,以及在事后清理资源。

异常发生的原因有很多,通常包含以下几大类:

用户输入了非法数据。

要打开的文件不存在。

网络通信时连接中断,或者JVM内存溢出。

这些异常有的是因为用户错误引起,有的是程序错误引起的。

要理解Java异常处理是如何工作的,你需要掌握以下三种类型的异常:

检查性异常:最具代表的检查性异常是用户错误或问题引起的异常,这是程序员无法预见的。例如要打开一个不存在文件时,一个异常就发生了,这些异常在编译时不能被简单地忽略。

运行时异常: 运行时异常是可能被程序员避免的异常。与检查性异常相反,运行时异常可以在编译时被忽略。

错误: 错误不是异常,而是脱离程序员控制的问题。错误在代码中通常被忽略。例如,当栈溢出时,一个错误就发生了,它们在编译也检查不到的。

所有的异常类是从java.lang.Exception 类继承的子类。

Exception 类是 Throwable 类的子类。除了Exception类外,Throwable还有一个子类Error 。

Java 程序通常不捕获错误。错误一般发生在严重故障时,它们在Java程序处理的范畴之外。

Error 用来指示运行时环境发生的错误。例如,JVM 内存溢出。一般地,程序不会从错误中恢复。

异常类有两个主要的子类:IOException 类和 RuntimeException 类。

本文就针对处理的是Exception类异常。

2、统一异常处理

本实战中将异常码、异常信息进行封装,通过properties配置文件进行集中化定义,并支持国际化异常码的定义,来统一异常处理。

2.1 消息结果的封装

全系统统一返回的数据格式为:

{

"statusCode":"00000000",

"msg":"成功",

"data": {

"username":"xcbeyond",

"sex":"男",

"age":18

}

}

标准的json字符串,statusCode:状态码,msg:提示信息,data:结果数据(以实际数据而定的json)。

定义一个实体类Result,用来封装消息返回数据,如下:

package com.xcbeyond.execption.data;

import com.alibaba.fastjson.JSONObject;

import com.fasterxml.jackson.annotation.JsonInclude;

import com.xcbeyond.execption.util.ObjectUtils;

import java.io.Serializable;

/**

* 返回结果

* @Auther: xcbeyond

* @Date: 2019/5/24 17:55

*/

@JsonInclude(value = JsonInclude.Include.NON_NULL)

public class Result implements Serializable {

//状态码

private String statusCode;

//提示信息

private String msg;

//结果数据

private Object data;

public Result() {

}

public Result(String statusCode, String msg) {

this.statusCode = statusCode;

this.msg = msg;

}

public String getStatusCode() {

return statusCode;

}

public void setStatusCode(String statusCode) {

this.statusCode = statusCode;

}

public String getMsg() {

return msg;

}

public void setMsg(String msg) {

this.msg = msg;

}

public Object getData() {

return data;

}

public void setData(Object data) {

this.data = data;

}

/**

* 重写toString方法,让Result对象以json字符串形式存在

* @return

* Json字符串

*/

@Override

public String toString() {

JSONObject json = new JSONObject();

json.put("statusCode", this.statusCode);

json.put("msg", this.msg);

if (null != this.data) {

json.put("data", ObjectUtils.modelToMap(this.data));

}

return json.toJSONString();

}

}

2.2 异常码、异常信息配置文件定义化 *

将异常码、异常信息统一集中定义到properties配置文件中,避免硬编码在代码中,方便维护,便于后期变动统一修改。异常码文件位于项目resources目录下\resources\error\,如下:

异常码文件名统一格式:模块名_error_zh_CN.properties/模块名_error_en_US.properties(zh_CN、en_US区分国际化定义)

异常码统一格式定义,具体以实际项目情况而定,可参考如下标准定义:

#错误码定义8位

# ┌─1─┬─2─┬─3─┬─4─┬─5─┬─6─┬─7─┬─8─┐

# │预留 │C/B端│ 模块名 │ 错误码 │

# └─1─┴─2─┴─3─┴─4─┴─5─┴─6─┴─7─┴─8─┘

#第1位:

# 预留

#第2位:

# C/B端(客户端或服务端) 0-服务端, 1-客户端

#第3、4位:

# 2位模块名

#第5、6、7、8位:

# 4位错误码(后4位),各位含义如下:

# 第5为:类别,可按业务分类、接口分类等划分,0-9

# 第6-8位:3位具体错误码

# 第6位:按以下含义定义分类:

# 0:预留

# 1:非空检查类提示,数据为空、不为空检查

# 2:有效性检查提示,数据有效性检查(如格式、存在、不存在、不在有效值范围等)

# 3:业务逻辑类提示,合法性/一致性/完整性检查提示

# 4:预留/待扩展定义

# 5:预留/待扩展定义

# 6:预留/待扩展定义

# 7:预留/待扩展定义

# 8:预留/待扩展定义

# 9:预留/待扩展定义

# 第7、8位:二位顺序标号,00-99

封装异常码工具类ErrorUtils,用于从异常码文件中获取错误提示信息等,如下:

package com.xcbeyond.execption.util;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.context.NoSuchMessageException;

import org.springframework.context.support.ResourceBundleMessageSource;

import org.springframework.core.io.Resource;

import org.springframework.core.io.support.PathMatchingResourcePatternResolver;

import java.util.ArrayList;

import java.util.List;

import java.util.Locale;

/**

* 错误工具类,用于从错误码配置文件中获取错误提示信息等

* 支持国际化。

* @Auther: xcbeyond

* @Date: 2019/5/24 17:16

*/

public class ErrorUtils {

private static final Logger log = LoggerFactory.getLogger(ErrorUtils.class);

private static ResourceBundleMessageSource resourceBundle = new ResourceBundleMessageSource();

private static final String ZH_LANGUAGE = "CHINESE";

private static final String EN_LANGUAGE = "AMERICAN/ENGLISH";

private static final String FILE_KEYWORKS = "error";

private static final String JAR_RESOURCES = "classpath*:error/*error*.properties";

private static final String RESOURCES = "classpath*:*error*.properties";

/**

* 静态代码块。

* 用于加载错误码配置文件

*/

static {

try {

PathMatchingResourcePatternResolver patternResolver = new PathMatchingResourcePatternResolver();

List nameListCn = new ArrayList();

Resource[] jarResources = patternResolver.getResources(JAR_RESOURCES);

if (log.isDebugEnabled())

log.debug("加载CLASSPATH下[error]文件夹错误码配置文件[" + jarResources.length + "]");

for (Resource resource : jarResources) {

String fileName = resource.getFilename();

fileName = fileName.substring(0, fileName.indexOf(FILE_KEYWORKS) + 5);

if (log.isDebugEnabled())

log.debug("加载[error]下错误码配置文件[" + resource.getFilename() + "][" + fileName + "]");

nameListCn.add("error/" + fileName);

}

Resource[] resources = patternResolver.getResources(RESOURCES);

if (log.isDebugEnabled())

log.debug("加载CLASSPATH根目录错误码配置文件[" + resources.length + "]");

for (Resource resource : resources) {

String fileName = resource.getFilename();

fileName = fileName.substring(0, fileName.indexOf(FILE_KEYWORKS) + 5);

if (log.isDebugEnabled())

log.debug("加载错误码配置文件[" + resource.getFilename() + "][" + fileName + "]");

nameListCn.add(fileName);

}

resourceBundle.setBasenames((String[]) nameListCn.toArray(new String[0]));

resourceBundle.setCacheSeconds(5);

} catch (Throwable localThrowable) {

}

}

/**

* 获取错误码描述信息

* @param errCode 错误码

* @return

*/

public static String getErrorDesc(String errCode) {

return getErrorDesc(errCode, "CHINESE");

}

/**

* 获取错误码描述信息

* @param errCode 错误码

* @param userLang 国际化语言

* @return

*/

public static String getErrorDesc(String errCode, String userLang) {

String errDesc = "";

try {

if ((null == userLang) || (ZH_LANGUAGE.equals(userLang))) {

errDesc = resourceBundle.getMessage(errCode, null, Locale.SIMPLIFIED_CHINESE);

} else if (EN_LANGUAGE.equals(userLang)) {

errDesc = resourceBundle.getMessage(errCode, null, Locale.US);

}

} catch (NoSuchMessageException localNoSuchMessageException) {

}

return errDesc;

}

/**

* 获取错误码描述信息

* @param errCode 错误码

* @param args 错误描述信息中参数

* @return

*/

public static String getParseErrorDesc(String errCode, String[] args) {

return getParseErrorDesc(errCode, ZH_LANGUAGE, args);

}

/**

* 获取错误码描述信息

* @param errCode 错误码

* @param userLang 国际化语言

* @param args 错误描述信息中参数

* @return

*/

public static String getParseErrorDesc(String errCode, String userLang, String[] args) {

String errDesc = "";

try {

if ((null == userLang) || (ZH_LANGUAGE.equals(userLang)))

errDesc = resourceBundle.getMessage(errCode, args, Locale.SIMPLIFIED_CHINESE);

else if (EN_LANGUAGE.equals(userLang))

errDesc = resourceBundle.getMessage(errCode, args, Locale.US);

} catch (NoSuchMessageException localNoSuchMessageException) {

}

return errDesc;

}

}

2.3 异常类封装

本文封装两类异常:

系统级异常:指系统级别的,如:网络通信时连接中断、系统连接、超时等异常

业务处理异常:指用户输入了非法数据等业务逻辑存在的异常

(其他类别异常,可自行封装,如SQL类异常)

(1)异常基类BaseException,所有异常类都继承此类,如下:

package com.xcbeyond.execption;

import java.io.Serializable;

/**

* 异常基类

* @Auther: xcbeyond

* @Date: 2019/5/28 16:27

*/

public class BaseException extends RuntimeException implements Serializable {

public BaseException() {

}

public BaseException(String message) {

super(message);

}

public BaseException(Throwable cause) {

super(cause);

}

public BaseException(String message, Throwable cause) {

super(message, cause);

}

}

(2)系统级异常SystemException,如下:

package com.xcbeyond.execption;

import com.xcbeyond.execption.data.Result;

/**

* 系统级异常。

* 指系统级别的,如:网络通信时连接中断、系统连接、超时等异常

* @Auther: xcbeyond

* @Date: 2019/5/28 16:26

*/

public class SystemException extends BaseException{

private Result result = new Result();

public SystemException(Result result) {

super(result.getStatusCode()+ ":" + result.getMsg());

this.result = result;

}

public SystemException(String code, String msg) {

super(code + ":" + msg);

this.result.setStatusCode(code);

this.result.setMsg(msg);

}

public SystemException(Result result, Throwable cause) {

super(result.getStatusCode() + ":" + result.getMsg(), cause);

this.result = result;

}

public SystemException(String code, String msg, Throwable cause) {

super(code + ":" + msg, cause);

this.result.setStatusCode(code);

this.result.setMsg(msg);

}

public Result getResult() {

return result;

}

public void setResult(Result result) {

this.result = result;

}

}

(3)业务处理异常类BusinessException,如下:

语言

方法

3173

WGPq58teZ3

4636

2009/04/27 08:39:04

package com.xcbeyond.execption;

import com.xcbeyond.execption.data.Result;

/**

* 业务处理异常

* 指用户输入了非法数据等业务逻辑存在的异常

* @Auther: xcbeyond

* @Date: 2018/12/24 11:20

*/

public class BusinessException extends BaseException {

private Result result = new Result();

public BusinessException(Result result) {

super(result.getStatusCode()+ ":" + result.getMsg());

this.result = result;

}

public BusinessException(String code, String msg) {

super(code + ":" + msg);

this.result.setStatusCode(code);

this.result.setMsg(msg);

}

public BusinessException(Result result, Throwable cause) {

super(result.getStatusCode() + ":" + result.getMsg(), cause);

this.result = result;

}

public BusinessException(String code, String msg, Throwable cause) {

super(code + ":" + msg, cause);

this.result.setStatusCode(code);

this.result.setMsg(msg);

}

public Result getResult() {

return result;

}

public void setResult(Result result) {

this.result = result;

}

}

(4)异常工具类ExecptionUtils

为方便在业务代码中进行统一异常调用,特封装异常工具类ExecptionUtils,如下:

package com.xcbeyond.execption.util;

import com.xcbeyond.execption.BusinessException;

import com.xcbeyond.execption.SystemException;

import com.xcbeyond.execption.data.Result;

/**

* 异常工具类

* @Auther: xcbeyond

* @Date: 2019/5/27 09:37

*/

public class ExecptionUtils {

/**

* 业务处理异常

* @param errCode 异常码

* @return

*/

public static BusinessException businessException(String errCode) {

return new BusinessException(createResult(errCode));

}

/**

* 业务处理异常

* @param errCode 自定义异常码

* @param msg 自定义异常提示

* @return

*/

public static BusinessException businessException(String errCode, String msg) {

return new BusinessException(createResult(errCode, msg));

}

/**

* 业务处理异常

* @param errCode 异常码

* @param args 错误描述信息中的参数

* @return

*/

public static BusinessException businessException(String errCode, String... args) {

return new BusinessException(createResult(errCode, args));

}

/**

* 系统级异常

* @param errCode 异常码

* @return

*/

public static SystemException systemException(String errCode) {

return new SystemException(createResult(errCode));

}

/**

* 业务处理异常

* @param errCode 自定义异常码

* @param msg 自定义异常提示

* @return

*/

public static SystemException systemException(String errCode, String msg) {

return new SystemException(createResult(errCode, msg));

}

/**

* 系统级异常

* @param errCode 异常码

* @param args 错误描述信息中的参数

* @return

*/

public static SystemException systemException(String errCode, String... args) {

return new SystemException(createResult(errCode, args));

}

private static Result createResult(String errCode) {

return new Result(errCode, getErrorMsg(errCode));

}

private static Result createResult(String errCode, String msg) {

return new Result(errCode, msg);

}

private static Result createResult(String errCode, String[] args) {

return new Result(errCode, getErrorMsg(errCode, args));

}

/**

* 获取错误信息

* @param errCode 错误码

* @return

*/

private static String getErrorMsg(String errCode) {

return ErrorUtils.getErrorDesc(errCode);

}

/**

* 获取错误信息

* @param errCode 错误码

* @param args 错误描述信息中的参数

* @return

*/

private static String getErrorMsg(String errCode, String[] args) {

return ErrorUtils.getParseErrorDesc(errCode, args);

}

}

2.4 全局异常捕获

一般异常捕获都是通过try/catch、throw new等方式进行捕获,而频繁的这样操作,有时让人觉得麻烦,代码变得不是那么的干净,尤其业务复杂的场合。就像下面这种:

try{

..........

}catch(Exception1 e){

..........

}catch(Exception2 e){

...........

}catch(Exception3 e){

...........

}

这样的代码既不简洁好看 ,我们敲着也烦, 一般我们可能想到用拦截器去处理。而在spring中提供了更好的方案,注解@ControllerAdvice和@ExceptionHandler,进行全局统一异常处理。

本文定义全局异常捕获类GlobalExceptionHandler,如下:

package com.xcbeyond.execption.handler;

import com.xcbeyond.execption.BusinessException;

import com.xcbeyond.execption.SystemException;

import com.xcbeyond.execption.data.Result;

import org.springframework.http.HttpStatus;

import org.springframework.http.ResponseEntity;

import org.springframework.web.bind.annotation.ControllerAdvice;

import org.springframework.web.bind.annotation.ExceptionHandler;

/**

* 全局异常捕获处理

* @Auther: xcbeyond

* @Date: 2019/5/28 15:19

*/

@ControllerAdvice

public class GlobalExceptionHandler {

/**

* 业务逻辑异常。

* HTTP响应状态为200

* @param businessException

* @return

*/

@ExceptionHandler(value = BusinessException.class)

public ResponseEntity businessExceptionHandler(BusinessException businessException) {

Result result = businessException.getResult();

return new ResponseEntity(result, HttpStatus.OK);

}

/**

* 系统异常。

* HTTP响应状态为400

* @param systemException

* @return

*/

@ExceptionHandler(value = SystemException.class)

public ResponseEntity systemExceptionHandler(SystemException systemException) {

Result result = systemException.getResult();

return new ResponseEntity(result, HttpStatus.BAD_REQUEST);

}

}

2.5 应用

将上述定义封装的异常,进行实际应用。

下述只是为了进行异常应用测试,并不符合实际业务场景。

以用户登录接口的service层UserServiceImpl类实现讲解,代码如下:

package com.xcbeyond.execption.service.impl;

import com.xcbeyond.execption.model.User;

import com.xcbeyond.execption.service.UserService;

import com.xcbeyond.execption.util.ExecptionUtils;

import org.springframework.http.HttpStatus;

import org.springframework.http.ResponseEntity;

import org.springframework.stereotype.Service;

import org.springframework.util.StringUtils;

/**

* @Auther: xcbeyond

* @Date: 2019/5/28 17:04

*/

@Service

public class UserServiceImpl implements UserService {

public ResponseEntity login(User user) {

if (StringUtils.isEmpty(user.getUsername())) {

throw ExecptionUtils.businessException("EE3001");

}

if (StringUtils.isEmpty(user.getPassword())) {

throw ExecptionUtils.businessException("EE3002");

}

if (!"xcbeyond".equals(user.getUsername())) {

throw ExecptionUtils.businessException("EE4001", user.getUsername());

}

/**

* 测试系统级异常.

* 通过用户名和密码相同时,来模拟网络连接异常

*/

if (user.getPassword().equals(user.getUsername())) {

throw ExecptionUtils.systemException("999999", "网络链接异常");

}

return new ResponseEntity(HttpStatus.OK);

}

}

此例有三类场合异常处理:

(1)不带参的逻辑异常处理

throw ExecptionUtils.businessException("EE3002");

返回数据:

(2)带参的逻辑异常处理

throw ExecptionUtils.businessException("EE4001", user.getUsername());

(3)系统级异常处理

throw ExecptionUtils.systemException("EE9999");

java异常处理封装_Java统一异常处理(配置文件集中化定义)相关推荐

  1. java model 封装_Java封装统一的Result Model案例

    在开发过程中,有时候会需要使用错误码+错误信息的形式,来返回某些业务操作的错误结果信息,来代替效率较低的异常传递. 这样就需要封装一个统一的Result model作为返回值,代替直接返回数据等结果. ...

  2. java finally 抛出异常_java的异常处理机制(try catch finally)

    1 引子 try-catch-finally恐怕是大家再熟悉不过的语句了,而且感觉用起来也是很简单,逻辑上似乎也是很容易理解.不过, 我亲自体验的"教训"告诉我,这个东西可不是想象 ...

  3. java通过异常处理错误_java 通过异常处理错误

    1.java异常标准 在java中,Throwable这个类是所有异常或错误的父类.Throwable可以分为两种类型: error:表示编译时和系统错误,除特殊情况外,一般不用担心 exceptio ...

  4. java 异常练习题_java入门异常处理练习题问题

    tppe 大概方式:1.判断用户输入的类型是否正确,不正确捕获异常,把他包装成我自己定义的异常2.判断用户输入的数是多少2.1.如果是1,则打印"输入图书名称",用户输入,定义一个 ...

  5. java异常处理机制_Java的异常处理机制

    Throwable 类是 Java 语言中所有错误或异常的超类.只有当对象是此类(或其子类之一)的实例时,才能通过 Java 虚拟机或者 Java 的 throw 语句抛出.类似地,只有此类或其子类之 ...

  6. java编写自定义异常类,统一异常处理

    /** * 自定义异常类 */ public class MyBaseException extends RuntimeException{private static final long seri ...

  7. java 文件封装_Java 封装

    在面向对象程式设计方法中,封装(英语:Encapsulation)是指,一种将抽象性函式接口的实作细节部份包装.隐藏起来的方法. 封装可以被认为是一个保护屏障,防止该类的代码和数据被外部类定义的代码随 ...

  8. java properties 保存_Java 读写Properties配置文件

    转自:https://www.cnblogs.com/xudong-bupt/p/3758136.html 1.Properties类与Properties配置文件 Properties类继承自Has ...

  9. java oo 封装_Java从小白到入门,Day6。JAVAOO-封装

    封装是把过程和数据包围起来,对数据的访问只能通过已定义的接口.面向对象计算始于这个基本概念,即现实世界可以被描绘成一系列完全自治.封装的对象,这些对象通过一个受保护的接口访问其他对象.封装是一种信息隐 ...

最新文章

  1. 线程局部存储(很有局限性,但有时候可以用一下)
  2. Linux Mint无法打开系统设置,以及很多系统图标
  3. Spring与Hibernate两种组合方式
  4. 信号处理常用算法介绍
  5. JAVA复习5(集合——集合的遍历 Iteratorforeach、Enumeration——HashMap、HashTable、LinkedHashMap——map的遍历)
  6. Qbxt 模拟题 day3(am) T3 选数字 (select)(贪心)
  7. Cache-Control的一些认识
  8. Smuxi 0.8.10 发布 - IRC 客户端软件
  9. 三层神经网络实现手写数字图像分类
  10. 最新emoji表情代码大全_抖音不用考虑我我没感受铁打的图片,最新表情包高清大全[多图]-软件教程...
  11. html如何制作斜线表头表格,2种方法教你怎样在WPS excel中绘制表格斜线表头
  12. 《嵌入式-STM32开发指南》第三部分 外设篇 - 第4章 超声波测距
  13. 在唯一密钥属性“fileExtension”设置为“.json”时,无法添加类型为“mimeMap”的重复集合项...
  14. C# NPOI 导出Excel 日期格式
  15. “云钉一体”战略解读:阿里打通了数字化的“罗马引水桥”
  16. 系统集成项目应怎样管?本文经验值得借鉴
  17. 每日英语--Week13
  18. [转帖]江湖经验:喝酒的学问技巧,社会新人一定要看~!
  19. 配置基于接口的ARP表项限制和端口安全(限制用户私自接入傻瓜交换机或非法主机接入)
  20. 在少儿编程中使用easygui(3):enterbox和multenterbox

热门文章

  1. C#编程(三十三)----------Array类
  2. .net、mono和C#
  3. SecureCRT使用小技巧
  4. 有关linux下find和xargs的使用
  5. DatabaseMetaData的使用
  6. 禁止Apache列出目录内容
  7. 修改Extmail和Extman的源代码增加公司部门和中文名字段
  8. 第五周课程总结试验报告三
  9. cookie 和 session 区别
  10. js面试题:创建一个json对象people,并追加属性:姓名、性别、年龄,追加run方法...