首页 /  技术专区  /  Vert.x 宽屏模式 >

Vert.x借助AsyncResult优雅处理异常

说起java的异常处理,大家首先想到的是简单粗暴的try.....catch...finally.

但在Vert.x中,Vert.x为我们封装了更加优雅的异常处理方式,大多数情况下不需要我们手写try....catch。

Vert.x中,大多数Handler接口都是Handler<AsyncResult<T>>的形式,其中AsyncResult,里面既封装了正确的返回结果,也封装了Vert.x帮我们捕捉到的异常。


1、我们修改配置文件数据库密码,将它改为错误的密码,用来测试异常。

{
  "port": 3306,
  "host": "127.0.0.1",
  "database": "db",
  "user": "root",
  "password": "errorPassword"
}

2、编写HandleExceptionVerticle代码

package vertx;

import io.vertx.config.ConfigRetriever;
import io.vertx.core.AbstractVerticle;
import io.vertx.core.Future;
import io.vertx.core.Promise;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.Router;
import io.vertx.mysqlclient.MySQLConnectOptions;
import io.vertx.mysqlclient.MySQLPool;
import io.vertx.sqlclient.*;

import java.util.ArrayList;

public class HandleExceptionVerticle extends AbstractVerticle {

  //声明Router
  Router router;

  //配置连接参数
  MySQLConnectOptions connectOptions;

  //配置连接池 Pool options
  PoolOptions poolOptions = new PoolOptions()
    .setMaxSize(5);

  //Create the client pool
  MySQLPool client;

  @Override
  public void start(Promise<Void> startPromise) throws Exception {

    ConfigRetriever retriever = ConfigRetriever.create(vertx);

    retriever.getConfig(ar -> {
      if (ar.failed()) {
        // Failed to retrieve the configuration
      } else {
        JsonObject config = ar.result();

        connectOptions = new MySQLConnectOptions()
          .setPort(config.getInteger("port"))
          .setHost(config.getString("host"))
          .setDatabase(config.getString("database"))
          .setUser(config.getString("user"))
          .setPassword(config.getString("password"));

        client = MySQLPool.pool(vertx, connectOptions, poolOptions);

        //初始化Router
        router = Router.router(vertx);

        //配置Router解析url
        router.route("/").handler(
          req -> {
            req.response()
              .putHeader("content-type", "text/plain")
              .end("Hello from Vert.x!");
          }
        );

        //配置Router解析url
        router.route("/test/list").handler(
          req -> {
            var page = (Integer.valueOf(req.request().getParam("page")) - 1) * 10;
            var size = Integer.valueOf(req.request().getParam("size"));
            //Get a connection from the pool
            this.getCon()
              .compose(con -> this.getRows(con, page, size))
              .onSuccess(row -> {
                var list = new ArrayList<JsonObject>();
                row.forEach(item -> {
                  var json = new JsonObject();
                  json.put("id", item.getValue("id"));
                  json.put("name", item.getValue("name"));
                  json.put("age", item.getValue("age"));
                  json.put("info", item.getValue("info"));
                  list.add(json);
                });
                req.response()
                  .putHeader("content-type", "application/json")
                  .end(list.toString());
              })
            .onFailure(throwable -> {
              //真实的项目开发中,我们可以在这里捕获Future+Promise异步链式调用的异常
              //在这里统一处理,比如写入日志文件
              req.response()
                .putHeader("content-type", "application/json")
                .end(throwable.toString());
            });
          }
        );

        //将Router与vertx HttpServer 绑定
        vertx.createHttpServer().requestHandler(router).listen(8888, http -> {
          if (http.succeeded()) {
            startPromise.complete();
            System.out.println("HTTP server started on port 8888");
          } else {
            startPromise.fail(http.cause());
          }
        });
      }
    });
  }

  //第一步 获取数据库链接
  private Future<SqlConnection> getCon(){
    Promise<SqlConnection> promise = Promise.promise();
    client.getConnection(ar1 -> {
      if (ar1.succeeded()) {
        System.out.println("Connected");

        //Obtain our connection
        SqlConnection conn = ar1.result();
        promise.complete(conn);
      } else {
        System.out.println("数据库连接不成功!");
        //Vert.x帮我们捕获异常后,我们只需要做接下来的处理即可,比如写日志
        promise.fail(ar1.cause());  //这里就相当于继续向上抛出异常,用Promise来向上抛异常
      }
    });
    return promise.future();
  }

  //第二步 用获取到的链接查询数据库
  private Future<RowSet<Row>> getRows(SqlConnection conn, Integer page, Integer size){
    Promise<RowSet<Row>> promise = Promise.promise();
    conn
      .preparedQuery("select id, name, age, info from person limit ?, ?")
      .execute(Tuple.of(page, size), ar2 -> {
        //Release the connection to the pool
        conn.close();

        if(ar2.succeeded()){
          promise.complete(ar2.result());
        }else{
          promise.fail(ar2.cause());
        }
      });
    return promise.future();
  }

}

3、启动测试

控制台

image.png

接口返回

image.png


头像
0/200
图片验证码