Merge pull request #386 from KevinGilmore/master

Spring Data Couchbase tutorial
This commit is contained in:
Eugen 2016-03-12 12:06:46 -06:00
commit d2d15f812e
19 changed files with 674 additions and 0 deletions

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src/main/resources"/>
<classpathentry kind="src" path="src/main/java"/>
<classpathentry kind="src" output="target/test-classes" path="src/test/java"/>
<classpathentry kind="src" path="src/test/resources"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER"/>
<classpathentry kind="output" path="target/classes"/>
</classpath>

View File

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>spring-data-couchbase-2</name>
<comment>This project is a simple template for a jar utility using Spring.
</comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.springframework.ide.eclipse.core.springbuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.m2e.core.maven2Builder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.springframework.ide.eclipse.core.springnature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.m2e.core.maven2Nature</nature>
</natures>
</projectDescription>

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<beansProjectDescription>
<version>1</version>
<pluginVersion><![CDATA[2.2.7.200909012107-CI-R3397-B453]]></pluginVersion>
<configSuffixes>
<configSuffix><![CDATA[xml]]></configSuffix>
</configSuffixes>
<enableImports><![CDATA[true]]></enableImports>
<configs>
</configs>
<configSets>
<configSet>
<name><![CDATA[test]]></name>
<allowBeanDefinitionOverriding>true</allowBeanDefinitionOverriding>
<incomplete>false</incomplete>
<configs>
</configs>
</configSet>
</configSets>
</beansProjectDescription>

View File

