Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
Mum, I want to be a Groovy
full-stack developer
@ilopmarIván López
Hello!
I am Iván López
@ilopmar
http://greachconf.com@madridgug
Thank you very much!
Q&A
Just kidding!
Full-stack developer
Backend language
Javascript
HTML
Mobile App
Polaromatic
1.
Demo
2.
Application flow
3.
Backend
Polaromatic
▷ Spring Boot
▷ Core App
▷ Spring MVC
▷ Spring Integration Flow
<file:inbound-channel-adapter directory="work" channel="incommingFilesChannel"/>
<chain input-channel="incommingFilesChann...
<file:inbound-channel-adapter directory="work" channel="incommingFilesChannel"/>
<chain input-channel="incommingFilesChann...
<file:inbound-channel-adapter directory="work" channel="incommingFilesChannel"/>
<chain input-channel="incommingFilesChann...
class ImageConverterService {
private static final String DEFAULT_CAPTION = "#LearningSpringBoot with Polaromaticn"
Random...
FlickrDownloader
▷ Spring Boot CLI
▷ Download Flickr Interesting pictures
▷ Jsoup, GPars
▷ 55 lines of Groovy code
(micros...
@Slf4j
@EnableScheduling
@Grab('org.jsoup:jsoup:1.8.1')
@Grab('commons-io:commons-io:2.4')
@Grab('org.codehaus.gpars:gpars...
@Slf4j
@EnableScheduling
@Grab('org.jsoup:jsoup:1.8.1')
@Grab('commons-io:commons-io:2.4')
@Grab('org.codehaus.gpars:gpars...
FlickrDownloader
@Slf4j
@EnableScheduling
@Grab('org.jsoup:jsoup:1.8.1')
@Grab('commons-io:commons-io:2.4')
@Grab('org.cod...
FlickrDownloader
@Slf4j
@EnableScheduling
@Grab('org.jsoup:jsoup:1.8.1')
@Grab('commons-io:commons-io:2.4')
@Grab('org.cod...
FlickrDownloader
@Slf4j
@EnableScheduling
@Grab('org.jsoup:jsoup:1.8.1')
@Grab('commons-io:commons-io:2.4')
@Grab('org.cod...
FlickrDownloader
2015-04-17 21:56:11.139 INFO 16447 --- [111617-worker-1] polaromatic.FlickrDownloader
2015-04-17 21:56:11...
FlickrDownloader
2015-04-17 21:56:11.139 INFO 16447 --- [111617-worker-1] polaromatic.FlickrDownloader
2015-04-17 21:56:11...
4.
Frontend
Fronted
▷ MarkupTemplateEngine (HTML)
▷ Websockets
▷ Grooscript
HTML
yieldUnescaped '<!DOCTYPE html>'
html {
head {
title "Polaromatic"
link(rel: 'stylesheet', href: '/css/app.css')
link...
HTML
body {
...
div(id: 'header') {
div(class: 'center') {
a(href: 'https://github.com/lmivan/contest', target: 'blank') {...
Websockets
@Configuration
@EnableWebSocketMessageBroker
class WebsocketConfig extends AbstractWebSocketMessageBrokerConfig...
Websockets
class BrowserPushService {
@Autowired
SimpMessagingTemplate template
Photo pushToBrowser(Photo photo) {
log.deb...
Websockets
class BrowserPushService {
@Autowired
SimpMessagingTemplate template
Photo pushToBrowser(Photo photo) {
log.deb...
class Connection {
@GsNative
def initOn(source, path) {/*
var socket = new SockJS(path);
return [Handlebars.compile(source...
5.
Android
Android App
▷ Disclaimer: I'm not an Android developer
▷ Lazybones template (@marioggar)
▷ Traits, @CompileStatic
▷ SwissK...
Android
trait Toastable {
@OnUIThread
void showToastMessage(String message) {
Toast toast = Toast.makeText(applicationCont...
Android
trait Toastable {
@OnUIThread
void showToastMessage(String message) {
Toast toast = Toast.makeText(applicationCont...
6.
Tests
Tests
▷ Spock Framework
▷ 0.7 for more than 3 years
▷ Now 1.0
▷ JUnit compatible
Spock
class BrowserPushServiceSpec extends Specification {
void 'should push a converted photo to the browser'() {
given: ...
7.
Build tool
Build tool
▷ Gradle
▷ Multiproject to build backend, documentation
and android
Gradle
subprojects {
buildscript {
repositories {
jcenter()
}
}
repositories {
jcenter()
}
}
task wrapper(type: Wrapper) {...
8.
Documentation
Documentation
▷ Asciidoctor (FTW!)
▷ Gradle plugin
▷ Backends: html, epub, pdf,...
Asciidoctor
buildscript {
dependencies {
classpath 'org.asciidoctor:asciidoctor-gradle-plugin:1.5.2'
}
}
apply plugin: 'or...
Asciidoctor
[source,xml,indent=0]
.src/main/resources/resources.xml
----
include::{polaromaticBackResources}/resources.xml...
Asciidoctor
[source,xml,indent=0]
.src/main/resources/resources.xml
----
include::{polaromaticBackResources}/resources.xml...
Asciidoctor
9.
Summary
“
Groovy, groovy everywhere...
Thanks!
Any questions?
@ilopmar
lopez.ivan@gmail.com
https://github.com/lmivan
Iván López
http://kcy.me/22key
Spring I/O 2015 - Mum, I want to be a Groovy full-stack developer
Spring I/O 2015 - Mum, I want to be a Groovy full-stack developer
Spring I/O 2015 - Mum, I want to be a Groovy full-stack developer
Spring I/O 2015 - Mum, I want to be a Groovy full-stack developer
Spring I/O 2015 - Mum, I want to be a Groovy full-stack developer
Spring I/O 2015 - Mum, I want to be a Groovy full-stack developer
Spring I/O 2015 - Mum, I want to be a Groovy full-stack developer
Spring I/O 2015 - Mum, I want to be a Groovy full-stack developer
Spring I/O 2015 - Mum, I want to be a Groovy full-stack developer
Spring I/O 2015 - Mum, I want to be a Groovy full-stack developer
Upcoming SlideShare
Loading in …5
×

of

Spring I/O 2015 - Mum, I want to be a Groovy full-stack developer Slide 1 Spring I/O 2015 - Mum, I want to be a Groovy full-stack developer Slide 2 Spring I/O 2015 - Mum, I want to be a Groovy full-stack developer Slide 3 Spring I/O 2015 - Mum, I want to be a Groovy full-stack developer Slide 4 Spring I/O 2015 - Mum, I want to be a Groovy full-stack developer Slide 5 Spring I/O 2015 - Mum, I want to be a Groovy full-stack developer Slide 6 Spring I/O 2015 - Mum, I want to be a Groovy full-stack developer Slide 7 Spring I/O 2015 - Mum, I want to be a Groovy full-stack developer Slide 8 Spring I/O 2015 - Mum, I want to be a Groovy full-stack developer Slide 9 Spring I/O 2015 - Mum, I want to be a Groovy full-stack developer Slide 10 Spring I/O 2015 - Mum, I want to be a Groovy full-stack developer Slide 11 Spring I/O 2015 - Mum, I want to be a Groovy full-stack developer Slide 12 Spring I/O 2015 - Mum, I want to be a Groovy full-stack developer Slide 13 Spring I/O 2015 - Mum, I want to be a Groovy full-stack developer Slide 14 Spring I/O 2015 - Mum, I want to be a Groovy full-stack developer Slide 15 Spring I/O 2015 - Mum, I want to be a Groovy full-stack developer Slide 16 Spring I/O 2015 - Mum, I want to be a Groovy full-stack developer Slide 17 Spring I/O 2015 - Mum, I want to be a Groovy full-stack developer Slide 18 Spring I/O 2015 - Mum, I want to be a Groovy full-stack developer Slide 19 Spring I/O 2015 - Mum, I want to be a Groovy full-stack developer Slide 20 Spring I/O 2015 - Mum, I want to be a Groovy full-stack developer Slide 21 Spring I/O 2015 - Mum, I want to be a Groovy full-stack developer Slide 22 Spring I/O 2015 - Mum, I want to be a Groovy full-stack developer Slide 23 Spring I/O 2015 - Mum, I want to be a Groovy full-stack developer Slide 24 Spring I/O 2015 - Mum, I want to be a Groovy full-stack developer Slide 25 Spring I/O 2015 - Mum, I want to be a Groovy full-stack developer Slide 26 Spring I/O 2015 - Mum, I want to be a Groovy full-stack developer Slide 27 Spring I/O 2015 - Mum, I want to be a Groovy full-stack developer Slide 28 Spring I/O 2015 - Mum, I want to be a Groovy full-stack developer Slide 29 Spring I/O 2015 - Mum, I want to be a Groovy full-stack developer Slide 30 Spring I/O 2015 - Mum, I want to be a Groovy full-stack developer Slide 31 Spring I/O 2015 - Mum, I want to be a Groovy full-stack developer Slide 32 Spring I/O 2015 - Mum, I want to be a Groovy full-stack developer Slide 33 Spring I/O 2015 - Mum, I want to be a Groovy full-stack developer Slide 34 Spring I/O 2015 - Mum, I want to be a Groovy full-stack developer Slide 35 Spring I/O 2015 - Mum, I want to be a Groovy full-stack developer Slide 36 Spring I/O 2015 - Mum, I want to be a Groovy full-stack developer Slide 37 Spring I/O 2015 - Mum, I want to be a Groovy full-stack developer Slide 38 Spring I/O 2015 - Mum, I want to be a Groovy full-stack developer Slide 39 Spring I/O 2015 - Mum, I want to be a Groovy full-stack developer Slide 40 Spring I/O 2015 - Mum, I want to be a Groovy full-stack developer Slide 41 Spring I/O 2015 - Mum, I want to be a Groovy full-stack developer Slide 42 Spring I/O 2015 - Mum, I want to be a Groovy full-stack developer Slide 43 Spring I/O 2015 - Mum, I want to be a Groovy full-stack developer Slide 44 Spring I/O 2015 - Mum, I want to be a Groovy full-stack developer Slide 45 Spring I/O 2015 - Mum, I want to be a Groovy full-stack developer Slide 46 Spring I/O 2015 - Mum, I want to be a Groovy full-stack developer Slide 47 Spring I/O 2015 - Mum, I want to be a Groovy full-stack developer Slide 48 Spring I/O 2015 - Mum, I want to be a Groovy full-stack developer Slide 49 Spring I/O 2015 - Mum, I want to be a Groovy full-stack developer Slide 50 Spring I/O 2015 - Mum, I want to be a Groovy full-stack developer Slide 51 Spring I/O 2015 - Mum, I want to be a Groovy full-stack developer Slide 52 Spring I/O 2015 - Mum, I want to be a Groovy full-stack developer Slide 53 Spring I/O 2015 - Mum, I want to be a Groovy full-stack developer Slide 54 Spring I/O 2015 - Mum, I want to be a Groovy full-stack developer Slide 55 Spring I/O 2015 - Mum, I want to be a Groovy full-stack developer Slide 56 Spring I/O 2015 - Mum, I want to be a Groovy full-stack developer Slide 57 Spring I/O 2015 - Mum, I want to be a Groovy full-stack developer Slide 58 Spring I/O 2015 - Mum, I want to be a Groovy full-stack developer Slide 59
Upcoming SlideShare
Fiware rock&roll vt
Next
Download to read offline and view in fullscreen.

8 Likes

Share

Download to read offline

Spring I/O 2015 - Mum, I want to be a Groovy full-stack developer

Download to read offline

How many times have you ever heard the term “Full-Stack developer”? In most of the cases it means that you have to be fluent with a backend language, html, javascript, maybe Android or iOS… What if I told you that you can be a Full-Stack developer using only Groovy?In this talk I’ll present the technological stack of Polaromatic, the application with I won the Learning Spring Boot contest, and you’ll learn that it’s possible to write the whole stack with Groovy: Backend, Javascript, HTML, Android, test, build tool,… Isn’t that amazing?

Related Books

Free with a 30 day trial from Scribd

See all

Spring I/O 2015 - Mum, I want to be a Groovy full-stack developer

  1. 1. Mum, I want to be a Groovy full-stack developer @ilopmarIván López
  2. 2. Hello! I am Iván López @ilopmar http://greachconf.com@madridgug
  3. 3. Thank you very much! Q&A
  4. 4. Just kidding!
  5. 5. Full-stack developer Backend language Javascript HTML Mobile App
  6. 6. Polaromatic
  7. 7. 1. Demo
  8. 8. 2. Application flow
  9. 9. 3. Backend
  10. 10. Polaromatic ▷ Spring Boot ▷ Core App ▷ Spring MVC ▷ Spring Integration Flow
  11. 11. <file:inbound-channel-adapter directory="work" channel="incommingFilesChannel"/> <chain input-channel="incommingFilesChannel"> <service-activator ref="fileService" method="preprocessFile"/> <service-activator ref="imageConverterService" method="applyEffect"/> <service-activator ref="browserPushService" method="pushToBrowser"/> <service-activator ref="metricsService" method="updateMetrics"/> <service-activator ref="fileService" method="deleteTempFiles"/> </chain> Spring Integration Flow
  12. 12. <file:inbound-channel-adapter directory="work" channel="incommingFilesChannel"/> <chain input-channel="incommingFilesChannel"> <service-activator ref="fileService" method="preprocessFile"/> <service-activator ref="imageConverterService" method="applyEffect"/> <service-activator ref="browserPushService" method="pushToBrowser"/> <service-activator ref="metricsService" method="updateMetrics"/> <service-activator ref="fileService" method="deleteTempFiles"/> </chain> Spring Integration Flow Photo preprocessFile(File file) { def pr = new PolaroidRequest(file) this.preprocessFile(pr) } File service
  13. 13. <file:inbound-channel-adapter directory="work" channel="incommingFilesChannel"/> <chain input-channel="incommingFilesChannel"> <service-activator ref="fileService" method="preprocessFile"/> <service-activator ref="imageConverterService" method="applyEffect"/> <service-activator ref="browserPushService" method="pushToBrowser"/> <service-activator ref="metricsService" method="updateMetrics"/> <service-activator ref="fileService" method="deleteTempFiles"/> </chain> Spring Integration Flow File service Photo preprocessFile(File file) { def pr = new PolaroidRequest(file) this.preprocessFile(pr) } Photo preprocessFile(PolaroidRequest polaroidRequest) { String outputFile = File.createTempFile("output", ".png").path return new Photo(input: polaroidRequest.inputFile.absolutePath, output: outputFile, text: polaroidRequest.text) }
  14. 14. class ImageConverterService { private static final String DEFAULT_CAPTION = "#LearningSpringBoot with Polaromaticn" Random rnd = new Random() Photo applyEffect(Photo photo) { log.debug "Applying effect to file: ${photo.input}..." def inputFile = photo.input def outputFile = photo.output double polaroidRotation = rnd.nextInt(6).toDouble() String caption = photo.text ?: DEFAULT_CAPTION def op = new IMOperation() op.addImage(inputFile) op.thumbnail(300, 300) .set("caption", caption) .gravity("center") .pointsize(20) .background("black") .polaroid(rnd.nextBoolean() ? polaroidRotation : -polaroidRotation) .addImage(outputFile) def command = new ConvertCmd() command.run(op) photo } } Image converter
  15. 15. FlickrDownloader ▷ Spring Boot CLI ▷ Download Flickr Interesting pictures ▷ Jsoup, GPars ▷ 55 lines of Groovy code (microservice?)
  16. 16. @Slf4j @EnableScheduling @Grab('org.jsoup:jsoup:1.8.1') @Grab('commons-io:commons-io:2.4') @Grab('org.codehaus.gpars:gpars:1.2.1') class FlickrDownloader { static final String FLICKER_INTERESTING_URL = "https://www.flickr.com/explore/interesting/7days" static final String WORK_DIR = "./work" final File workDir = new File(WORK_DIR) @Scheduled(fixedRate = 30000L) void downloadFlickrInteresting() { def photos = extractPhotosFromFlickr() withPool { photos.eachParallel { photoUrl -> log.info "Downloading photo ${photoUrl}" def tempFile = download(photoUrl) FileUtils.moveFileToDirectory(tempFile, workDir, true) } } } } FlickrDownloader
  17. 17. @Slf4j @EnableScheduling @Grab('org.jsoup:jsoup:1.8.1') @Grab('commons-io:commons-io:2.4') @Grab('org.codehaus.gpars:gpars:1.2.1') class FlickrDownloader { static final String FLICKER_INTERESTING_URL = "https://www.flickr.com/explore/interesting/7days" static final String WORK_DIR = "./work" final File workDir = new File(WORK_DIR) @Scheduled(fixedRate = 30000L) void downloadFlickrInteresting() { def photos = extractPhotosFromFlickr() withPool { photos.eachParallel { photoUrl -> log.info "Downloading photo ${photoUrl}" def tempFile = download(photoUrl) FileUtils.moveFileToDirectory(tempFile, workDir, true) } } } } FlickrDownloader
  18. 18. FlickrDownloader @Slf4j @EnableScheduling @Grab('org.jsoup:jsoup:1.8.1') @Grab('commons-io:commons-io:2.4') @Grab('org.codehaus.gpars:gpars:1.2.1') class FlickrDownloader { static final String FLICKER_INTERESTING_URL = "https://www.flickr.com/explore/interesting/7days" static final String WORK_DIR = "./work" final File workDir = new File(WORK_DIR) @Scheduled(fixedRate = 30000L) void downloadFlickrInteresting() { def photos = extractPhotosFromFlickr() withPool { photos.eachParallel { photoUrl -> log.info "Downloading photo ${photoUrl}" def tempFile = download(photoUrl) FileUtils.moveFileToDirectory(tempFile, workDir, true) } } } } private List extractPhotosFromFlickr() { Document doc = Jsoup.connect(FLICKER_INTERESTING_URL).get() Elements images = doc.select("img.pc_img") def photos = images .listIterator() .collect { it.attr('src').replace('_m.jpg', '_b.jpg') } photos }
  19. 19. FlickrDownloader @Slf4j @EnableScheduling @Grab('org.jsoup:jsoup:1.8.1') @Grab('commons-io:commons-io:2.4') @Grab('org.codehaus.gpars:gpars:1.2.1') class FlickrDownloader { static final String FLICKER_INTERESTING_URL = "https://www.flickr.com/explore/interesting/7days" static final String WORK_DIR = "./work" final File workDir = new File(WORK_DIR) @Scheduled(fixedRate = 30000L) void downloadFlickrInteresting() { def photos = extractPhotosFromFlickr() withPool { photos.eachParallel { photoUrl -> log.info "Downloading photo ${photoUrl}" def tempFile = download(photoUrl) FileUtils.moveFileToDirectory(tempFile, workDir, true) } } } } private File download(String url) { def tempFile = File.createTempFile('flickr_downloader', '') tempFile << url.toURL().bytes tempFile }
  20. 20. FlickrDownloader @Slf4j @EnableScheduling @Grab('org.jsoup:jsoup:1.8.1') @Grab('commons-io:commons-io:2.4') @Grab('org.codehaus.gpars:gpars:1.2.1') class FlickrDownloader { static final String FLICKER_INTERESTING_URL = "https://www.flickr.com/explore/interesting/7days" static final String WORK_DIR = "./work" final File workDir = new File(WORK_DIR) @Scheduled(fixedRate = 30000L) void downloadFlickrInteresting() { def photos = extractPhotosFromFlickr() withPool { photos.eachParallel { photoUrl -> log.info "Downloading photo ${photoUrl}" def tempFile = download(photoUrl) FileUtils.moveFileToDirectory(tempFile, workDir, true) } } } }
  21. 21. FlickrDownloader 2015-04-17 21:56:11.139 INFO 16447 --- [111617-worker-1] polaromatic.FlickrDownloader 2015-04-17 21:56:11.139 INFO 16447 --- [111617-worker-2] polaromatic.FlickrDownloader 2015-04-17 21:56:11.139 INFO 16447 --- [111617-worker-3] polaromatic.FlickrDownloader 2015-04-17 21:56:11.354 INFO 16447 --- [111617-worker-1] polaromatic.FlickrDownloader 2015-04-17 21:56:11.375 INFO 16447 --- [111617-worker-2] polaromatic.FlickrDownloader 2015-04-17 21:56:11.527 INFO 16447 --- [111617-worker-3] polaromatic.FlickrDownloader 2015-04-17 21:56:11.537 INFO 16447 --- [111617-worker-2] polaromatic.FlickrDownloader 2015-04-17 21:56:11.612 INFO 16447 --- [111617-worker-2] polaromatic.FlickrDownloader 2015-04-17 21:56:11.693 INFO 16447 --- [111617-worker-2] polaromatic.FlickrDownloader 2015-04-17 22:02:17.019 INFO 9872 --- [pool-1-thread-1] polaromatic.FlickrDownloader 2015-04-17 22:02:19.451 INFO 9872 --- [pool-1-thread-1] polaromatic.FlickrDownloader 2015-04-17 22:02:21.661 INFO 9872 --- [pool-1-thread-1] polaromatic.FlickrDownloader 2015-04-17 22:02:22.079 INFO 9872 --- [pool-1-thread-1] polaromatic.FlickrDownloader 2015-04-17 22:02:22.877 INFO 9872 --- [pool-1-thread-1] polaromatic.FlickrDownloader 2015-04-17 22:02:23.392 INFO 9872 --- [pool-1-thread-1] polaromatic.FlickrDownloader 2015-04-17 22:02:23.749 INFO 9872 --- [pool-1-thread-1] polaromatic.FlickrDownloader 2015-04-17 22:02:24.250 INFO 9872 --- [pool-1-thread-1] polaromatic.FlickrDownloader 2015-04-17 22:02:24.695 INFO 9872 --- [pool-1-thread-1] polaromatic.FlickrDownloader
  22. 22. FlickrDownloader 2015-04-17 21:56:11.139 INFO 16447 --- [111617-worker-1] polaromatic.FlickrDownloader 2015-04-17 21:56:11.139 INFO 16447 --- [111617-worker-2] polaromatic.FlickrDownloader 2015-04-17 21:56:11.139 INFO 16447 --- [111617-worker-3] polaromatic.FlickrDownloader 2015-04-17 21:56:11.354 INFO 16447 --- [111617-worker-1] polaromatic.FlickrDownloader 2015-04-17 21:56:11.375 INFO 16447 --- [111617-worker-2] polaromatic.FlickrDownloader 2015-04-17 21:56:11.527 INFO 16447 --- [111617-worker-3] polaromatic.FlickrDownloader 2015-04-17 21:56:11.537 INFO 16447 --- [111617-worker-2] polaromatic.FlickrDownloader 2015-04-17 21:56:11.612 INFO 16447 --- [111617-worker-2] polaromatic.FlickrDownloader 2015-04-17 21:56:11.693 INFO 16447 --- [111617-worker-2] polaromatic.FlickrDownloader 2015-04-17 22:02:17.019 INFO 9872 --- [pool-1-thread-1] polaromatic.FlickrDownloader 2015-04-17 22:02:19.451 INFO 9872 --- [pool-1-thread-1] polaromatic.FlickrDownloader 2015-04-17 22:02:21.661 INFO 9872 --- [pool-1-thread-1] polaromatic.FlickrDownloader 2015-04-17 22:02:22.079 INFO 9872 --- [pool-1-thread-1] polaromatic.FlickrDownloader 2015-04-17 22:02:22.877 INFO 9872 --- [pool-1-thread-1] polaromatic.FlickrDownloader 2015-04-17 22:02:23.392 INFO 9872 --- [pool-1-thread-1] polaromatic.FlickrDownloader 2015-04-17 22:02:23.749 INFO 9872 --- [pool-1-thread-1] polaromatic.FlickrDownloader 2015-04-17 22:02:24.250 INFO 9872 --- [pool-1-thread-1] polaromatic.FlickrDownloader 2015-04-17 22:02:24.695 INFO 9872 --- [pool-1-thread-1] polaromatic.FlickrDownloader
  23. 23. 4. Frontend
  24. 24. Fronted ▷ MarkupTemplateEngine (HTML) ▷ Websockets ▷ Grooscript
  25. 25. HTML yieldUnescaped '<!DOCTYPE html>' html { head { title "Polaromatic" link(rel: 'stylesheet', href: '/css/app.css') link(rel: 'stylesheet', href: '/css/gh-fork-ribbon.css') ['webjars/sockjs-client/0.3.4-1/sockjs.min.js', 'webjars/stomp-websocket/2.3.1-1/stomp.min.js', 'webjars/jquery/2.1.3/jquery.min.js', 'webjars/handlebars/2.0.0-1/handlebars.min.js', 'js/Connection.js'] .each { yieldUnescaped "<script src='$it'></script>" } } }
  26. 26. HTML body { ... div(id: 'header') { div(class: 'center') { a(href: 'https://github.com/lmivan/contest', target: 'blank') { img(src: 'images/polaromatic-logo.png') } p('Polaromatic') span('Powered by Spring Boot') } } div(id: 'timeline', class: 'center') } script(id: 'photo-template', type: 'text/x-handlebars-template') { div(class: 'photo-cover') { div(class: 'photo', style: 'visibility:hidden; height:0') { img(src: '{{image}}') } } } yieldUnescaped "<script>Connection().start()</script>" }
  27. 27. Websockets @Configuration @EnableWebSocketMessageBroker class WebsocketConfig extends AbstractWebSocketMessageBrokerConfigurer { @Override void configureMessageBroker(MessageBrokerRegistry config) { config.enableSimpleBroker '/notifications' } @Override void registerStompEndpoints(StompEndpointRegistry registry) { registry.addEndpoint('/polaromatic').withSockJS() } }
  28. 28. Websockets class BrowserPushService { @Autowired SimpMessagingTemplate template Photo pushToBrowser(Photo photo) { log.debug "Pushing file to browser: ${photo.output}" String imageB64 = new File(photo.output).bytes.encodeBase64().toString() template.convertAndSend "/notifications/photo", imageB64 return photo } }
  29. 29. Websockets class BrowserPushService { @Autowired SimpMessagingTemplate template Photo pushToBrowser(Photo photo) { log.debug "Pushing file to browser: ${photo.output}" String imageB64 = new File(photo.output).bytes.encodeBase64().toString() template.convertAndSend "/notifications/photo", imageB64 return photo } } <chain input-channel="incommingFilesChannel"> <service-activator ref="fileService" method="preprocessFile"/> <service-activator ref="imageConverterService" method="applyEffect"/> <service-activator ref="browserPushService" method="pushToBrowser"/> <service-activator ref="metricsService" method="updateMetrics"/> <service-activator ref="fileService" method="deleteTempFiles"/> </chain>
  30. 30. class Connection { @GsNative def initOn(source, path) {/* var socket = new SockJS(path); return [Handlebars.compile(source), Stomp.over(socket)]; */} def start() { def source = $("#photo-template").html() def (template, client) = initOn(source, '/polaromatic') client.debug = null client.connect(gs.toJavascript([:])) { -> client.subscribe('/notifications/photo') { message -> def context = [image: 'data:image/png;base64,' + message.body] def html = template(context) $("#timeline").prepend(html) $("#timeline .photo:first-child img").on("load") { $(this).parent().css(gs.toJavascript(display: 'none', visibility: 'visible', height: 'auto')) $(this).parent().slideDown() } } } } } Grooscript (Javascript)
  31. 31. 5. Android
  32. 32. Android App ▷ Disclaimer: I'm not an Android developer ▷ Lazybones template (@marioggar) ▷ Traits, @CompileStatic ▷ SwissKnife
  33. 33. Android trait Toastable { @OnUIThread void showToastMessage(String message) { Toast toast = Toast.makeText(applicationContext, message, Toast.LENGTH_SHORT) toast.show() } }
  34. 34. Android trait Toastable { @OnUIThread void showToastMessage(String message) { Toast toast = Toast.makeText(applicationContext, message, Toast.LENGTH_SHORT) toast.show() } } @CompileStatic public class ShareActivity extends Activity implements Toastable { ... showToastMessage(getString(R.string.share_ok_msg)) ... }
  35. 35. 6. Tests
  36. 36. Tests ▷ Spock Framework ▷ 0.7 for more than 3 years ▷ Now 1.0 ▷ JUnit compatible
  37. 37. Spock class BrowserPushServiceSpec extends Specification { void 'should push a converted photo to the browser'() { given: 'a photo' def output = File.createTempFile("output", "") def photo = new Photo(output: output.path) and: 'a mocked SimpMessagingTemplate' def mockSimpMessagingTemplate = Mock(SimpMessagingTemplate) and: 'the push service' def browserPushService = new BrowserPushService(template: mockSimpMessagingTemplate) when: 'pushing the photo to the browser' browserPushService.pushToBrowser(photo) then: 'the photo is pushed' 1 * mockSimpMessagingTemplate.convertAndSend('/notifications/photo', "") } }
  38. 38. 7. Build tool
  39. 39. Build tool ▷ Gradle ▷ Multiproject to build backend, documentation and android
  40. 40. Gradle subprojects { buildscript { repositories { jcenter() } } repositories { jcenter() } } task wrapper(type: Wrapper) { gradleVersion = '2.2.1' } include 'polaromatic-back' include 'polaromatic-groid' include 'polaromatic-docs' build.gradle settings.gradle
  41. 41. 8. Documentation
  42. 42. Documentation ▷ Asciidoctor (FTW!) ▷ Gradle plugin ▷ Backends: html, epub, pdf,...
  43. 43. Asciidoctor buildscript { dependencies { classpath 'org.asciidoctor:asciidoctor-gradle-plugin:1.5.2' } } apply plugin: 'org.asciidoctor.convert' asciidoctor { sourceDir 'src/docs' outputDir "${buildDir}/docs" attributes 'source-highlighter': 'coderay', toc : 'left', icons : 'font' }
  44. 44. Asciidoctor [source,xml,indent=0] .src/main/resources/resources.xml ---- include::{polaromaticBackResources}/resources.xml[tags=appFlow] ---- <1> Define the integration with the file system <2> Preprocess the file received <3> Apply the Polaroid effect <4> Send the new photo to the browser using Websockets <5> Update the metrics <6> Delete all temporary files
  45. 45. Asciidoctor [source,xml,indent=0] .src/main/resources/resources.xml ---- include::{polaromaticBackResources}/resources.xml[tags=appFlow] ---- <1> Define the integration with the file system <2> Preprocess the file received <3> Apply the Polaroid effect <4> Send the new photo to the browser using Websockets <5> Update the metrics <6> Delete all temporary files <!-- tag::appFlow[] --> <file:inbound-channel-adapter directory="work" channel="incommingFilesChannel"/> <!--1--> <chain input-channel="incommingFilesChannel"> <service-activator ref="fileService" method="preprocessFile"/> <!--2--> <service-activator ref="imageConverterService" method="applyEffect"/> <!--3--> <service-activator ref="browserPushService" method="pushToBrowser"/> <!--4--> <service-activator ref="metricsService" method="updateMetrics"/> <!--5--> <service-activator ref="fileService" method="deleteTempFiles"/> <!--6--> </chain> <!-- end::appFlow[]-->
  46. 46. Asciidoctor
  47. 47. 9. Summary
  48. 48. “ Groovy, groovy everywhere...
  49. 49. Thanks! Any questions? @ilopmar lopez.ivan@gmail.com https://github.com/lmivan Iván López http://kcy.me/22key
  • ssuser9e8fe3

    Aug. 7, 2016
  • chjin

    Oct. 18, 2015
  • jacobdanner

    May. 28, 2015
  • dirolwhite

    May. 15, 2015
  • halyph

    May. 7, 2015
  • JonasHavers

    Apr. 30, 2015
  • ysb33r

    Apr. 29, 2015
  • semurat

    Apr. 29, 2015

How many times have you ever heard the term “Full-Stack developer”? In most of the cases it means that you have to be fluent with a backend language, html, javascript, maybe Android or iOS… What if I told you that you can be a Full-Stack developer using only Groovy?In this talk I’ll present the technological stack of Polaromatic, the application with I won the Learning Spring Boot contest, and you’ll learn that it’s possible to write the whole stack with Groovy: Backend, Javascript, HTML, Android, test, build tool,… Isn’t that amazing?

Views

Total views

2,204

On Slideshare

0

From embeds

0

Number of embeds

65

Actions

Downloads

22

Shares

0

Comments

0

Likes

8

×