打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
再说Play!framework
企业应用
这篇帖子的内容我本来想发到http://www.iteye.com/topic/806660这里的主贴里去的,想挽回被隐藏的命运,但我写完本贴的内容,却发现为时已晚。好吧,我承认,上一个贴的标题容易引发口水,这次我们实事求是,从代码出发,通过一个小例子较完整的介绍play!framework的开发过程:
就拿play!framwork自带的房间预订(booking)的例子吧:
1、 下载play  解压,配置环境变量
2、 打开命令行:转到合适的目录,输入Play new booking   这样,项目即生成完毕。
3、     进入项目目录中,执行play eclipsify  或者play netbeansify  这样即可将生成的项目导入到eclipse或者netbeans中。
打开项目目录我们可以看到:
解释下各个目录:
app 包含所有的model,controller以及view(模板)。
conf下是一个application.conf 配置文件。
lib是Play依赖的第三方jar。
logs是日志
public下包含你引用的js,css以及,images等。
test下所有的测试文件在此。
这样的一个目录显然与传统的JEE目录完全不一样,事实上,它已经摒弃了servlet,jsp那些东西,而完全自己实现了HTTP,您会问,那它是不是无法正常运行于标准的servlet容器中,请不要担心,我们在开发完成后可以使用命令play war –odir  这个命令生成可以正常运行于servlet容器中的项目目录。
Play分为开发模式和生产模式两种,而切换的配置在application.conf中:
Application.mode=dev 生产模式请改为:prod
主要区别在于开发模式中您无需重启server,每次请求都会查看是否有文件发生改变,改变即编译,这对于传统Java EE开发人员无疑是相当敏捷的。而这种方式同样会导致性能下降,所以生产模式中就不会这样了,而是采用预编译机制。
下面开始coding:
按照OO的开发模式 首先编写模型层:
在app包下新建类Hotel.java 继承Model ,如下:
Java代码
@Entity
public class Hotel extends Model {
@Required
public String name;
public String address;
public String city;
…..省略部分字段
@Column(precision=6, scale=2)
public BigDecimal price;
public String toString() {
return "Hotel(" + name + "," + address + "," + city + "," + zip + ")";
}
}
其中继承Model基类实现了一个富血的Domain Model(这不是比传统的PO更加OO ?),完全基于JPA,上手非常简单
同样Booking类:
Java代码
@Entity
public class Booking extends Model {
@Required
@ManyToOne
public User user;
@Required
@ManyToOne
public Hotel hotel;
@Required
@Temporal(TemporalType.DATE)
public Date checkinDate;
@Required
@Temporal(TemporalType.DATE)
public Date checkoutDate;
@Required(message="Credit card number is required")
@Match(value="^\\d{16}$", message="Credit card number must be numeric and 16 digits long")
public String creditCard;
@Required(message="Credit card name is required")
public String creditCardName;
public int creditCardExpiryMonth;
public int creditCardExpiryYear;
public boolean smoking;
public int beds;
public Booking(Hotel hotel, User user) {
this.hotel = hotel;
this.user = user;
}
public BigDecimal getTotal() {
return hotel.price.multiply( new BigDecimal( getNights() ) );
}
public int getNights() {
return (int) ( checkoutDate.getTime() - checkinDate.getTime() ) / 1000 / 60 / 60 / 24;
}
public String getDescription() {
DateFormat df = DateFormat.getDateInstance(DateFormat.MEDIUM);
return hotel==null ? null : hotel.name +
", " + df.format( checkinDate ) +
" to " + df.format( checkoutDate );
}
public String toString() {
return "Booking(" + user + ","+ hotel + ")";
}
}
User类 类似,不再给出。
编写Controller  在controller包中编写类:Hotels  继承Controller(这儿Application继承Controller)
Java代码
public class Hotels extends Application {
@Before//拦截器
static void checkUser() {
if(connected() == null) {
flash.error("Please log in first");
Application.index();
}
}
public static void index() {
List<Booking> bookings = Booking.find("byUser", connected()).fetch();//这句是不是更加面向对象?
render(bookings);
}
public static void list(String search, Integer size, Integer page) {
List<Hotel> hotels = null;
page = page != null ? page : 1;
if(search.trim().length() == 0) {
//分页的代码是不是很简单?链式调用更加方便
hotels = Hotel.all().fetch(page, size);
} else {
search = search.toLowerCase();
hotels = Hotel.find("lower(name) like ? OR lower(city) like ?", "%"+search+"%", "%"+search+"%").fetch(page, size);
}
render(hotels, search, size, page);
}
public static void book(Long id) {
Hotel hotel = Hotel.findById(id);
render(hotel);
}
public static void confirmBooking(Long id, Booking booking) {
Hotel hotel = Hotel.findById(id);
booking.hotel = hotel;
booking.user = connected();
validation.valid(booking);
// Errors or revise
if(validation.hasErrors() || params.get("revise") != null) {
render("@book", hotel, booking);
}
// Confirm
if(params.get("confirm") != null) {
booking.save();
flash.success("Thank you, %s, your confimation number for %s is %s", connected().name, hotel.name, booking.id);
index();
}
// Display booking
render(hotel, booking);
}
public static void saveSettings(String password, String verifyPassword) {
User connected = connected();
connected.password = password;
validation.valid(connected);
validation.required(verifyPassword);
validation.equals(verifyPassword, password).message("Your password doesn't match");
if(validation.hasErrors()) {
render("@settings", connected, verifyPassword);
}
connected.save();
flash.success("Password updated");
index();
}
上面的代码中展示了
1.@before 这个注解基本就是个拦截器的意思,所有访问这个Controler方法的请求都会先执行@before方法。
2、controller中的几个作用域:
1、session这儿的session只支持您放里面放String类型,而不是和传统JEE中任何对象都可以放到session中。这儿的session和rails的类似。
2、flash 跨请求的存储对象
3、params  基本相当于request.getParameters();
4、renderArgs  渲染到模板的数据,上面代码中您看到的render里面的就是放到了这个renderArgs里面了。还有个validation存放验证数据。
基类Controller里定义了很多好用的方法:如果您想使用ajax返回JSON,则使用renderJSON()  play使用的json序列化工具是gson.jar,您想返回一个文件流,使用renderBinary(File f,String name)方法。
上面没有展示文件上传的代码:我再贴一个文件上传的代码:
Java代码
public static void save(Picture picture,File pic){
File uploadFile=new    File(Play.applicationPath.getAbsoluteFile()+”/public/uploads”);
play.libs.Files.copy(pic,uploadFile);
picture.url =path;
picture.save();
QZ_Admin.pictures();
}
其它的Controller不再给出
这儿会有同学问,我没有配置和URL映射规则啊。事实上,play借鉴rails默认大于配置的思想,默认的映射规则是/Controller/method?params  这种。当然您也可以在配置文件routes中重新设定您所需要的映射规则。同时模板的位置默认也和Controller的名字有很大关系,比如这人我们Controller的名字叫Hotels  方法名是Index  那如果您不指定渲染模板的话默认play会去views 下面的Hotels文件夹下找index.html模板。这种约定是不是限制了很多东西?会不会对开发造成一些影响,我个人认为是有的,由于和Controller,method的名字关系密切,这需要你良好的规划,以保证你的项目目录的合理,以及URL的优雅。
最后是编写模板:
在views  下面建立文件夹 Hotels  新建文件index.html
Java代码
#{extends 'main.html' /}///在views文件夹下面编写main.html一般为网站所有页面的公共部分,比如header和footer
#{set title:'Search' /}//为每一个页面设置title  在Main.html有变量title
<table>
<thead>
<tr>
<th>Name</th>
<th>Address</th>
<th>City, State</th>
<th>Check in</th>
<th>Check out</th>
<th>Confirmation number</th>
<th>Action</th>
</tr>
</thead>
<tbody>
#{list bookings, as:'booking'}  //遍历
<tr>
<td>${booking.hotel.name}</td>
<td>${booking.hotel.address}</td>
<td>${booking.hotel.city},${booking.hotel.state}, ${booking.hotel.country}</td>
<td>${booking.checkinDate.format('yyyy-MM-dd')}</td>
<td>${booking.checkoutDate.format('yyyy-MM-dd')}</td>
<td>${booking.id}</td>
<td>
#{a @cancelBooking(booking.id)}Cancel#{/a}
</td>
</tr>
#{/list}
</tbody>
</table>
这样,一个简单的模板页面就编写完成了。Play的模板相较于jsp或者JSTL以及struts2标签啥的都更加简单,也没有freemarker 空指针异常(可能有童鞋喜欢这个)这些问题。具体其它的用法可以参看play的帮助文档。
以上基本上就把play的大体用法说完了,现在我再写下play其它让人心动的地方:
1、 缓存支持:
Java代码
2、  public static void showProduct(String id) {
3、      Product product = Cache.get("product_" + id, Product.class);
4、      if(product == null) {
5、          product = Product.findById(id);
6、          Cache.set("product_" + id, product, "30mn");
7、      }
8、      render(product);
9、  }
而您可以使用EhCache或者Memcached作为缓存的实现。使用起来非常方便
2、 JOB支持:
Java代码
3、  @Every("1h")
4、  public class Bootstrap extends Job {
5、
6、      public void doJob() {
7、          List<User> newUsers = User.find("newAccount = true").fetch();
8、          for(User user : newUsers) {
9、              Notifier.sayWelcome(user);
10、         }
11、     }
12、
13、 }
这段代码即会每1小时运行一次。
3、 Email支持:
Java代码
4、  Template t =TemplateLoader.load("UserCenter/mailTemplate.html");//邮件模板
5、  Scope.RenderArgs templateBinding = Scope.RenderArgs.current();
6、  templateBinding.put("url","http;//url"));
7、  String result =t.render(templateBinding.data);
8、  Mail.send("from@163.com", "to@163.com", "",result,"text/html")
以上即是使用模板发送邮件的例子。当然您需要在application.conf指定发邮件的一些参数
4、非常多的好用的module:比如支持lucene的search-module ,MongoDB module,GAE module,Excel Module,GWT Module,PDF Module等等。
以上大体介绍了play!framework的开发示例以及一些基本特点。大家可以讨论下你对Play!framework看法,但请勿鄙视一把走人,或者发表带有人身攻击的言论,谢谢!
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
Eclipse启动过程(源码级剖析)
Enterprise Java Community: JBoss Seam: A Deep Integration Framework
Effective java学习笔记1:考虑使用静态工厂方法代替构造方法
Java中使用Jedis操作Redis
【JAVA SE基础篇】20.类的定义,对象和类的关系,以及类的写法和调用
Play框架指南:配置你喜欢的IDE
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服