Your SlideShare is downloading. ×
0
Play! Framework for JavaEE Developers
Play! Framework for JavaEE Developers
Play! Framework for JavaEE Developers
Play! Framework for JavaEE Developers
Play! Framework for JavaEE Developers
Play! Framework for JavaEE Developers
Play! Framework for JavaEE Developers
Play! Framework for JavaEE Developers
Play! Framework for JavaEE Developers
Play! Framework for JavaEE Developers
Play! Framework for JavaEE Developers
Play! Framework for JavaEE Developers
Play! Framework for JavaEE Developers
Play! Framework for JavaEE Developers
Play! Framework for JavaEE Developers
Play! Framework for JavaEE Developers
Play! Framework for JavaEE Developers
Play! Framework for JavaEE Developers
Play! Framework for JavaEE Developers
Play! Framework for JavaEE Developers
Play! Framework for JavaEE Developers
Play! Framework for JavaEE Developers
Play! Framework for JavaEE Developers
Play! Framework for JavaEE Developers
Play! Framework for JavaEE Developers
Play! Framework for JavaEE Developers
Play! Framework for JavaEE Developers
Play! Framework for JavaEE Developers
Play! Framework for JavaEE Developers
Play! Framework for JavaEE Developers
Play! Framework for JavaEE Developers
Play! Framework for JavaEE Developers
Play! Framework for JavaEE Developers
Play! Framework for JavaEE Developers
Play! Framework for JavaEE Developers
Play! Framework for JavaEE Developers
Play! Framework for JavaEE Developers
Play! Framework for JavaEE Developers
Play! Framework for JavaEE Developers
Play! Framework for JavaEE Developers
Play! Framework for JavaEE Developers
Play! Framework for JavaEE Developers
Play! Framework for JavaEE Developers
Play! Framework for JavaEE Developers
Play! Framework for JavaEE Developers
Play! Framework for JavaEE Developers
Play! Framework for JavaEE Developers
Play! Framework for JavaEE Developers
Play! Framework for JavaEE Developers
Play! Framework for JavaEE Developers
Play! Framework for JavaEE Developers
Play! Framework for JavaEE Developers
Play! Framework for JavaEE Developers
Play! Framework for JavaEE Developers
Play! Framework for JavaEE Developers
Play! Framework for JavaEE Developers
Play! Framework for JavaEE Developers
Play! Framework for JavaEE Developers
Play! Framework for JavaEE Developers
Play! Framework for JavaEE Developers
Play! Framework for JavaEE Developers
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×
Saving this for later? Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime – even offline.
Text the download link to your phone
Standard text messaging rates apply

Play! Framework for JavaEE Developers

19,488

Published on

Play! Framework for JavaEE Developers …

Play! Framework for JavaEE Developers
Presented in JavaTWO Taiwan @ Jul 29,2011

Published in: Technology, Education
2 Comments
35 Likes
Statistics
Notes
No Downloads
Views
Total Views
19,488
On Slideshare
0
From Embeds
0
Number of Embeds
5
Actions
Shares
0
Downloads
585
Comments
2
Likes
35
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide

