diff --git a/complete/build.gradle b/complete/build.gradle index 8a10113..55875e4 100644 --- a/complete/build.gradle +++ b/complete/build.gradle @@ -1,4 +1,4 @@ -buildscript { +buildscript { //<1> repositories { mavenCentral() } @@ -9,7 +9,7 @@ buildscript { apply plugin: 'groovy' apply plugin: 'eclipse' -apply plugin: 'idea' +apply plugin: 'idea' //<2> apply plugin: 'org.springframework.boot' version = '0.0.1-SNAPSHOT' @@ -23,13 +23,21 @@ repositories { dependencies { compile('org.springframework.boot:spring-boot-starter-web') compile('org.codehaus.groovy:groovy') + + /** Add GORM */ //<3> compile("org.grails:gorm-hibernate5-spring-boot:6.1.5.RELEASE") compile "org.hibernate:hibernate-core:5.1.0.Final" compile "org.hibernate:hibernate-ehcache:5.1.0.Final" - runtime('com.h2database:h2:1.4.192') + + runtime('com.h2database:h2') + + /** Add additional dependencies so our database works properly with GORM at runtime*/ //<4> runtime "org.apache.tomcat:tomcat-jdbc:8.5.0" runtime "org.apache.tomcat.embed:tomcat-embed-logging-log4j:8.5.0" + testCompile('org.springframework.boot:spring-boot-starter-test') + + /** Add additional testing dependencies so we can use Spock */ //<5> testCompile 'org.spockframework:spock-core:1.1-groovy-2.4' testCompile 'org.spockframework:spock-spring:1.1-groovy-2.4' } \ No newline at end of file diff --git a/complete/gradle.properties b/complete/gradle.properties index f8f9c61..89b67fb 100644 --- a/complete/gradle.properties +++ b/complete/gradle.properties @@ -1,4 +1,4 @@ springBootVersion=1.5.4.RELEASE -grailsVersion=N/A - Spring Boot Version: 1.5.4.RELEASE gormVersion=6.1.5 gradleWrapperVersion=3.5.1 +grailsVersion=N/A - Spring Boot Version: 1.5.4.RELEASE diff --git a/complete/src/main/groovy/demo/GORMwithoutGrails/controller/MakeController.groovy b/complete/src/main/groovy/demo/GORMwithoutGrails/controller/MakeController.groovy index 5979ff6..ea05e8c 100644 --- a/complete/src/main/groovy/demo/GORMwithoutGrails/controller/MakeController.groovy +++ b/complete/src/main/groovy/demo/GORMwithoutGrails/controller/MakeController.groovy @@ -11,17 +11,8 @@ class MakeController { @Autowired MakeService makeService -// PostController(MakeService makeService) { -// this.makeService = makeService -// } - @RequestMapping("/") - String list(){ + String index(){ makeService.list() } - -// @RequestMapping("/{id}") -// public String get(@PathVariable(value = "id") int id){ -// makeService.get(id) -// } } diff --git a/complete/src/main/groovy/demo/GORMwithoutGrails/controller/ModelController.groovy b/complete/src/main/groovy/demo/GORMwithoutGrails/controller/ModelController.groovy index b867231..42bdcee 100644 --- a/complete/src/main/groovy/demo/GORMwithoutGrails/controller/ModelController.groovy +++ b/complete/src/main/groovy/demo/GORMwithoutGrails/controller/ModelController.groovy @@ -11,17 +11,8 @@ class ModelController { @Autowired ModelService modelService -// PostController(MakeService makeService) { -// this.makeService = makeService -// } - @RequestMapping("/") - String list(){ + String index(){ modelService.list() } - -// @RequestMapping("/{id}") -// public String get(@PathVariable(value = "id") int id){ -// makeService.get(id) -// } } diff --git a/complete/src/main/groovy/demo/GORMwithoutGrails/controller/VehicleController.groovy b/complete/src/main/groovy/demo/GORMwithoutGrails/controller/VehicleController.groovy index faa4039..883673d 100644 --- a/complete/src/main/groovy/demo/GORMwithoutGrails/controller/VehicleController.groovy +++ b/complete/src/main/groovy/demo/GORMwithoutGrails/controller/VehicleController.groovy @@ -11,17 +11,8 @@ class VehicleController { @Autowired VehicleService vehicleService -// PostController(MakeService makeService) { -// this.makeService = makeService -// } - @RequestMapping("/") - String list(){ + String index(){ vehicleService.list() } - -// @RequestMapping("/{id}") -// public String get(@PathVariable(value = "id") int id){ -// makeService.get(id) -// } } diff --git a/complete/src/main/groovy/demo/GORMwithoutGrails/domain/Driver.groovy b/complete/src/main/groovy/demo/GORMwithoutGrails/domain/Driver.groovy index adf8215..3abc297 100644 --- a/complete/src/main/groovy/demo/GORMwithoutGrails/domain/Driver.groovy +++ b/complete/src/main/groovy/demo/GORMwithoutGrails/domain/Driver.groovy @@ -5,10 +5,12 @@ import grails.gorm.annotation.Entity @Entity class Driver extends User { + /** Properties */ String name static hasMany = [ vehicles: Vehicle ] + /** Required in order to bootstrap data */ static mapping = { version false } diff --git a/complete/src/main/groovy/demo/GORMwithoutGrails/domain/Make.groovy b/complete/src/main/groovy/demo/GORMwithoutGrails/domain/Make.groovy index 6e98251..a1a965b 100644 --- a/complete/src/main/groovy/demo/GORMwithoutGrails/domain/Make.groovy +++ b/complete/src/main/groovy/demo/GORMwithoutGrails/domain/Make.groovy @@ -6,8 +6,10 @@ import org.grails.datastore.gorm.GormEntity @Entity class Make implements GormEntity { + /** Properties */ String name + /** Required in order to bootstrap data */ static mapping = { version false } diff --git a/complete/src/main/groovy/demo/GORMwithoutGrails/domain/Model.groovy b/complete/src/main/groovy/demo/GORMwithoutGrails/domain/Model.groovy index fa0a3a3..ea64646 100644 --- a/complete/src/main/groovy/demo/GORMwithoutGrails/domain/Model.groovy +++ b/complete/src/main/groovy/demo/GORMwithoutGrails/domain/Model.groovy @@ -6,8 +6,10 @@ import org.grails.datastore.gorm.GormEntity @Entity class Model implements GormEntity { + /** Properties */ String name + /** Required in order to bootstrap data */ static mapping = { version false } diff --git a/complete/src/main/groovy/demo/GORMwithoutGrails/domain/User.groovy b/complete/src/main/groovy/demo/GORMwithoutGrails/domain/User.groovy index d1c08b8..0b58f2f 100644 --- a/complete/src/main/groovy/demo/GORMwithoutGrails/domain/User.groovy +++ b/complete/src/main/groovy/demo/GORMwithoutGrails/domain/User.groovy @@ -10,6 +10,7 @@ class User implements Serializable, GormEntity { private static final long serialVersionUID = 1 + /** Properties */ String username String password boolean enabled = true diff --git a/complete/src/main/groovy/demo/GORMwithoutGrails/domain/Vehicle.groovy b/complete/src/main/groovy/demo/GORMwithoutGrails/domain/Vehicle.groovy index d96d437..27c099d 100644 --- a/complete/src/main/groovy/demo/GORMwithoutGrails/domain/Vehicle.groovy +++ b/complete/src/main/groovy/demo/GORMwithoutGrails/domain/Vehicle.groovy @@ -5,12 +5,14 @@ import org.grails.datastore.gorm.GormEntity @Entity class Vehicle implements GormEntity { - + /** Properties */ String name + /** Objects */ Make make Model model + /** Required in order to bootstrap data */ static mapping = { version false } diff --git a/complete/src/main/groovy/demo/GORMwithoutGrails/service/MakeServiceImpl.groovy b/complete/src/main/groovy/demo/GORMwithoutGrails/service/MakeServiceImpl.groovy index 5ab0605..874f1a8 100644 --- a/complete/src/main/groovy/demo/GORMwithoutGrails/service/MakeServiceImpl.groovy +++ b/complete/src/main/groovy/demo/GORMwithoutGrails/service/MakeServiceImpl.groovy @@ -8,6 +8,7 @@ import org.springframework.transaction.annotation.Transactional @Transactional class MakeServiceImpl implements MakeService { + @Transactional(readOnly = true) @Override List list() { Make.list() diff --git a/complete/src/main/groovy/demo/GORMwithoutGrails/service/ModelServiceImpl.groovy b/complete/src/main/groovy/demo/GORMwithoutGrails/service/ModelServiceImpl.groovy index 21e4aa3..853b62a 100644 --- a/complete/src/main/groovy/demo/GORMwithoutGrails/service/ModelServiceImpl.groovy +++ b/complete/src/main/groovy/demo/GORMwithoutGrails/service/ModelServiceImpl.groovy @@ -8,6 +8,7 @@ import org.springframework.transaction.annotation.Transactional @Transactional class ModelServiceImpl implements ModelService { + @Transactional(readOnly = true) @Override List list() { Model.list() diff --git a/complete/src/main/groovy/demo/GORMwithoutGrails/service/VehicleServiceImpl.groovy b/complete/src/main/groovy/demo/GORMwithoutGrails/service/VehicleServiceImpl.groovy index bdb2e12..3ecf832 100644 --- a/complete/src/main/groovy/demo/GORMwithoutGrails/service/VehicleServiceImpl.groovy +++ b/complete/src/main/groovy/demo/GORMwithoutGrails/service/VehicleServiceImpl.groovy @@ -8,6 +8,7 @@ import org.springframework.transaction.annotation.Transactional @Transactional class VehicleServiceImpl implements VehicleService { + @Transactional(readOnly = true) @Override List list() { Vehicle.list() diff --git a/complete/src/main/resources/application.properties b/complete/src/main/resources/application.properties index c9bd460..d1029e1 100644 --- a/complete/src/main/resources/application.properties +++ b/complete/src/main/resources/application.properties @@ -1,6 +1,7 @@ +#Enable h2 console access via browser spring.h2.console.enabled=true spring.h2.console.path=/console spring.datasource.platform=h2 -#spring.jpa.properties.hibernate.hbm2ddl=auto -#spring.jpa.hibernate.ddl-auto=create-drop + +# Turn on hibernate bootstrap data spring.jpa.properties.hibernate.hbm2ddl.auto=create-drop \ No newline at end of file diff --git a/src/main/docs/guide/aboutVaadin.adoc b/src/main/docs/guide/aboutVaadin.adoc deleted file mode 100644 index 75ac7d2..0000000 --- a/src/main/docs/guide/aboutVaadin.adoc +++ /dev/null @@ -1,14 +0,0 @@ -First, lets start off with a bit about what Vaadin is. Vaadin is a Frontend Framework designed -to be a full replacement UI. It gives you the ability to develop your UI server-side in Java -(or in our case Grails) as well as still allowing more traditional front end development. For -our application we will be using the server-side developed components which give use the biggest -performance gains. Vaadin is also fully complimentary to the Grails framework. Vaadin does -not need to use Grails controllers and can connect directly to our service layer. This -leaves our controllers still fully functional with all the Grails goodness you have come to expect -for things such as REST API calls. - -If you require additional information on Vaadin please check out the official documentation -https://vaadin.com/docs/-/part/framework/introduction/intro-overview.html[here]. Additionally -you may find a fair number of examples in an older version of Vaadin and -https://vaadin.com/framework/whatsnew[this] page gives a good explanation of how some of these -features have been updated in Vaadin 8. \ No newline at end of file diff --git a/src/main/docs/guide/addingToVaadin.adoc b/src/main/docs/guide/addingToVaadin.adoc deleted file mode 100644 index cf7ed75..0000000 --- a/src/main/docs/guide/addingToVaadin.adoc +++ /dev/null @@ -1,46 +0,0 @@ -Finally time to start adding Vaadin code to our application! - -Consider `grails-app/vaadin/vaadin/VaadinGrailsUI.groovy` to be your Vaadin -controller / dispatcher as it will help you understand the Vaadin flow. Our `init()` -method is the applications entry point to Vaadin itself, this is your top level view -essentially. From here you can setup navigation and other whole app view components. - -Our `VaadinGrailsUI.groovy` as it currently is, is great for a -single page web application but its not the most flexible if we want to add navigation -components or other pages later on. With this in mind we are going to make it a bit more -flexible using views. Using views is also beneficial in helping keep our Vaadin frontend -well organized. - -NOTE: For more information on views and navigation with Vaadin look -https://vaadin.github.io/spring-tutorial/#_views_and_navigation_with_vaadin_spring[here]. - -[source,groovy] -./grails-app/vaadin/vaadin/VaadinGrailsUI.groovy ----- -include::{sourceDir}/grails-app/vaadin/vaadin/VaadinGrailsUI.groovy[] ----- - -<1> We add the `@Title` annotation to give our window / tab a nice name -<2> Add `@SpringViewDisplay` so we can use views -<3> Along with and `implements ViewDisplay` to our class -<4> Next create an additional panel for our UI -<5> Initial entry point into our Vaadin View -<6> Helper method for building our header -<7> Additional function required for using views; dynamically controls setting our view components - -==== Whats really going on here ... -In simple terms, we switch from -HorizontalLayout to a VerticleLayout and then we `setContent` to our root content. -Following setting up our root we setup our view to give us some added flexibility for -expanding our application later. Once we have built `springViewDisplay` we add it to -our root context. It is important to note that where you do something in Vaadin is -important and not, all at the same time. - -- ie. `setContent(root)` is fine in its current location but could also be the last line -in the method, its position does not matter. -- ie. If we move `root.addComponent(this.buildHeader())` below where we add our panel, -our header is now on the bottom. - -TIP: `init()` can get quite large quite fast so it is best to break out UI components -into their own methods like `buildHeader()` to keep your files clear and concise. - diff --git a/src/main/docs/guide/addingView.adoc b/src/main/docs/guide/addingView.adoc deleted file mode 100644 index cdd1919..0000000 --- a/src/main/docs/guide/addingView.adoc +++ /dev/null @@ -1,74 +0,0 @@ -Now to add the view which is the bulk of our Vaadin code. Create a new file located in -`grails-app/vaadin/vaadin` called `GarageView.groovy`. - -Next make the necessary updates. - -[source,groovy] -./grails-app/vaadin/vaadin/GarageView.groovy ----- -include::{sourceDir}/grails-app/vaadin/vaadin/GarageView.groovy[] ----- - -<1> Add `@SpringView` annotation and set the name so that your view can be found. -<2> The view should extend the layout style that is desired -<3> Set the actual view name -<4> Tells the view `init()` to execute after the main UI `init()` - -WARNING: Grails auto dependency injection is not able to detect services in Vaadin, -thus we require using the more traditional Spring annotation @Autowired in order -to get dependency injection to work properly. - -Our view is trying to mimic the layout of much of modern web design by making use of "Rows" -in our case we have 3 rows, a header, data collection, and data display (grid). As we develop -a pattern start to emerge in Vaadin for views. - -- Create layout -- Create UI component -- Add UI component to layout -- Add layout to view - -When adding layout to the view you can just use `addComponent()` as it is aware that it is -adding to itself, unlike the top level UI where `root.addComponent()` is required. - -To keep a clean file continue building each UI component as its own private method. An -important note if you are familiar with groovy is we are able to return like the following... - -[source,groovy] ----- -Label someMethod() { - new Label("Im a label") // return -} ----- - -But in your Vaadin files this will fail claiming that you are returning an un-initialized variable. -Its easy enough to work around but requires some minor extra coding. ie. - -[source,groovy] -./grails-app/vaadin/vaadin/GarageView.groovy ----- -include::{sourceDir}/grails-app/vaadin/vaadin/GarageView.groovy[indent=0, lines="81..86"] ----- - -Once we have built our UI components now we need to be able to interact with them. To do this -we add listeners to our components making use of groovy closures to specify what would happen -when an event occurs. In our case we are `updateVehicle()` which we then `submit()` - -[source,groovy] -./grails-app/vaadin/vaadin/GarageView.groovy ----- -include::{sourceDir}/grails-app/vaadin/vaadin/GarageView.groovy[indent=0, lines="54..59"] ----- - -Using the listeners we build the vehicle object which is then submitted when the button is clicked. -The last line of our submit method reloads our view to refresh the newly updated data. - -[source,groovy] -./grails-app/vaadin/vaadin/GarageView.groovy ----- -include::{sourceDir}/grails-app/vaadin/vaadin/GarageView.groovy[indent=0, lines="159..162"] ----- - -Now that everything is in place return to <> to run your app. If everything is as -it should be you will see the following. - -image::runningGarageApp.png[] \ No newline at end of file diff --git a/src/main/docs/guide/configuringTheApp.adoc b/src/main/docs/guide/configuringTheApp.adoc index c5848c7..45c5a70 100644 --- a/src/main/docs/guide/configuringTheApp.adoc +++ b/src/main/docs/guide/configuringTheApp.adoc @@ -11,3 +11,28 @@ as your `build.gradle` file. image::gradleProperties.png[] +Now lets edit your new properties file and add the following to it. + +[source,groovy] +./gradle.properties +---- +include::{sourceDir}/gradle.properties[indent=0, lines="1..3"] +---- + +This sets us up for our next step of editing our build config and adding some necessary +dependencies to our project. + +[source,groovy] +./build.gradle +---- +include::{sourceDir}/build.gradle[indent=0, lines="1..43"] +---- + +<1> We have removed the ext block in favor of using one of our properties in the +`gradle.properties` file we just created. +<2> Apply an IDE specific plugin for IntelliJ since that is what we are using (Not Required). +<3> Add the required dependencies to add GORM to our project. +<4> Add additional tomcat dependencies, without these the database will not work correctly when running. +<5> Extra testing dependencies so we can use Spock with Spring Boot. + + diff --git a/src/main/docs/guide/creatingTestData.adoc b/src/main/docs/guide/creatingTestData.adoc index 7315438..fc21262 100644 --- a/src/main/docs/guide/creatingTestData.adoc +++ b/src/main/docs/guide/creatingTestData.adoc @@ -1,7 +1,18 @@ -Now that our domain is in place, lets preload some data to work with. +Now that all our app config is complete and we should be able to view our tables at +http://localhost:8080/console lets go ahead and bootstrap some data. Since we don't have a +built in bootstraping construct like we do in Grails we make use of a hibernate feature that +allows us to auto import a sql file. -[source,groovy] -./grails-app/init/vaadin/Bootstrap.groovy +First lets create a new file `import.sql` in `src/main/resources`. Once you have created +the sql file go ahead and edit it and add the following. + +[source,sql] +./src/main/resources/import.sql +---- +include::{sourceDir}/src/main/resources/import.sql[] ---- -include::{sourceDir}/grails-app/init/vaadin/Bootstrap.groovy[] ----- \ No newline at end of file + +Now as mentioned in the last section make sure that in +your `application.properties` file you have `spring.jpa.properties.hibernate.hbm2ddl.auto=create-drop`. +Without that line hibernate will not pickup on your `import.sql` and will not bootstrap +your data. \ No newline at end of file diff --git a/src/main/docs/guide/creatingTheControllers.adoc b/src/main/docs/guide/creatingTheControllers.adoc index 218e4d1..519d82e 100644 --- a/src/main/docs/guide/creatingTheControllers.adoc +++ b/src/main/docs/guide/creatingTheControllers.adoc @@ -1,41 +1,46 @@ -While completely unnecessary for Vaadin we want to demonstrate that there is no conflict -between Grails controllers and the Vaadin Framework. +Finally lets create some controllers so we can have basic UI access to our data. [source,bash] ---- - $ grails create-controller vaadin.GarageController + $ cd src/main/groovy/demo/GORMwithoutGrails/controller + $ touch MakeController + $ touch ModelController + $ touch VehicleController ---- -Now let’s edit our controller under grails-app/controllers/vaadin/. -We will import one of our services, update our index method, and add the following annotation. - -- @GrailsCompileStatic - increases application performance +Now let’s edit our controllers under src/main/groovy/demo/GORMwithoutGrails/controller. +We will import one of our services and update our index method. Our controllers will have +the following annotations + - @RestController - Denotes the controller as restful and that it can return data via url + - @RequestMapping("/someUrl") - Sets the base url mapping for the entire controller + - @Autowired - Allows use to use dependency injection to access our services + - @RequestMapping("/") [on the method] - Sets the url mapping for the method, beyond the base url [source,groovy] -./grails-app/controllers/vaadin/GarageController.groovy +./src/main/groovy/demo/GORMwithoutGrails/controller/MakeController.groovy ---- -include::{sourceDir}/grails-app/controllers/vaadin/GarageController.groovy[] +include::{sourceDir}/src/main/groovy/demo/GORMwithoutGrails/controller/MakeController.groovy[] ---- -<1> Declaring our service -<2> `index()` calls our service and renders the output as JSON - -At this point lets make sure everything is working properly and run <> -the application. - -Now we can exercise the API using cURL or another API tool. - -Make a GET request to /garage to get a list of Vehicles: - -[source,bash] +[source,groovy] +./src/main/groovy/demo/GORMwithoutGrails/controller/ModelController.groovy +---- +include::{sourceDir}/src/main/groovy/demo/GORMwithoutGrails/controller/ModelController.groovy[] ---- - $ curl -X "GET" "http://localhost:8080/garage" - [{"id":1,"driver":{"id":1},"make":{"id":1},"model":{"id":1},"name":"Pickup"}, - {"id":2,"driver":{"id":1},"make":{"id":1},"model":{"id":2},"name":"Economy"}, - {"id":3,"driver":{"id":2},"make":{"id":2},"model":{"id":3},"name":"Minivan"}] +[source,groovy] +./src/main/groovy/demo/GORMwithoutGrails/controller/VehicleController.groovy ---- +include::{sourceDir}/src/main/groovy/demo/GORMwithoutGrails/controller/VehicleController.groovy[] +---- + +Now that we have controllers with url mappings we have everything we need to test our +application live. Go back to <> and run the application. We can now access +the application via the browser and see our bootstrapped data returned + + - http://localhost:8080/makes/ + - http://localhost:8080/models/ + - http://localhost:8080/vehicles/ - no data bootstrapped for this one -If data comes back everything is setup and connected properly at this point and we have -verified that we have some test data. Now lets look at how to attach Vaadin to Grails \ No newline at end of file +image::urlData1.png[] \ No newline at end of file diff --git a/src/main/docs/guide/creatingTheDomain.adoc b/src/main/docs/guide/creatingTheDomain.adoc index ae4fb77..f7257c4 100644 --- a/src/main/docs/guide/creatingTheDomain.adoc +++ b/src/main/docs/guide/creatingTheDomain.adoc @@ -1,50 +1,80 @@ -Lets start by creating our domain model for the application. +Now with our packages in place lets go ahead and create our domain objects. + + - Driver.groovy + - Make.groovy + - Model.groovy + - User.groovy + - Vehicle.groovy + +NOTE: Our domain is based off of work in previous guides. + +Feel free to use your favorite IDE to create these or execute the following [source,bash] ---- - $ grails create-domain-class vaadin.Driver - $ grails create-domain-class vaadin.Make - $ grails create-domain-class vaadin.Model - $ grails create-domain-class vaadin.User - $ grails create-domain-class vaadin.Vehicle +$ cd complete/src/main/groovy/demo/GORMwithoutGrails/domain/ +$ touch Driver.groovy +$ touch Make.groovy +$ touch Model.groovy +$ touch User.groovy +$ touch Vehicle.groovy ---- -Now let’s edit our domain classes under grails-app/domain/vaadin/. -We’ll add some properties and the three following annotations. +Next lets do the same thing to setup our testing files. + +[source,bash] +---- +$ cd complete/src/test/groovy/demo/GORMwithoutGrails/domain/ +$ touch DriverSpec.groovy +$ touch MakeSpec.groovy +$ touch ModelSpec.groovy +$ touch VehicleSpec.groovy +---- -- @GrailsCompileStatic - increases application performance -- @EqualsAndHashCode - Auto generates equals and hashCode methods -- @ToString - Auto generates toString method +Now that all our class stubs are in place lets go ahead and edit them. [source,groovy] -./grails-app/domain/vaadin/Make.groovy +./src/main/groovy/demo/GORMwithoutGrails/domain/Make.groovy ---- -include::{sourceDir}/grails-app/domain/vaadin/Make.groovy[] +include::{sourceDir}/src/main/groovy/demo/GORMwithoutGrails/domain/Make.groovy[] ---- [source,groovy] -./grails-app/domain/vaadin/Model.groovy +./src/main/groovy/demo/GORMwithoutGrails/domain/Model.groovy ---- -include::{sourceDir}/grails-app/domain/vaadin/Model.groovy[] +include::{sourceDir}/src/main/groovy/demo/GORMwithoutGrails/domain/Model.groovy[] ---- [source,groovy] -./grails-app/domain/vaadin/Vehicle.groovy +./src/main/groovy/demo/GORMwithoutGrails/domain/Vehicle.groovy ---- -include::{sourceDir}/grails-app/domain/vaadin/Vehicle.groovy[] +include::{sourceDir}/src/main/groovy/demo/GORMwithoutGrails/domain/Vehicle.groovy[] ---- -There is a bit more to our Driver.groovy than meets the eye versus the first 3 classes. That's -because we are actually extending our User.groovy class with driver. This will grant us +There is a bit more to our `Driver.groovy` than meets the eye versus the first 3 classes. That's +because we are actually extending our `User.groovy class with driver. This will grant us some extra flexibility in the future as we grow our application. + +[source,groovy] +./src/main/groovy/demo/GORMwithoutGrails/domain/Driver.groovy +---- +include::{sourceDir}/src/main/groovy/demo/GORMwithoutGrails/domain/Driver.groovy[] +---- + [source,groovy] -./grails-app/domain/vaadin/Driver.groovy +./src/main/groovy/demo/GORMwithoutGrails/domain/User.groovy ---- -include::{sourceDir}/grails-app/domain/vaadin/Driver.groovy[] +include::{sourceDir}/src/main/groovy/demo/GORMwithoutGrails/domain/User.groovy[] ---- +Unlike standard GORM we annotate our domain classes with the `@Entity` annotation so that +when our application runs Spring Boot will pick up on our domain. Additionally we add the +`implements GormEntity<>` to our domain. This is not required but helps IDE's pick up the +domain correctly. Finally we add [source,groovy] -./grails-app/domain/vaadin/User.groovy ---- -include::{sourceDir}/grails-app/domain/vaadin/User.groovy[] ----- \ No newline at end of file +static mapping = { + version false +} +---- +TIP: Turning off the auto version is so we can bootstrap simple data without complications. \ No newline at end of file diff --git a/src/main/docs/guide/creatingTheServices.adoc b/src/main/docs/guide/creatingTheServices.adoc index 657b05c..b32c181 100644 --- a/src/main/docs/guide/creatingTheServices.adoc +++ b/src/main/docs/guide/creatingTheServices.adoc @@ -1,41 +1,57 @@ -Next lets create our service layer for our application so Grails and Vaadin can share -resources. +Next lets create our service layer for our application. [source,bash] ---- - $ grails create-service vaadin.DriverService - $ grails create-service vaadin.MakeService - $ grails create-service vaadin.ModelService - $ grails create-service vaadin.VehicleService + $ cd src/main/groovy/demo/GORMwithoutGrails/service + $ touch MakeService + $ touch MakeServiceImpl + $ touch ModelService + $ touch ModelServiceImpl + $ touch VehicleService + $ touch VehicleServiceImpl ---- -Now let’s edit our service classes under grails-app/services/vaadin/. -We’ll add a `listAll()` method to all of the classes. This method will have the following additional annotation. +Now let’s edit our service classes under src/main/groovy/demo/GORMwithoutGrails/service. +We’ll add a `list()` method to all of the classes. This method will have the following additional annotation. - @Transactional(readOnly = true) - good practice to have on methods that only return data [source,groovy] -./grails-app/services/vaadin/DriverService.groovy +./src/main/groovy/demo/GORMwithoutGrails/service/MakeService.groovy ---- -include::{sourceDir}/grails-app/services/vaadin/DriverService.groovy[] +include::{sourceDir}/src/main/groovy/demo/GORMwithoutGrails/service/MakeService.groovy[] ---- [source,groovy] -./grails-app/services/vaadin/MakeService.groovy +./src/main/groovy/demo/GORMwithoutGrails/service/MakeServiceImpl.groovy ---- -include::{sourceDir}/grails-app/services/vaadin/MakeService.groovy[] +include::{sourceDir}/src/main/groovy/demo/GORMwithoutGrails/service/MakeServiceImpl.groovy[] ---- [source,groovy] -./grails-app/services/vaadin/ModelService.groovy +./src/main/groovy/demo/GORMwithoutGrails/service/ModelService.groovy ---- -include::{sourceDir}/grails-app/services/vaadin/ModelService.groovy[] +include::{sourceDir}/src/main/groovy/demo/GORMwithoutGrails/service/ModelService.groovy[] ---- -Our VehicleService.groovy has an additional `save()` method so that we can add new data to our application. +[source,groovy] +./src/main/groovy/demo/GORMwithoutGrails/service/ModelServiceImpl.groovy +---- +include::{sourceDir}/src/main/groovy/demo/GORMwithoutGrails/service/ModelServiceImpl.groovy[] +---- [source,groovy] -./grails-app/services/vaadin/VehicleService.groovy +./src/main/groovy/demo/GORMwithoutGrails/service/VehicleService.groovy ---- -include::{sourceDir}/grails-app/services/vaadin/VehicleService.groovy[] ----- \ No newline at end of file +include::{sourceDir}/src/main/groovy/demo/GORMwithoutGrails/service/VehicleService.groovy[] +---- + +[source,groovy] +./src/main/groovy/demo/GORMwithoutGrails/service/VehicleServiceImpl.groovy +---- +include::{sourceDir}/src/main/groovy/demo/GORMwithoutGrails/service/VehicleServiceImpl.groovy[] +---- + +Additionally all our service classes make use of the `@Service('someName')` annotation. +This annotation tells Spring what our services are called so it can properly map our +dependency injection. \ No newline at end of file diff --git a/src/main/docs/guide/testingTheDomain.adoc b/src/main/docs/guide/testingTheDomain.adoc new file mode 100644 index 0000000..a8bc473 --- /dev/null +++ b/src/main/docs/guide/testingTheDomain.adoc @@ -0,0 +1,56 @@ +With our domain objects complete we will now create some basic tests to show that we can +successfully run a Spring Boot application with GORM. Lets go ahead and edit our Spec +files we created earlier and make use of those extra Spock dependencies that we included. + +[source,groovy] +./src/test/groovy/demo/GORMwithoutGrails/domain/MakeSpec.groovy +---- +include::{sourceDir}/src/test/groovy/demo/GORMwithoutGrails/domain/MakeSpec.groovy[] +---- + +[source,groovy] +./src/test/groovy/demo/GORMwithoutGrails/domain/ModelSpec.groovy +---- +include::{sourceDir}/src/test/groovy/demo/GORMwithoutGrails/domain/ModelSpec.groovy[] +---- + +[source,groovy] +./src/test/groovy/demo/GORMwithoutGrails/domain/DriverSpec.groovy +---- +include::{sourceDir}/src/test/groovy/demo/GORMwithoutGrails/domain/DriverSpec.groovy[] +---- + +[source,groovy] +./src/test/groovy/demo/GORMwithoutGrails/domain/VehicleSpec.groovy +---- +include::{sourceDir}/src/test/groovy/demo/GORMwithoutGrails/domain/VehicleSpec.groovy[] +---- + +All our tests are virtually identical sans we are testing different objects. +We start by `extends Specification` from Spock followed by declaring our `HibernateDatastore`. +There are a couple of new annotations + + - @Shared - denotes that the datastore will be shared among all tests in the Spec + - @AutoCleanup - ensuring that the datastore is disposed of properly + - @Rollback - ensures any data created during the test is removed + +The test themselves are standard Spock tests where we are creating a base instance of our +domain class and saving it. We then check that an object was in fact created. + +To execute your new tests and see that everything runs correctly, execute the following +from the top level project directory. + +[source,bash] +---- +$ ./gradlew test +---- + +When its complete you should see something like this in your terminal. + +image::testResults.png[] + +At this point we have shown that it is possible to get GORM working with Spring Boot, and +not only is it possible, its fairly painless to harness this new power. But, we don't want to +stop here as we want to offer the most complete view possible when learning how to connect +new technology. Next we will look at the remaining configuration to getting a full app up +and running. \ No newline at end of file diff --git a/src/main/docs/guide/toc.yml b/src/main/docs/guide/toc.yml index f629937..49c1612 100644 --- a/src/main/docs/guide/toc.yml +++ b/src/main/docs/guide/toc.yml @@ -6,12 +6,15 @@ runningTheApp: title: Running the Application configuringTheApp: title: Configuring your Build -#writingTheApp: -# title: Writing the Application -# creatingTheDomain: Creating the domain -# creatingTestData: Bootstrap Data -# creatingTheServices: Creating the service layer -# creatingTheControllers: Creating a controller +writingTheAppPartOne: + title: Writing the Application Part 1 + creatingTheDomain: Creating the domain + testingTheDomain: Testing our domain +writingTheAppPartTwo: + title: Writing the Application Part 2 + creatingTestData: Bootstrap Data + creatingTheServices: Creating the service layer + creatingTheControllers: Creating a controller # addingToVaadin: Vaadin # addingView: Adding your view #themingTheApp: diff --git a/src/main/docs/guide/writingTheApp.adoc b/src/main/docs/guide/writingTheApp.adoc deleted file mode 100644 index 5cf20de..0000000 --- a/src/main/docs/guide/writingTheApp.adoc +++ /dev/null @@ -1,6 +0,0 @@ -For this guide, you can either create the starting project yourself, -or use the `initial` project included in the guide's repo to get started. - -NOTE: The `initial` project is based on the concept of the completed project from the -http://guides.grails.org/building-a-react-app/guide/index.html[Building a React App Guide]. -Please refer to that guide for an alternate version of this app. diff --git a/src/main/docs/guide/writingTheAppPartOne.adoc b/src/main/docs/guide/writingTheAppPartOne.adoc new file mode 100644 index 0000000..199c471 --- /dev/null +++ b/src/main/docs/guide/writingTheAppPartOne.adoc @@ -0,0 +1,19 @@ +Since this is a Spring Boot application and not Grails we start out with a much simpler base +directory structure. + +image::baseLayoutWithPackage.png[] + +Lets start off by adding a few more packages to keep our application organized. Create the following ... + + - config + - controller + - domain + - service + +image::subPackages.png[] + +As well as add the following sub package to test ... + + - domain + +image::testSubPackage.png[] \ No newline at end of file diff --git a/src/main/docs/guide/writingTheAppPartTwo.adoc b/src/main/docs/guide/writingTheAppPartTwo.adoc new file mode 100644 index 0000000..0787ea6 --- /dev/null +++ b/src/main/docs/guide/writingTheAppPartTwo.adoc @@ -0,0 +1,39 @@ +Now that we have a fully tested GORM implementation in our Spring Boot application +lets expand that to a full application and see how to finish connection everything up. + +==== Additional App Config +Beyond our simple domain tests getting everything configured properly takes a few extra changes. +If you started with our `initial` app or if you created your own, you will find that you have +a `src/main/resources/application.properties`. Lets go ahead and add some options in there. + +IMPORTANT: There is a lot going on in these two files so + pay close attention as these are the connecting glue. + +[source,groovy] +./src/main/resources/application.properties +---- +include::{sourceDir}/src/main/resources/application.properties[] +---- + +The last line is required in order to make use of hibernates auto importing feature to +bootstrap data. Without this line being set to `create` or `create-drop` it will not +bootstrap our data (more on this next). + +The first 3 lines enable h2 console access in the browser so you can navigate to +http://localhost:8080/console[] and view your database. + +image::consoleLogin.png[] +image::loggedInConsole.png[] + +Next create an additional `application.yml` in `src/main/resources`. After creation go +ahead and edit the file and add the following. + +[source,groovy] +./src/main/resources/application.yml +---- +include::{sourceDir}/src/main/resources/application.yml[] +---- + +The `dataSource` block is what ties your database and GORM together. Without this your +domain tests will pass but if you run the application and go to view your database at +http://localhost:8080/console[] it will always be empty and no tables will be generated. \ No newline at end of file diff --git a/src/main/resources/img/baseLayout.png b/src/main/resources/img/baseLayout.png new file mode 100644 index 0000000..e98c41a Binary files /dev/null and b/src/main/resources/img/baseLayout.png differ diff --git a/src/main/resources/img/baseLayoutWithPackage.png b/src/main/resources/img/baseLayoutWithPackage.png new file mode 100644 index 0000000..b1811c5 Binary files /dev/null and b/src/main/resources/img/baseLayoutWithPackage.png differ diff --git a/src/main/resources/img/consoleLogin.png b/src/main/resources/img/consoleLogin.png new file mode 100644 index 0000000..39f6eba Binary files /dev/null and b/src/main/resources/img/consoleLogin.png differ diff --git a/src/main/resources/img/gradleProperties.png b/src/main/resources/img/gradleProperties.png new file mode 100644 index 0000000..fae9e3c Binary files /dev/null and b/src/main/resources/img/gradleProperties.png differ diff --git a/src/main/resources/img/loggedInConsole.png b/src/main/resources/img/loggedInConsole.png new file mode 100644 index 0000000..d1155a6 Binary files /dev/null and b/src/main/resources/img/loggedInConsole.png differ diff --git a/src/main/resources/img/subPackages.png b/src/main/resources/img/subPackages.png new file mode 100644 index 0000000..c67a01f Binary files /dev/null and b/src/main/resources/img/subPackages.png differ diff --git a/src/main/resources/img/testResults.png b/src/main/resources/img/testResults.png new file mode 100644 index 0000000..e6c8ce3 Binary files /dev/null and b/src/main/resources/img/testResults.png differ diff --git a/src/main/resources/img/testSubPackage.png b/src/main/resources/img/testSubPackage.png new file mode 100644 index 0000000..acc3417 Binary files /dev/null and b/src/main/resources/img/testSubPackage.png differ diff --git a/src/main/resources/img/urlData1.png b/src/main/resources/img/urlData1.png new file mode 100644 index 0000000..89cc2ec Binary files /dev/null and b/src/main/resources/img/urlData1.png differ diff --git a/test.properties b/test.properties deleted file mode 100644 index e69de29..0000000