├── .gitignore ├── README.md ├── pom.xml └── src ├── main ├── java │ └── com │ │ └── arya │ │ └── cassandra │ │ ├── SpringBootCassandraCrudApplication.java │ │ ├── config │ │ ├── CassandraConfig.java │ │ └── OpenAPIConfig.java │ │ ├── controller │ │ ├── SuperHeroController.java │ │ └── SuperHeroQueryController.java │ │ ├── model │ │ ├── SuperHero.java │ │ └── SuperPowers.java │ │ ├── repository │ │ ├── SuperHeroQueryRepository.java │ │ ├── SuperHeroRepository.java │ │ └── impl │ │ │ └── SuperHeroQueryRepositoryImpl.java │ │ ├── service │ │ ├── SuperHeroQueryService.java │ │ ├── SuperHeroService.java │ │ └── impl │ │ │ ├── SuperHeroQueryServiceImpl.java │ │ │ └── SuperHeroServiceImpl.java │ │ └── utils │ │ └── HelperUtil.java └── resources │ ├── application.yml │ └── static │ ├── spring-boot-cassandra-crud-Swagger.PNG │ └── spring-data-cassandra-output.PNG └── test └── java └── com └── arya └── cassandra └── SpringBootCassandraCrudApplicationTests.java /.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | .gradle 3 | build/ 4 | !gradle/wrapper/gradle-wrapper.jar 5 | !**/src/main/**/build/ 6 | !**/src/test/**/build/ 7 | **/bin/** 8 | **/target/** 9 | 10 | ### STS ### 11 | .apt_generated 12 | .classpath 13 | .factorypath 14 | .project 15 | .settings 16 | .springBeans 17 | .sts4-cache 18 | 19 | ### IntelliJ IDEA ### 20 | .idea 21 | *.iws 22 | *.iml 23 | *.ipr 24 | out/ 25 | !**/src/main/**/out/ 26 | !**/src/test/**/out/ 27 | 28 | ### NetBeans ### 29 | /nbproject/private/ 30 | /nbbuild/ 31 | /dist/ 32 | /nbdist/ 33 | /.nb-gradle/ 34 | 35 | ### VS Code ### 36 | .vscode/ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # spring-boot-cassandra-crud 2 | Spring boot CRUD (Create, Read, Update, Delete) demo application with cassandra DB - 3 | In this application, we have implemented CRUD (Create, Read, Update, Delete) operations using spring data and cassandra DB. 4 | 5 | 6 | ## Prerequisites 7 | - Java 8 | - [Spring Boot](https://spring.io/projects/spring-boot) 9 | - [Maven](https://maven.apache.org/guides/index.html) 10 | - [Cassandra](https://cassandra.apache.org/) 11 | 12 | 13 | ## Tools 14 | - Eclipse or IntelliJ IDEA (or any preferred IDE) with embedded Gradle 15 | - Maven (version >= 3.6.0) 16 | - Postman (or any RESTful API testing tool) 17 | - cqlsh (cassandra query language shell) - for monitoring stored data 18 | 19 | 20 | 21 | ### Build and Run application 22 | _GOTO >_ **~/absolute-path-to-directory/spring-boot-cassandra-crud** 23 | and try below command in terminal 24 | > **```mvn spring-boot:run```** it will run application as spring boot application 25 | 26 | or 27 | > **```mvn clean install```** it will build application and create **jar** file under target directory 28 | 29 | Run jar file from below path with given command 30 | > **```java -jar ~/path-to-spring-boot-cassandra-crud/target/spring-boot-cassandra-crud-0.0.1-SNAPSHOT.jar```** 31 | 32 | Or 33 | > run main method from `SpringBootCassandraCrudApplication.java` as spring boot application. 34 | 35 | 36 | || 37 | | --------- | 38 | | **_Note_** : In `SpringBootCassandraCrudApplication.java` class we have autowired SuperHero repository.
If there is no record present in DB for SuperHero model class, static data is getting inserted in DB from `HelperUtil.java` class when we are starting the app for the first time.| 39 | 40 | 41 | --- 42 | ### For API document using OpenAPI UI 43 | 44 | > **http://localhost:8080/swagger-ui-custom.html** 45 | 46 | ![Swagger Documentation](https://github.com/rahul-ghadge/spring-boot-cassandra-crud/blob/master/src/main/resources/static/spring-boot-cassandra-crud-Swagger.PNG?raw=true "Spring Data Cassandra Swagger") 47 | 48 | --- 49 | 50 | ### Install JDK8 51 | Step 1: Download JDK8 from [JDK site](https://www.oracle.com/java/technologies/javase/javase-jdk8-downloads.html). 52 | Step 2: Install downloaded an executable file. 53 | Step 3: Add JDK8 path as environment variable. 54 | 55 | 56 | 57 | ### Setup cqlsh (cassandra query language shell) - for monitoring stored data 58 | Step 1: **Python2.7** is mandatory for cqlsh to handle user requests. Download Python2.7 from [Python site](https://www.python.org/downloads/release/python-2718/). 59 | Step 2: Install downloaded an executable file. 60 | Step 3: Add Python2.7 path as environment variable. 61 | 62 | 63 | 64 | 65 | ### Setup Cassandra 66 | Step 1: Download the latest version of apache-cassandra-x.xx.x from [Cassandra site](https://cassandra.apache.org/download/). 67 | Step 2: Unzip the compressed zip file using a compression tool to any location. Ex. c:\apache-cassandra-x.xx.x 68 | Step 3: Add c:\apache-cassandra-x.xx.x\bin path as environment variable. 69 | 70 | 71 | --- 72 | 73 | #### Start the Cassandra and cqlsh 74 | 75 | ##### Start Cassandra 76 | Make sure bin path is set for cassandra in environment variable. 77 | > `cassandra` 78 | 79 | If no error on the console means cassandra is started and running. 80 | 81 | 82 | ##### Start cqlsh 83 | Make sure path is set for the python in environment variable. 84 | > `cqlsh` 85 | 86 | If no error on the console means **cqlsh** is connected. 87 | 88 | 89 | ### Code Snippets 90 | 1. #### Maven Dependencies 91 | Need to add below dependency to enable cassandra in **pom.xml**. 92 | ``` 93 | 94 | org.springframework.boot 95 | spring-boot-starter-data-cassandra 96 | 97 | 98 | 99 | 100 | org.projectlombok 101 | lombok 102 | true 103 | 104 | ``` 105 | 106 | For API documentation using swagger and OpenApi UI add below dependency. 107 | ``` 108 | 109 | org.springdoc 110 | springdoc-openapi-ui 111 | 1.4.4 112 | 113 | ``` 114 | 115 | 2. #### Properties file 116 | Placed properties in **application.yml** file related to cassandra which we are reading in **CassandraConfig.java** class 117 | and configuring cassandra connection for Cassandra. 118 | API documentation related swagger UI path is also placed here which will enable Swagger API Doc on same path. 119 | **src/main/resources/application.yml** 120 | ``` 121 | spring: 122 | data: 123 | cassandra: 124 | contact-points: localhost 125 | port: 9042 126 | keyspace-name: simple_crud 127 | #username: cassandra 128 | #password: cassandra 129 | #schema-act: create_if_not_exists 130 | 131 | springdoc: 132 | version: 1.0.0 133 | swagger-ui: 134 | path: /swagger-ui-custom.html 135 | ``` 136 | 137 | 138 | 3. #### Model class 139 | Below are the model classes which we will store in cassandra and perform CRUD operations. 140 | **com.arya.cassandra.model.SuperHero.java** 141 | **com.arya.cassandra.model.SuperPowers.java** 142 | ``` 143 | @Data 144 | @Builder 145 | @Table("super_hero") 146 | public class SuperHero implements Serializable { 147 | @PrimaryKey 148 | private Long id; 149 | private String name; 150 | @Column("super_name") 151 | private String superName; 152 | private String profession; 153 | private int age; 154 | @Column("super_powers") 155 | private SuperPowers superPowers; 156 | } 157 | 158 | 159 | @Data 160 | @Builder 161 | @UserDefinedType("super_powers") 162 | public class SuperPowers implements Serializable { 163 | private String strength; 164 | private String durability; 165 | private boolean canFly; 166 | } 167 | ``` 168 | 169 | 170 | 4. #### Cassandra Configuration 171 | This is the most important class in this application, where all cassandra related configuration is placed 172 | and using this class we are connecting to cassandra and creating **KEYSPACE** and **TABLES** also while starting the application. 173 | 174 | ``` 175 | import org.springframework.beans.factory.annotation.Value; 176 | import org.springframework.context.annotation.Configuration; 177 | import org.springframework.data.cassandra.config.AbstractCassandraConfiguration; 178 | import org.springframework.data.cassandra.config.SchemaAction; 179 | import org.springframework.data.cassandra.core.cql.keyspace.CreateKeyspaceSpecification; 180 | import org.springframework.data.cassandra.core.cql.keyspace.DropKeyspaceSpecification; 181 | import org.springframework.data.cassandra.core.cql.keyspace.KeyspaceOption; 182 | 183 | import java.util.Collections; 184 | import java.util.List; 185 | 186 | @Configuration 187 | public class CassandraConfig extends AbstractCassandraConfiguration { 188 | 189 | @Value("${spring.data.cassandra.keyspace-name: simple_crud}") 190 | private String KEYSPACE; 191 | 192 | @Value("${spring.data.cassandra.contact-points: localhost}") 193 | private String CONTACT_POINT; 194 | 195 | @Value("${spring.data.cassandra.port: 9042}") 196 | private int PORT; 197 | 198 | 199 | @Override 200 | public String getContactPoints() { 201 | return CONTACT_POINT; 202 | } 203 | 204 | @Override 205 | protected int getPort() { 206 | return PORT; 207 | } 208 | 209 | @Override 210 | public SchemaAction getSchemaAction() { 211 | return SchemaAction.CREATE_IF_NOT_EXISTS; 212 | } 213 | 214 | @Override 215 | protected List getKeyspaceCreations() { 216 | return Collections.singletonList(CreateKeyspaceSpecification.createKeyspace(KEYSPACE) 217 | .ifNotExists() 218 | .with(KeyspaceOption.DURABLE_WRITES, true) 219 | .withSimpleReplication(3L)); 220 | } 221 | 222 | @Override 223 | protected String getLocalDataCenter() { 224 | return "datacenter1"; 225 | } 226 | 227 | //@Override 228 | //protected List getKeyspaceDrops() { 229 | // return Collections.singletonList(DropKeyspaceSpecification.dropKeyspace(KEYSPACE)); 230 | //} 231 | 232 | @Override 233 | protected String getKeyspaceName() { 234 | return KEYSPACE; 235 | } 236 | 237 | @Override 238 | public String[] getEntityBasePackages() { 239 | return new String[] {"com.arya.cassandra.model"}; 240 | } 241 | } 242 | ``` 243 | 244 | 245 | 246 | 5. #### CRUD operation for Super Heroes 247 | 248 | In **com.arya.cassandra.controller.SuperHeroController.java** class, 249 | we have exposed 5 endpoints for basic CRUD operations 250 | - GET All Super Heroes 251 | - GET by ID 252 | - POST to store Super Hero in DB 253 | - PUT to update Super Hero 254 | - DELETE by ID 255 | 256 | ``` 257 | @RestController 258 | @RequestMapping("/super-heroes") 259 | public class SuperHeroController { 260 | 261 | @GetMapping("/save") 262 | public ResponseEntity> save(); 263 | 264 | @GetMapping 265 | public ResponseEntity> findAll(); 266 | 267 | @GetMapping("/{id}") 268 | public ResponseEntity findById(@PathVariable String id); 269 | 270 | @PostMapping 271 | public ResponseEntity save(@RequestBody SuperHero superHero); 272 | 273 | @PutMapping 274 | public ResponseEntity update(@RequestBody SuperHero superHero); 275 | 276 | @DeleteMapping("/{id}") 277 | public ResponseEntity delete(@PathVariable String id); 278 | } 279 | ``` 280 | 281 | In **com.arya.cassandra.repository.SuperHeroRepository.java**, we are extending `CassandraRepository` interface which enables CRUD related methods. 282 | ``` 283 | @Repository 284 | public interface SuperHeroRepository extends CassandraRepository { 285 | } 286 | ``` 287 | 288 | In **com.arya.cassandra.service.impl.SuperHeroServiceImpl.java**, we are autowiring above interface using `@Autowired` annotation and doing CRUD operation. 289 | 290 | 291 | 6. #### Query operation for SuperHero 292 | In **com.arya.cassandra.controller.SuperHeroQueryController.java** class Cassandra queries API Endpoints are placed. 293 | we are autowiring SuperHeroQueryService interface using `@Autowired` annotation and reaching to Service layer. 294 | In **com.arya.cassandra.service.impl.SuperHeroQueryServiceImpl.java**, 295 | we are autowiring SuperHeroQueryRepository interface using `@Autowired` annotation and reaching to DAO layer. 296 | In **com.arya.cassandra.repository.impl.SuperHeroQueryRepositoryImpl.java**, 297 | we are autowiring `CassandraOperations` interface which enables CRUD related methods. 298 | ``` 299 | @Autowired 300 | private CassandraOperations cassandraTemplate; 301 | ``` 302 | 303 | 304 | 305 |
306 | 307 | ### API Endpoints 308 | 309 | - #### Super Hero CRUD Operations 310 | > **GET Mapping** http://localhost:8080/super-heroes - Get all Super Heroes 311 | 312 | > **GET Mapping** http://localhost:8080/super-heroes/1 - Get Super Hero by ID 313 | 314 | > **POST Mapping** http://localhost:8080/super-heroes - Add new Super Hero in DB 315 | 316 | Request Body 317 | ``` 318 | { 319 | "id": 1, 320 | "name": "Tony", 321 | "superName": "Iron Man", 322 | "profession": "Business", 323 | "age": 50, 324 | "superPowers": { 325 | "strength": "Suit", 326 | "durability": "Month", 327 | "canFly": true 328 | } 329 | } 330 | ``` 331 | 332 | > **PUT Mapping** http://localhost:8080/super-heroes - Update existing Super Hero for given ID 333 | 334 | Request Body 335 | ``` 336 | { 337 | "id": 1, 338 | "name": "Tony", 339 | "superName": "Iron Man", 340 | "profession": "Business", 341 | "age": 50, 342 | "superPowers": { 343 | "strength": "Only if he is in a suit", 344 | "durability": "Month", 345 | "canFly": true 346 | } 347 | } 348 | ``` 349 | 350 | > **DELETE Mapping** http://localhost:8080/super-heroes/1 - Delete Super Hero by ID 351 | 352 | 353 | 354 | ### Output 355 | 356 | ![Alt text](https://github.com/rahul-ghadge/spring-boot-cassandra-crud/blob/master/src/main/resources/static/spring-data-cassandra-output.PNG?raw=true "Spring Data Cassandra output") 357 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.3.3.RELEASE 9 | 10 | 11 | com.arya.cassandra 12 | spring-boot-cassandra-crud 13 | 0.0.1-SNAPSHOT 14 | spring-boot-cassandra-crud 15 | Demo project for Spring Boot Cassandra CRUD demo 16 | 17 | 18 | 1.8 19 | 20 | 21 | 22 | 23 | 24 | org.springframework.boot 25 | spring-boot-starter-web 26 | 27 | 28 | 29 | org.projectlombok 30 | lombok 31 | true 32 | 33 | 34 | 35 | org.springframework.boot 36 | spring-boot-starter-data-cassandra 37 | 38 | 39 | 40 | org.springdoc 41 | springdoc-openapi-ui 42 | 1.4.4 43 | 44 | 45 | 46 | org.springframework.boot 47 | spring-boot-starter-test 48 | test 49 | 50 | 51 | org.junit.vintage 52 | junit-vintage-engine 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | org.springframework.boot 62 | spring-boot-maven-plugin 63 | 64 | 65 | 66 | org.apache.maven.plugins 67 | maven-surefire-plugin 68 | 2.22.2 69 | 70 | true 71 | 72 | 73 | 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /src/main/java/com/arya/cassandra/SpringBootCassandraCrudApplication.java: -------------------------------------------------------------------------------- 1 | package com.arya.cassandra; 2 | 3 | import com.arya.cassandra.model.SuperHero; 4 | import com.arya.cassandra.repository.SuperHeroRepository; 5 | import com.arya.cassandra.utils.HelperUtil; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.boot.CommandLineRunner; 10 | import org.springframework.boot.SpringApplication; 11 | import org.springframework.boot.autoconfigure.SpringBootApplication; 12 | import org.springframework.context.annotation.Bean; 13 | import org.springframework.data.cassandra.repository.config.EnableCassandraRepositories; 14 | 15 | import java.util.List; 16 | 17 | @SpringBootApplication 18 | @EnableCassandraRepositories 19 | public class SpringBootCassandraCrudApplication { 20 | 21 | private final Logger logger = LoggerFactory.getLogger(getClass()); 22 | 23 | 24 | public static void main(String[] args) { 25 | SpringApplication.run(SpringBootCassandraCrudApplication.class, args); 26 | } 27 | 28 | @Autowired 29 | private SuperHeroRepository superHeroRepository; 30 | 31 | @Bean 32 | CommandLineRunner runner() { 33 | return args -> { 34 | List superHeroes = superHeroRepository.findAll(); 35 | if (superHeroes.isEmpty()) { 36 | logger.info("******* Inserting Super heroes to DB *******"); 37 | superHeroRepository.saveAll(HelperUtil.getSuperHeroesData()); 38 | } else { 39 | logger.info("******* Super heroes stored in DB Size :: {}", superHeroes.size()); 40 | logger.info("******* Super heroes stored in DB :: {}", superHeroes); 41 | } 42 | }; 43 | } 44 | 45 | } -------------------------------------------------------------------------------- /src/main/java/com/arya/cassandra/config/CassandraConfig.java: -------------------------------------------------------------------------------- 1 | package com.arya.cassandra.config; 2 | 3 | import org.springframework.beans.factory.annotation.Value; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.data.cassandra.config.AbstractCassandraConfiguration; 6 | import org.springframework.data.cassandra.config.SchemaAction; 7 | import org.springframework.data.cassandra.core.cql.keyspace.CreateKeyspaceSpecification; 8 | import org.springframework.data.cassandra.core.cql.keyspace.KeyspaceOption; 9 | 10 | import java.util.Collections; 11 | import java.util.List; 12 | 13 | @Configuration 14 | public class CassandraConfig extends AbstractCassandraConfiguration { 15 | 16 | @Value("${spring.data.cassandra.keyspace-name: simple_crud}") 17 | private String keyspace; 18 | 19 | @Value("${spring.data.cassandra.contact-points: localhost}") 20 | private String contactPoint; 21 | 22 | @Value("${spring.data.cassandra.port: 9042}") 23 | private int port; 24 | 25 | 26 | @Override 27 | public String getContactPoints() { 28 | return contactPoint; 29 | } 30 | 31 | @Override 32 | protected int getPort() { 33 | return port; 34 | } 35 | 36 | @Override 37 | public SchemaAction getSchemaAction() { 38 | return SchemaAction.CREATE_IF_NOT_EXISTS; 39 | } 40 | 41 | @Override 42 | protected List getKeyspaceCreations() { 43 | return Collections.singletonList(CreateKeyspaceSpecification.createKeyspace(keyspace) 44 | .ifNotExists() 45 | .with(KeyspaceOption.DURABLE_WRITES, true) 46 | .withSimpleReplication(3L)); 47 | } 48 | 49 | @Override 50 | protected String getLocalDataCenter() { 51 | return "datacenter1"; 52 | } 53 | 54 | @Override 55 | protected String getKeyspaceName() { 56 | return keyspace; 57 | } 58 | 59 | @Override 60 | public String[] getEntityBasePackages() { 61 | return new String[] {"com.arya.cassandra.model"}; 62 | } 63 | 64 | } -------------------------------------------------------------------------------- /src/main/java/com/arya/cassandra/config/OpenAPIConfig.java: -------------------------------------------------------------------------------- 1 | package com.arya.cassandra.config; 2 | 3 | import io.swagger.v3.oas.models.OpenAPI; 4 | import io.swagger.v3.oas.models.info.Info; 5 | import io.swagger.v3.oas.models.info.License; 6 | import org.springframework.beans.factory.annotation.Value; 7 | import org.springframework.context.annotation.Bean; 8 | import org.springframework.context.annotation.Configuration; 9 | 10 | @Configuration 11 | public class OpenAPIConfig { 12 | 13 | @Bean 14 | public OpenAPI customOpenAPI(@Value("${springdoc.version}") String appVersion) { 15 | return new OpenAPI() 16 | .info(new Info().title("Super Hero API") 17 | .version(appVersion) 18 | .description("This is a sample CRUD application using spring data and cassandra.") 19 | .termsOfService("http://swagger.io/terms/") 20 | .license(new License().name("Apache 2.0").url("http://springdoc.org"))); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/arya/cassandra/controller/SuperHeroController.java: -------------------------------------------------------------------------------- 1 | package com.arya.cassandra.controller; 2 | 3 | 4 | import com.arya.cassandra.model.SuperHero; 5 | import com.arya.cassandra.service.SuperHeroService; 6 | import io.swagger.v3.oas.annotations.Operation; 7 | import io.swagger.v3.oas.annotations.Parameter; 8 | import io.swagger.v3.oas.annotations.media.ArraySchema; 9 | import io.swagger.v3.oas.annotations.media.Content; 10 | import io.swagger.v3.oas.annotations.media.Schema; 11 | import io.swagger.v3.oas.annotations.responses.ApiResponse; 12 | import io.swagger.v3.oas.annotations.responses.ApiResponses; 13 | import io.swagger.v3.oas.annotations.tags.Tag; 14 | import org.slf4j.Logger; 15 | import org.slf4j.LoggerFactory; 16 | import org.springframework.beans.factory.annotation.Autowired; 17 | import org.springframework.http.HttpStatus; 18 | import org.springframework.http.MediaType; 19 | import org.springframework.http.ResponseEntity; 20 | import org.springframework.util.StringUtils; 21 | import org.springframework.web.bind.annotation.*; 22 | 23 | import java.util.List; 24 | 25 | @RestController 26 | @RequestMapping("/super-heroes") 27 | @Tag(name = "Superhero JPA controller", description = "Superhero CRUD API with documentation annotations") 28 | public class SuperHeroController { 29 | 30 | Logger logger = LoggerFactory.getLogger(getClass()); 31 | 32 | @Autowired 33 | private SuperHeroService superHeroService; 34 | 35 | 36 | @Operation(summary = "Save dummy Superheroes") 37 | @ApiResponses(value = { 38 | @ApiResponse(responseCode = "201", description = "Saved superheroes list"), 39 | @ApiResponse(responseCode = "500", description = "Internal server error", content = @Content) 40 | }) 41 | @GetMapping("/save") 42 | @ResponseStatus(value = HttpStatus.CREATED) 43 | public void save() { 44 | 45 | logger.info("*** Storing dummy static data to DB ***"); 46 | List list = superHeroService.save(); 47 | logger.info("Stored data to DB :: {}", list); 48 | } 49 | 50 | 51 | @Operation(summary = "Get all Superheroes") 52 | @ApiResponses(value = { 53 | @ApiResponse(responseCode = "200", description = "Superheroes list", 54 | content = { @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, array = @ArraySchema(schema = @Schema(implementation = SuperHero.class)))}), 55 | @ApiResponse(responseCode = "500", description = "Internal server error", content = @Content) 56 | }) 57 | @GetMapping 58 | public ResponseEntity> findAll() { 59 | 60 | logger.info("*** Getting Superheroes from DB ***"); 61 | List list = superHeroService.findAll(); 62 | logger.info("Superheroes fetched from DB :: {}", list); 63 | 64 | return ResponseEntity.ok().body(list); 65 | } 66 | 67 | 68 | 69 | 70 | @Operation(summary = "Get a Superhero by its id") 71 | @ApiResponses(value = { 72 | @ApiResponse(responseCode = "200", description = "Found the Superhero", 73 | content = {@Content(mediaType = MediaType.APPLICATION_JSON_VALUE, schema = @Schema(implementation = SuperHero.class))}), 74 | @ApiResponse(responseCode = "400", description = "Invalid id supplied", content = @Content), 75 | @ApiResponse(responseCode = "404", description = "Superhero not found", content = @Content), 76 | @ApiResponse(responseCode = "500", description = "Internal server error", content = @Content) 77 | }) 78 | @GetMapping("/{id}") 79 | public ResponseEntity findById(@PathVariable Long id) { 80 | 81 | logger.info("*** Getting Superhero from DB for Id :: {}", id); 82 | SuperHero superHero = superHeroService.findById(id); 83 | 84 | if (StringUtils.isEmpty(superHero.getName())) 85 | return ResponseEntity.notFound().build(); 86 | 87 | logger.info("Superhero fetched :: {}", superHero); 88 | return ResponseEntity.ok().body(superHero); 89 | } 90 | 91 | 92 | 93 | 94 | @Operation(summary = "Create Superhero ") 95 | @ApiResponses(value = { 96 | @ApiResponse(responseCode = "200", description = "Save Superhero", 97 | content = { @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, schema = @Schema(implementation = SuperHero.class))}), 98 | @ApiResponse(responseCode = "500", description = "Internal server error", content = @Content) 99 | }) 100 | @PostMapping 101 | public ResponseEntity save(@Parameter(description = "Superhero object to be created") @RequestBody SuperHero superHero) { 102 | 103 | logger.info("*** Saving Superhero to DB :: {}", superHero); 104 | SuperHero savedSuperHero = superHeroService.save(superHero); 105 | logger.info("*** Saved Superhero to DB ***"); 106 | 107 | return ResponseEntity.ok().body(savedSuperHero); 108 | } 109 | 110 | 111 | 112 | @Operation(summary = "Update Superhero") 113 | @ApiResponses(value = { 114 | @ApiResponse(responseCode = "200", description = "Update Superhero", 115 | content = { @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, schema = @Schema(implementation = SuperHero.class))}), 116 | @ApiResponse(responseCode = "500", description = "Internal server error", content = @Content) 117 | }) 118 | @PutMapping 119 | public ResponseEntity update(@Parameter(description = "Superhero object to be updated") @RequestBody SuperHero superHero) { 120 | 121 | logger.info("*** Updating Superhero :: {}", superHero); 122 | SuperHero updatedSuperHero = superHeroService.update(superHero); 123 | logger.info("*** Updated Superhero to DB :: {}", superHero); 124 | 125 | return ResponseEntity.ok().body(updatedSuperHero); 126 | } 127 | 128 | 129 | 130 | 131 | @Operation(summary = "Delete the Superhero by its id") 132 | @ApiResponses(value = { 133 | @ApiResponse(responseCode = "200", description = "Delete the Superhero", 134 | content = {@Content(mediaType = MediaType.APPLICATION_JSON_VALUE, schema = @Schema(implementation = String.class))}) 135 | }) 136 | @DeleteMapping("/{id}") 137 | public ResponseEntity delete(@Parameter(description = "Superhero id to be deleted") @PathVariable Long id) { 138 | 139 | logger.info("*** Deleting Superhero from DB for Id :: {}", id); 140 | superHeroService.delete(id); 141 | logger.info("*** Deleted Superhero from DB for Id :: {}", id); 142 | 143 | return ResponseEntity.ok().body("Deleted successfully...!"); 144 | } 145 | } -------------------------------------------------------------------------------- /src/main/java/com/arya/cassandra/controller/SuperHeroQueryController.java: -------------------------------------------------------------------------------- 1 | package com.arya.cassandra.controller; 2 | 3 | 4 | import com.arya.cassandra.model.SuperHero; 5 | import com.arya.cassandra.service.SuperHeroQueryService; 6 | import io.swagger.v3.oas.annotations.Operation; 7 | import io.swagger.v3.oas.annotations.Parameter; 8 | import io.swagger.v3.oas.annotations.media.ArraySchema; 9 | import io.swagger.v3.oas.annotations.media.Content; 10 | import io.swagger.v3.oas.annotations.media.Schema; 11 | import io.swagger.v3.oas.annotations.responses.ApiResponse; 12 | import io.swagger.v3.oas.annotations.responses.ApiResponses; 13 | import io.swagger.v3.oas.annotations.tags.Tag; 14 | import org.springframework.beans.factory.annotation.Autowired; 15 | import org.springframework.http.MediaType; 16 | import org.springframework.web.bind.annotation.GetMapping; 17 | import org.springframework.web.bind.annotation.PathVariable; 18 | import org.springframework.web.bind.annotation.RequestMapping; 19 | import org.springframework.web.bind.annotation.RestController; 20 | 21 | import java.util.List; 22 | 23 | @RestController 24 | @RequestMapping("/super-heroes-query") 25 | @Tag(name = "Superhero Query controller", description = "Get Superhero APIs using Queries") 26 | public class SuperHeroQueryController { 27 | 28 | @Autowired 29 | private SuperHeroQueryService superHeroQueryService; 30 | 31 | 32 | @Operation(summary = "Get all Superheroes using query") 33 | @ApiResponses(value = { 34 | @ApiResponse(responseCode = "200", description = "Superheroes list", 35 | content = { @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, array = @ArraySchema(schema = @Schema(implementation = SuperHero.class)))}), 36 | @ApiResponse(responseCode = "500", description = "Internal server error", content = @Content) 37 | }) 38 | @GetMapping 39 | public List getAll() { 40 | return superHeroQueryService.getAll(); 41 | } 42 | 43 | 44 | @Operation(summary = "Get all Superheroes by name using query") 45 | @ApiResponses(value = { 46 | @ApiResponse(responseCode = "200", description = "Superheroes list", 47 | content = { @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, array = @ArraySchema(schema = @Schema(implementation = SuperHero.class)))}), 48 | @ApiResponse(responseCode = "500", description = "Internal server error", content = @Content) 49 | }) 50 | @GetMapping("/name/{name}") 51 | public List getSuperHeroByName(@Parameter(description = "Superhero name to be fetched") @PathVariable String name) { 52 | return superHeroQueryService.getSuperHeroByName(name); 53 | } 54 | 55 | 56 | @Operation(summary = "Get one Superhero by name using query") 57 | @ApiResponses(value = { 58 | @ApiResponse(responseCode = "200", description = "Get one Superhero by name", 59 | content = { @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, schema = @Schema(implementation = SuperHero.class))}), 60 | @ApiResponse(responseCode = "500", description = "Internal server error", content = @Content) 61 | }) 62 | @GetMapping("/one-by-name/{name}") 63 | public SuperHero getOneSuperHeroByName(@Parameter(description = "Superhero name to be fetched") @PathVariable String name) { 64 | return superHeroQueryService.getOneSuperHeroByName(name); 65 | } 66 | 67 | @Operation(summary = "Get one Superhero by name like using query (Only on indexed columns)") 68 | @ApiResponses(value = { 69 | @ApiResponse(responseCode = "200", description = "Get one Superhero by name like", 70 | content = { @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, array = @ArraySchema(schema = @Schema(implementation = SuperHero.class)))}), 71 | @ApiResponse(responseCode = "500", description = "Internal server error", content = @Content) 72 | }) 73 | @GetMapping("/name-like/{name}") 74 | public List getSuperHeroByNameLike(@Parameter(description = "Superhero name to be fetched") @PathVariable String name) { 75 | return superHeroQueryService.getSuperHeroByNameLike(name); 76 | } 77 | 78 | 79 | @Operation(summary = "Get one Superhero by super name using query") 80 | @ApiResponses(value = { 81 | @ApiResponse(responseCode = "200", description = "Get one Superhero by super name", 82 | content = { @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, schema = @Schema(implementation = SuperHero.class))}), 83 | @ApiResponse(responseCode = "500", description = "Internal server error", content = @Content) 84 | }) 85 | @GetMapping("/one-by-superName/{superName}") 86 | public SuperHero getSingleSuperHeroBySuperName(@Parameter(description = "Superhero super name to be fetched") @PathVariable String superName) { 87 | return superHeroQueryService.getSingleSuperHeroBySuperName(superName); 88 | } 89 | 90 | 91 | @Operation(summary = "Get all Superheroes whose age greater than using query") 92 | @ApiResponses(value = { 93 | @ApiResponse(responseCode = "200", description = "Superheroes list", 94 | content = { @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, array = @ArraySchema(schema = @Schema(implementation = SuperHero.class)))}), 95 | @ApiResponse(responseCode = "500", description = "Internal server error", content = @Content) 96 | }) 97 | @GetMapping("/age-greater-than/{age}") 98 | public List getSuperHeroByAgeGreaterThan(@Parameter(description = "Superheroes fetched whose age greater than") @PathVariable int age) { 99 | return superHeroQueryService.getSuperHeroByAgeGreaterThan(age); 100 | } 101 | 102 | @Operation(summary = "Get all Superhero who can or can not fly using query") 103 | @ApiResponses(value = { 104 | @ApiResponse(responseCode = "200", description = "Superheroes list", 105 | content = { @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, array = @ArraySchema(schema = @Schema(implementation = SuperHero.class)))}), 106 | @ApiResponse(responseCode = "500", description = "Internal server error", content = @Content) 107 | }) 108 | @GetMapping("/can-fly/{canFly}") 109 | public List getSuperHeroWhoCanFly(@Parameter(description = "Superhero who can or can not fly to be fetched") @PathVariable boolean canFly) { 110 | return superHeroQueryService.getSuperHeroWhoCanFly(canFly); 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /src/main/java/com/arya/cassandra/model/SuperHero.java: -------------------------------------------------------------------------------- 1 | package com.arya.cassandra.model; 2 | 3 | import lombok.Builder; 4 | import lombok.Data; 5 | 6 | import org.springframework.data.cassandra.core.mapping.Column; 7 | import org.springframework.data.cassandra.core.mapping.PrimaryKey; 8 | import org.springframework.data.cassandra.core.mapping.Table; 9 | 10 | import java.io.Serializable; 11 | 12 | @Data 13 | @Builder 14 | @Table("super_hero") 15 | public class SuperHero implements Serializable { 16 | 17 | @PrimaryKey 18 | private Long id; 19 | 20 | private String name; 21 | 22 | @Column("super_name") 23 | private String superName; 24 | 25 | private String profession; 26 | 27 | private int age; 28 | 29 | @Column("super_powers") 30 | private SuperPowers superPowers; 31 | 32 | } -------------------------------------------------------------------------------- /src/main/java/com/arya/cassandra/model/SuperPowers.java: -------------------------------------------------------------------------------- 1 | package com.arya.cassandra.model; 2 | 3 | import lombok.Builder; 4 | import lombok.Data; 5 | import org.springframework.data.cassandra.core.mapping.UserDefinedType; 6 | 7 | import java.io.Serializable; 8 | 9 | @Data 10 | @Builder 11 | @UserDefinedType("super_powers") 12 | public class SuperPowers implements Serializable { 13 | 14 | private String strength; 15 | 16 | private String durability; 17 | 18 | private boolean canFly; 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/arya/cassandra/repository/SuperHeroQueryRepository.java: -------------------------------------------------------------------------------- 1 | package com.arya.cassandra.repository; 2 | 3 | import com.arya.cassandra.model.SuperHero; 4 | 5 | import java.util.List; 6 | 7 | public interface SuperHeroQueryRepository { 8 | 9 | List save(); 10 | 11 | List getAll(); 12 | 13 | List getSuperHeroByName(String name); 14 | 15 | SuperHero getOneSuperHeroByName(String name); 16 | 17 | List getSuperHeroByNameLike(String name); 18 | 19 | SuperHero getSingleSuperHeroBySuperName(String superName); 20 | 21 | List getSuperHeroByAgeGreaterThan(int age); 22 | 23 | List getSuperHeroWhoCanFly(boolean canFly); 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/arya/cassandra/repository/SuperHeroRepository.java: -------------------------------------------------------------------------------- 1 | package com.arya.cassandra.repository; 2 | 3 | import com.arya.cassandra.model.SuperHero; 4 | import org.springframework.data.cassandra.repository.CassandraRepository; 5 | import org.springframework.stereotype.Repository; 6 | 7 | @Repository 8 | public interface SuperHeroRepository extends CassandraRepository { 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/com/arya/cassandra/repository/impl/SuperHeroQueryRepositoryImpl.java: -------------------------------------------------------------------------------- 1 | package com.arya.cassandra.repository.impl; 2 | 3 | import com.arya.cassandra.model.SuperHero; 4 | import com.arya.cassandra.repository.SuperHeroQueryRepository; 5 | import com.arya.cassandra.utils.HelperUtil; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.data.cassandra.core.CassandraOperations; 8 | import org.springframework.data.cassandra.core.query.Criteria; 9 | import org.springframework.data.cassandra.core.query.Query; 10 | import org.springframework.stereotype.Repository; 11 | 12 | import java.util.List; 13 | import java.util.stream.Collectors; 14 | 15 | @Repository 16 | public class SuperHeroQueryRepositoryImpl implements SuperHeroQueryRepository { 17 | 18 | @Autowired 19 | private CassandraOperations cassandraTemplate; 20 | 21 | @Override 22 | public List save() { 23 | List superHeroes = cassandraTemplate.select(Query.empty(), SuperHero.class); 24 | if (superHeroes.isEmpty()) 25 | cassandraTemplate.insert(HelperUtil.getSuperHeroesData()); 26 | 27 | return cassandraTemplate.select(Query.empty(), SuperHero.class); 28 | } 29 | 30 | @Override 31 | public List getAll() { 32 | return cassandraTemplate.select(Query.empty(), SuperHero.class); 33 | } 34 | 35 | @Override 36 | public List getSuperHeroByName(String name) { 37 | return cassandraTemplate.select(Query.query(Criteria.where("name").is(name)).withAllowFiltering(), SuperHero.class); 38 | } 39 | 40 | @Override 41 | public SuperHero getOneSuperHeroByName(String name) { 42 | return cassandraTemplate.selectOne(Query.query(Criteria.where("name").is(name)).withAllowFiltering(), SuperHero.class); 43 | } 44 | 45 | @Override 46 | public List getSuperHeroByNameLike(String name) { 47 | return cassandraTemplate.select(Query.query(Criteria.where("name").like(name)).withAllowFiltering(), SuperHero.class); 48 | } 49 | 50 | @Override 51 | public SuperHero getSingleSuperHeroBySuperName(String superName) { 52 | return cassandraTemplate.selectOne(Query.query(Criteria.where("super_name").is(superName)).withAllowFiltering(), SuperHero.class); 53 | } 54 | 55 | @Override 56 | public List getSuperHeroByAgeGreaterThan(int age) { 57 | return cassandraTemplate.select(Query.query(Criteria.where("age").gt(age)).withAllowFiltering(), SuperHero.class); 58 | } 59 | 60 | @Override 61 | public List getSuperHeroWhoCanFly(boolean canFly) { 62 | List superHeroList = cassandraTemplate.select(Query.empty(), SuperHero.class); 63 | return superHeroList.stream().filter(superHero -> superHero.getSuperPowers().isCanFly() == canFly).collect(Collectors.toList()); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/com/arya/cassandra/service/SuperHeroQueryService.java: -------------------------------------------------------------------------------- 1 | package com.arya.cassandra.service; 2 | 3 | import com.arya.cassandra.model.SuperHero; 4 | 5 | import java.util.List; 6 | 7 | public interface SuperHeroQueryService { 8 | 9 | List save(); 10 | 11 | List getAll(); 12 | 13 | List getSuperHeroByName(String name); 14 | 15 | SuperHero getOneSuperHeroByName(String name); 16 | 17 | List getSuperHeroByNameLike(String name); 18 | 19 | SuperHero getSingleSuperHeroBySuperName(String superName); 20 | 21 | List getSuperHeroByAgeGreaterThan(int age); 22 | 23 | List getSuperHeroWhoCanFly(boolean canFly); 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/arya/cassandra/service/SuperHeroService.java: -------------------------------------------------------------------------------- 1 | package com.arya.cassandra.service; 2 | 3 | 4 | import com.arya.cassandra.model.SuperHero; 5 | 6 | import java.util.List; 7 | 8 | public interface SuperHeroService { 9 | 10 | List save(); 11 | 12 | List findAll(); 13 | 14 | SuperHero findById(Long id); 15 | 16 | SuperHero save(SuperHero superHero); 17 | 18 | SuperHero update(SuperHero superHero); 19 | 20 | void delete(Long id); 21 | 22 | } -------------------------------------------------------------------------------- /src/main/java/com/arya/cassandra/service/impl/SuperHeroQueryServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.arya.cassandra.service.impl; 2 | 3 | import com.arya.cassandra.model.SuperHero; 4 | import com.arya.cassandra.repository.SuperHeroQueryRepository; 5 | import com.arya.cassandra.service.SuperHeroQueryService; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.stereotype.Service; 8 | 9 | import java.util.List; 10 | 11 | @Service 12 | public class SuperHeroQueryServiceImpl implements SuperHeroQueryService { 13 | 14 | @Autowired 15 | private SuperHeroQueryRepository superHeroQueryRepository; 16 | 17 | @Override 18 | public List save() { 19 | return superHeroQueryRepository.save(); 20 | } 21 | 22 | @Override 23 | public List getAll() { 24 | return superHeroQueryRepository.getAll(); 25 | } 26 | 27 | @Override 28 | public List getSuperHeroByName(String name) { 29 | return superHeroQueryRepository.getSuperHeroByName(name); 30 | } 31 | 32 | @Override 33 | public SuperHero getOneSuperHeroByName(String name) { 34 | return superHeroQueryRepository.getOneSuperHeroByName(name); 35 | } 36 | 37 | @Override 38 | public List getSuperHeroByNameLike(String name) { 39 | return superHeroQueryRepository.getSuperHeroByNameLike(name); 40 | } 41 | 42 | @Override 43 | public SuperHero getSingleSuperHeroBySuperName(String superName) { 44 | return superHeroQueryRepository.getSingleSuperHeroBySuperName(superName); 45 | } 46 | 47 | @Override 48 | public List getSuperHeroByAgeGreaterThan(int age) { 49 | return superHeroQueryRepository.getSuperHeroByAgeGreaterThan(age); 50 | } 51 | 52 | @Override 53 | public List getSuperHeroWhoCanFly(boolean canFly) { 54 | return superHeroQueryRepository.getSuperHeroWhoCanFly(canFly); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/com/arya/cassandra/service/impl/SuperHeroServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.arya.cassandra.service.impl; 2 | 3 | import com.arya.cassandra.model.SuperHero; 4 | import com.arya.cassandra.repository.SuperHeroRepository; 5 | import com.arya.cassandra.service.SuperHeroService; 6 | import com.arya.cassandra.utils.HelperUtil; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.stereotype.Service; 9 | 10 | import java.util.List; 11 | 12 | @Service 13 | public class SuperHeroServiceImpl implements SuperHeroService { 14 | 15 | @Autowired 16 | private SuperHeroRepository repository; 17 | 18 | @Override 19 | public List save() { 20 | 21 | List superHeroes = repository.findAll(); 22 | if (superHeroes.isEmpty()) 23 | repository.saveAll(HelperUtil.getSuperHeroesData()); 24 | 25 | return repository.findAll(); 26 | } 27 | 28 | @Override 29 | public List findAll() { 30 | return repository.findAll(); 31 | } 32 | 33 | @Override 34 | public SuperHero findById(Long id) { 35 | return repository.findById(id).orElse(SuperHero.builder().build()); 36 | } 37 | 38 | @Override 39 | public SuperHero save(SuperHero superHero) { 40 | return repository.save(superHero); 41 | } 42 | 43 | @Override 44 | public SuperHero update(SuperHero superHero) { 45 | return repository.save(superHero); 46 | } 47 | 48 | @Override 49 | public void delete(Long id) { 50 | repository.findById(id).ifPresent(superHero -> repository.delete(superHero)); 51 | } 52 | } -------------------------------------------------------------------------------- /src/main/java/com/arya/cassandra/utils/HelperUtil.java: -------------------------------------------------------------------------------- 1 | package com.arya.cassandra.utils; 2 | 3 | import com.arya.cassandra.model.SuperHero; 4 | import com.arya.cassandra.model.SuperPowers; 5 | 6 | import java.util.Arrays; 7 | import java.util.List; 8 | import java.util.function.Supplier; 9 | 10 | public class HelperUtil { 11 | 12 | private HelperUtil() { 13 | } 14 | 15 | public static List getSuperHeroesData() { 16 | return superHeroesSupplier.get(); 17 | } 18 | 19 | private static final Supplier> superHeroesSupplier = () -> 20 | Arrays.asList( 21 | SuperHero.builder().id(1L).name("Bruce").superName("Hulk").profession("Doctor").age(50) 22 | .superPowers(SuperPowers.builder().strength("Body").durability("Week").canFly(false).build()).build(), 23 | 24 | SuperHero.builder().id(2L).name("Tony").superName("Iron Man").profession("Business man").age(45) 25 | .superPowers(SuperPowers.builder().strength("Suit").durability("Month").canFly(true).build()).build(), 26 | 27 | SuperHero.builder().id(3L).name("Peter").superName("Spider Man").profession("Student").age(21) 28 | .superPowers(SuperPowers.builder().strength("Spider sense").durability("Lifelong").canFly(true).build()).build() 29 | ); 30 | } -------------------------------------------------------------------------------- /src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | data: 3 | cassandra: 4 | contact-points: localhost 5 | port: 9042 6 | keyspace-name: simple_crud 7 | #username: cassandra 8 | #password: cassandra 9 | #schema-act: create_if_not_exists 10 | 11 | springdoc: 12 | version: 1.0.0 13 | swagger-ui: 14 | path: /swagger-ui-custom.html 15 | 16 | #logging: 17 | # level: 18 | # root: DEBUG -------------------------------------------------------------------------------- /src/main/resources/static/spring-boot-cassandra-crud-Swagger.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rahul-ghadge/spring-boot-cassandra-crud/0ea9ebbe658dc24e97368f1797e2720a3cf14499/src/main/resources/static/spring-boot-cassandra-crud-Swagger.PNG -------------------------------------------------------------------------------- /src/main/resources/static/spring-data-cassandra-output.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rahul-ghadge/spring-boot-cassandra-crud/0ea9ebbe658dc24e97368f1797e2720a3cf14499/src/main/resources/static/spring-data-cassandra-output.PNG -------------------------------------------------------------------------------- /src/test/java/com/arya/cassandra/SpringBootCassandraCrudApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.arya.cassandra; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class SpringBootCassandraCrudApplicationTests { 8 | 9 | // @Test 10 | // void contextLoads() { 11 | // } 12 | 13 | } 14 | --------------------------------------------------------------------------------