Skip to content

Discover API ​

本文档详细介绍了 /api/discover 接口的功能、返回数据结构及其实现代码,并说明了前后端交互时传递消息的处理逻辑,帮助开发人员全面了解该接口的设计思想和实现细节。


1. 接口说明 ​

  • 接口地址:GET /api/discover
  • 接口功能:返回博客或新闻内容的列表,主要用于展示摘要信息,便于用户快速了解相关内容。

客户端只需通过 GET 请求访问 /api/discover 接口,即可获得格式化后的 JSON 数据列表。


2. 返回数据格式 ​

接口返回一个 JSON 对象,其中主要包含一个 blogs 数组。数组中的每个元素代表一条博客或新闻记录,结构示例如下:

json
{
  "blogs": [
    {
      "content": "Summer is the perfect time to fast-track your education and save money! ...",
      "description": null,
      "url": "https://www.kapiolani.hawaii.edu/event-directory/summer-session-2025/",
      "title": "Kapiʻolani CC Summer Session: Save Money, Graduate Faster!",
      "similarity": null,
      "thumbnail": "https://www.kapiolani.hawaii.edu/wp-content/uploads/studentgreatlawn2025_1920.jpg"
    }
  ]
}

字段说明 ​

  • content
    文章部分内容预览,用于帮助用户快速了解文章概要。

  • description
    文章摘要或描述,当前返回为 null,后续可扩展为详细的内容简介。

  • url
    原始内容的链接地址,点击后可跳转到详细页面或原文。

  • title
    文章标题,简明扼要地反映博客或新闻的主题。

  • thumbnail
    缩略图链接,用于前端展示图片资源。

  • similarity
    当前记录的相似度信息,暂时返回 null,后续可能用于扩展相关性评分功能。


3. 后端实现代码 ​

下面的 Java 代码展示了 /api/discover 接口的实现。代码使用自定义注解进行路由映射与请求方法定义,实现了将博客或新闻内容封装为 JSON 数据返回给客户端的功能。

接口控制器代码 ​

java
package nexus.io.max.search.controller;

import java.util.ArrayList;
import java.util.List;

import nexus.io.annotation.Get;
import nexus.io.annotation.RequestPath;
import nexus.io.max.search.vo.DiscoverResultVo;
import nexus.io.model.web.WebPageContent;

@RequestPath("/api/discover")
public class ApiDiscoverController {

  @Get
  public DiscoverResultVo index() {
    List<WebPageContent> blogs = new ArrayList<>();
    WebPageContent webPageContent = new WebPageContent()
        .setUrl("https://www.kapiolani.hawaii.edu/event-directory/summer-session-2025/")
        .setTitle("Kapiʻolani CC Summer Session: Save Money, Graduate Faster!")
        .setThumbnail("https://www.kapiolani.hawaii.edu/wp-content/uploads/studentgreatlawn2025_1920.jpg")
        .setContent("Summer is the perfect time to fast-track your education and save money! ...");
    blogs.add(webPageContent);
    DiscoverResultVo discoverResultVo = new DiscoverResultVo(blogs);
    return discoverResultVo;
  }
}

代码解析 ​

  • 路由映射
    类上使用 @RequestPath("/api/discover") 注解,标识该控制器处理 /api/discover 路径下的请求;方法上使用 @Get 注解,表明该方法响应 GET 请求。

  • 业务逻辑

    1. 创建一个 List<WebPageContent> 用于存放博客内容数据。
    2. 构造 WebPageContent 对象,并依次设置文章的 URL、标题、缩略图和内容。
    3. 将对象添加至列表中,再使用该列表构造一个 DiscoverResultVo 实例返回给前端。

4. 使用说明 ​

  • 调用方式
    前端通过发送 GET 请求至 /api/discover 接口,即可获取格式化后的博客或新闻内容列表。

  • 扩展方向

    • 后续可在返回数据中增加 similarity、description 等字段,进一步丰富信息内容。
    • 支持分页或数量控制参数,以适应大规模数据返回场景。
    • 根据业务需求调整数据查询和缓存策略,提升接口响应效率和扩展性。

5. 前后端交互示例 ​

在实际业务中,前端会向后端发送一条消息,用于请求对指定网页进行内容汇总。下面是前端传递消息的示例:

