Java 项目创建 -- 统一结果处理、统一异常处理

一世执手 提交于 2020-04-27 13:51:13

一、IDEA 插件使用

1、说明

  此处使用 SpringBoot 2.2.6 、JDK 1.8 、mysql 8.0.18 作为演示。

  使用 IDEA 作为开发工具。

 

2、IDEA 插件 -- Lombok

(1)简介
  Lombok 能通过注解的方式,在编译时自动为属性生成构造器、getter/setter、equals、hashcode、toString 等方法。
  比如在实体类上使用 @Data 注解,就可以省去 getter、 setter 等方法的编写,但是在编译生成的字节码文件中有getter和setter方法。

 

(2)安装

  Settings -> Plugins,搜索 Lombok。点击 install 安装后重启 IDEA 即可。

 

 

 

(3)使用

Step1:
  使用 maven 添加依赖,引入对应的 jar 包。

<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.12</version>
</dependency>

 

Step2:
  使用各种注解,简化代码编写。比如 @Data。

 

3、IDEA 插件 -- Easy Code

(1)简介
  Easy Code 是 IDEA 的一个插件,可以直接对数据的表生成 entity, controller, service, dao, mapper 等代码,无需任何编码,简单而强大。

 

(2)安装

  Settings -> Plugins,搜索 EasyCode。点击 install 安装后重启 IDEA 即可。

 

 

 

(3)使用
Step1:
  创建一个 SpringBoot 项目。

 

 

 

Step2:
  连接数据库,并创建一个 数据表,用于测试。

DROP DATABASE IF EXISTS test;

CREATE DATABASE test;

USE test;

