scala italy 2013 extended scalatra vs spring mvc

45
Scala Italy 25 may 2013 Scalatra comparison with SpringMVC Massimiliano Dessì 1 Monday, May 27, 13

Upload: massimiliano-dessi

Post on 11-Nov-2014

1.384 views

Category:

Technology


0 download

DESCRIPTION

Scalatra Spring MVC From Java to Scala Web Akka Actors

TRANSCRIPT

Page 1: Scala Italy 2013 extended Scalatra vs Spring MVC

Scala Italy 25 may 2013Scalatra comparison with SpringMVC

Massimiliano Dessì

1

Monday, May 27, 13

Page 2: Scala Italy 2013 extended Scalatra vs Spring MVC

GDG SardegnaSpeaker

Max has more than 13 years of experience in programming. He’s a proud father of three.Manager of GTUG Sardegna, Founder of SpringFramework IT, co-founder of Jug Sardegna.Author of Spring 2.5 AOP. He works in Energeya as a Product Architect and lives in Cagliari, Italy.

2

Monday, May 27, 13

Page 3: Scala Italy 2013 extended Scalatra vs Spring MVC

GDG Sardegna

Scalatra - SpringMVC

CRUD HTML

REST

JSON

Routing

Template

Security

Agenda

3

Monday, May 27, 13

Page 4: Scala Italy 2013 extended Scalatra vs Spring MVC

GDG Sardegna

Spring , Since 2004 - Java Full Stack - Lot of people involvednow property of VMware

Scalatra , Since 2009 - Scala Http Microframework (DSL) the BBC, LinkedIn,

the Guardian, games website IGN,

UK government

rely on Scalatra.

Some info

4

Monday, May 27, 13

Page 5: Scala Italy 2013 extended Scalatra vs Spring MVC

GDG Sardegna

REST

class JellyBeans extends ScalatraServlet {

get("/jellybs/:id") { ... }

post("/jellybs") { ... }

put("/jellybs/:id") { ... }

delete("/jellybs/:id") { ... } }

For browser add PUT & DELETE support client side X-HTTP-METHOD-OVERRIDE or _method=put _method=delete in the post body

class JellyBeansBrowser extends ScalatraFilter with MethodOverride

5

Monday, May 27, 13

Page 6: Scala Italy 2013 extended Scalatra vs Spring MVC

GDG SardegnaMassimiliano Dessì

Routes

