1. 先决条件

  • 用Boot3.3.3连接Cassandra5.0;

2. Dependency

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>

<dependency>
	<groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-cassandra</artifactId>
</dependency>

3. Product

import java.util.UUID;
import org.springframework.data.cassandra.core.mapping.Column;
import org.springframework.data.cassandra.core.mapping.PrimaryKey;
import org.springframework.data.cassandra.core.mapping.Table;

@Table
public class Product {

	@PrimaryKey
	@Column(value = "product_id")
	private UUID productId;

	@Column(value = "product_name")
	private String productName;

	@Column(value = "product_memo")
	private String productMemo;

	@Column(value = "product_state")
	private boolean productState;

	public Product() {}

	public Product(UUID productId, String productName,
		String productMemo, boolean productState) {
		super();
		this.productId = productId;
		this.productName = productName;
		this.productMemo = productMemo;
		this.productState = productState;
	}

	@Override
	public String toString() {
		return "Product [productId=" + productId
			+ ", productName=" + productName + ", productMemo="
			+ productMemo + ", productState=" + productState + "]";
	}

	public UUID getProductId() {
		return productId;
	}
	public void setProductId(UUID productId) {
		this.productId = productId;
	}

	public String getProductName() {
		return productName;
	}
	public void setProductName(String productName) {
		this.productName = productName;
	}

	public String getProductMemo() {
		return productMemo;
	}
	public void setProductMemo(String productMemo) {
		this.productMemo = productMemo;
	}

	public boolean isProductState() {
		return productState;
	}
	public void setProductState(boolean productState) {
		this.productState = productState;
	}

}

4. ProductRepository

import java.util.List;
import java.util.UUID;
import io.os.cassandra.model.Product;
import org.springframework.data.cassandra.repository.AllowFiltering;
import org.springframework.data.cassandra.repository.CassandraRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface ProductRepository extends CassandraRepository<Product,UUID> {

	//@AllowFiltering:允许方法对服务器端筛选,等效于
	//select * from product where product_state = [true/false];
	@AllowFiltering
	List<Product> findByProductState(boolean productState);

	List<Product> findByProductMemo(String productName);

}

5. ProductController

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import io.os.cassandra.model.Product;
import io.os.cassandra.repository.ProductRepository;

@RestController
@RequestMapping("/api/product")
public class ProductController {

	@Autowired
	private ProductRepository productRepository;

	@GetMapping("/getAllProductProduct")
	public ResponseEntity<List<Product>> getAllProductProduct(
		@RequestParam(required = false,value = "productMemo") String productMemo) {

		try {
			List<Product> productList = new ArrayList<Product>();

		    if (productMemo == null) {
		    	productRepository.findAll().forEach(productList::add);
		    } else {
		    	productRepository.findByProductMemo(productMemo).forEach(productList::add);
		    }

		    if (productList.isEmpty()) {
		    	return new ResponseEntity<>(HttpStatus.NO_CONTENT);
		    } else {
		    	return new ResponseEntity<>(productList, HttpStatus.OK);
		    }
		  } catch (Exception e) {
			  return new ResponseEntity<>(null, HttpStatus.INTERNAL_SERVER_ERROR);
		  }
	}

	@GetMapping("/getProductById/{id}")
	public ResponseEntity<Product> getProductById(
		@PathVariable("id") String id) {
		var product = productRepository.findById(UUID.fromString(id));

		if (product.isPresent()) {
			return new ResponseEntity<>(product.get(), HttpStatus.OK);
		} else {
		    return new ResponseEntity<>(HttpStatus.NOT_FOUND);
		}
	}

	@PostMapping("/createProduct")
	public ResponseEntity<Product> createProduct(
		@RequestBody Product product) {
		var requestProduct = new Product(
			UUID.randomUUID(),product.getProductName(),
			product.getProductMemo(),product.isProductState());

		try {
			Product p = productRepository.save(requestProduct);
		    return new ResponseEntity<>(p,HttpStatus.CREATED);
		} catch (Exception e) {
		    return new ResponseEntity<>(null, HttpStatus.INTERNAL_SERVER_ERROR);
		}
	}

