Java project creation -- unified result processing and exception handling

1, IDEA plug-in use

1. Description

Spring boot 2.2.6, JDK 1.8 and mysql 8.0.18 are used as demonstration here.

Use IDEA as a development tool.

 

2. IDEA plug-in -- Lombok

(1) Introduction
Lombok can automatically generate constructor, getter/setter, equals, hashcode, toString and other methods for properties during compilation through annotation.
For example, using @ Data annotation on entity classes can save the writing of getter, setter and other methods, but there are getter and setter methods in bytecode files generated by compilation.

 

(2) Installation

Settings - > plugins, search Lombok. Click install and restart IDEA.

 

 

 

(3) Use

Step1:
Use maven to add dependency and introduce corresponding jar package.

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

 

Step2:
Use various annotations to simplify code writing. For example, @ Data.

 

3. IDEA plug-in -- Easy Code

(1) Introduction
Easy Code is a plug-in of IDEA, which can directly generate entity, controller, service, dao, mapper and other codes for data tables, without any coding, simple and powerful.

 

(2) Installation

Settings - > plugins, search for EasyCode. Click install and restart IDEA.

 

 

 

(3) Use
Step1:
Create a spring boot project.

 

 

 

Step2:
Connect to the database and create a data table for testing.

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:
Right click the table name and select EASYCODE - > generate code to generate the code.

 

 

 

Select the path of the code generation and the package name.

 

 

 

Automatically create the required files.

 

 

 

Step4:
Of course, it can't be used directly. You have to add related dependencies, annotations, and database connection information to use.
Add dependency:
For example: lombok, mybatis plus, MySQL connector Java, and web startup classes.

<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>

 

Add note:
Add @ Mapper annotation to dao layer, or add @ MapperScan annotation to startup class to scan dao layer.
The @ Data annotation can be added to entity to simplify getter and setter methods.

 

To configure the yml file:

# Configure data sources
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: 123456
    url: jdbc:mysql://localhost:3306/test

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

 

Step 5: start the project and access the controller

 

 

 

2, Java project construction -- unified result processing

1. Why use uniform results?

Most front-end and back-end projects use JSON format for data interaction, defining a unified data specification, which is conducive to front-end and back-end interaction, as well as information processing.

2. Data format? How to deal with it? Code implementation?

(1) Data format?
Whether the response is successful (success: true / false)
Response status code (Code: 200 / 400 / 500, etc.)
Description of status code (message: access success / system exception, etc.)
Response data (data: processed data)

[The output format is as follows:]