@ -0,0 +1,105 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.baeldung</groupId>
<artifactId>spring-data-couchbase-2</artifactId>
<version>0.1-SNAPSHOT</version>
<name>spring-data-couchbase-2</name>
<packaging>jar</packaging>
<dependencies>
<!-- Spring Context and Couchbase Peristence -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring-framework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring-framework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-couchbase</artifactId>
<version>${spring-data-couchbase.version}</version>
</dependency>
<!-- Hibernate JSR-303 Bean Validation -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>${hibernate-validator.version}</version>
</dependency>
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>${joda-time.version}</version>
</dependency>
<!-- Logging with SLF4J & LogBack -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${org.slf4j.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>${org.slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>log4j-over-slf4j</artifactId>
<version>${org.slf4j.version}</version>
</dependency>
<!-- Test-Scoped Dependencies -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring-framework.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
</plugins>
</build>
<properties>
<java.version>1.7</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring-framework.version>4.2.4.RELEASE</spring-framework.version>
<spring-data-couchbase.version>2.0.0.RELEASE</spring-data-couchbase.version>
<hibernate-validator.version>5.2.4.Final</hibernate-validator.version>
<joda-time.version>2.9.2</joda-time.version>
<logback.version>1.1.3</logback.version>
<org.slf4j.version>1.7.12</org.slf4j.version>
<junit.version>4.11</junit.version>
</properties>
</project>

View File

@ -0,0 +1,32 @@
package org.baeldung.spring.data.couchbase;
import java.util.Arrays;
import java.util.List;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.couchbase.config.AbstractCouchbaseConfiguration;
import org.springframework.data.couchbase.repository.config.EnableCouchbaseRepositories;
@Configuration
@EnableCouchbaseRepositories(basePackages={"org.baeldung.spring.data.couchbase"})
public class MyCouchbaseConfig extends AbstractCouchbaseConfiguration {
public static final List<String> NODE_LIST = Arrays.asList("localhost");
public static final String BUCKET_NAME = "baeldung";
public static final String BUCKET_PASSWORD = "";
@Override
protected List<String> getBootstrapHosts() {
return NODE_LIST;
}
@Override
protected String getBucketName() {
return BUCKET_NAME;
}
@Override
protected String getBucketPassword() {
return BUCKET_PASSWORD;
}
}

View File

@ -0,0 +1,87 @@
package org.baeldung.spring.data.couchbase.model;
import javax.validation.constraints.NotNull;
import org.joda.time.DateTime;
import org.springframework.data.annotation.Id;
import org.springframework.data.couchbase.core.mapping.Document;
import com.couchbase.client.java.repository.annotation.Field;
@Document
public class Person {
@Id
private String id;
@Field
@NotNull
private String firstName;
@Field
@NotNull
private String lastName;
@Field
@NotNull
private DateTime created;
@Field
private DateTime updated;
public Person(String id, String firstName, String lastName) {
this.id = id;
this.firstName = firstName;
this.lastName = lastName;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public DateTime getCreated() {
return created;
}
public void setCreated(DateTime created) {
this.created = created;
}
public DateTime getUpdated() {
return updated;
}
public void setUpdated(DateTime updated) {
this.updated = updated;
}
@Override
public int hashCode() {
int hash = 1;
if(id != null) {
hash = hash * 31 + id.hashCode();
}
if(firstName != null) {
hash = hash * 31 + firstName.hashCode();
}
if(lastName != null) {
hash = hash * 31 + lastName.hashCode();
}
return hash;
}
@Override
public boolean equals(Object obj) {
if((obj == null) || (obj.getClass() != this.getClass())) return false;
if(obj == this) return true;
Person other = (Person) obj;
return this.hashCode() == other.hashCode();
}
}

View File

@ -0,0 +1,11 @@
package org.baeldung.spring.data.couchbase.repos;
import java.util.List;
import org.baeldung.spring.data.couchbase.model.Person;
import org.springframework.data.repository.CrudRepository;
public interface PersonRepository extends CrudRepository<Person, String> {
List<Person> findByFirstName(String firstName);
List<Person> findByLastName(String lastName);
}

View File

@ -0,0 +1,58 @@
package org.baeldung.spring.data.couchbase.service;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.baeldung.spring.data.couchbase.model.Person;
import org.baeldung.spring.data.couchbase.repos.PersonRepository;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
@Service
@Qualifier("PersonRepositoryService")
public class PersonRepositoryService implements PersonService {
private PersonRepository repo;
@Autowired
public void setPersonRepository(PersonRepository repo) {
this.repo = repo;
}
public Person findOne(String id) {
return repo.findOne(id);
}
public List<Person> findAll() {
List<Person> people = new ArrayList<Person>();
Iterator<Person> it = repo.findAll().iterator();
while(it.hasNext()) {
people.add(it.next());
}
return people;
}
public List<Person> findByFirstName(String firstName) {
return repo.findByFirstName(firstName);
}
public List<Person> findByLastName(String lastName) {
return repo.findByLastName(lastName);
}
public void create(Person person) {
person.setCreated(DateTime.now());
repo.save(person);
}
public void update(Person person) {
person.setUpdated(DateTime.now());
repo.save(person);
}
public void delete(Person person) {
repo.delete(person);
}
}

View File

@ -0,0 +1,22 @@
package org.baeldung.spring.data.couchbase.service;
import java.util.List;
import org.baeldung.spring.data.couchbase.model.Person;
public interface PersonService {
Person findOne(String id);
List<Person> findAll();
List<Person> findByFirstName(String firstName);
List<Person> findByLastName(String lastName);
void create(Person person);
void update(Person person);
void delete(Person person);
}

View File

@ -0,0 +1,55 @@
package org.baeldung.spring.data.couchbase.service;
import java.util.List;
import org.baeldung.spring.data.couchbase.model.Person;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.couchbase.core.CouchbaseTemplate;
import org.springframework.stereotype.Service;
import com.couchbase.client.java.view.ViewQuery;
@Service
@Qualifier("PersonTemplateService")
public class PersonTemplateService implements PersonService {
private static final String DESIGN_DOC = "person";
private CouchbaseTemplate template;
@Autowired
public void setCouchbaseTemplate(CouchbaseTemplate template) {
this.template = template;
}
public Person findOne(String id) {
return template.findById(id, Person.class);
}
public List<Person> findAll() {
return template.findByView(ViewQuery.from(DESIGN_DOC, "all"), Person.class);
}
public List<Person> findByFirstName(String firstName) {
return template.findByView(ViewQuery.from(DESIGN_DOC, "byFirstName"), Person.class);
}
public List<Person> findByLastName(String lastName) {
return template.findByView(ViewQuery.from(DESIGN_DOC, "byLastName"), Person.class);
}
public void create(Person person) {
person.setCreated(DateTime.now());
template.insert(person);
}
public void update(Person person) {
person.setUpdated(DateTime.now());
template.update(person);
}
public void delete(Person person) {
template.remove(person);
}
}

View File

@ -0,0 +1,17 @@
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>web - %date [%thread] %-5level %logger{36} - %message%n
</pattern>
</encoder>
</appender>
<logger name="org.springframework" level="WARN" />
<logger name="org.baeldung" level="DEBUG" />
<root level="INFO">
<appender-ref ref="STDOUT" />
</root>
</configuration>

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<project name="Spring Batch: ${project.name}">
<bannerLeft>
<name>Spring Sample: ${project.name}</name>
<href>index.html</href>
</bannerLeft>
<skin>
<groupId>org.springframework.maven.skins</groupId>
<artifactId>maven-spring-skin</artifactId>
<version>1.0.5</version>
</skin>
<body>
<links>
<item name="${project.name}" href="index.html"/>
</links>
<menu ref="reports"/>
</body>
</project>

View File

@ -0,0 +1,13 @@
package org.baeldung.spring.data.couchbase;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { MyCouchbaseConfig.class, IntegrationTestConfig.class })
@TestExecutionListeners(listeners = { DependencyInjectionTestExecutionListener.class })
public abstract class IntegrationTest {
}

View File

@ -0,0 +1,9 @@
package org.baeldung.spring.data.couchbase;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan(basePackages = "org.baeldung.spring.data.couchbase")
public class IntegrationTestConfig {
}

View File

@ -0,0 +1,11 @@
package org.baeldung.spring.data.couchbase;
import org.springframework.data.couchbase.core.convert.MappingCouchbaseConverter;
public class TestCouchbaseConfig extends MyCouchbaseConfig {
@Override
public String typeKey() {
return MappingCouchbaseConverter.TYPEKEY_SYNCGATEWAY_COMPATIBLE;
}
}

View File

@ -0,0 +1,13 @@
package org.baeldung.spring.data.couchbase.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
public class PersonRepositoryServiceTest extends PersonServiceTest {
@Autowired
@Qualifier("PersonRepositoryService")
public void setPersonService(PersonService service) {
this.personService = service;
}
}

View File

@ -0,0 +1,126 @@
package org.baeldung.spring.data.couchbase.service;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.util.List;
import org.baeldung.spring.data.couchbase.IntegrationTest;
import org.baeldung.spring.data.couchbase.MyCouchbaseConfig;
import org.baeldung.spring.data.couchbase.model.Person;
import org.joda.time.DateTime;
import org.junit.BeforeClass;
import org.junit.Test;
import com.couchbase.client.java.Bucket;
import com.couchbase.client.java.Cluster;
import com.couchbase.client.java.CouchbaseCluster;
import com.couchbase.client.java.document.JsonDocument;
import com.couchbase.client.java.document.json.JsonObject;
public abstract class PersonServiceTest extends IntegrationTest {
static final String typeField = "_class";
static final String john = "John";
static final String smith = "Smith";
static final String johnSmithId = "person:" + john + ":" + smith;
static final Person johnSmith = new Person(johnSmithId, john, smith);
static final JsonObject jsonJohnSmith = JsonObject.empty()
.put(typeField, Person.class.getName())
.put("firstName", john)
.put("lastName", smith)
.put("created", DateTime.now().getMillis());
static final String foo = "Foo";
static final String bar = "Bar";
static final String foobarId = "person:" + foo + ":" + bar;
static final Person foobar = new Person(foobarId, foo, bar);
static final JsonObject jsonFooBar = JsonObject.empty()
.put(typeField, Person.class.getName())
.put("firstName", foo)
.put("lastName", bar)
.put("created", DateTime.now().getMillis());
PersonService personService;
@BeforeClass
public static void setupBeforeClass() {
Cluster cluster = CouchbaseCluster.create(MyCouchbaseConfig.NODE_LIST);
Bucket bucket = cluster.openBucket(MyCouchbaseConfig.BUCKET_NAME, MyCouchbaseConfig.BUCKET_PASSWORD);
bucket.upsert(JsonDocument.create(johnSmithId, jsonJohnSmith));
bucket.upsert(JsonDocument.create(foobarId, jsonFooBar));
bucket.close();
cluster.disconnect();
}
@Test
public void whenFindingPersonByJohnSmithId_thenReturnsJohnSmith() {
Person actualPerson = personService.findOne(johnSmithId);
assertNotNull(actualPerson);
assertNotNull(actualPerson.getCreated());
assertEquals(johnSmith, actualPerson);
}
@Test
public void whenFindingAllPersons_thenReturnsTwoOrMorePersonsIncludingJohnSmithAndFooBar() {
List<Person> resultList = personService.findAll();
assertNotNull(resultList);
assertFalse(resultList.isEmpty());
assertTrue(resultContains(resultList, johnSmith));
assertTrue(resultContains(resultList, foobar));
assertTrue(resultList.size() >= 2);
}
@Test
public void whenFindingByFirstNameJohn_thenReturnsOnlyPersonsNamedJohn() {
String expectedFirstName = john;
List<Person> resultList = personService.findByFirstName(expectedFirstName);
assertNotNull(resultList);
assertFalse(resultList.isEmpty());
assertTrue(allResultsContainExpectedFirstName(resultList, expectedFirstName));
}
@Test
public void whenFindingByLastNameSmith_thenReturnsOnlyPersonsNamedSmith() {
String expectedLastName = smith;
List<Person> resultList = personService.findByLastName(expectedLastName);
assertNotNull(resultList);
assertFalse(resultList.isEmpty());
assertTrue(allResultsContainExpectedLastName(resultList, expectedLastName));
}
private boolean resultContains(List<Person> resultList, Person person) {
boolean found = false;
for(Person p : resultList) {
if(p.equals(person)) {
found = true;
break;
}
}
return found;
}
private boolean allResultsContainExpectedFirstName(List<Person> resultList, String firstName) {
boolean found = false;
for(Person p : resultList) {
if(p.getFirstName().equals(firstName)) {
found = true;
break;
}
}
return found;
}
private boolean allResultsContainExpectedLastName(List<Person> resultList, String lastName) {
boolean found = false;
for(Person p : resultList) {
if(p.getLastName().equals(lastName)) {
found = true;
break;
}
}
return found;
}
}

View File

@ -0,0 +1,13 @@
package org.baeldung.spring.data.couchbase.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
public class PersonTemplateServiceTest extends PersonServiceTest {
@Autowired
@Qualifier("PersonTemplateService")
public void setPersonService(PersonService service) {
this.personService = service;
}
}

View File

@ -0,0 +1,17 @@
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>web - %date [%thread] %-5level %logger{36} - %message%n
</pattern>
</encoder>
</appender>
<logger name="org.springframework" level="WARN" />
<logger name="org.baeldung" level="DEBUG" />
<root level="INFO">
<appender-ref ref="STDOUT" />
</root>
</configuration>