Skip to content

Commit 29a97f6

Browse files
author
Paul Warren
committed
Initial commit
0 parents  commit 29a97f6

File tree

219 files changed

+7528
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

219 files changed

+7528
-0
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
.DS_Store

.project

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<projectDescription>
3+
<name>spring-content</name>
4+
<comment></comment>
5+
<projects>
6+
</projects>
7+
<buildSpec>
8+
<buildCommand>
9+
<name>org.eclipse.m2e.core.maven2Builder</name>
10+
<arguments>
11+
</arguments>
12+
</buildCommand>
13+
</buildSpec>
14+
<natures>
15+
<nature>org.eclipse.m2e.core.maven2Nature</nature>
16+
</natures>
17+
</projectDescription>

.settings/org.eclipse.m2e.core.prefs

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
activeProfiles=
2+
eclipse.preferences.version=1
3+
resolveWorkspaceProjects=true
4+
version=1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
eclipse.preferences.version=1
2+
org.jboss.ide.eclipse.as.core.singledeployable.deployableList=

.travis.yml

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
language: java
2+
3+
jdk:
4+
- oraclejdk8
5+
6+
script:
7+
- mvn test

README.md

+320
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,320 @@
1+
![Alt text](https://travis-ci.org/paulcwarren/spring-content.svg?branch=master)
2+
3+
# Getting Started With Spring Content
4+
5+
This guide walks you through building an application that uses Spring Content to store and retrieve content in a database.
6+
7+
## What you'll build
8+
9+
You'll build an application that stores Document POJOs in a Mongo database.
10+
11+
## What you'll need
12+
13+
- About 15 minutes
14+
- A favorite text editor or IDE
15+
- JDK 1.8 or later
16+
- Maven 3.0+
17+
- MongoDB 3.0.7
18+
- You can also import the code from this guide as well as view the web page directly into Spring Tool Suite (STS) and work your way through it from there.
19+
20+
## How to complete this guide
21+
22+
Like most Spring Getting Started guides, you can start form scratch and complete each step, or you can bypass basic setup steps that are already familiar to you. Either way, you end up with working code.
23+
24+
To start from scratch, move on to Build with Maven.
25+
26+
To skip the basics, do the following:
27+
28+
- Download and unzip the source repository for this guide, or clone it using Git: `git clone https://[email protected]/paulcwarren/spring-content.git`
29+
- cd into spring-content/spring-gs-accessing-data-mongo/initial
30+
- Jump ahead to `Define a simple entity`.
31+
When you’re finished, you can check your results against the code in `spring-content/spring-gs-accessing-content-mongo/complete`.
32+
33+
## Build with Maven
34+
35+
First you set up a basic build script. You can use any build system you like when building apps with Spring, but the code you need to work with [Maven](https://maven.apache.org/) is included here. If you’re not familiar with Maven, refer to [Building Java Projects with Maven](http://spring.io/guides/gs/maven).
36+
37+
### Create a directory structure
38+
39+
In a project directory of your choosing, create the following subdirectory structure; for example, with `mkdir -p src/main/java/hello` on *nix systems:
40+
41+
```
42+
∟ src
43+
∟ main
44+
∟ java
45+
∟ docs
46+
```
47+
48+
`pom.xml`
49+
50+
51+
<?xml version="1.0" encoding="UTF-8"?>
52+
<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">
53+
<modelVersion>4.0.0</modelVersion>
54+
55+
<groupId>org.springframework.content.gs</groupId>
56+
<artifactId>gs-accessing-content-jpa</artifactId>
57+
<version>0.1.0</version>
58+
59+
<parent>
60+
<groupId>org.springframework.boot</groupId>
61+
<artifactId>spring-boot-starter-parent</artifactId>
62+
<version>1.2.7.RELEASE</version>
63+
</parent>
64+
65+
<dependencies>
66+
<dependency>
67+
<groupId>org.springframework.boot</groupId>
68+
<artifactId>spring-boot-starter-data-mongodb</artifactId>
69+
</dependency>
70+
<dependency>
71+
<groupId>org.springframework.boot</groupId>
72+
<artifactId>spring-boot-starter-data-rest</artifactId>
73+
</dependency>
74+
<dependency>
75+
<groupId>org.springframework.boot</groupId>
76+
<artifactId>spring-boot-starter-web</artifactId>
77+
</dependency>
78+
<dependency>
79+
<groupId>org.springframework.boot</groupId>
80+
<artifactId>spring-boot-starter-content-mongo</artifactId>
81+
<version>1.2.1.RELEASE</version>
82+
</dependency>
83+
<dependency>
84+
<groupId>org.springframework.boot</groupId>
85+
<artifactId>spring-boot-starter-content-rest</artifactId>
86+
<version>1.2.1.RELEASE</version>
87+
</dependency>
88+
</dependencies>
89+
90+
<properties>
91+
<java.version>1.8</java.version>
92+
</properties>
93+
94+
<build>
95+
<plugins>
96+
<plugin>
97+
<groupId>org.springframework.boot</groupId>
98+
<artifactId>spring-boot-maven-plugin</artifactId>
99+
</plugin>
100+
</plugins>
101+
</build>
102+
</project>
103+
104+
The [Spring Boot Maven plugin](https://github.com/spring-projects/spring-boot/tree/master/spring-boot-tools/spring-boot-maven-plugin) provides many convenient features:
105+
106+
- It collects all the jars on the classpath and builds a single, runnable "über-jar", which makes it more convenient to execute and transport your service.
107+
- It searches for the `public static void main()` method to flag as a runnable class.
108+
- It provides a built-in dependency resolver that sets the version number to match [Spring Boot dependencies](https://github.com/spring-projects/spring-boot/blob/master/spring-boot-dependencies/pom.xml). You can override any version you wish, but it will default to Boot’s chosen set of versions.
109+
110+
### Define a simple entity with content
111+
112+
In this example, you store Document objects, annotated as a Mongo entity with Content.
113+
114+
`src/main/java/docs/SpringDocument.java`
115+
116+
package docs;
117+
118+
import org.springframework.content.annotations.Content;
119+
import org.springframework.content.annotations.ContentId;
120+
import org.springframework.content.annotations.ContentLength;
121+
import org.springframework.data.annotation.Id;
122+
import org.springframework.data.mongodb.core.mapping.Document;
123+
124+
@Document
125+
public class SpringDocument {
126+
127+
@Id
128+
private String id;
129+
130+
private String title;
131+
private List<String> keywords;
132+
133+
@Content
134+
private ContentMetadata content;
135+
136+
... getters and setters ...
137+
138+
public static class ContentMetadata {
139+
140+
public ContentMetadata() {}
141+
142+
@ContentId
143+
private String id;
144+
145+
@ContentLength
146+
private long length;
147+
148+
@MimeType
149+
private String mimeType;
150+
151+
.. getters and setters ...
152+
153+
}
154+
}
155+
156+
157+
158+
Here you have a standard Spring Data entity bean class `SpringDocument` class with several attributes, `id`, `title`, `keywords`.
159+
160+
>**Note:** For more information on Spring Data annotations see the relevant [Spring Data](http://docs.spring.io/spring-data/commons/docs/current/reference/html/) documentation.
161+
162+
In addition this entity bean also has the `content` attribute annotated with the Spring Content annotation `@Content`, indicating that instances of `ContentMetadata` are content entities. These entities will be mapped to Mongo's GridFS.
163+
164+
`ContentMetadata` has three attributes, `id`, `length` and `mimeType`. The `id` attribute is annotated with `@ContentId` so that Spring Content will recognize it as the content entity's ID.
165+
166+
The `length` attribute is annotated with `@ContentLength` so that Spring Content will recognize it as the content entity's content length.
167+
168+
Finally, the `mimeType` attribute is annotated with `@MimeType` so that Spring Content REST will recognize it as the content entity's mime type.
169+
170+
All of these annotated attributes will be managed by Spring Content.
171+
172+
### Create a Spring Data Repository
173+
174+
So that we can perform simple CRUD operations, over a hypermedia-based API, create a simple repository for the `SpringDocument` class annotated with as a `@RepositoryRestResource`.
175+
176+
`src/main/java/docs/SpringDocumentRepository.java`
177+
178+
package docs;
179+
180+
import org.springframework.data.repository.CrudRepository;
181+
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
182+
183+
@RepositoryRestResource(path="/docs", collectionResourceRel="docs")
184+
public interface SpringDocumentRepository extends CrudRepository<SpringDocument, String> {
185+
186+
}
187+
188+
### Add a Spring Content ContentStore
189+
190+
Just like Spring Data focuses on storing data in a database, Spring Content focuses on storing content in various stores, in this case in Mongo GridFS store. It's most compelling feature is the ability to create content store implementations automatically, at runtime, from a content store interface.
191+
192+
To see how this works, create a content store interface that works with SpringDocument's `ContentMetadata` entity:
193+
194+
`src/main/java/docs/ContentMetadataContentStore.java`
195+
196+
package docs;
197+
198+
import org.springframework.content.common.repository.ContentStore;
199+
200+
import docs.SpringDocument.ContentMetadata;
201+
import internal.org.springframework.content.rest.annotations.ContentStoreRestResource;
202+
203+
@ContentStoreRestResource
204+
public interface ContentMetadataContentStore extends ContentStore<ContentMetadata, String> {
205+
}
206+
207+
`ContentMetadataContentStore` extends the `ContentStore` interface. The type of the content entity and the type of the content entity's ID, `ContentMetadata` and `String` respectively, are specified in the generic parameters on `ContentStore`. By extending `ContentStore`, `ContentMetadataContentStore` inherits several methods for working with persisted content.
208+
209+
In a java application, you would expect to write an implementation for the `ContentMetadaDataContentStore` class. But what makes Spring Content so powerful is that you don't have to do this. Spring Content will create an implementation on the fly when you run the application.
210+
211+
Likewise, in a web-based application you would also expect to implement HTTP handlers allowing you to PUT and GET content over HTTP. With Spring Content REST these are also implemented for you when you add the `ContentStoreRestResource` annotation to your content store.
212+
213+
Let's wire this up and see what it looks like!
214+
215+
### Create an application class
216+
217+
Spring Content integrates seamlessly into Spring Boot, therefore you create the standard Application class.
218+
219+
`src/main/java/docs/Application.java`
220+
221+
package docs;
222+
223+
import org.springframework.boot.SpringApplication;
224+
import org.springframework.boot.autoconfigure.SpringBootApplication;
225+
226+
@SpringBootApplication
227+
public class ContentApplication {
228+
229+
public static void main(String[] args) {
230+
SpringApplication.run(ContentApplication.class);
231+
}
232+
}
233+
234+
### Build an executable JAR
235+
236+
You can build a single executable JAR file that contains all the necessary dependencies, classes and resources. This makes it easy to ship, version and deploy.
237+
238+
If you are using Maven, you can run the application using `mvn spring-boot:run`. Or you can build the JAR file with `mvn clean package` and run the JAR by typing:
239+
240+
java -jar target/spring-gs-accessing-content-mongo-0.1.0.jar
241+
242+
> **Note:** The procedure above will create a runnable JAR. You can also opt to [build a classic WAR file](http://spring.io/guides/gs/convert-jar-to-war/) instead.
243+
244+
### Handle Content
245+
246+
First create an instance of a `SpringDocument`. Using curl, issue the following command:
247+
248+
curl -XPOST -H 'Content-Type:application/json' -d '{"title":"test doc","keywords":["one","two"]}' http://localhost:8080/docs
249+
250+
Check that this `SpringDocument` was created by issing the following command:
251+
252+
curl http://localhost:8080/docs
253+
254+
and this should respond with:
255+
256+
{
257+
"_embedded" : {
258+
"docs" : [ {
259+
"title" : "test doc",
260+
"keywords" : [ "one", "two" ],
261+
"content" : null,
262+
"_links" : {
263+
"self" : {
264+
"href" : "http://localhost:8080/docs/5636224fa82677aa529322b6"
265+
}
266+
}
267+
} ]
268+
}
269+
}
270+
271+
which shows us there is one document that may be fetched with a `GET` request to `http://localhost:8080/docs/5636224fa82677aa529322b6`
272+
273+
> **Note:** you're IDs will obviously be different, adjust as appropriate
274+
275+
Notice, that the `content` attribute is null. That is because we haven't added any content yet so let's add some, issue the following command:
276+
277+
curl -XPOST -F file=@/tmp/test.txt http://localhost:8080/docs/5636224fa82677aa529322b6/content
278+
279+
> **Note:** In our example /tmp/test.txt contains the simple plain text `Hello Spring Content World!` but this could be any binary content
280+
281+
Now, re-query the original `SpringDocument` again:-
282+
283+
curl http://localhost:8080/docs/5636224fa82677aa529322b6
284+
285+
This time it should respond with:
286+
287+
{
288+
"title" : "test doc",
289+
"keywords" : [ "one", "two" ],
290+
"content" : {
291+
"length" : 28,
292+
"mimeType" : "text/plain"
293+
},
294+
"_links" : {
295+
"self" : {
296+
"href" : "http://localhost:8080/docs/5636224fa82677aa529322b6"
297+
},
298+
"content" : {
299+
"href" : "http://localhost:8080/docs/5636224fa82677aa529322b6/content/64bf2339-c8e5-44f1-b960-aeb9ea8e4a7e"
300+
}
301+
}
302+
}
303+
304+
We see the `content` attribute now contains useful information about the document's content, namely `length` and `mimeType`. These were set automatically by Spring Content.
305+
306+
Similarly, `_links` also now contains a linkrel for `content` allowing clients to navigate from this `SpringDocument` resource to it's content. Let's do that now, issue the command:
307+
308+
http://localhost:8080/docs/5636224fa82677aa529322b6/content/64bf2339-c8e5-44f1-b960-aeb9ea8e4a7e
309+
310+
which responds:
311+
312+
Hello Spring Content World!
313+
314+
### Summary
315+
316+
Congratulations! You've written a simple application that uses Spring Content and Spring Content REST to save objects with content to a database and to fetch them again using a hypermedia-based REST API - all without writing a single concrete implementation class.
317+
318+
### Want to know more
319+
320+
Read more about the project including it's anticipated backlog [here](spring-content.md).

0 commit comments

Comments
 (0)