在Java Web开发中,为了提供更统一、更友好的API接口,我们通常会自定义返回结果和异常处理机制。这样做的好处是可以将业务逻辑与HTTP响应的封装解耦,提高代码的可读性和可维护性。本文将介绍如何在Java Web项目中自定义返回结果和异常处理。
在Java编程中,异常处理是一个非常重要的组成部分。Java标准库提供了一系列的内置异常类,如NullPointerException
、IOException
等。然而,在实际开发中,我们有时需要定义一些与特定业务逻辑或框架相关的异常类。本文将介绍如何在Java中创建自定义异常处理类,并阐述其重要性和用法。
一、自定义返回结果
1. 定义返回结果类
首先我们需要定义一个返回结果类,用于封装API接口的相应数据。这个类通常包含状态码、消息和数据等字段。
首先在创建一个 ResultCodeEnum 枚举类,用来作为前后端状态数据交换状态码:
package com.javaclimb.service.base.result;
import lombok.Getter;
import lombok.ToString;
/**
* @Author cb
* @createTime
* @Version
* @注释:前后端数据交换状态码
*/
@Getter
@ToString
public enum ResultCodeEnum {
SUCCESS(true, 20000, "成功"),
UNKNOWN_REASON(false, 20001, "未知错误"),
BAD_SQL_GRAMMAR(false, 21001, "sql 语法错误"),
JSON_PARSE_ERROR(false, 21002, "json 解析异常"),
PARAM_ERROR(false, 21003, "参数不正确"),
FILE_UPLOAD_ERROR(false, 21004, "文件上传错误"),
FILE_DELETE_ERROR(false, 21005, "文件刪除错误"),
EXCEL_DATA_IMPORT_ERROR(false, 21006, "Excel 数据导入错误"),
VIDEO_UPLOAD_ALIYUN_ERROR(false, 22001, "视频上传至阿里云失败"),
VIDEO_UPLOAD_TOMCAT_ERROR(false, 22002, "视频上传至业务服务器失败"),
VIDEO_DELETE_ALIYUN_ERROR(false, 22003, "阿里云视频文件删除失败"),
FETCH_VIDEO_UPLOADAUTH_ERROR(false, 22004, "获取上传地址和凭证失败"),
REFRESH_VIDEO_UPLOADAUTH_ERROR(false, 22005, "刷新上传地址和凭证失败"),
FETCH_PLAYAUTH_ERROR(false, 22006, "获取播放凭证失败"),
URL_ENCODE_ERROR(false, 23001, "URL编码失败"),
ILLEGAL_CALLBACK_REQUEST_ERROR(false, 23002, "非法回调请求"),
FETCH_ACCESSTOKEN_FAILD(false, 23003, "获取 accessToken 失败"),
FETCH_USERINFO_ERROR(false, 23004, "获取用户信息失败"),
LOGIN_ERROR(false, 23005, "登录失败"),
COMMENT_EMPTY(false, 24006, "评论内容必须填写"),
PAY_RUN(false, 25000, "支付中"),
PAY_UNIFIEDORDER_ERROR(false, 25001, "统一下单错误"),
PAY_ORDERQUERY_ERROR(false, 25002, "查询支付结果错误"),
ORDER_EXIST_ERROR(false, 25003, "课程已购买"),
GATEWAY_ERROR(false, 26000, "服务不能访问"),
CODE_ERROR(false, 28000, "验证码错误"),
LOGIN_PHONE_ERROR(false, 28009, "手机号码不正确"),
LOGIN_MOBILE_ERROR(false, 28001, "账号不正确"),
LOGIN_PASSWORD_ERROR(false, 28008, "密码不正确"),
LOGIN_DISABLED_ERROR(false, 28002, "该用户已被禁用"),
REGISTER_MOBLE_ERROR(false, 28003, "手机号已被注册"),
LOGIN_AUTH(false, 28004, "需要登录"),
LOGIN_ACL(false, 28005, "没有权限"),
SMS_SEND_ERROR(false, 28006, "短信发送失败"),
SMS_SEND_ERROR_BUSINESS_LIMIT_CONTROL(false, 28007, "短信发送过于频繁"),
DIVIDE_ZERO(false, 29001, "除零错误");
private final Boolean success;
private final Integer code;
private final String message;
ResultCodeEnum(Boolean success, Integer code, String message) {
this.success = success;
this.code = code;
this.message = message;
}
}
再创建一个 result.java 类
package com.result;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.media.SchemaProperties;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.Data;
import org.apache.ibatis.annotations.Property;
import java.util.HashMap;
import java.util.Map;
/**
* @Author cb
* @createTime
* @Version
* @注释:全局统一返回结果
*/
@Data
@Schema(description = "返回码")
public class Result {
@Schema(description = "是否成功")
private Boolean success;
@Schema(description = "返回码")
private Integer code;
@Schema(description = "返回消息")
private String message;
@Schema(description = "返回数据")
private Map<String, Object> data = new HashMap<>();
public Result () {
}
public static Result ok() {
Result r = new Result();
r.setSuccess(ResultCodeEnum.SUCCESS.getSuccess());
r.setCode(ResultCodeEnum.SUCCESS.getCode());
r.setMessage(ResultCodeEnum.SUCCESS.getMessage());
return r;
}
public static Result error() {
Result r = new Result ();
r.setSuccess(ResultCodeEnum.UNKNOWN_REASON.getSuccess());
r.setCode(ResultCodeEnum.UNKNOWN_REASON.getCode());
r.setMessage(ResultCodeEnum.UNKNOWN_REASON.getMessage());
return r;
}
public static Result setResult(ResultCodeEnum resultCodeEnum) {
Result r = new Result ();
r.setSuccess(resultCodeEnum.getSuccess());
r.setCode(resultCodeEnum.getCode());
r.setMessage(resultCodeEnum.getMessage());
return r;
}
public Result success(Boolean success) {
this.setSuccess(success);
return this;
}
public Result message(String message) {
this.setMessage(message);
return this;
}
public Result code(Integer code) {
this.setCode(code);
return this;
}
public Result data(String key, Object value) {
this.data.put(key, value);
return this;
}
public Result data(Map<String, Object> map) {
this.setData(map);
return this;
}
}
2. 在Controller中使用自定义返回结果
在Controller层,我们可以使用自定义的 result
类来封装响应数据,并返回给前端。
package com.controller.admin;
import com.result.Result;
import com.result.ResultCodeEnum;
import java.util.List;
/**
*
* @author cb
* @since
*/
@RestController
@RequestMapping("/admin/teacher")
@CrossOrigin
@Tag(name = "文档API",description = "")
public class TeacherController {
@Operation(description = "测试接口")
@GetMapping("/getString")
public result getTest(){
return Result.ok().message("测试成功").data("数据值的键",数据值);
}
}
二、自定义异常处理
1. 定义自定义异常类
当业务逻辑出现错误时,我们可以抛出自定义的异常类,以便进行统一的异常处理。
首先创建一个 ExceptionUtils 类来拿到异常错误信息。
package com.utils;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
/**
* @Author cb
* @createTime
* @Version
* @注释:从异常信息中拿到错误信息栈
*/
public class ExceptionUtils {
public static String getMessage(Exception e) {
StringWriter sw = null;
PrintWriter pw = null;
try {
sw = new StringWriter();
pw = new PrintWriter(sw);
// 将出错的栈信息输出到printWriter中
e.printStackTrace(pw);
pw.flush();
sw.flush();
} finally {
if (sw != null) {
try {
sw.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
if (pw != null) {
pw.close();
}
}
return sw.toString();
}
}
再创建一个自定义类 JavaclimbException 继承 RuntimeException
里面就写自定义需要处理的哪一类异常。
package com.exception;
import com.result.ResultCodeEnum;
import lombok.Data;
/**
* @Author cb
* @createTime
* @Version
* @注释:自定义异常,用户自己主动抛出的异常
*/
@Data
public class JavaclimbException extends RuntimeException {
private Integer code;
public JavaclimbException(ResultCodeEnum resultCodeEnum) {
super(resultCodeEnum.getMessage());
this.code = resultCodeEnum.getCode();
}
}
2. 使用@ControllerAdvice进行全局异常处理
package com.admin;
import com.result.Result;
import com.result.ResultCodeEnum;
import com.exception.JavaclimbException;
import java.util.List;
/**
*
* @author cb
*
*/
@RestController
@RequestMapping("/admin")
@CrossOrigin
@Tag(name = "文档API",description = "")
public class TeacherController {
@Operation(description = "测试接口")
@GetMapping("/getString")
public Result getTest(){
return Result.ok().message("测试成功").data("数据值的键",数据值);
}
/**
* 异常测试
*/
@Operation(description = "异常测试")
@GetMapping("exceptionTest")
public R exceptionTest(){
try {
int a = 1/0;
} catch (Exception e) {
e.printStackTrace();
throw new JavaclimbException(ResultCodeEnum.DIVIDE_ZERO);
}
return Result.ok();
}
}