On this post we will use Gradle and spring boot in order to create a project that integrates spring-mvc and the Apache Cassandra database.
First we will begin with our Gradle configuration
group 'com.gkatzioura' version '1.0-SNAPSHOT' apply plugin: 'java' apply plugin: 'eclipse' apply plugin: 'idea' apply plugin: 'spring-boot' buildscript { repositories { mavenCentral() } dependencies { classpath("org.springframework.boot:spring-boot-gradle-plugin:1.2.5.RELEASE") } } jar { baseName = 'gs-serving-web-content' version = '0.1.0' } repositories { mavenCentral() } sourceCompatibility = 1.8 repositories { mavenCentral() } dependencies { compile "org.springframework.boot:spring-boot-starter-thymeleaf" compile "org.springframework.data:spring-data-cassandra:1.2.2.RELEASE" compile 'org.slf4j:slf4j-api:1.6.6' compile 'ch.qos.logback:logback-classic:1.0.13' testCompile "junit:junit" } task wrapper(type: Wrapper) { gradleVersion = '2.3' }
We will create the keyspace and the table on our Cassandra database
CREATE KEYSPACE IF NOT EXISTS example WITH replication = {'class': 'SimpleStrategy', 'replication_factor': '1'} AND durable_writes = true; CREATE TABLE IF NOT EXISTS example.greetings ( user text, id timeuuid, greet text, creation_date timestamp, PRIMARY KEY (user, id) ) WITH CLUSTERING ORDER BY (id DESC);
We can run a file containing cql statements by using cqlsh
cqlsh -f database_creation.cql
Cassandra connection information will reside on META-INF/cassandra.properties
cassandra.contactpoints=localhost cassandra.port=9042 cassandra.keyspace=example
Now we can proceed with the Cassandra configuration using spring annotations.
package com.gkatzioura.spring.config; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource; import org.springframework.core.env.Environment; import org.springframework.data.cassandra.config.CassandraClusterFactoryBean; import org.springframework.data.cassandra.config.CassandraSessionFactoryBean; import org.springframework.data.cassandra.config.SchemaAction; import org.springframework.data.cassandra.convert.CassandraConverter; import org.springframework.data.cassandra.convert.MappingCassandraConverter; import org.springframework.data.cassandra.core.CassandraOperations; import org.springframework.data.cassandra.core.CassandraTemplate; import org.springframework.data.cassandra.mapping.BasicCassandraMappingContext; import org.springframework.data.cassandra.mapping.CassandraMappingContext; import org.springframework.data.cassandra.repository.config.EnableCassandraRepositories; @Configuration @PropertySource(value = {"classpath:META-INF/cassandra.properties"}) @EnableCassandraRepositories(basePackages = {"com.gkatzioura.spring"}) public class CassandraConfig { @Autowired private Environment environment; private static final Logger LOGGER = LoggerFactory.getLogger(CassandraConfig.class); @Bean public CassandraClusterFactoryBean cluster() { CassandraClusterFactoryBean cluster = new CassandraClusterFactoryBean(); cluster.setContactPoints(environment.getProperty("cassandra.contactpoints")); cluster.setPort(Integer.parseInt(environment.getProperty("cassandra.port"))); return cluster; } @Bean public CassandraMappingContext mappingContext() { return new BasicCassandraMappingContext(); } @Bean public CassandraConverter converter() { return new MappingCassandraConverter(mappingContext()); } @Bean public CassandraSessionFactoryBean session() throws Exception { CassandraSessionFactoryBean session = new CassandraSessionFactoryBean(); session.setCluster(cluster().getObject()); session.setKeyspaceName(environment.getProperty("cassandra.keyspace")); session.setConverter(converter()); session.setSchemaAction(SchemaAction.NONE); return session; } @Bean public CassandraOperations cassandraTemplate() throws Exception { return new CassandraTemplate(session().getObject()); } }
Then we create the Greeting entity.
package com.gkatzioura.spring.entity; import com.datastax.driver.core.utils.UUIDs; import org.springframework.cassandra.core.PrimaryKeyType; import org.springframework.data.cassandra.mapping.Column; import org.springframework.data.cassandra.mapping.PrimaryKeyColumn; import org.springframework.data.cassandra.mapping.Table; import java.util.Date; import java.util.UUID; @Table(value = "greetings") public class Greeting { @PrimaryKeyColumn(name = "id",ordinal = 1,type = PrimaryKeyType.CLUSTERED) private UUID id = UUIDs.timeBased(); @PrimaryKeyColumn(name="user",ordinal = 0,type = PrimaryKeyType.PARTITIONED) private String user; @Column(value = "greet") private String greet; @Column(value = "creation_date") private Date creationDate; public UUID getId() { return id; } public void setId(UUID id) { this.id = id; } public Date getCreationDate() { return creationDate; } public void setCreationDate(Date creationDate) { this.creationDate = creationDate; } public String getUser() { return user; } public void setUser(String user) { this.user = user; } public String getGreet() { return greet; } public void setGreet(String greet) { this.greet = greet; } }
In order to access the data, a repository should be created. In our case we will add some extra functionality to the repository by adding some queries.
package com.gkatzioura.spring.repository; import com.gkatzioura.spring.entity.Greeting; import org.springframework.data.cassandra.repository.CassandraRepository; import org.springframework.data.cassandra.repository.Query; import org.springframework.data.repository.NoRepositoryBean; import java.util.UUID; public interface GreetRepository extends CassandraRepository<Greeting> { @Query("SELECT*FROM greetings WHERE user=?0 LIMIT ?1") Iterable<Greeting> findByUser(String user,Integer limit); @Query("SELECT*FROM greetings WHERE user=?0 AND id<?1 LIMIT ?2") Iterable<Greeting> findByUserFrom(String user,UUID from,Integer limit); }
Now we can implement the controller in order to access the data through http.
By post we can save a Greeting entity.
Through get we can fetch all the greetings received.
By specifying user we can use the Cassandra query to fetch greetings for a specific user.
package com.gkatzioura.spring.controller; import com.gkatzioura.spring.entity.Greeting; import com.gkatzioura.spring.repository.GreetRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import java.util.ArrayList; import java.util.Date; import java.util.List; @RestController public class GreetingController { @Autowired private GreetRepository greetRepository; @RequestMapping(value = "/greeting",method = RequestMethod.GET) @ResponseBody public List<Greeting> greeting() { List<Greeting> greetings = new ArrayList<>(); greetRepository.findAll().forEach(e->greetings.add(e)); return greetings; } @RequestMapping(value = "/greeting/{user}/",method = RequestMethod.GET) @ResponseBody public List<Greeting> greetingUserLimit(@PathVariable String user,Integer limit) { List<Greeting> greetings = new ArrayList<>(); greetRepository.findByUser(user,limit).forEach(e -> greetings.add(e)); return greetings; } @RequestMapping(value = "/greeting",method = RequestMethod.POST) @ResponseBody public String saveGreeting(@RequestBody Greeting greeting) { greeting.setCreationDate(new Date()); greetRepository.save(greeting); return "OK"; } }
Last but not least our Application class
package com.gkatzioura.spring; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
In order to run just run
gradle bootRun
Have you done any example on custom implementation of method declared in interface for Spring-Data-Cassandra. The JPA example of the same is http://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.misc.jpa-context