Scala Lift Framework Overview
Introduction
Lift is considered one of the most complex and at the same time powerful web frameworks existing at the moment (albeit little known), largely because it actively uses the functionality of the Scala language. To study it you need to make a lot of effort. But it's worth it, if only because it is very different from standard MVC frameworks and knowledge of alternative technologies will expand your horizons.
In this article I will talk about the main features of this framework.
View first
Probably the most important feature is the View First concept. This means that the View (XML template) is the entry point to your application (unlike traditional methods, where the controller is the entry point). Scala-code is not embedded in the View (in Lift - it is impossible to write logic on the page), but it is called from the template. Thanks to the View First concept, each element (form, search field, chat, list of something, etc.) can be completely isolated from the others in a separate snippet. This greatly reduces the connectedness of components and makes it easy to reuse them in other parts of the site.
This is how the snippet responsible for the logic of the form looks like:
class Snippet = {
def form_elements = {
var textValue: String = ""
var selectValue: String = ""
def process() {
println(textValue)
println(selectValue)
}
// SHtml.onSubmit - привязывает к определнному элементу формы функцию, которая будет вызываться на сервере при сабмите формы. Функция принимает значение поля и делает с ним какую-либо логику.
"#textField" #> SHtml.onSubmit(value => textValue = value) &
"#selectField" #> SHtml.onSubmit(value => selectValue = value) &
"#hidden" #> SHtml.onSubmitUnit(process) // hidden элемент нужен для вызова функции process()
}
}
And the template:
Selectors
I also want to say a few words about the method of "linking" server variables with View. For this, the selector mechanism is used, which is very similar to real css selectors. Here are a couple of examples:
Finding an element with id = “elemid” and setting its “class” attribute
def snippet = "#elemid [class]" #> "someclass"
using the & method you can combine multiple selectors
def snippet = {
"button [onclick]" #> Alert("some reaction") &
"button [class]" #> "someclass"
}
In order to pass XML to the method, which the selectors will change, you need to add the lift attribute to the corresponding tag (there are other ways, but I like this most), which indicates the snippet that will process this XML.
In my opinion, this is an ideally concise way of linking logic and representation. The view does not touch at all (only the lift tag is added), the logic in the snippet is read very easily. The designer only needs to not touch the lift tags.
Configuration
All configuration is done on Scala. This means that you do not need to implement 40% of your code in XML files to create a flexible configuration. This also means that the compiler will prompt you if you specified an invalid parameter in the configuration somewhere. This is very convenient when the project has a large and long configuration.
Security
The elevator guarantees protection against many common vulnerabilities according to OWASP . The funny thing is that you do not need to do anything for this, just write code in Lift. Here's what Rasmus Lerdorf (the person in charge of security at Yahoo) says about FourSquare (a project that is entirely written in Lift):
"Four stars to @foursquare - 1st site in a while I have taken a good look at that didn't have a single security issue (that I could find)"
twitter.com/rasmus/status/5929904263 .
This means that the developer does not need to worry about security and he can completely concentrate on the business logic.
Ajax Support
Here's how to implement a regular ajax button:
class Snippet {
def button = {
def process() = {
println("сохраняем что нибудь в базу на сервере");
Alert("алерт клиенту, что то успешно сохранено в базу")
}
"button [onclick]" #> SHtml.ajaxInvoke(process)
}
}
And xml template:
When a button is clicked, an ajax call will be made to the server, the process function will be called on the server and any javaScript reaction will be returned. Minimum code, maximum logic. This principle can be traced throughout the framework.
Comet Support
Lift has very good Comet support, which is practically the pride of the framework. Here's what a simple example of a watch will look like that is updated from the server every 10 seconds:
object Tick
class Clock extends CometActor {
Schedule.schedule(this, Tick, 10 seconds)
def render = "#time *" #> now.toString
override def lowPriority = {
case Tick =>
val js = SetHtml("time", Text(now.toString))
partialUpdate(js) // пушим js-код в браузер клиенту
Schedule.schedule(this, Tick, 10 seconds) // шедулим событие
}
}
Template
Thanks to the excellent support of comets, such complex things as delayed loading are implemented very simply. On the necessary content, you need to call the built-in snippet LazyLoad. At the same time, nothing needs to be changed in our snippet that creates the content.
какой-либо тяжелый контент, который будет подгружаться лениво
Snippet:
def lazy_content = {
Thread.sleep(3000) // задержка для наглядности
"div *" #> "я загрузилось на 3 секунды позже всей страницы"
}
Compactness
When you write on Lift, you write 2-3 times less code than if you wrote on a java framework (for example, one program copied your project from Play to Lift, on its implementation it took 24k lines, and on Lift 6k link ) . And if you compare with frameworks such as Spring MVC / Struts, then the difference will be even greater. Moreover, all code is statically typed.
Conclusion
I have described only a small part of the functionality. In one article, it is impossible to reveal all aspects of such a large framework. For those who want to dig deeper, here are the links:
liftweb.net - the main site
www.assembla.com/wiki/show/liftweb - wiki
exploring.liftweb.net/onepage - a book written by the author of the framework