{
  "success": true,
  "code": 200,
  "message": "Query user list",
  "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) How to deal with it?
success is set to Boolean type.
code is set to Integer type.   
message is set to String type.
data is set to the HashMap type.
The constructor is private and uses static methods to return class objects.
Use chain call (that is, the method returns the object itself, return this).

(3) Code implementation?
Step 1: create a unified Result processing class, Result.

 

[The code implementation is as follows:]

package com.lyh.common.util;

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

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

/**
 * Uniform result return class. Method is written as a chain call (that is, return this of the return class itself).
 * Constructor is private, instantiation is not allowed, but static methods ok and error are provided to return an instance.
 * Static method description:
 *      ok     Returns the result of a successful operation (instance object).
 *      error  Returns the result of a failed operation (instance object).
 *
 * General method description:
 *      success      Used to customize whether the response is successful
 *      code         For custom response status codes
 *      message      For custom response messages
 *      data         For custom response data
 *
 * Description of dependent information:
 *      The @ Data annotation is used here. You need to import lombok dependent files.
 *      The constant of HttpStatus is used to represent the response status code, which needs to be imported into httpcore dependent files.
 */
@Data
public class Result {
    /**
     * Whether the response is successful, true means success, false means failure
     */
    private Boolean success;

    /**
     * Response status code, 200 successful, 500 system abnormal
     */
    private Integer code;

    /**
     * Response message
     */
    private String message;

    /**
     * Response data
     */
    private Map<String, Object> data = new HashMap<>();

    /**
     * Default private constructor
     */
    private Result(){}

    /**
     * Private custom constructor
     * @param success Whether the response is successful
     * @param code Response status code
     * @param message Response message
     */
    private Result(Boolean success, Integer code, String message){
        this.success = success;
        this.code = code;
        this.message = message;
    }

    /**
     * Returns the result of a default successful operation. The default response status code is 200
     * @return Instance object for successful operation
     */
    public static Result ok() {
        return new Result(true, HttpStatus.SC_OK, "success");
    }

    /**
     * Returns the result of a custom successful operation
     * @param success Whether the response is successful
     * @param code Response status code
     * @param message Response message
     * @return Instance object for successful operation
     */
    public static Result ok(Boolean success, Integer code, String message) {
        return new Result(success, code, message);
    }

    /**
     * Returns the result of a default failed operation. The default response status code is 500
     * @return Instance object for failed operation
     */
    public static Result error() {
        return new Result(false, HttpStatus.SC_INTERNAL_SERVER_ERROR, "error");
    }

    /**
     * Returns the result of a custom failed operation
     * @param success Whether the response is successful
     * @param code Response status code
     * @param message Corresponding message
     * @return Instance object for failed operation
     */
    public static Result error(Boolean success, Integer code, String message) {
        return new Result(success, code, message);
    }

    /**
     * Whether the custom response succeeded
     * @param success Whether the response is successful
     * @return Current instance object
     */
    public Result success(Boolean success) {
        this.setSuccess(success);
        return this;
    }

    /**
     * Custom response status code
     * @param code Response status code
     * @return Current instance object
     */
    public Result code(Integer code) {
        this.setCode(code);
        return this;
    }

    /**
     * Custom response message
     * @param message Response message
     * @return Current instance object
     */
    public Result message(String message) {
        this.setMessage(message);
        return this;
    }

    /**
     * Custom response data, set one map set at a time
     * @param map Response data
     * @return Current instance object
     */
    public Result data(Map<String, Object> map) {
        this.data.putAll(map);
        return this;
    }

    /**
     * Set the response data in general, and set one key value pair at a time
     * @param key key
     * @param value data
     * @return Current instance object
     */
    public Result data(String key, Object value) {
        this.data.put(key, value);
        return this;
    }
}

 

Step 2: dependency information

<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 status code reference address

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

 

(4) Use:
Modify a controller as follows:
If the query user is successful, call ok to return the query result.
If the query fails, call error to return the query failure information.

@GetMapping("selectOne")
public Result selectOne(Integer id) {
    Emp emp = this.empService.queryById(id);
    if (emp == null) {
        return Result.error().message("user does not exist");
    }
    return Result.ok().data("items", emp).message("query was successful");
}

 

 

Start the service and access:
Test query user unsuccessful return result:

{
    "success": false,
    "code": 500,
    "message": "user does not exist",
    "data": {}
}

 

 

Test the returned result of query user success:

{
    "success": true,
    "code": 200,
    "message": "query was successful",
    "data": {
        "items": {
            "id": 1,
            "name": "tom",
            "salary": 6000.0,
            "age": 20,
            "email": "tom@163.com"
        }
    }
}

 

 

3, Java project construction -- Unified exception handling

1. Why unified exception handling?

When using unified result processing, we can predict and handle some exceptions in advance, but a runtime exception may not be predicted and handled. In this case, we can use unified exception processing. When an exception occurs, the processing operation will be triggered to ensure the robustness of the program.

2. How? How to deal with it? Code implementation?

(1) How?
Use the @ ControllerAdvice or @ RestControllerAdvice annotation as the core of unified exception handling.
Both annotations are provided by Spring MVC. A slice notification that acts on the control layer.
Function:
Global exception handling.
Global data binding.
Global data preprocessing.

[@ ControllerAdvice differs from @ RestControllerAdvice:]
    @The RestControllerAdvice annotation contains the @ ControllerAdvice and @ ResponseBody annotations.
    Similar to the difference between @ Controller and @ RestController.
    @The @ ResponseBody annotation does not need to be added when the RestControllerAdvice returns json data.

 

(2) How to deal with it?
Use the @ controlleradvise or @ restcontrolleradvise annotation to mark a global exception handling class.
The @ ExceptionHandler annotation is used inside the global exception handling class to catch exceptions.
You can customize an exception information collection class to handle exceptions in a project and collect exception information.

(3) Code implementation?
Step1 (optional operation):
Customize an exception class to handle exceptions in the project and collect exception information.

[Code implementation:]

package com.lyh.common.exception;

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

/**
 * Custom exception,
 * You can customize the exception message and the response status code (500 by default).
 *
 * Description of dependent information:
 *      The @ Data annotation is used here. You need to import lombok dependent files.
 *      The constant of HttpStatus is used to represent the response status code, which needs to be imported into httpcore dependent files.
 */
@Data
public class GlobalException extends RuntimeException {
    /**
     * Save exception information
     */
    private String message;

    /**
     * Save response status code
     */
    private Integer code = HttpStatus.SC_INTERNAL_SERVER_ERROR;

    /**
     * The default construction method is to build an exception instance object according to the exception information
     * @param message Exception information
     */
    public GlobalException(String message) {
        super(message);
        this.message = message;
    }

    /**
     * Build an exception instance object based on exception information and response status code
     * @param message Exception information
     * @param code Response status code
     */
    public GlobalException(String message, Integer code) {
        super(message);
        this.message = message;
        this.code = code;
    }

    /**
     * According to the exception information, the exception object builds an exception instance object
     * @param message Exception information
     * @param e Exception object
     */
    public GlobalException(String message, Throwable e) {
        super(message, e);
        this.message = message;
    }

    /**
     * According to the exception information, respond to the status code and build an exception instance object
     * @param message Exception information
     * @param code Response status code
     * @param e Exception object
     */
    public GlobalException(String message, Integer code, Throwable e) {
        super(message, e);
        this.message = message;
        this.code = code;
    }
}

 

Step2:
Define a global exception handling class, GlobalExceptionHandler.
Mark this class with the @ restcontrolleradvise annotation.
The @ ExceptionHandler annotation is used internally to catch exceptions.

[Code implementation:]

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;

/**
 * Global exception handling class.
 * Use slf4j to save the log information.
 * The uniform Result processing class Result is used here to wrap exception information.
 */
@RestControllerAdvice
public class GlobalExceptionHandler {
    private Logger logger = LoggerFactory.getLogger(getClass());

    /**
     * Handle Exception exception
     * @param e abnormal
     * @return Processing results
     */
    @ExceptionHandler(Exception.class)
    public Result handlerException(Exception e) {
        logger.error(e.getMessage(), e);
        return Result.error().message("System exception");
    }

    /**
     * Handle null pointer exception
     * @param e abnormal
     * @return Processing results
     */
    @ExceptionHandler(NullPointerException.class)
    public Result handlerNullPointerException(NullPointerException e) {
        logger.error(e.getMessage(), e);
        return Result.error().message("Null pointer exception");
    }

    /**
     * Handling custom exceptions
     * @param e abnormal
     * @return Processing results
     */
    @ExceptionHandler(GlobalException.class)
    public Result handlerGlobalException(GlobalException e) {
        logger.error(e.getMessage(), e);
        return Result.error().message(e.getMessage()).code(e.getCode());
    }
}

 

(4) Use?
Modify a controller as follows:
A null pointer exception is thrown when the parameter does not exist.
When the parameter is - 1, a custom exception is thrown and handled.
When the query result is null, a custom exception is thrown and handled.
When the query is successful, it is processed correctly and returned.

@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("Parameter exception", 400);
    }
    if (emp == null) {
        throw new GlobalException("No results found, please confirm whether the input is correct");
    }
    return Result.ok().data("items", emp).message("query was successful");
}

 

 

Start the service and access:
When the parameter does not exist:

{
    "success": false,
    "code": 500,
    "message": "Null pointer exception",
    "data": {}
}

 

 

Parameter exists, but when - 1:

{
    "success": false,
    "code": 400,
    "message": "Parameter exception",
    "data": {}
}

 

 

When the parameter exists, but the query result is null:

{
    "success": false,
    "code": 500,
    "message": "No results found, please confirm whether the input is correct",
    "data": {}
}

 

 

Parameter exists, when query result exists:

{
    "success": true,
    "code": 200,
    "message": "query was successful",
    "data": {
        "items": {
            "id": 1,
            "name": "tom",
            "salary": 6000.0,
            "age": 20,
            "email": "tom@163.com"
        }
    }
}

Keywords: Java Lombok MySQL Spring

Added by juneym on Sun, 26 Apr 2020 14:45:44 +0300