Skip to content

返回图片 ​

下面的文档将介绍在 tio-boot 框架中,如何在 Controller 中返回图片给浏览器,包括生成验证码图片、二维码图片以及与 Next.js 配合返回图片的完整示例。


1. 返回验证码图片 ​

利用 Hutool 库生成并返回图形验证码。此示例通过 LineCaptcha 来生成带有干扰线的图形验证码,并以 JPEG 图片的形式返回给前端。

1.1 代码示例 ​

java
import java.io.ByteArrayOutputStream;
import java.io.IOException;

import nexus.io.annotation.AController;
import nexus.io.annotation.RequestPath;
import nexus.io.model.body.RespBodyVo;
import nexus.io.tio.http.common.HttpRequest;
import nexus.io.tio.http.common.HttpResponse;
import nexus.io.tio.http.server.util.Resps;

import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.LineCaptcha;

@RequestPath("/captcha")
public class CaptchaController {

  @RequestPath("")
  public HttpResponse captcha(HttpRequest request) {
    // 创建线性验证码,尺寸为 200x100
    LineCaptcha captcha = CaptchaUtil.createLineCaptcha(200, 100);

    try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
      // 将验证码图片写入输出流
      captcha.write(outputStream);

      // 将输出流转换为字节数组
      byte[] captchaBytes = outputStream.toByteArray();

      // 使用 Resps 工具类创建包含验证码图片的响应
      HttpResponse response = Resps.bytesWithContentType(request, captchaBytes, "image/jpeg");

      // 返回响应
      return response;
    } catch (IOException e) {
      e.printStackTrace();
      return Resps.json(request, RespBodyVo.fail("Error generating captcha"));
    }
  }
}

1.2 代码解析 ​

  1. 依赖与导包

    • import cn.hutool.captcha.LineCaptcha;:来自 Hutool 库的验证码生成类。
    • import nexus.io.tio.http.server.util.Resps;:tio-boot 提供的工具类,用于快速创建各种响应类型。
  2. 路由定义

    • @RequestPath("/captcha"):类级别的注解,表示当请求路径以 /captcha 为前缀时,交由该类处理。
    • @RequestPath(""):方法级别的注解,处理具体的请求路径 /captcha(此处等同于 "/captcha")。
  3. 生成并返回验证码

    • LineCaptcha captcha = CaptchaUtil.createLineCaptcha(200, 100);:生成 200×100 大小的验证码图片。
    • captcha.write(outputStream);:将验证码写入到内存的 ByteArrayOutputStream。
    • Resps.bytesWithContentType(request, captchaBytes, "image/jpeg"):将字节数组作为图片响应返回,并指定其 Content-Type 为 image/jpeg。
  4. 异常处理

    • 若捕获到 IOException,则返回一个包含错误信息的 JSON 响应。

2. 返回二维码图片 ​

利用 Hutool 和 ZXing 生成并返回二维码图片。

2.1 Maven 依赖 ​

若需使用 ZXing 核心库,需要在 pom.xml 中添加以下依赖:

xml
<dependency>
  <groupId>com.google.zxing</groupId>
  <artifactId>core</artifactId>
  <version>3.4.1</version>
</dependency>

2.2 代码示例 ​

java
import java.io.ByteArrayOutputStream;
import java.io.IOException;

import nexus.io.annotation.RequestPath;
import nexus.io.model.body.RespBodyVo;
import nexus.io.tio.http.common.HttpRequest;
import nexus.io.tio.http.common.HttpResponse;
import nexus.io.tio.http.server.util.Resps;

import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.qrcode.QrCodeUtil;


@RequestPath("/qr")
public class QrController {

  @RequestPath("")
  public HttpResponse qr(HttpRequest request, String content) {
    // 获取要生成的二维码内容
    if (StrUtil.isBlank(content)) {
      return Resps.json(request, RespBodyVo.fail("No content provided for QR code"));
    }

    try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
      // 生成二维码图片,并写入到输出流(300×300 像素,PNG 格式)
      QrCodeUtil.generate(content, 300, 300, "png", outputStream);

      // 将输出流转换为字节数组
      byte[] qrCodeBytes = outputStream.toByteArray();

      // 使用 Resps 工具类创建一个包含二维码图片的响应
      HttpResponse response = Resps.bytesWithContentType(request, qrCodeBytes, "image/png");

      // 返回响应
      return response;
    } catch (IOException e) {
      e.printStackTrace();
      return Resps.json(request, RespBodyVo.fail("Error generating QR code"));
    }
  }
}

