Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Vinna, Reinventing the wheel

Vinna, Reinventing the wheel

Les slides de la présentation de Vinna, un mini-framework MVC web écrit en Java lors de la technozaure du 22/05/2013 à Zenika

Jawher Moussa

May 22, 2013
Tweet

More Decks by Jawher Moussa

Other Decks in Programming

Transcript

  1. Modèle de dev: on accède à des pages qui font

    des callbacks vers du Java Thursday, 23 May, 13
  2. C’est pas mauvais en soi, mais y’a des cas où

    on veut du stateless: site web public par exemple Thursday, 23 May, 13
  3. Les créateurs de JSF 1 avaient complètement oublié le verbe

    GET ainsi que la possibilité de répéter un bloc HTML LOL Thursday, 23 May, 13
  4. Impossible de faire des URLs propres (faut que ça pointe

    vers un fichier de page) sans url rewriting LOL x 2 Thursday, 23 May, 13
  5. Les vues c’est juste du <HTML>*, on contrôle tout avec

    du Java *: Avec quand même des ids pour binder Thursday, 23 May, 13
  6. On peut faire du stateless, mais on passe notre temps

    à se battre contre le framework Thursday, 23 May, 13
  7. Très facile de finir avec toute sa base de données

    dans la session Thursday, 23 May, 13
  8. Lourd: e.g. un setter par paramètre à récupérer + configurer

    l’interceptor qu’il faut Thursday, 23 May, 13
  9. Non blocking, real time, bla bla bla, et pourtant, les

    perfs ne suivent pas Thursday, 23 May, 13
  10. On pense vraiment que le super framework MVC/Action sur JVM

    n’existe pas encore Thursday, 23 May, 13
  11. 3. Les standards tu ré-utiliseras* *: On aime bien ré-inventer

    la roue mais faut pas abuser non plus Thursday, 23 May, 13
  12. web.xml        <filter>          

         <filter-­‐name>vinnaFilter</filter-­‐name>                <filter-­‐class>vinna.VinnaFilter</filter-­‐class>                <init-­‐param>                        <param-­‐name>base-­‐package</param-­‐name>                        <param-­‐value>vinna</param-­‐value>                </init-­‐param>        </filter>        <filter-­‐mapping>              <filter-­‐name>vinnaFilter</filter-­‐name>              <url-­‐pattern>/*</url-­‐pattern>        </filter-­‐mapping> Thursday, 23 May, 13
  13. Ze contrôleur package  vinna.controllers; import  vinna.response.Response; import  vinna.response.StringResponse; public  class

     HelloController  {        public  Response  index()  {                return  new  StringResponse("Go  to  /hello/{your  name}  for  a  free  hug  !");        }        public  Response  sayHello(String  name,  String  ohai)  {                return  new  StringResponse(String.format("%s  %s  !",  (ohai  ==  null  ?  "Ohai"  :  ohai),  name));        } } Thursday, 23 May, 13
  14. web.xml        <filter>          

         <filter-­‐name>vinnaFilter</filter-­‐name>                <filter-­‐class>vinna.VinnaFilter</filter-­‐class>                <init-­‐param>                        <param-­‐name>application-­‐class</param-­‐name>                        <param-­‐value>vinna.VinnApp</param-­‐value>                </init-­‐param>        </filter>        <filter-­‐mapping>              <filter-­‐name>vinnaFilter</filter-­‐name>              <url-­‐pattern>/*</url-­‐pattern>        </filter-­‐mapping> Thursday, 23 May, 13
  15. Déclaration des routes package  vinna; import  java.util.Map; import  vinna.controllers.HelloController; import

     vinna.Vinna; public  class  VinnApp  extends  Vinna  {        @Override        protected  void  routes(Map<String,  Object>  config)  {                get("/").withController(HelloController.class).index();                get("/hello/{name}").withController(HelloController.class).sayHello(                                param("name").asString(),                                req.param("ohai").asString()                );        } } Thursday, 23 May, 13
  16. Ze même contrôleur package  vinna.controllers; import  vinna.response.Response; import  vinna.response.StringResponse; public

     class  HelloController  {        public  Response  index()  {                return  new  StringResponse("Go  to  /hello/{your  name}  for  a  free  hug  !");        }        public  Response  sayHello(String  name,  String  ohai)  {                return  new  StringResponse(String.format("%s  %s  !",  (ohai  ==  null  ?  "Ohai"  :  ohai),  name));        } } Thursday, 23 May, 13
  17. Une simple interface package  vinna.response; import  vinna.http.VinnaRequestWrapper; import  vinna.http.VinnaResponseWrapper; import

     javax.servlet.ServletException; import  java.io.IOException; public  interface  Response  {        public  void  execute(VinnaRequestWrapper  request,                                                VinnaResponseWrapper  response)                        throws  IOException,  ServletException; } Thursday, 23 May, 13
  18. Vinna fournit un builder ResponseBuilder.withStatus(404)        .addHeader("X-­‐Where",  "Zlocalhost")

           .cookie(new  Cookie("zcookie",  "zvalue"))        .etag("24674U75I8673")        .type("application/technozaure"); Thursday, 23 May, 13
  19. exemple: base.html <html> <head>        <meta  charset="utf-­‐8">  

         <title>Todorods</title>        <link  href="{{contextPath}}/css/bootstrap.min.css"  rel="stylesheet"> </head> <body> <div  class="container">        {%  block  content  %}        {%  end  %} </div> </body> </html> Thursday, 23 May, 13
  20. exemple : list.html {%  extends  base.html  %} {%  block  content

     %} <h1>TODO  list</h1> <table  class="table  table-­‐bordered  table-­‐striped">        <thead>        <tr>                <th>Title</th>                <th>Description</th>        </tr>        </thead>        <tbody>        {%  for  todos  %}        <tr>                <td>{{  title  }}</td>                <td>{{  description  }}</td>        </tr>        {%  end  %}        </tbody> </table> <hr/> <a  class="btn  btn-­‐primary"  href="new">Create</a> {%  end  %} Thursday, 23 May, 13
  21. exemple : create.html {%  extends  base.html  %} {%  block  content

     %} <h1>TODO</h1> <form  class="form-­‐horizontal"  method="post"  action="new">        <legend>Create  a  new  todo:</legend>        <fieldset>                <div  class="control-­‐group  {%  if  firstErrors.title  %}  error{%  end  %}">                        <label  class="control-­‐label"  for="title">Title</label>                        <div  class="controls">                                <input  type="text"  class="input-­‐xlarge"  id="title"  name="title"  value="{{title}}"/>                                {%  if  firstErrors.title  %}                                <span  class="help-­‐inline">{{firstErrors.title}}</span>                                {%  end  %}                        </div>                </div>                ...                <div  class="control-­‐group">                        <div  class="controls">                                <button  type="submit"  class="btn  btn-­‐primary">Create</button>                        </div>                </div>        </fieldset> </form> {%  end  %} Thursday, 23 May, 13
  22. Et bien plus de fonctionnalités, mais on a plus le

    temps là ... Thursday, 23 May, 13
  23. Exemples (déclaratif) GET    /css/bootstrap.min.css  pass GET    /**/*.js  pass

    GET    /        TodoController.list() GET    /new  TodoController.create() POST  /new  TodoController.create({req.param.title},  {req.param.debug}) req.param.debug:  true|false GET  /api/{id}  ApiTodoController.show({id})        id:  \d+ POST  /api  ApiTodoController.create(JacksonArgument) GET  /create  TodoController.create(TodoParameter) GET  /resource  Controller.get({req.header.ETag}) Thursday, 23 May, 13
  24. Exemples (programmatique) get("/css/bootstrap.min.css").pass(); get("/").withController(TodoController.class).list(); get("/new").withController(TodoController.class).create(); post("/new").withController(TodoController.class).create(        

           req.param("title").asString(),   req.param("description").asString()); get("/api").withController(ApiTodoController.class).list(); get("/api/{id:  \\d+}").withController(ApiTodoController.class)                .show(param("id").asLong()); post("/api").withController(ApiTodoController.class)                .create(custom(JacksonArgument.class).<Todo>asT()); get("/create").withController(TodoController.class).                create(custom(TodoParameter.class).asTodo()); Thursday, 23 May, 13
  25. De base Validation  validation  =  new  Validation(); validation.required(title,  "title").required(description,  "description");

    if  (validation.hasErrors())  {        return  new  CreateView(title,  description,  validation); } Thursday, 23 May, 13
  26. Avec JSR-303 public  class  Todo  {        private

     Long  id;        @NotNull        @Size(min  =  2,  max  =  128)        private  String  title;        @NotNull        @Size(max  =  512)        private  String  description; : : Validation  validation  =  new  Validation().validate(todo); if  (!validation.hasErrors())  {        :        : } Thursday, 23 May, 13
  27. Projet sur GitHub github.com/jawher/vinna • haklop, aka Éric • lpereir4,

    aka Lucien • jawher, aka Jawher Starring Thursday, 23 May, 13