	@PutMapping("/updateProduct/{id}")
	public ResponseEntity<Product> updateProduct(
		@PathVariable("id") String id,@RequestBody Product product) {

		var updateProduct = productRepository.findById(UUID.fromString(id));

		if (updateProduct.isPresent()) {
			var p = updateProduct.get();
			p.setProductName(product.getProductName());
			p.setProductMemo(product.getProductMemo());
			p.setProductState(product.isProductState());
			return new ResponseEntity<>(productRepository.save(p), HttpStatus.OK);
		} else {
			return new ResponseEntity<>(HttpStatus.NOT_FOUND);
		}
	}

	@DeleteMapping("/deleteProductById/{id}")
	public ResponseEntity<HttpStatus> deleteProductById(
		@PathVariable("id") String id) {
		try {
			productRepository.deleteById(UUID.fromString(id));
		    return new ResponseEntity<>(HttpStatus.NO_CONTENT);
		} catch (Exception e) {
		    return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
		}
	}

	@DeleteMapping("/deleteAllProduct")
	public ResponseEntity<HttpStatus> deleteAllProduct() {
		try {
			productRepository.deleteAll();
		    return new ResponseEntity<>(HttpStatus.NO_CONTENT);
		} catch (Exception e) {
		    return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
		}
	}

	@GetMapping("/getProductByState")
	public ResponseEntity<List<Product>> findByProductState() {
		try {
			var productList = productRepository.findByProductState(true);

		    if (productList.isEmpty()) {
		    	return new ResponseEntity<>(HttpStatus.NO_CONTENT);
		    } else {
		    	return new ResponseEntity<>(productList, HttpStatus.OK);
		    }
		} catch (Exception e) {
			return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
		}
	}

}

6. application.yaml

  • application.yaml和CassandraConfig.java,二选一

server:
  port: 8080
  servlet:
    context-path: /

spring:
  data:
    cassandra:
      repositories:
        type: imperative
  cassandra:
    keyspace-name: elf
    port: 9042
    contact-points:
    - 192.168.0.123:9042
    schema-action: create-if-not-exists
    password: cassandra
    username: cassandra
    # /opt/cassandra/bin/nodetool status命令查询
    local-datacenter: datacenter1
import java.net.InetSocketAddress;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.cassandra.repository.config.EnableCassandraRepositories;
import com.datastax.oss.driver.api.core.CqlSession;

@Configuration
@EnableCassandraRepositories
public class CassandraConfig {

	@Bean
	CqlSession session() {
		return CqlSession.builder().withKeyspace("elf")
			.withAuthCredentials("cassandra", "cassandra")
			.withLocalDatacenter("datacenter1")
			.addContactPoint(InetSocketAddress.createUnresolved("192.168.0.123",9042))
			.build();
	}

}

7. CassandraEntry

import java.lang.invoke.MethodHandles;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringBootConfiguration;

@SpringBootApplication
public class CassandraEntry {

	public static void main(String[] sa) {
		var cls = MethodHandles.lookup().lookupClass();
		SpringApplication.run(cls,sa);
	}

}

8. Environment

  • /opt/cassandra/bin/nodetool status
    命令得到数据中心:Datacenter: datacenter1

# cassandra为Cassandra容器名
docker start cassandra

# docker exec -it cassandra /bin/bash

# 查询集群状态,用于应用程序连接等,详情参考Troubleshooting章节
# /opt/cassandra/bin/nodetool status

# cqlsh 127.0.0.1 9042 -u cassandra -p cassandra

# describe keyspaces;

9. Product.cql

create keyspace if not exists elf with replication={'class':'SimpleStrategy','replication_factor':1};

use elf;

create table if not exists product(
	product_id uuid primary key,
	product_name varchar,
	product_memo text,
   	product_state boolean
);
select * from elf.product;

 product_id | product_memo | product_name | product_state
------------+--------------+--------------+---------------

(0 rows)

10. Testing

  • 参考CassandraTesting.adoc;