2.3 代码解析 ​

  1. 依赖与导包

    • QrCodeUtil 来自 Hutool 提供的二维码工具类,需要依赖 ZXing 进行二维码生成。
  2. 路由定义

    • @RequestPath("/qr"):类级别注解,处理以 /qr 开头的请求。
  3. 获取参数并生成二维码

    • 通过方法签名中的 String content 获取前端传入的二维码内容。
    • 使用 QrCodeUtil.generate(content, 300, 300, "png", outputStream) 方法生成二维码,并输出到 ByteArrayOutputStream。
  4. 创建响应并返回

    • Resps.bytesWithContentType(request, qrCodeBytes, "image/png"):封装生成的二维码字节码为 PNG 格式并返回。
    • 若 content 为空或二维码生成出错,则返回相应的 JSON 格式错误信息。

2.4 请求示例 ​

bash
GET http://localhost/qr?content=tio-boot

上述请求将生成包含文本 “tio-boot” 的二维码图片。


3. 与 Next.js 配合返回图片 ​

以下示例展示了如何处理 Next.js 向后端请求图片的场景,尤其在使用 _next/image API 时,需要根据请求参数解析并返回对应的图片文件。

3.1 代码示例 ​

java
package nexus.io.admin.controller;

import java.io.File;

import nexus.io.annotation.Get;
import nexus.io.annotation.RequestPath;
import nexus.io.tio.boot.http.TioRequestContext;
import nexus.io.tio.http.common.HttpResponse;
import nexus.io.tio.http.server.util.Resps;
import nexus.io.tio.utils.hutool.FileUtil;
import nexus.io.tio.utils.hutool.FilenameUtils;
import nexus.io.tio.utils.url.UrlUtils;

@RequestPath("/_next")
public class NextImageController {
  String staticFileFolder = "blog-ui/";

  // 示例:/_next/image?url=%2Fstatic%2Fimages%2Fnicolaus-avatar.png&w=48&q=75
  @Get("/image")
  public HttpResponse image(String url, int w, int q) {
    HttpResponse response = TioRequestContext.getResponse();
    // 1. 对 url 进行解码
    url = UrlUtils.decode(url);
    // 2. 获取文件后缀作为返回类型
    String suffix = FilenameUtils.getSuffix(url);
    // 3. 构造图片文件路径
    File file = new File(staticFileFolder + url);

    if (file.exists()) {
      // 读取文件内容
      byte[] readBytes = FileUtil.readBytes(file);
      // 指定图片的 contentType
      Resps.bytesWithContentType(response, readBytes, "image/" + suffix);
      return response;
    } else {
      // 文件不存在,返回 404
      return response.setStatus(404);
    }
  }
}

3.2 代码解析 ​

  1. 路由定义

    • @RequestPath("/_next"):类级别注解,表示处理 /_next 开头的请求。
    • @Get("/image"):方法级别注解,处理 GET /_next/image 请求。
  2. 处理图片请求

    • String url, int w, int q:方法参数分别对应请求中的 url、w、q 参数。例如 url=%2Fstatic%2Fimages%2Fnicolaus-avatar.png。
    • UrlUtils.decode(url):对路径进行 URL 解码。
    • 使用 FilenameUtils.getSuffix(url) 获取文件后缀,以便设置正确的响应 Content-Type。
    • 若文件存在,读取文件字节数组,并以 image/[suffix] 的形式返回;否则返回 404。
  3. 前端请求示例

bash
GET http://localhost/_next/image?url=%2Fstatic%2Fimages%2Fnicolaus-avatar.png&w=48&q=75

该请求会在服务器指定的目录 blog-ui/ 下寻找 static/images/nicolaus-avatar.png 文件,并将其以图片形式返回给浏览器。


4. 总结 ​

在 tio-boot 中返回图片的核心思路主要如下:

  1. 获取或生成图片:

    • 验证码、二维码等可使用 Hutool 库来生成。
    • 直接读取本地或网络文件,也可用 File、FileUtil 等工具类来操作。
  2. 输出为字节流:

    • 将生成或读取到的图片转换为 byte[] 数组。
  3. 设置合适的 Content-Type:

    • 对于验证码或普通图片可设置 image/jpeg、image/png 等。
    • 对于 SVG 等矢量格式可设置 image/svg+xml。
  4. 返回响应:

    • 使用 Resps.bytesWithContentType() 将字节数组和对应的 Content-Type 打包成可识别的 HttpResponse。
    • 若出现异常或者文件不存在,则返回相应的错误信息或 404 状态码。

通过以上示例,可以轻松地在 tio-boot 环境中生成并返回验证码、二维码等各类图片。结合 Next.js 等前端框架时,只需根据请求参数解析目标文件路径并返回即可,从而实现前后端的无缝衔接。

MIT Licensed