json
{
  "type": "message",
  "userId": "7130314803843072",
  "message": {
    "messageId": "7142056710082560",
    "chatId": "7142056709832704",
    "content": "Summary: https://www.kapiolani.hawaii.edu/event-directory/summer-session-2025/"
  },
  "files": [],
  "focusMode": "webSearch",
  "copilotEnabled": true,
  "optimizationMode": "speed",
  "history": []
}

在后端处理逻辑中,会解析该消息,提取出 URL,并调用 MaxWebPageService.fetch 方法对该网页进行汇总。下面展示部分核心业务逻辑代码:

java
List<WebPageContent> webPageContents = null;
// 使用 MaxSearchSearchService 对 Tavily Search API 进行调用
if (quesiton != null && quesiton.startsWith("Summary: ")) {
  webPageContents = new ArrayList<>(1);
  String[] split = quesiton.split(" ");
  if (split.length > 1 && split[1].startsWith("http")) {
    WebPageContent webpageContent = Aop.get(MaxWebPageService.class).fetch(split[1]);
    webPageContents.add(webpageContent);
  }
} else {
  webPageContents = maxSearchSearchService.search(quesiton);
}

6. 网页内容抓取服务 ​

MaxWebPageService 类提供了网页内容抓取的功能,实现如下:

java
package nexus.io.max.search.services;

import java.io.IOException;
import java.util.concurrent.locks.Lock;

import org.jsoup.Connection;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;

import com.google.common.util.concurrent.Striped;
import nexus.io.db.activerecord.Db;
import nexus.io.db.activerecord.Row;
import nexus.io.model.web.WebPageContent;
import nexus.io.tio.utils.snowflake.SnowflakeIdUtils;

public class MaxWebPageService {

  private static final Striped<Lock> locks = Striped.lock(1024);

  public WebPageContent fetch(String url) {
    String sql = "select title, markdown from web_page_cache where url=?";
    Row row = Db.findFirst(sql, url);
    if (row == null) {
      Lock lock = locks.get(url);
      lock.lock();
      row = Db.findFirst(sql, url);
      if (row == null) {
        try {
          Connection connect = Jsoup.connect(url);
          Document document = connect.get();
          String title = document.title();
          String text = document.body().text();
          Row set = Row.by("id", SnowflakeIdUtils.id())
                     .set("url", url)
                     .set("title", title)
                     .set("type", "html")
                     .set("markdown", text);
          Db.save("web_page_cache", set);
          return new WebPageContent().setTitle(title).setContent(text).setUrl(url);
        } catch (IOException e) {
          return new WebPageContent().setTitle("IOException").setContent(e.getMessage()).setUrl(url);
        } finally {
          lock.unlock();
        }
      }
    }
    String title = row.getString("title");
    String markdown = row.getString("markdown");
    return new WebPageContent().setTitle(title).setContent(markdown).setUrl(url);
  }
}

代码解析 ​

  • 缓存查询
    首先通过数据库查询判断指定 URL 的网页内容是否已被缓存,如果存在则直接返回缓存数据,避免重复抓取。

  • 线程锁机制
    采用分布式锁(Striped<Lock>),确保同一 URL 的抓取操作不会并发执行,从而保证数据一致性和线程安全。

  • 网页抓取与数据保存
    使用 Jsoup 连接并解析网页内容,获取网页标题和正文,并将结果存入数据库缓存中,供后续请求直接返回。


7. 总结 ​

Discover API 通过简洁明了的设计,实现了博客或新闻内容的提取、封装与返回,为前端展示提供了稳定、灵活的数据接口。该接口具有以下特点:

  • 清晰的接口设计:通过 RESTful 风格实现接口调用,便于维护和扩展。
  • 灵活的数据结构:返回的 JSON 格式清晰,易于前端解析与展示。
  • 完善的业务逻辑:不仅支持简单的内容列表返回,还支持根据前端消息进行网页内容抓取和缓存。
  • 良好的扩展性:后续可根据实际业务需求扩展更多字段(如相似度评分、详细描述)和功能(如分页、数量控制)。

通过本篇文档,开发人员能够快速理解 Discover API 的设计思想及实现细节,并在实际项目中进行有效应用与扩展。

MIT Licensed