Spring Boot + GraphQL API 实战:使用 React 和 Auth0 构建安全数据平台

作者:API传播员 · 2025-10-22 · 阅读时间:6分钟

GraphQL API 能够通过对象间的引用,在单一响应中返回所有相关数据。

本教程将逐步演示如何使用 Spring Boot 和 Spring for GraphQL 构建一个 GraphQL API,以查询 Neo4j 数据库中的公司、人员和属性数据。同时,我们还将展示如何使用 Next.js 和 MUI 数据网格构建一个 React 客户端来消费该 API。整个项目的客户端和服务器均通过 Auth0 进行身份验证,服务器使用 Okta Spring Boot Starter,而客户端则使用 Auth0 React SDK。


使用 Spring Boot 构建 GraphQL API

初始化 Spring Boot 项目

资源服务器是一个基于 Spring Boot 的 Web 应用程序,它通过 Spring for GraphQL 提供 GraphQL API。该 API 使用 Spring Data Neo4j 查询 Neo4j 数据库中的公司及其相关人员和属性信息。

通过 Spring Initializr 和 HTTPie 创建项目:

https start.spring.io/starter.zip 
  bootVersion==3.2.1 
  language==java 
  packaging==jar 
  javaVersion==17 
  type==gradle-project 
  dependencies==data-neo4j,graphql,docker-compose,web 
  groupId==com.okta.developer 
  artifactId==spring-graphql 
  name=="Spring Boot API" 
  description=="Demo project of a Spring Boot GraphQL API" 
  packageName==com.okta.developer.demo > spring-graphql-api.zip

解压项目文件后,开始编辑项目。在 src/main/resources/graphql 目录下创建名为 [schema](https://www.explinks.com/blog/ua-what-is-schema-in-database/).graphqls 的文件,定义 GraphQL API 的架构

type Query {
  companyList(page: Int): [Company!]!
  companyCount: Int
}

type Company {
  id: ID
  SIC: String
  category: String
  companyNumber: String
  countryOfOrigin: String
  incorporationDate: String
  mortgagesOutstanding: Int
  name: String
  status: String
  controlledBy: [Person!]!
  owners: [Property!]!
}type Person {
  id: ID
  birthMonth: String
  birthYear: String
  nationality: String
  name: String
  countryOfResidence: String
}type Property {
  id: ID
  address: String
  county: String
  district: String
  titleNumber: String
}

定义领域模型

src/main/java 下创建包 com.okta.developer.demo.domain,并添加以下类:

Person 类

package com.okta.developer.demo.domain;

import org.springframework.data.neo4j.core.schema.GeneratedValue;
import org.springframework.data.neo4j.core.schema.Id;
import org.springframework.data.neo4j.core.schema.Node;@Node
public class Person {
    @Id
    @GeneratedValue
    private Long id;
    private String birthMonth;
    private String birthYear;
    private String countryOfResidence;
    private String name;
    private String nationality;    // 构造函数、getter 和 setter 方法
}

Property 类

package com.okta.developer.demo.domain;

import org.springframework.data.neo4j.core.schema.GeneratedValue;
import org.springframework.data.neo4j.core.schema.Id;
import org.springframework.data.neo4j.core.schema.Node;@Node
public class Property {
    @Id
    @GeneratedValue
    private Long id;
    private String address;
    private String county;
    private String district;
    private String titleNumber;    // 构造函数、getter 和 setter 方法
}

Company 类

package com.okta.developer.demo.domain;

import org.springframework.data.neo4j.core.schema.GeneratedValue;
import org.springframework.data.neo4j.core.schema.Id;
import org.springframework.data.neo4j.core.schema.Node;
import org.springframework.data.neo4j.core.schema.Relationship;import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;@Node
public class Company {
    @Id
    @GeneratedValue
    private Long id;
    private String SIC;
    private String category;
    private String companyNumber;
    private String countryOfOrigin;
    private LocalDate incorporationDate;
    private Integer mortgagesOutstanding;
    private String name;
    private String status;    @Relationship(type = "HAS_CONTROL", direction = Relationship.Direction.INCOMING)
    private List controlledBy = new ArrayList();    private List owns = new ArrayList();    // 构造函数、getter 和 setter 方法
}

创建 Repository 和 Controller

CompanyRepository

package com.okta.developer.demo.repository;

import com.okta.developer.demo.domain.Company;
import org.springframework.data.neo4j.repository.ReactiveNeo4jRepository;public interface CompanyRepository extends ReactiveNeo4jRepository {
}

CompanyController

package com.okta.developer.demo.controller;

import com.okta.developer.demo.domain.Company;
import com.okta.developer.demo.repository.CompanyRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.graphql.data.method.annotation.Argument;
import org.springframework.graphql.data.method.annotation.QueryMapping;
import org.springframework.stereotype.Controller;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;@Controller
public class CompanyController {
    @Autowired
    private CompanyRepository companyRepository;    @QueryMapping
    public Flux companyList(@Argument Long page) {
        return companyRepository.findAll().skip(page * 10).take(10);
    }    @QueryMapping
    public Mono companyCount() {
        return companyRepository.count();
    }
}

构建 React 客户端

初始化 Next.js 项目

在 Spring Boot 项目的父目录下运行以下命令:

npx create-next-app@latest react-graphql

根据提示配置项目,并安装必要的依赖项:

cd react-graphql
npm install @mui/x-data-grid @mui/material @emotion/react @emotion/styled axios

创建 API 客户端

src/services 目录下创建 base.tsx 文件:

import axios from 'axios';

export const backendAPI = axios.create({
  baseURL: process.env.NEXT_PUBLIC_API_SERVER_URL,
});export default backendAPI;

添加 companies.tsx 文件:

import { backendAPI } from './base';

export const CompanyApi = {
  getCompanyList: async (page: number) => {
    const response = await backendAPI.post('/graphql', {
      query: { companyList(page: ${page}) { id name category } },
    });
    return response.data.data.companyList;
  },
};

创建数据表组件

src/components/company 目录下创建 CompanyTable.tsx

import { DataGrid } from '@mui/x-data-grid';

const CompanyTable = ({ rows, columns }) => {
  return ;
};export default CompanyTable;

使用 Auth0 添加安全性

配置 Auth0

在 Auth0 中创建一个应用程序,并获取客户端 ID 和域名。将这些信息添加到 .env.local 文件中:

NEXT_PUBLIC_AUTH0_DOMAIN=
NEXT_PUBLIC_AUTH0_CLIENT_ID=

集成 Auth0 到 React

安装 Auth0 React SDK:

npm install @auth0/auth0-react

src/components/authentication 目录下创建 Auth0ProviderWithNavigate.tsx

import { Auth0Provider } from '@auth0/auth0-react';

const Auth0ProviderWithNavigate = ({ children }) => {
  const domain = process.env.NEXT_PUBLIC_AUTH0_DOMAIN;
  const clientId = process.env.NEXT_PUBLIC_AUTH0_CLIENT_ID;  return (
    
      {children}
    
  );
};export default Auth0ProviderWithNavigate;

总结

通过本教程,您学会了如何使用 Spring Boot 构建 GraphQL API,并通过 React 客户端消费该 API。此外,您还了解了如何使用 Auth0 为应用程序添加身份验证功能。GraphQL 的灵活性使得客户端可以快速调整查询以满足需求,而 Auth0 提供了安全且便捷的身份验证解决方案。

原文链接: https://auth0.com/blog/how-to-build-a-graphql-api-with-spring-boot/