Transcript

  • 1. JavaTWO專業技術大會<br />
  • 2. Play!Framework for JavaEE Developers<br />
  • 3. Who am I<br />Exp : JSP/Servlet , Tapestry , Spring/Hibernate/JavaEE , Wicket , Android , Grails , Play! Framework<br />http://gplus.to/smallufo<br />http://twitter.com/smallufo<br />smallufo@gmail.com<br />
  • 4. Web Framework Experiences<br /><ul><li>JSP/Servlet
  • 5. Too old , cumbersome
  • 6.  Tapestry (old experience, T5 is very good)
  • 7. Complicated , evolution/deprecation too fast
  • 8.  Wicket
  • 9. Too elaborate , fail to see the wood for the trees
  • 10. May lead to over-engineered architecture for OO-purism
  • 11. Spend too much time refactoring
  • 12. Maybe web component reuse is just a myth
  • 13. Grails (old experience, without Groovy++)
  • 14. Slow
  • 15. Too many inconsistent DSLs (URL-mapping , DB , logging...)
  • 16. Not Java , IDE unfriendly</li></li></ul><li>Conventional JavaEE Stack<br />
  • 17. Conventional JavaEE Stack<br /><ul><li>Want standard page ?
  • 18. Let&apos;s define JSP/JSTL (JSR-53)
  • 19. And let Apache (or others) to implement Jakata Taglibs
  • 20.  Want web components ?
  • 21. Let&apos;s define Java Server Faces (JSR-127)
  • 22. And let communities to implement MyFaces, PrimeFaces, ICEfaces...
  • 23. Want restful ?
  • 24. Let&apos;s define JAX-RS (JSR-311)
  • 25. And let communities to implement CXF, Jersey, RESTEasy, Wink...</li></li></ul><li>Conventional JavaEE Stack<br /><ul><li>Lots of ...
  • 26. Specs
  • 27. Implementations
  • 28. Configurations
  • 29. Tedious , Error-prone
  • 30. Unless you use a full-fledged JavaEE Server (Glassfish or WebLogic ...)
  • 31. Layered
  • 32. Defined by Standards/Specs
  • 33. Assembled by Interfaces</li></ul>OVER ARCHITECTED<br />
  • 34.
  • 35. Play’s App Looks Like ?<br />conf/routes<br />app/App.java<br />GET /hello App.hello<br />public class App extends Controller {<br /> public static void hello() {<br /> User user = User.findById(1L);<br /> render(user);<br /> }<br />} <br />views/App/hello.html<br />Hello World : ${user.name}<br />http://localhost:9000/hello<br />
  • 36. And Play is ...<br /><ul><li>A full stack framework (platform)
  • 37. Totally independent of JavaEE environment
  • 38. RESTful
  • 39. No session
  • 40. Stateless
  • 41. Pure server side
  • 42. Similar to Rails / Django
  • 43. Rich domain model
  • 44. Unlike JavaEE&apos;s anemic domain model</li></li></ul><li>Full Stack Framework?<br /><ul><li>Bundles compiler , embedded server , hibernate , logger , test runner , email , groovy template engine, scala...
  • 45. Can be packaged as a WAR and deployed to servlet containers</li></li></ul><li>Play! A Glued Pure Web Framework<br />Shallow!<br />Most libs are directly <br />exposed to Play! &amp; replaceable<br />Where Magic Happens<br />
  • 46. Play! URLs are RESTful &amp; SEO-friendly<br />UGLY<br />GRACEFUL<br /><ul><li>/car/1
  • 47. /listcar/page1/count10
  • 48. /listcar/page1?count=10
  • 49. /listcar/page/1/count/10
  • 50. /car.jsp?id=1
  • 51. /listcars.jsp?page=1&amp;count=10
  • 52. http://www.facebook.com/ photo.php? fbid=2121715487568&amp; set=o.172881386106136&amp; type=1&amp;theater</li></li></ul><li>Play is not based on Servlet<br />Many java server side frameworks (Spring MVC / Struts / Wicket / JSF / Tapestry ...) are based on servlets, but Play! is not!<br />You cannot do such things :<br /><ul><li>session.setAttribute(&quot;user&quot; , user); 
  • 53. Use HttpSessionListener to count sessions (online users)
  • 54. ServletFilter
  • 55. Servlet-related securities
  • 56.  @ServletSecurity
  • 57.  &lt;auth-constraint /&gt; , &lt;security-role /&gt;</li></li></ul><li>Play! is Stateless<br /><ul><li>Play! shares nothing between each request!
  • 58. The most important feature you have to keep in mind
  • 59. No session!
  • 60. Session is the source of all problems of the JavaEE platform!
  • 61. Session replication 
  • 62. Sticky session
  • 63. Play uses (delegates to) memcached to eliminates such headaches</li></li></ul><li>Play&apos;s Informative Error Page<br />
  • 64. Play&apos;s Domain Objects Are Rich<br />Play<br />*Spring promoted JavaEE<br />User extends Model<br />User extends Object<br />UserDao.java<br /><ul><li>save(User u)</li></ul>User u = new User(...)<br />u.save()<br />UserDaoImpl implements UserDao<br /><ul><li>void setEntityManager(...)
  • 65. save(User u)</li></ul>Client.java<br />@Inject UserDao userDao<br />User u = new User(...)<br />userDao.save(u)<br />VS<br />*JPA advocates eliminating the DAO layer<br />
  • 66. Play&apos;s Architecture<br />$ play new myproj<br />myproj<br />app<br />controllers<br />models<br />conf<br />application.conf<br />views<br />messages<br />lib<br />foo<br />routes<br />modules<br />bar<br />public<br />images<br />javascripts<br />src<br />stylesheets<br />
  • 67. conf/application.conf<br />application.name=myapp<br />application.mode=dev<br />application.secret=OOXXOOXXOOXXOOXXOOXX<br />http.port=9000<br />java.source=1.6<br />db.url=jdbc:mysql:...<br />db.driver=com.mysql.jdbc.Driver<br />db.user=user<br />db.pass=pass<br />hibernate.use_sql_comments=true<br />hibernate.format_sql = true<br />XForwardedSupport=127.0.0.1<br />
  • 68. Play&apos;s Architecture<br />controllers<br />app<br />MyController.java<br />public static void index()<br />public static void show()<br />models<br />views<br />MyController<br />index.html<br />foo<br />show.html<br />bar<br />
  • 69. conf/routes<br />HTTP method<br />URI Pattern<br />Action<br />GET    /                      App.index<br />POST   /login                 App.login<br />GET    /tag/{name}            App.tag(name)<br />GET    /list/{page}           App.list(page)<br />GET    /list/{&lt;[0-9]+&gt;page}   App.list(page)<br />GET    /list/{page}/{count}   App.list(page,count)<br />GET    /public/               staticDir:public<br />*      /{controller}/{action} {controller}.{action}<br />
  • 70. Play&apos;s Request Life Cycle<br />
  • 71. Controllers and Redirections<br />public class App extends play.mvc.Controller {<br />  public static void index() {<br />    render(); // views/App/index.html contains a login form<br />  }<br />  public static void login(String name,String passwd) {<br />    if(...) // success<br />      welcome();<br />    else   // failed<br />      index();<br />  }<br />  public static void welcome() {<br />    render();  // renders views/App/welcome.html <br />  }<br />}<br />
  • 72. Controller Interceptions<br />public class App extends play.mvc.Controller {<br />  @play.mvc.Before(unless={“index”, “login”})<br />  public static void intercept() {<br />    if (session.get(&quot;uid&quot;)==null) <br />      index();<br />  }<br />  public static void index() {...}<br />  public static void login(String name,Stringpasswd){..}<br />  public static void welcome() {...}<br />}<br />
  • 73. Session : A Signed Cookie<br />public static void login(String name , String passwd) {<br />  User u = ...<br />  if (...) {<br />    session.put(&quot;uid&quot; , u.id);<br />  }<br />}<br />Only put index data to session<br />Never store sensitive data<br />signed, <br />uneditable!<br />
  • 74. Controller Revisited<br />public static void show(Long uid, String type) {<br />  User u = ...<br />  if (type.equals(&quot;json&quot;) {<br />    renderJSON(u);   // provided by GSON<br />  } <br />  else if (type.equals(&quot;xml&quot;) {<br />    renderXml(u);    // provided by XStream<br />  } <br />  <br />  render(u);  <br />}<br />Why not continue rendering?<br />play.mvc.Controller<br />throw new RenderJson(jsonString);<br />throw new RenderXml(xml);<br />throw new RenderTemplate(...);<br />
  • 75. Controller and View<br />controllers/App.java<br />public static void showUser(Long uid) {<br />  User u = ...<br />  List&lt;Car&gt; cars = ...<br />  renderArgs.put(&quot;user&quot;,u);<br />  render(cars, company, job, ...);  <br />}<br />public static void showCar(Long id) {...}<br />renderArgs.put(“cars”,car);<br />renderArgs.put(“company”,company);<br />renderArgs.put(“job”,job);<br />same<br />views/App/showUser.html<br />Hello ${user.name} , these are your cars :<br />#{list items:cars , as:&apos;car&apos;}<br />  #{a @showCar(car.id)} ${car.name} #{/a}<br />#{/list}<br />template tag<br />@App.showCar(car.id)<br />
  • 76. How objects are passed to View !?<br />controllers/App.java<br />public static void showUser(Long uid) {<br />  renderArgs.put(&quot;user&quot;,u);<br />  render(cars , ...);  <br />}<br />!!??<br />views/App/showUser.html<br />${user.name}<br />#{list items:cars , as:&apos;car&apos;}<br />Let&apos;s decompile it...<br />
  • 77. public static void showUser(Long uid)<br />{<br />  play.classloading.enhancers.LocalvariablesNamesEnhancer.LocalVariablesNamesTracer.enter();<br />  play.classloading.enhancers.LocalvariablesNamesEnhancer.LocalVariablesNamesTracer.addVariable(&quot;uid&quot;, uid);<br />  if(!play.classloading.enhancers.ControllersEnhancer.ControllerInstrumentation.isActionCallAllowed())<br />  {<br />    Controller.redirect(&quot;controllers.App.showUser&quot;, new Object[] {<br />      uid<br />    });<br />  } else<br />  {<br />    play.classloading.enhancers.ControllersEnhancer.ControllerInstrumentation.stopActionCall();<br />    User u = (User)User.findById(uid);<br />    play.classloading.enhancers.LocalvariablesNamesEnhancer.LocalVariablesNamesTracer.addVariable(&quot;u&quot;, u);<br />    List cars = Car.all().fetch();<br />    play.classloading.enhancers.LocalvariablesNamesEnhancer.LocalVariablesNamesTracer.addVariable(&quot;cars&quot;, cars);<br />    Object obj = null;<br />    play.mvc.Scope.RenderArgs renderargs = null;<br />    renderargs = (play.mvc.Scope.RenderArgs)Java.invokeStatic(Desc.getType(&quot;Lplay/mvc/Scope$RenderArgs;&quot;), &quot;current&quot;);<br />    renderargs.put(&quot;user&quot;, u);<br />    render(new Object[] {<br />      cars<br />    });<br />  }<br />  break MISSING_BLOCK_LABEL_120;<br />  Exception exception;<br />  exception;<br />  Object obj1 = null;<br />  play.classloading.enhancers.LocalvariablesNamesEnhancer.LocalVariablesNamesTracer.exit();<br />  throw exception;<br />  Object obj2 = null;<br />  play.classloading.enhancers.LocalvariablesNamesEnhancer.LocalVariablesNamesTracer.exit();<br />  return;<br />}<br />
  • 78. Who Modifies My Code !?<br />Who ?<br /><ul><li>Play&apos;s custom classloader &amp; JDT &amp; javassist</li></ul>When ?<br /><ul><li>DEV mode : When you modify the code and reload the page
  • 79. PROD mode : App&apos;s start time</li></ul>How ?<br /><ul><li>At compile time , some classes are enhanced by play.classloading.enhancers.* (powered by javassist)
  • 80. ContinuationEnhancer
  • 81. ControllerEnhancer
  • 82. PropertiesEnhancer
  • 83. LocalvariablesNamesEnhancer, ...</li></ul>Impact ?<br /><ul><li>Rapid development time !</li></li></ul><li>View Template<br />object path<br />${objectname}<br />${object.property}<br />implicit objects<br />${params.userId}<br />${session.userId}<br />${request.userId}<br />built-in tags<br />#{if} ... #{/if} #{else}... #{/else}<br />#{list items:users , as:&apos;user&apos;}<br />  ${user.name}<br />#{/list}<br />#{a @App.showUser(user.id)} show user #{/a}<br />#{form @App.login() } ... #{/form}<br />
  • 84. Rich Domain Object Model<br />package models;<br />@javax.persistence.Entity<br />public class User extends play.db.jpa.Model {<br />  public String username;<br />  public String password;<br />}<br />Support JPA&apos;s annotations : @Column , @ManyToOne , @OneToMany ...<br />NO more getters &amp; setters... Great !<br />
  • 85. Rich Domain Object Model<br />BUT...<br />The underlayer is hibernate &amp; hibernate needs getter/setter<br />Again...<br />Who modifies my model ?<br />
  • 86. Rich Domain Object Model<br />In Fact...<br />    Your model still contains getter/setter , modified by Play&apos;s custom classloader &amp; JDT &amp; javassist<br />User.java<br />public String getUsername() {<br />  return &quot;overridden&quot;;<br />}<br />${user.username} will be ??<br />
  • 87. Rich Domain Object<br />User u = User.findById(1);<br />User u = User.find(&quot;byUsernameAndPassword&quot;, username , password).first();<br />User u = User.find(&quot;select u from User u where u.username = :username and u.password = :password&quot;)<br />  .bind(&quot;username&quot;,username)<br />  .bind(&quot;password&quot;,password)<br />  .first();<br />List&lt;User&gt; users = User.all().fetch();<br />User.em().createQuery(...);<br />
  • 88. Validations : Controller<br />#{form @App.login()}<br /> &lt;p&gt;<br />username<br /> &lt;input type=“text” name=“username” value=“${flash.username}” /&gt;<br /> &lt;span class=“error”&gt;#{error &apos;username&apos;/}&lt;/span&gt;<br /> &lt;/p&gt;<br /> &lt;p&gt;<br />password<br /> &lt;input type=“password” name=“password” value=“${flash.password}” /&gt;<br /> &lt;span class=“error”&gt;#{error &apos;password&apos;/}&lt;/span&gt;<br /> &lt;/p&gt;<br /> &lt;input type=&quot;submit&quot; value=“Login&quot; /&gt;<br /> &lt;span class=“error”&gt;#{error ‘other&apos;/}&lt;/span&gt;<br />#{/form}<br />username<br />請輸入帳號<br />password<br />請輸入密碼<br />Login<br />帳號或密碼輸入錯誤<br />
  • 89. Validations : Controller<br />public static void login(<br />@Required(message =&quot;請輸入帳號&quot;)String username, <br />@Required(message =&quot;請輸入密碼&quot;)String password) {<br /> User user = User.login(username , password);<br /> if (validation.hasErrors()){<br /> params.flash(); // add parameters to flash scope<br /> validation.keep(); // keeps the errors<br /> flash.error(validation.errors().get(0).toString());<br /> render(“pleaseLogin.html”);<br /> }<br /> flash.success(“welcome : “ + user.username);<br /> render();<br />}<br />
  • 90. Validation : Model<br />public class User extends Model {<br />@Required @MinSize(6)<br /> public username;<br />@Required @MinSize(6)<br /> public password;<br /> public static User login(String username , String password) {<br /> Validation validation = Validation.current();<br /> User user = ...<br /> validation.isTrue(user!=null)<br /> .key(“other”).message(“帳號或密碼輸入錯誤”);<br /> return user;<br />}}<br />Will @MinSize affect login() ?<br />
  • 91. Validations<br />@Required , @Min , @Max , @MinSize , @MaxSize , @Range , @Email , @URL ...<br />Custom validation annotation<br />extends AbstractAnnotationCheck &amp; implements isSatisfied()<br />i18n messages<br />/conf/messages<br />
  • 92. Cache<br />Conventional JavaEE&apos;s Way<br />public User getUser(String name) {<br />  Session s = (Session)em.getDelegate();<br />  Criteria c = s.createCriteria(User.class);<br />  c.add(Restrictions.eq(&quot;username&quot;,name);<br />  c.setMaxResults(1);<br />  c.setCacheable(true);<br />  if (c.uniqueResult() == null)<br />    return null;<br />  return (User) c.uniqueResult();<br />}<br />
  • 93. Cache<br />Play&apos;s Way : Not In Favor of 2nd Level<br />public static User getUser(String name) {<br />  String key=&quot;username_&quot;+name;<br />  User user = Cache.get(key,User.class);<br />  if (user != null)<br />    return user;<br />  user = User.find(&quot;byUsername&quot;,name).first();<br />  Cache.set(key,user,&quot;30mn&quot;);<br />  return user;<br />}<br />
  • 94. Cache - Problem !<br />User.java {<br />  public static User getUser(Long id) {<br />    String key = &quot;userId_&quot;+id;<br />    ...<br />  }<br />  public static List&lt;User&gt; getUsers(Long page, int cnt) {<br />    String key=&quot;users_&quot;+page+&quot;_&quot;+cnt;<br />    ...<br />  }<br />}<br />public interface UserDao.java {<br /> public User getUser(Long id);<br /> public List&lt;User&gt; getUsers(Long page, int cnt);<br />}<br />
  • 95. Conventional JavaEE&apos;s Way<br />User u1 = userDao.getUsers(1,10).get(0);<br />User u2 = userDao.get(1L);<br />assertTrue(u1.equals(u2)); // PASSED<br />u2.modifySomething(...);<br />userDao.save(u2);<br />User u3 = userDao.getUsers(1,10).get(0);<br />assertTrue(u3.equals(u2)); // PASSED<br />Play&apos;s Way<br />User u1 = User.getUsers(1,10).get(0);<br />User u2 = User.getUser(1L);<br />assertTrue(u1.equals(u2)); // PASSED<br />u2.modifySomething(...);<br />u2.save();<br />User u3 = User.getUsers(1,10).get(0);<br />assertTrue(u3.equals(u2)); // FAILED!<br />
  • 96. Cache Problem : Reason <br />users_1_10<br />cache key :<br />TIME<br />u<br />u<br />u<br />u<br />u<br />u<br />u<br />u<br />u<br />u<br />u1<br />userId_1<br />cache key :<br />u<br />modified / updated<br />u2<br />users_1_10<br />cache key :<br />?<br />u<br />u<br />u<br />u<br />u<br />u<br />u<br />u<br />u<br />u3<br />
  • 97. Cache - Problem! How to Solve It ?<br /><ul><li>Ignore it , accept it
  • 98. Never cache sensitive data
  • 99. Two phase list retrieval
  • 100. Cache object ids instead of objects</li></ul>public static List&lt;User&gt; getUsers(Long page, int cnt) {<br />  String key=&quot;users_&quot;+page+&quot;_&quot;+cnt;  <br />  List&lt;Long&gt; userIds = <br />    User.find(&quot;select u.id from User u)<br />    .fetch(page,cnt);<br />  Cache.set(key, userIds, &quot;1mn&quot;);<br />  // iterate each id in result and query cache or fetch<br />}<br />
  • 101. Cache : Wait... I saw Model.em() ? <br />How about get underlaying Hibernate’s session and setCacheable(true) ?<br />Session s = (Session) User.em().getDelegate();<br />Critieria c = s.createCriteria(...);<br />c.add(... criterions ... );<br />c.setCacheable(true);<br />
  • 102. Play&apos;s Module System<br />
  • 103. Module : CRUD<br />package models;<br />public class User extends Model { ... }<br />package controllers;<br />public class Users extends CRUD { ... }<br />Cars , Photos , Logs<br />even ...<br />Boxs , Buss, Kisss<br />
  • 104. Module GAE + Module Siena<br />public class User extends siena.Model { <br />  public String uid;<br />  public static User getUser(String uid) {<br />    return User.all(User.class).filter(&quot;uid&quot;,uid).get();<br />  }<br />  public static User getUsers(int page , int count) {<br />    return User<br />      .all(User.class)<br />      .fetch(count,(page-1)*count);<br />  }<br />}<br />Don&apos;t forget war/WEB-INF/appengine-web.xml<br />$ play gae:deploy <br />Done !<br />
  • 105. Play on GAE<br /><ul><li>Simplest way to deploy Java Apps on GAE !
  • 106. Shortest cold start time
  • 107. Less than 10 seconds
  • 108. Cache is wrapped to GAE&apos;s memcache
  • 109. Mail is wrapped to GAE&apos;s mail service</li></li></ul><li>Issue : Portal-like Page<br /><ul><li>Many blocks query DB in every page
  • 110. Passing these query results in every action is cumbersome
  • 111. Solution : @Before and renderArgs.put()</li></ul>@Before<br />static void addDefaults() {<br />  renderArgs.put(&quot;brands&quot;, Brand.all().fetch());<br />  renderArgs.put(&quot;forums&quot;, Forum.getAll()); <br />  renderArgs.put(&quot;tags&quot; , Tag.getAll());<br />}<br />
  • 112. Issue : High Availability<br />&lt;VirtualHost *:80&gt;<br /> ServerName myapp.com<br /> &lt;Location /balancer-manager&gt;<br />  SetHandler balancer-manager<br />  Order Deny,Allow<br />  Deny from all<br />  Allow from .myapp.com<br /> &lt;/Location&gt;<br /> &lt;Proxy balancer://mycluster&gt;<br />   BalancerMember http://localhost:9002<br />   BalancerMember http://localhost:9003 status=+H<br /> &lt;/Proxy&gt;<br /> &lt;Proxy *&gt;<br />   Order Allow,Deny<br />   Allow From All<br /> &lt;/Proxy&gt;<br /> ProxyPreserveHost on<br /> ProxyPass /balancer-manager !<br /> ProxyPass / balancer://mycluster/<br /> ProxyPassReverse / http://localhost:9002/<br /> ProxyPassReverse / http://localhost:9003/<br />&lt;/VirtualHost&gt;<br />Apache Web Server<br />localhost:9002<br />localhost:9003<br />Same directory structures &amp; application.secret , only different http.port<br />
  • 113. Issue : Action Burst<br />controllers/App<br />controllers/App<br />login()<br />logout()<br />register()<br />myaccount()<br />mybooks()<br />index()<br />page()<br />search()<br />showbook()<br />login()<br />logout()<br />register()<br />myaccount()<br />mybooks()<br />index()<br />page()<br />search()<br />showBook()<br />listUsers()<br />editUser()<br />editBook()<br />controllers/Admin<br />listUsers()<br />editUser()<br />editBook()<br />
  • 114. Issues : Validation Dilemma<br />Validation in controllers ?<br />validation in models ?<br />or hybrid ?<br />
  • 115. Issue : DI<br />Dependency Injection is not so useful in Play’s Rich Domain Object environment<br />
  • 116. Case Study : VAGTW.COM<br />VW/Audi Car Problem Stats<br />
  • 117. vagtw.com Data Model<br />
  • 118. VAGTW.com development<br /><ul><li>Dev in one month (Since 2010/4/1)
  • 119. Modified from Play&apos;s YABE sample
  • 120. 10 days learning Play! &amp; modeling &amp; coding
  • 121. 20 days tuning HTML &amp; CSS(3)
  • 122. 2010/5/1 Debut
  • 123. Peak 4x users in 15 mins
  • 124. Indexed by Google in 2 days
  • 125. Indexed by Yahoo in 2 weeks
  • 126. Indexed by Bing after 2 months</li></li></ul><li>Conclusions<br />IS ...<br /><ul><li>A Glued Pure Web Framework
  • 127. Loose
  • 128. Shallow
  • 129. non-Standardized
  • 130. Page-based
  • 131. Stateless</li></ul>IS-NOT ...<br /><ul><li>A Java library
  • 132. Full-Fledged JavaEE stack
  • 133. Standard
  • 134. Strict
  • 135. Defined-assembled by interfaces
  • 136. Component-based
  • 137. Stateful (Session-aware)</li></li></ul><li>Conclusions : Use Play! If You...<br />Have to prototype or build something quickly<br />Don’t want to buy high-priced Java application servers<br />Are not so OO-purism, feel OK without interfaces<br />Many Play’s “hook” are not enforced by abctract mathods or interfaces<br />Know JavaScript &amp; other JS frameworks<br />You can build slick UIs without sluggish server-state implementation responses (Wicket/JSF...)<br />Feel OK about object inconsistences in cache<br />Want to develop GAE apps<br />Your team have a strong mendiator<br />Because programming in play is too unrestrained<br />Want to learn Scala<br />
  • 138. 小心<br />回不去了<br />

×