class JellyBeans extends ScalatraServlet {

get("/jellybs/:id") {

val id:Int = params.getOrElse("id", halt(400)).toInt ...

}

get("/jellybs/download/*.*") { //with wildcard...

}

get("""^\/j(.*)/f(.*)""".or) { //REGEX...

}

post("/jellybs", request.getRemoteHost == "127.0.0.1", request.getRemoteUser == "admin") { .... }

6

Monday, May 27, 13

Page 7: Scala Italy 2013 extended Scalatra vs Spring MVC

GDG Sardegna

REST

@Controllerpublic class JellyBeansController{

@RequestMapping(value = "/jellybs/{id}", method = RequestMethod.GET) @ResponseStatus(HttpStatus.OK) //Http 200 public @ResponseBody JellyB getItem(@PathVariable("id") Integer id) {...}

@RequestMapping(value = "/jellybs", method = RequestMethod.POST) //Http 201 @ResponseStatus(HttpStatus.CREATED) //Http 201 public void createJelly(HttpServletRequest req, HttpServletResponse res, @RequestBody JellyB item) { ... }

@RequestMapping(value = "/jellybs/{id}", method = RequestMethod.PUT) @ResponseStatus(HttpStatus.NO_CONTENT) //Http 204

public void updateItem(@RequestBody JellyB item, @PathVariable("id") Integer id) { ... }

@RequestMapping(value = "/items/{id}", method = RequestMethod.DELETE) @ResponseStatus(HttpStatus.NO_CONTENT)//204 public void deleteItem(@PathVariable("id") String id) { ... } }

For browser add PUT & DELETE support client side X-HTTP-METHOD-OVERRIDE or _method=put _method=delete in the post body

<filter> <filter-name>hiddenMethodFilter</filter-name> <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class></filter>

7

Monday, May 27, 13

Page 8: Scala Italy 2013 extended Scalatra vs Spring MVC

GDG Sardegna

Routes

class JellyBeans extends ScalatraServlet {

get("/jellybs/:id") {

val id:Int = params.getOrElse("id", halt(400)).toInt ...

}

get("/jellybs/download/*.*") { //with wildcard...

}

get("""^\/j(.*)/f(.*)""".or) { //REGEX...

}

post("/jellybs", request.getRemoteHost == "127.0.0.1", request.getRemoteUser == "admin") { .... }

8

Monday, May 27, 13

Page 9: Scala Italy 2013 extended Scalatra vs Spring MVC

GDG Sardegna

HandlerMapping

@Controllerpublic class JellyBeansController{

@RequestMapping(value="/jelly.pdf",method = RequestMethod.GET)public ModelAndView pdf(HttpServletRequest req,@RequestParam String id) {

... }

@RequestMapping(value = "/jellybs/{id}", method = RequestMethod.GET) public String getItem(@PathVariable("id") Integer id) { ... }

@RequestMapping(value = "/jellybs", method = RequestMethod.POST) public void createJelly(@ModelAttribute(”jelly”) JellyB jelly) { ... }}

DefaultAnnotationHandlerMappingSimpleUrlHandlerMappingControllerClassNameHandlerMapping

9

Monday, May 27, 13

Page 10: Scala Italy 2013 extended Scalatra vs Spring MVC

GDG Sardegna

Filter

class JellyBeans extends ScalatraServlet {

before() {db.acquireConnecioncontentType="text/html"

}

get("/") {val menu = db.findWelcome()templateEngine.layout("index.ssp", menu)

}

after() {db.releaseConnection

}}

Like Servlet Filter (or Aspect Oriented Programming) You can add logic before or the

routes

10

Monday, May 27, 13

Page 11: Scala Italy 2013 extended Scalatra vs Spring MVC

GDG Sardegna

Handler Interceptor

public interface HandlerInterceptor{

//before call method’s controllerboolean preHandle(HttpServletRequest req, HttpServletResponse res, Object handler) throws Exception;

//after call method’s controllervoid postHandle(HttpServletRequest req, HttpServletResponse res, Object handler, ModelAndView mav) throws Exception;

//after view render()void afterCompletition(HttpServletRequest req, HttpServletResponse res, Object handler, Exception ex) throws Exception;

}

Handler mapped on all controllers (as a property of Handlermapping config)or mapped on url path with <mvc:interceptors> tags

Like Servlet Filter (or Aspect Oriented Programming) You can add logic before or after

the controllers methods

11

Monday, May 27, 13

Page 12: Scala Italy 2013 extended Scalatra vs Spring MVC

GDG Sardegna

Handlers

Handlers are top level methods for http routines

class JellyBeans extends ScalatraServlet {

notFound { <h1>Not found</h1>}

halt(status = 301, headers = Map("Location" -> "http://www.codemotion.com/"))

get("/jellybs/names/*") { "Name not found!"}

}

12

Monday, May 27, 13

Page 13: Scala Italy 2013 extended Scalatra vs Spring MVC

GDG Sardegna

Handlers

class JellyBeans extends ScalatraServlet {

get("/jellybs/names/:who") { params("who") match { case "Cherry" => "Found Cherry!" case _ => pass() /* call the next matching route route, routes are matched from bottom up*/ }}

get("/jellybs/download/:id") { jellyBeanService.find(params("id")) match {

case Some(jellybean) => Ok(jellybean) case None => NotFound("Sorry, jellybean not found")

} }

}

13

Monday, May 27, 13

Page 14: Scala Italy 2013 extended Scalatra vs Spring MVC

GDG Sardegna

Request Response & Friends

class JellyBeans extends ScalatraServlet {

get("/jellybs/shows/:id") { //access to request,response, session and params request.body //request body as a string request.cookies // cookie map request.isAjax // is ajaxRequest request.getSession // HttpServletSession request.locale // user locale response.getOutputStream //response outputstream servletContext.get("myIntParam") //servlet context val idString = params("id") val id = params.getAs[Int]("id")

//val id = params.getOrElse("id", halt(500)) //another way ....

}}

14

Monday, May 27, 13

Page 15: Scala Italy 2013 extended Scalatra vs Spring MVC

GDG Sardegna

Request Response & Friends

class JellyBeans extends ScalatraServlet {

get("/jellybs/*/conf/*") { // Matches "GET /jellybs/one/conf/two" multiParams("splat") // Seq("one", "two")

//wildcard accessible with key splat }

get("""^\/jelly(.*)/fla(.*)""".r) { // Matches "GET /jellybs/flavor" multiParams("captures") // == Seq("bs", "vor")}

}

15

Monday, May 27, 13

Page 16: Scala Italy 2013 extended Scalatra vs Spring MVC

GDG Sardegna

Gzip

class GzipJellyBeans extends ScalatraServlet with GZipSupport{ get("/") { <html> <body> <h1>This is <a href="http://en.wikipedia.org/wiki/Sparta">Sparta</a>! </h1> </body> </html> }}

16

Monday, May 27, 13

Page 17: Scala Italy 2013 extended Scalatra vs Spring MVC

GDG SardegnaFlash message

class FlashServlet extends ScalatraServlet with FlashMapSupport{

post("/jellybs/create") { flash("notice") = "jellybean created successfully" redirect("/home") //redirect }

get("/home") { ssp("/home") //Scala Server Pages }

17

Monday, May 27, 13

Page 18: Scala Italy 2013 extended Scalatra vs Spring MVC

GDG Sardegna

ExceptionResolvers

<bean id="exceptionResolver" class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"> <property name="exceptionMappings"> <props> <prop key="org.springframework.web.HttpSessionRequiredException">welcome</prop> ... </props> </property> </bean>

or in a annotated @Controller class

@ExceptionHandlerpublic String requestParamNotPresent(HttpMediaTypeException ex)

18

Monday, May 27, 13

Page 19: Scala Italy 2013 extended Scalatra vs Spring MVC

GDG Sardegna

Binding

To avoid manual binding from http and our Object Scalatra provide a binding module

case class MyClass(id: Integer, name: String)

post("/myroute") { val cmd = command[CreateMyClassCommand] ...}

19

Monday, May 27, 13

Page 20: Scala Italy 2013 extended Scalatra vs Spring MVC

GDG Sardegna

Binding

Under the hood

abstract class MyClassCommand[S](implicit mf: Manifest[S]) extends ModelCommand[S] with JsonCommand {

   implicit def todoStringValidators(b: FieldDescriptor[String]) =

new MyClassStringValidations(b) }

class CreateMyClassCommand extends MyClassCommand[MyClass] { protected implicit val jsonFormats = DefaultFormats

val name: Field[String] = asType[String]("name").notBlank.minLength(3) }

20

Monday, May 27, 13

Page 21: Scala Italy 2013 extended Scalatra vs Spring MVC

GDG Sardegna

Binding

Under the hood

class MyClassStringValidations(b: FieldDescriptor[String]) { def startsWithCap(message: String = "%s must start with a capital letter.") = b.validateWith(_ =>

     _ flatMap { new PredicateValidator[String](

b.name, """^[A-Z,0-9]""".r.findFirstIn(_).isDefined,

message).validate(_)    )

} ) }

21

Monday, May 27, 13

Page 22: Scala Italy 2013 extended Scalatra vs Spring MVC

GDG Sardegna

CommandObject

@RequestMapping(value = "/items/{id}", method = RequestMethod.PUT) @ResponseStatus(HttpStatus.NO_CONTENT) public String updateItem(JellyB item) { ... }

Spring bind the request body on the object used in the method (JellyB)

Objects Validation with jsr 303 annotation or with Validator Spring InterfaceError message with JSP/JSTL tags

22

Monday, May 27, 13

Page 23: Scala Italy 2013 extended Scalatra vs Spring MVC

GDG Sardegna

Upload

import org.scalatra.ScalatraServletimport org.scalatra.servlet.FileUploadSupportimport javax.servlet.annotation.MultipartConfig

@MultipartConfig(maxFileSize=10*1024)trait StorageRoutes extends FileUploadSupport {

self: ScalatraServlet =>}

23

Monday, May 27, 13

Page 24: Scala Italy 2013 extended Scalatra vs Spring MVC

GDG Sardegna

JSON

Automatic Serialization and deserialization of any Case class

object JSONServlet extends ScalatraServlet with JacksonJsonSupport{

case class JellyBean(id: Int, name: String, flavor:String)

protected implicit val jsonFormats: Formats = DefaultFormats

before() { contentType = formats("json") }

....

24

Monday, May 27, 13

Page 25: Scala Italy 2013 extended Scalatra vs Spring MVC

GDG SardegnaActors

The routes can returns a Future

class MyActorServlet(system:ActorSystem, myActor:ActorRef) extends ScalatraServlet with FutureSupport {

import _root_.akka.pattern.ask implicit val timeout = Timeout(10) protected implicit def executor: ExecutionContext = system.dispatcher

get("/async") { myActor ? "Do stuff and give me an answer" }

get("/fire-forget") { myActor ! "Hey, you know what?" Accepted() //if you do not want return a future }

}

25

Monday, May 27, 13

Page 26: Scala Italy 2013 extended Scalatra vs Spring MVC

GDG Sardegna

Actors

get("/async") { myActor ? "Do stuff and give me an answer" }

get("/fire-forget") { myActor ! "Hey, you know what?" Accepted() //if you don’t want return a future }

class CodemotionActor extends Actor { def receive = { case "Do stuff and give me an answer" => sender ! "The answer is 42" case "Hey, you know what?" => println("Yeah I know...") } } }

26

Monday, May 27, 13

Page 27: Scala Italy 2013 extended Scalatra vs Spring MVC

GDG Sardegna

Akka

Akka start in the Bootstrap of Scalatra

class ScalatraBootstrap extends LifeCycle {

val system = ActorSystem() val codemotionActor = system.actorOf(Props[CodemotionActor])

override def init(context: ServletContext) { context.mount(new JSONServlet, "/jellybs/*") context.mount(new FrontServlet, "/template/*") context.mount(new MyActorServlet(system, codemotionActor), "/actors/*") }

override def destroy(context:ServletContext) { system.shutdown() }}

27

Monday, May 27, 13

Page 28: Scala Italy 2013 extended Scalatra vs Spring MVC

GDG Sardegna

Deployment

Scalatra is based on regular Java Servlet 3.0it can start from:

Standalone from jetty embeddedFrom Servlet container

HerokuJelastic

CloudBeesGAE (not out of the box )

web.xml<?xml version="1.0" encoding="UTF-8"?><web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0"> <listener> <listener-class>org.scalatra.servlet.ScalatraListener</listener-class> </listener>

<servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>/img/*</url-pattern> <url-pattern>/css/*</url-pattern> <url-pattern>/js/*</url-pattern> <url-pattern>/assets/*</url-pattern> </servlet-mapping></web-app>

28

Monday, May 27, 13

Page 29: Scala Italy 2013 extended Scalatra vs Spring MVC

GDG Sardegna

JSON

Automatic Serialization and deserialization of any Case class

object JSONServlet extends ScalatraServlet with JacksonJsonSupport{

...

get("/jellybs/all"){ jellyBeanRepo.all //from class to json }

post("/jellybs/create") { val jb = parsedBody.extract[JellyBean] //from json to class ... } }

29

Monday, May 27, 13

Page 30: Scala Italy 2013 extended Scalatra vs Spring MVC

GDG Sardegna

JSON

30

JSON with third party lib es Jackson

@JsonCreator public JellyB(Map map) {...}

@JsonAnyGetter public Map toMap() {...}

Automatic binding

public @ResponseBody JellyB getItem(...)

public void updateItem(@RequestBody JellyB item)

Monday, May 27, 13

Page 31: Scala Italy 2013 extended Scalatra vs Spring MVC

GDG Sardegna

Template

Html inline,Scalate

Twirl (Play2 template)

Scalate mean

SSP (Scala Server Page)Scaml

MustacheJade

31

Monday, May 27, 13

Page 32: Scala Italy 2013 extended Scalatra vs Spring MVC

GDG Sardegna

Template

class ScalateServlet extends ScalatraServlet with ScalateSupport{

get("/"jellybeans/ssp) { contentType="text/html" ssp("/index", "foo" -> "uno", "bar" -> "two") // the layout used it’s WEB-INF/layouts/default.ssp }

get("/jellybeans/jade") { jade("/index", "layout" -> "", "foo" -> "one", "bar" -> "two") // render without a layout. }

get("/jellybeans/direct") { templateEngine.layout("/jellybeans/index.ssp") //direct invoking of scalate }

32

Monday, May 27, 13

Page 33: Scala Italy 2013 extended Scalatra vs Spring MVC

GDG Sardegna

Template

SSP

<%@ var body: String %><%@ var title: String = "Some Default Title" %><%@ var head: String = "" %><html><head> <title>${title}</title> <%-- page specific head goes here --%> ${unescape(head)}</head><body> <p>layout header goes here...</p>

${unescape(body)} <p>layout footer goes here...</p></body></html>

33

Monday, May 27, 13

Page 34: Scala Italy 2013 extended Scalatra vs Spring MVC

GDG Sardegna

Template

JADE

!!! 5html(lang="en") head title= pageTitle :javascript if (foo) { bar() } body h1 Jade - node template engine #container - if (youAreUsingJade) p You are amazing - else p Get on it! :coffeescript alert "Hello, Coffee!"

34

Monday, May 27, 13

Page 35: Scala Italy 2013 extended Scalatra vs Spring MVC

GDG Sardegna

Template

Mustache

Hello {{name}} You have just won ${{value}}!{{#in_ca}}Well, ${{taxed_value}}, after taxes.{{/in_ca}}

35

Monday, May 27, 13

Page 36: Scala Italy 2013 extended Scalatra vs Spring MVC

GDG Sardegna

Template

SCAML

!!! XML!!!%html %head %title Myspace %body %h1 I am the international space station %p Sign my guestbook

36

Monday, May 27, 13

Page 37: Scala Italy 2013 extended Scalatra vs Spring MVC

GDG Sardegna

ViewResolver

JSP, JSTL, Tiles, FreeMarker, XSLT, PDF, Velocity, JExcelApi, JSON, Atom, RSS, JasperReports

Explicit view with different ViewResolver with different order values, or with ContentTypeNegotiationViewResolver

mapping different mediaTypes

37

Monday, May 27, 13

Page 38: Scala Italy 2013 extended Scalatra vs Spring MVC

GDG Sardegna

Authentication & Security

Scalatra uses Scentry a porting of Ruby Warden authentication

class OurAuthStrategy(protected override val app: ScalatraBase, realm: String) extends BasicAuthStrategy[User](app, realm) {

protected def validate(userName: String, password: String): Option[User] = { if(userName == "myusername" && password == "secret") Some(User("myusername")) else None }

protected def getUserId(user: User): String = user.id}

case class User(id: String)

38

Monday, May 27, 13

Page 39: Scala Italy 2013 extended Scalatra vs Spring MVC

GDG Sardegna

Authentication & Security

Now we need to combine our strategy and ScentrySupporttrait AuthenticationSupport extends ScentrySupport[User] with BasicAuthSupport[User] { self: ScalatraBase =>

val realm = "Scalatra Basic Auth Example"

protected def fromSession = { case id: String => User(id) } protected def toSession = { case usr: User => usr.id } protected val scentryConfig = (new ScentryConfig {}).asInstanceOf[ScentryConfiguration]

}

39

Monday, May 27, 13

Page 40: Scala Italy 2013 extended Scalatra vs Spring MVC

GDG Sardegna

Authentication & Security

Now we need to combine our strategy and ScentrySupport

trait AuthenticationSupport extends ScentrySupport[User] with BasicAuthSupport[User] { ....

override protected def configureScentry = { scentry.unauthenticated { scentry.strategies("Basic").unauthenticated() scentry.strategies("") } }

override protected def registerAuthStrategies = { scentry.register("Basic", app => new OurBasicAuthStrategy(app, realm)) }

protected def validate(userName: String, password: String): Option[User] = { if(userName == "scalatra" && password == "scalatra") Some(User("scalatra")) else None }}

40

Monday, May 27, 13

Page 41: Scala Italy 2013 extended Scalatra vs Spring MVC

GDG Sardegna

Authentication & Security

Now we can use the Authentication for all routes defined in our Authenticated Servlets

class AuthenticatedServlet extends ScalatraServlet with AuthenticationSupport{

//every route goes under authentication

}

Unauthenticated user will see a browser prompt login

41

Monday, May 27, 13

Page 42: Scala Italy 2013 extended Scalatra vs Spring MVC

GDG Sardegna

SpringSecurity

FilterServlet to protect urls, roles and AOP intercepting based on User Roles

<filter> <filter-name>springSecurityFilterChain</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> </filter> <filter-mapping> <filter-name>springSecurityFilterChain</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>

<sec:http>" " <sec:form-login login-page="/login.jsp" login-processing-url="/j_security_check" default-target-url="/"" " " always-use-default-target="true" authentication-failure-url="/loginError.jsp"/>" " <sec:logout logout-url="/logout.jsp" invalidate-session="true" logout-success-url="/login.jsp" />" " <sec:intercept-url pattern="/styles/**" filters="none"/>" " <sec:intercept-url pattern="/scripts/**" filters="none"/>" " <sec:intercept-url pattern="/img/**" filters="none"/>" " <sec:anonymous username="guest" granted-authority="ROLE_GUEST" />"

42

Monday, May 27, 13

Page 43: Scala Italy 2013 extended Scalatra vs Spring MVC

GDG Sardegna

Test

Test with Specs2

class FrontServletSpec extends ScalatraSpec { def is = "GET / on FrontServlet" ^ "should return status 200" ! root200 ^ end

addServlet(classOf[FrontServlet], "/*")

def root200 = get("/") { status must_== 200 }}

43

Monday, May 27, 13

Page 44: Scala Italy 2013 extended Scalatra vs Spring MVC

GDG Sardegna

Q & A

GTUG Sardegna

44

Monday, May 27, 13

Page 45: Scala Italy 2013 extended Scalatra vs Spring MVC

GDG Sardegna

Thanks for your attention!

Massimiliano: @desmax74

GTUG Sardegna

45

Thanks for you attention!Massimiliano: @desmax74

Monday, May 27, 13