CREATE TABLE emp(
    id int PRIMARY KEY auto_increment,
    name varchar(50),
    salary decimal(10, 2),
    age int,
    email varchar(50)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO emp VALUES(null, "tom", 6000, 20, "tom@163.com");

 

 

 

Step3:
  右键表名,选择 EasyCode -> Generate Code,生成代码。

 

 

 

选择代码生成的路径 以及 包名。

 

 

 

自动创建需要的文件。

 

 

 

Step4:
  当然这样并不能直接使用,还得添加相关依赖、注解、以及数据库连接信息才能使用。
添加依赖:
  比如: lombok、mybatis-plus、mysql-connector-java 以及 web 启动类。


<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.12</version>
    <scope>provided</scope>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<!-- https://mvnrepository.com/artifact/com.baomidou/mybatis-plus-boot-starter -->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.3.1</version>
</dependency>

<!-- mysql -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.18</version>
</dependency>

 

添加注解:
  dao 层添加 @Mapper 注解,或者在启动类上添加 @MapperScan 注解扫描 dao 层。
  entity 上可以添加 @Data 注解,用于简化 getter、setter 方法。

 

配置 yml 文件:

# 配置数据源
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: 123456
    url: jdbc:mysql://localhost:3306/test

# 配置 mybatis-plus
mybatis-plus:
  mapper-location: classpath:/mapper/**/*.xml
  global-config:
    db-config:
      id-type: auto

 

Step5:启动项目,并访问 controller

 

 

 

二、Java 项目构建 -- 统一结果处理

1、为什么使用统一结果?

  大部分前后端项目采用 JSON 格式进行数据交互,定义一个统一的数据规范,有利于前后台的交互、以及信息处理。

2、数据格式?如何处理?代码实现?

(1)数据格式?
  是否响应成功(success: true / false)
  响应状态码(code:200 / 400 / 500 等)
  状态码描述(message:访问成功 / 系统异常等)
  响应数据(data:处理的数据)



【输出格式如下所示:】

{
  "success": true,
  "code": 200,
  "message": "查询用户列表",
  "data": {
    "itms": [
      {
        "id": "1",
        "username": "admin",
        "role": "ADMIN",
        "createTime": "2020-4-24T15:32:29",
        "modifiedTime": "2020-4-24T15:41:40"
      },{
        "id": "2",
        "username": "zhangsan",
        "role": "USER",
        "createTime": "2020-4-24T15:32:29",
        "modifiedTime": "2020-4-24T15:41:40"
      }
    ]
  }
}

 

(2)如何处理?
  success 设置成 Boolean 类型。
  code 设置成 Integer 类型。  
  message 设置成 String 类型。
  data 设置成 HashMap 类型。
  构造器私有,且使用静态方法返回类对象。
  采用链式调用(即方法返回对象为其本身,return this)。





(3)代码实现?
  Step1:创建一个 统一结果处理类 Result 。

 

【代码实现如下:】

package com.lyh.common.util;

import lombok.Data;
import org.apache.http.HttpStatus;

import java.util.HashMap;
import java.util.Map;

/**
 * 统一结果返回类。方法采用链式调用的写法(即返回类本身 return this)。
 * 构造器私有,不允许进行实例化,但提供静态方法 ok、error 返回一个实例。
 * 静态方法说明:
 *      ok     返回一个 成功操作 的结果(实例对象)。
 *      error  返回一个 失败操作 的结果(实例对象)。
 *
 * 普通方法说明:
 *      success      用于自定义响应是否成功
 *      code         用于自定义响应状态码
 *      message      用于自定义响应消息
 *      data         用于自定义响应数据
 *
 * 依赖信息说明:
 *      此处使用 @Data 注解,需导入 lombok 相关依赖文件。
 *      使用 HttpStatus 的常量表示 响应状态码,需导入 httpcore 相关依赖文件。
 */
@Data
public class Result {
    /**
     * 响应是否成功,true 为成功,false 为失败
     */
    private Boolean success;

    /**
     * 响应状态码, 200 成功,500 系统异常
     */
    private Integer code;

    /**
     * 响应消息
     */
    private String message;

    /**
     * 响应数据
     */
    private Map<String, Object> data = new HashMap<>();

    /**
     * 默认私有构造器
     */
    private Result(){}

    /**
     * 私有自定义构造器
     * @param success 响应是否成功
     * @param code 响应状态码
     * @param message 响应消息
     */
    private Result(Boolean success, Integer code, String message){
        this.success = success;
        this.code = code;
        this.message = message;
    }

    /**
     * 返回一个默认的 成功操作 的结果,默认响应状态码 200
     * @return 成功操作的实例对象
     */
    public static Result ok() {
        return new Result(true, HttpStatus.SC_OK, "success");
    }

    /**
     * 返回一个自定义 成功操作 的结果
     * @param success 响应是否成功
     * @param code 响应状态码
     * @param message 响应消息
     * @return 成功操作的实例对象
     */
    public static Result ok(Boolean success, Integer code, String message) {
        return new Result(success, code, message);
    }

    /**
     * 返回一个默认的 失败操作 的结果,默认响应状态码为 500
     * @return 失败操作的实例对象
     */
    public static Result error() {
        return new Result(false, HttpStatus.SC_INTERNAL_SERVER_ERROR, "error");
    }

    /**
     * 返回一个自定义 失败操作 的结果
     * @param success 响应是否成功
     * @param code 响应状态码
     * @param message 相应消息
     * @return 失败操作的实例对象
     */
    public static Result error(Boolean success, Integer code, String message) {
        return new Result(success, code, message);
    }

    /**
     * 自定义响应是否成功
     * @param success 响应是否成功
     * @return 当前实例对象
     */
    public Result success(Boolean success) {
        this.setSuccess(success);
        return this;
    }

    /**
     * 自定义响应状态码
     * @param code 响应状态码
     * @return 当前实例对象
     */
    public Result code(Integer code) {
        this.setCode(code);
        return this;
    }

    /**
     * 自定义响应消息
     * @param message 响应消息
     * @return 当前实例对象
     */
    public Result message(String message) {
        this.setMessage(message);
        return this;
    }

    /**
     * 自定义响应数据,一次设置一个 map 集合
     * @param map 响应数据
     * @return 当前实例对象
     */
    public Result data(Map<String, Object> map) {
        this.data.putAll(map);
        return this;
    }

    /**
     * 通用设置响应数据,一次设置一个 key - value 键值对
     * @param key 键
     * @param value 数据
     * @return 当前实例对象
     */
    public Result data(String key, Object value) {
        this.data.put(key, value);
        return this;
    }
}

 

Step2:依赖信息

<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpcore</artifactId>
    <version>4.4.13</version>
</dependency>

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.12</version>
    <scope>provided</scope>
</dependency>

 

Step3:HttpStatus 状态码参考地址

http://hc.apache.org/httpcomponents-core-ga/httpcore/apidocs/org/apache/http/HttpStatus.html

 

(4)使用:
  修改某个 controller 如下所示:
  若查询用户成功,调用 ok 返回查询到的结果。
  若查询用户失败,调用 error 返回查询失败信息。


@GetMapping("selectOne")
public Result selectOne(Integer id) {
    Emp emp = this.empService.queryById(id);
    if (emp == null) {
        return Result.error().message("用户不存在");
    }
    return Result.ok().data("items", emp).message("查询成功");
}

 

 

启动服务并访问:
  测试查询用户不成功的返回结果:

{
    "success": false,
    "code": 500,
    "message": "用户不存在",
    "data": {}
}

 

 

  测试查询用户成功的返回结果:

{
    "success": true,
    "code": 200,
    "message": "查询成功",
    "data": {
        "items": {
            "id": 1,
            "name": "tom",
            "salary": 6000.0,
            "age": 20,
            "email": "tom@163.com"
        }
    }
}

 

 

三、Java 项目构建 -- 统一异常处理

1、为什么使用统一异常处理?

  使用统一结果处理时,有些异常我们可以提前预知并处理,但是一个运行时异常,我们不一定能预知并处理,这时可以使用统一异常处理,当异常发生时,触发该处理操作,从而保证程序的健壮性。

2、怎么做?如何处理?代码实现?

(1)怎么做?
  使用 @ControllerAdvice 或者 @RestControllerAdvice 注解作为统一异常处理的核心。
  这两个注解都是 Spring MVC 提供的。作用于 控制层 的一种切面通知。
功能:
  全局异常处理。
  全局数据绑定。
  全局数据预处理。





【@ControllerAdvice 与 @RestControllerAdvice 区别:】
    @RestControllerAdvice 注解包含了 @ControllerAdvice 与 @ResponseBody 注解。
    类似于 @Controller 与 @RestController 的区别。
    @RestControllerAdvice 返回 json 数据时不需要添加 @ResponseBody 注解。

 

(2)如何处理?
  使用 @ControllerAdvice 或者 @RestControllerAdvice 注解标记一个 全局异常处理类。
  全局异常处理类内部使用 @ExceptionHandler 注解去捕获异常。
  可以自定义一个异常信息收集类,用于处理项目中的异常,并收集异常信息。


(3)代码实现?
  Step1(可选操作):
    自定义一个异常类,用于处理项目中的异常,并收集异常信息。

【代码实现:】

package com.lyh.common.exception;

import lombok.Data;
import org.apache.http.HttpStatus;

/**
 * 自定义异常,
 * 可以自定义 异常信息 message 以及 响应状态码 code(默认为 500)。
 *
 * 依赖信息说明:
 *      此处使用 @Data 注解,需导入 lombok 相关依赖文件。
 *      使用 HttpStatus 的常量表示 响应状态码,需导入 httpcore 相关依赖文件。
 */
@Data
public class GlobalException extends RuntimeException {
    /**
     * 保存异常信息
     */
    private String message;

    /**
     * 保存响应状态码
     */
    private Integer code = HttpStatus.SC_INTERNAL_SERVER_ERROR;

    /**
     * 默认构造方法,根据异常信息 构建一个异常实例对象
     * @param message 异常信息
     */
    public GlobalException(String message) {
        super(message);
        this.message = message;
    }

    /**
     * 根据异常信息、响应状态码构建 一个异常实例对象
     * @param message 异常信息
     * @param code 响应状态码
     */
    public GlobalException(String message, Integer code) {
        super(message);
        this.message = message;
        this.code = code;
    }

    /**
     * 根据异常信息,异常对象构建 一个异常实例对象
     * @param message 异常信息
     * @param e 异常对象
     */
    public GlobalException(String message, Throwable e) {
        super(message, e);
        this.message = message;
    }

    /**
     * 根据异常信息,响应状态码,异常对象构建 一个异常实例对象
     * @param message 异常信息
     * @param code 响应状态码
     * @param e 异常对象
     */
    public GlobalException(String message, Integer code, Throwable e) {
        super(message, e);
        this.message = message;
        this.code = code;
    }
}

 

Step2:
  定义一个全局的异常处理类 GlobalExceptionHandler。
  使用 @RestControllerAdvice 注解标记这个类。
  内部使用 @ExceptionHandler 注解去捕获异常。


【代码实现:】

package com.lyh.common.exception;

import com.lyh.common.util.Result;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

/**
 * 全局异常处理类。
 * 使用 slf4j 保存日志信息。
 * 此处使用了 统一结果处理 类 Result 用于包装异常信息。
 */
@RestControllerAdvice
public class GlobalExceptionHandler {
    private Logger logger = LoggerFactory.getLogger(getClass());

    /**
     * 处理 Exception 异常
     * @param e 异常
     * @return 处理结果
     */
    @ExceptionHandler(Exception.class)
    public Result handlerException(Exception e) {
        logger.error(e.getMessage(), e);
        return Result.error().message("系统异常");
    }

    /**
     * 处理空指针异常
     * @param e 异常
     * @return 处理结果
     */
    @ExceptionHandler(NullPointerException.class)
    public Result handlerNullPointerException(NullPointerException e) {
        logger.error(e.getMessage(), e);
        return Result.error().message("空指针异常");
    }

    /**
     * 处理自定义异常
     * @param e 异常
     * @return 处理结果
     */
    @ExceptionHandler(GlobalException.class)
    public Result handlerGlobalException(GlobalException e) {
        logger.error(e.getMessage(), e);
        return Result.error().message(e.getMessage()).code(e.getCode());
    }
}

 

(4)使用?
  修改某个 controller 如下所示:
  参数不存在时,抛出 空指针异常。
  参数为 -1 时,抛出自定义异常并处理。
  查询结果为 null 时,抛出自定义异常并处理。
  查询成功时,正确处理并返回。




@GetMapping("selectOne")
public Result selectOne(Integer id) {
    Emp emp = this.empService.queryById(id);
    if (id == null) {
        throw new NullPointerException();
    }
    if (id == -1) {
        throw new GlobalException("参数异常", 400);
    }
    if (emp == null) {
        throw new GlobalException("未查询到结果,请确认输入是否正确");
    }
    return Result.ok().data("items", emp).message("查询成功");
}

 

 

启动服务并访问:
  参数不存在时:

{
    "success": false,
    "code": 500,
    "message": "空指针异常",
    "data": {}
}

 

 

  参数存在,但为 -1 时:

{
    "success": false,
    "code": 400,
    "message": "参数异常",
    "data": {}
}

 

 

  参数存在,但查询结果为 null 时:

{
    "success": false,
    "code": 500,
    "message": "未查询到结果,请确认输入是否正确",
    "data": {}
}

 

 

  参数存在,查询结果存在时:

{
    "success": true,
    "code": 200,
    "message": "查询成功",
    "data": {
        "items": {
            "id": 1,
            "name": "tom",
            "salary": 6000.0,
            "age": 20,
            "email": "tom@163.com"
        }
    }
}

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!