Mostrando entradas con la etiqueta play. Mostrar todas las entradas
Mostrando entradas con la etiqueta play. Mostrar todas las entradas
Play + Bootstrap + Dates
First of all, I hate HTML date input fields, because they're so broken when you start playing with different formats for different locales, and HTML5 input=date doesn't help either since not all browsers implement this and in case of Google's Chrome, it's so ugly that you won't use it.
To try to cope with this I'm using this date picker for Bootstrap which handles things pretty well until you hit a wall with how Play handles form data for dates. Basically, the problem is that even if your form class has a Date field and you registered a custom formatter as explained here, the Date value is not formatted when the template is rendered. Some code to explain
public class MyForm {
public LocalDate myDate;
}
In the controller you would have something like:
MyForm myForm = new MyForm();
myForm.myDate = new LocalDate();
return ok(
views.html.somePage.render(
form(MyForm.class).fill(myForm)
)
);
If you try to use the value from this form you'll see that it follows the ISO format yyyy-MM-dd, which is fine, until you're asked for this field to follow specific locale formats like dd/mm/yyyy or mm/dd/yyyy.
To fix this I've created my own implementation of the inputDate template:
Play 2.1 Modules and Maven Dependencies
For a new project we've decided to use the new "modules" feature which Play 2.1 brings to the framework. But, to be able to set our local maven repositories, it seems you have to do it for all sub-modules. So, in the parent's Build.scala file you should use something like:
With this you set all modules to use the same repositories, including the local maven repository.
With this you set all modules to use the same repositories, including the local maven repository.
A Play Framework server setup
What a wonderful surprise was that Play 2.0.x can't be deployed to application servers. Yes, there's a plugin, but I'm not really fond on depending in some guy's project for my business critical applications and the generated WAR wasn't really helpful since you still need to run a different instance of your application server for each Play application because you can only deploy to root ("/") and not as a specific path ("/myapp/").
Netty, although I don't get the whole .io domains thing, is what the guys at Play decided to use, so, for those of you who use Apache HTTP you can drop the AJP plugin and install the proxy_mod and proxy_http_mod.
When setting up a server, be it Tomcat, JBoss or Glassfish, my main target is flexibility and ease of configuration. I hate having to modify 30 different logger.xml files because some guy doesn't know about symlinks, or having to perform 30 manual operations to perform a release. Also, the start/stop process has to be as easy and centralized as possible since you never know who is the guy restarting your cluster at 4:00am is. Finally, deployments have to be as light and fast as possible.
With those objectives in mind, this is what I came up with:
There are two tricky parts here: creating the startup scripts with the correct classpath and separating Play's jar files from yours. Since my projects dependencies were few it was easy to simply copy them over from the target/stage folder. Another solution is to generate an empty Play application, run the stage option and copy the files generated there.
The startup scripts, however you do them, you have to provide the correct options to Java:
This will work with JDK 6 and JDK 7 which are the only ones which support this classpath definitions. Since we're running many Play instances, we need to provide different ports with the http.port options. To configure Play to use our common application.conf (which holds the configuration for the database connection) we use the config.file options. Finally, to provide different logger configurations to Logback we use the logger.file option.
What is accomplished by this setup:
Netty, although I don't get the whole .io domains thing, is what the guys at Play decided to use, so, for those of you who use Apache HTTP you can drop the AJP plugin and install the proxy_mod and proxy_http_mod.
When setting up a server, be it Tomcat, JBoss or Glassfish, my main target is flexibility and ease of configuration. I hate having to modify 30 different logger.xml files because some guy doesn't know about symlinks, or having to perform 30 manual operations to perform a release. Also, the start/stop process has to be as easy and centralized as possible since you never know who is the guy restarting your cluster at 4:00am is. Finally, deployments have to be as light and fast as possible.
With those objectives in mind, this is what I came up with:
$tree /home/play |-- bin | |-- all (script to start/stop all applications) | |-- play (script to start/stop the foo applications) | |-- deploy (script to deploy the applicationa) |-- etc | |-- application.conf (common Play configuration file used by all applications) | `-- logger.xml (common Logger configuration file used by all apps) |-- lib | |-- 2.0.2 | | |-- akka-actor.jar | | |-- akka-slf4j.jar | | |-- ... | | `-- xml-apis.jar | |-- 2.0.3 | | |-- akka-actor.jar | | |-- akka-slf4j.jar | | |-- ... | | `-- xml-apis.jar| `-- play -> lib |-- logs (Folder for log files from the different applications) | |-- foo.log | |-- bar.log | `-- api.log `-- webapps (Folder which contains our applications) |-- bar | |-- 0.1-SNAPSHOT | | |-- joda-time-2.1.jar | | |-- foo_2.9.1-1.0-SNAPSHOT.jar | | |-- foo-common-0.1-SNAPSHOT.jar | `-- current -> 0.1-SNAPSHOT |-- api | |-- 0.1-SNAPSHOT | | |-- joda-time-2.1.jar | | |-- foo-api_2.9.1-1.0-SNAPSHOT.jar | | |-- foo-common-0.1-SNAPSHOT.jar | `-- current -> 0.1-SNAPSHOT `-- foo |-- 0.1-SNAPSHOT | |-- joda-time-2.1.jar | |-- foo-common-0.1-SNAPSHOT.jar | |-- foo-bar_2.9.1-1.0-SNAPSHOT.jar `-- current -> 0.1-SNAPSHOT |
There are two tricky parts here: creating the startup scripts with the correct classpath and separating Play's jar files from yours. Since my projects dependencies were few it was easy to simply copy them over from the target/stage folder. Another solution is to generate an empty Play application, run the stage option and copy the files generated there.
The startup scripts, however you do them, you have to provide the correct options to Java:
This will work with JDK 6 and JDK 7 which are the only ones which support this classpath definitions. Since we're running many Play instances, we need to provide different ports with the http.port options. To configure Play to use our common application.conf (which holds the configuration for the database connection) we use the config.file options. Finally, to provide different logger configurations to Logback we use the logger.file option.
What is accomplished by this setup:
- Very Unix like structure (bin, logs, etc)
- Easy deploy (simply replace the current symlink)
- Easy patching (replace one of your jars and restart)
- Easy servers control (bash scripts)
Easily Secure your Play 2.0 Application
This is my first post about Play Framework. It's quite an interesting framework because of its dissociative identity disorder between Java and Scala. I'm liking it actually, except for two key things:
- The name (it's impossible to search stuff on the Net)
- The documentation (which brings us to this post)
- No IDE support for the Scala HTML stuff (at least in Eclipse Juno)
Nevertheless, it has some interesting stuff built in it like its MVC model based on annotations, the routes file, database evolution and those good looking TODO and error pages.
Authentication on Play!
After having some forms ready I got to the point of authentication, and lucky me (and for this blog) there's nothing, nada, niet, in Play's documentation about this. But, when you download Play 2.0.x you get a folder with samples for Java and Scala which I recommend because it's very useful. In this case the Zentasks project has a good starting point for understanding authentication in Play.
You can start with the plain application generated by play, run it and test that you get that nice welcome page that Play generates.
Then generate these files:
- Secured.java (auth)
- User.java (model)
- Authentication.java (controller)
- LoginForm.java (view)
Here's all the code:
The User model (1-12) will be responsible of persisting our authentication data (email, password, etc) and it's a standard JPA annotated class
Note here that we are not extending from play.db.ebean.Model nor we are using Play constraint annotations because in this example I wanted to also show that it's possible to use standard JPA entities. This means that our models can live outside of Play in a separate JAR with no dependencies to any ORM so we can reuse our models from different applications with different ORMs (at the moment I was testing with using Ebean or Hibernate for our project) or even with plain JDBC.
The LoginForm (14-30) class is bind to our form in the login.scala.html view:
The validate() method (25) is important because Play uses Spring to validate the forms data. In this case the validation is being done by Play's Constraints annotations and we use the method to authenticate the user.
You could also implement the org.springframework.validation.Validator interface if that makes you feel more confident.
The login.scala.html is a simple HTML form with the binding to the LoginForm (full package name)
The Authentication controller (32-70) is the responsible of handling the actions associated to authentication: login (34) and logout (62); and provides the authentication method (53).
The Secured class (72-83) will handle authentication specific logic, like what to do with unauthenticated users.
This class is a good place to add groups or profiles specific methods like isOwner or isMember.
And finally, edit your routes file to reflect the new controller
# Home page
GET / controllers.Application.index()
# Authentication
GET /login controllers.Authentication.login()
POST /login controllers.Authentication.authenticate()
GET /logout controllers.Authentication.logout()
Oh! And of course you have to configure your datasource to use the H2 database. Now restart the whole thing and when you go to http://localhost:9000/ you'll be redirected to http://localhost:9000/login and to logoff go to http://localhost:9000/logout
Common Models
One final note on having the models in a different JAR. For this example I created a maven project called common-models where all the persistence models and their tests are contained separately from the main Play application. To be able to add this project as a dependency to play, the Build.scala file should have something like:
val appDependencies = Seq(
"com.play" % "common-models" % "0.1-SNAPSHOT",
)
val main = PlayProject(appName, appVersion, appDependencies, mainLang = JAVA).settings(
resolvers += "Local Maven Repository" at "file:///"+Path.userHome.absolutePath+"/.m2/repository/"
)
And your application.conf ORM configuration should have something like:
db.default.driver=org.h2.Driver
db.default.url="jdbc:h2:mem:play"
db.default.user=sa
db.default.password=''
ebean.default="com.play.models.*"
In the common-models project I have the structure of the models as:
com.play.models.AbstractEntity
com.play.models.auth.User
com.play.models.auth.Profile
com.play.models.store.Location
com.play.models.store.Store
Just so you get the idea.
Suscribirse a:
Entradas (Atom)