最近项目上 ES相关的操作采用了GraphQL接口 其它采用Restful接口
做一个简单得demo
依赖相关
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.1</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>es-graphql-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>es-graphql-demo</name>
<description>es-graphql-demo</description>
<url/>
<licenses>
<license/>
</licenses>
<developers>
<developer/>
</developers>
<scm>
<connection/>
<developerConnection/>
<tag/>
<url/>
</scm>
<properties>
<java.version>21</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- GraphQL Spring Boot Starter -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-graphql</artifactId>
<scope>runtime</scope>
</dependency>
<!-- Elasticsearch -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
<!-- Lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.graphql</groupId>
<artifactId>spring-graphql</artifactId>
<version>1.2.4</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
相关配置
server:
port: 8989
spring:
application:
name: es-graphql-demo
elasticsearch:
uris: http://localhost:9200
graphql:
graphiql:
enabled: true
path: /graphiql
schema:
printer:
enabled: true
locations: classpath:graphql/
代码结构
Graphql Schema配置
es-graphql-demo\src\main\resources\graphql
type Query {
books(query: String, genre: String, year: Int): [Book]
book(id: ID!): Book
products: [Product]!
# 简单分页查询
pageProducts(
page: Int! = 1,
size: Int! = 10
): ProductPage!
product(id: ID!): Product
searchProducts(keyword: String!): [Product]!
}
type Mutation {
addBook(title: String!, author: String!, publishedYear: Int!, genre: String!): Book
updateBook(id: ID!, title: String, author: String, publishedYear: Int, genre: String): Book
deleteBook(id: ID!): Boolean
createProduct(input: ProductInput!): Product!
updateProduct(id: ID!, input: ProductInput!): Product!
deleteProduct(id: ID!): Boolean!
}
type Book {
id: ID!
title: String!
author: String!
publishedYear: Int!
genre: String!
}
type Product {
id: ID!
name: String!
price: Float!
description: String
}
type ProductPage {
totalCount: Int!
items: [Product]!
}
input ProductInput {
name: String!
price: Float!
description: String
}
package com.example.model;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;
/**
* @author Administrator
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Document(indexName = "books")
public class Book {
@Id
private String id;
@Field(type = FieldType.Text)
private String title;
@Field(type = FieldType.Text)
private String author;
@Field(type = FieldType.Integer)
private Integer publishedYear;
@Field(type = FieldType.Keyword)
private String genre;
}
package com.example.model;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;
/**
* @author Administrator
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Document(indexName = "products")
public class Product {
@Id
private String id;
@Field(type = FieldType.Text)
private String name;
@Field(type = FieldType.Double)
private Double price;
@Field(type = FieldType.Text)
private String description;
}
数据初始化
package com.example.config;
import com.example.model.Book;
import com.example.repository.BookRepository;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class DataInitializer {
@Bean
public CommandLineRunner initData(BookRepository bookRepository) {
return args -> {
bookRepository.deleteAll();
Book book1 = new Book();
book1.setTitle("Java Programming");
book1.setAuthor("John Doe");
book1.setPublishedYear(2020);
book1.setGenre("Programming");
Book book2 = new Book();
book2.setTitle("GraphQL in Action");
book2.setAuthor("Jane Smith");
book2.setPublishedYear(2021);
book2.setGenre("Programming");
Book book3 = new Book();
book3.setTitle("Elasticsearch Basics");
book3.setAuthor("Bob Johnson");
book3.setPublishedYear(2019);
book3.setGenre("Database");
bookRepository.save(book1);
bookRepository.save(book2);
bookRepository.save(book3);
};
}
}
package com.example.repository;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import org.springframework.stereotype.Repository;
import com.example.model.Book;
import java.util.List;
/**
* @author Administrator
*/
@Repository
public interface BookRepository extends ElasticsearchRepository<Book, String> {
List<Book> findByTitleContainingOrAuthorContaining(String title, String author);
List<Book> findByGenre(String genre);
List<Book> findByPublishedYear(Integer year);
}
package com.example.repository;
import com.example.model.Product;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
/**
* @author Administrator
*/
@Repository
public interface ProductRepository extends ElasticsearchRepository<Product, String> {
List<Product> findByNameContainingOrDescriptionContaining(String name, String description);
}
Graphql API
package com.example.controller;
import com.example.model.Product;
import com.example.repository.ProductRepository;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.graphql.data.method.annotation.Argument;
import org.springframework.graphql.data.method.annotation.MutationMapping;
import org.springframework.graphql.data.method.annotation.QueryMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
public class ProductGraphQLController {
private final ProductRepository productRepository;
public ProductGraphQLController(ProductRepository productRepository) {
this.productRepository = productRepository;
}
@QueryMapping
public PageImpl<Product> products() {
return (PageImpl<Product>) productRepository.findAll();
}
// 简单分页查询
@QueryMapping
public ProductPage pageProducts(
@Argument Integer page,
@Argument Integer size) {
Pageable pageable = PageRequest.of(page - 1, size);
Page<Product> productPage = productRepository.findAll(pageable);
return new ProductPage(
(int) productPage.getTotalElements(),
productPage.getContent()
);
}
@QueryMapping
public Product product(@Argument String id) {
return productRepository.findById(id).orElse(null);
}
@QueryMapping
public List<Product> searchProducts(@Argument String keyword) {
// 这里可以添加更复杂的搜索逻辑
return productRepository.findByNameContainingOrDescriptionContaining(keyword, keyword);
}
@MutationMapping
public Product createProduct(@Argument("input") ProductInput input) {
Product product = new Product();
product.setName(input.name());
product.setPrice(input.price());
product.setDescription(input.description());
return productRepository.save(product);
}
@MutationMapping
public Product updateProduct(@Argument String id, @Argument("input") ProductInput input) {
return productRepository.findById(id)
.map(existingProduct -> {
existingProduct.setName(input.name());
existingProduct.setPrice(input.price());
existingProduct.setDescription(input.description());
return productRepository.save(existingProduct);
})
.orElseThrow(() -> new RuntimeException("Product not found with id: " + id));
}
@MutationMapping
public Boolean deleteProduct(@Argument String id) {
productRepository.deleteById(id);
return true;
}
// 定义输入记录
public record ProductInput(String name, Double price, String description) {}
public record ProductPage(int totalCount,List<Product> items){}
}
Restful api
package com.example.controller;
import com.example.model.Book;
import com.example.model.Product;
import com.example.repository.BookRepository;
import com.example.repository.ProductRepository;
import org.springframework.data.domain.PageImpl;
import org.springframework.graphql.data.method.annotation.Argument;
import org.springframework.graphql.data.method.annotation.MutationMapping;
import org.springframework.graphql.data.method.annotation.QueryMapping;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* @author Administrator
*/
@RestController
public class BookController {
private final BookRepository bookRepository;
public BookController(BookRepository bookRepository) {
this.bookRepository = bookRepository;
}
@RequestMapping("/books")
public PageImpl<Book> products() {
return (PageImpl<Book>) bookRepository.findAll();
}
@RequestMapping("/books/{id}")
public Book product( @PathVariable String id) {
return bookRepository.findById(id).orElse(null);
}
@RequestMapping("/books/{keyword}")
public List<Book> searchProducts(@PathVariable String keyword) {
// 这里可以添加更复杂的搜索逻辑
return bookRepository.findByTitleContainingOrAuthorContaining(keyword, keyword);
}
@RequestMapping(value = "/book",method = RequestMethod.POST)
public Book createProduct(@RequestBody Book input) {
Book book = new Book();
book.setAuthor(input.getAuthor());
book.setTitle(input.getTitle());
book.setPublishedYear(input.getPublishedYear()) ;
book.setGenre(input.getGenre());
return bookRepository.save(book);
}
}
如果需要完整代码 可以给我留言