├── .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 | 
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 | 
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 |
--------------------------------------------------------------------------------