Premiers pas avec appserver.io : Installation, servlets et templates
Posté le Friday 14 August 2015 | Catégories : appserver.io, Linux, Ubuntu
appserver.io est un serveur web écrit en PHP, et conçu spécifiquement pour les grosses applications web PHP.
Il intègre dans ce but une série de fonctionnalités inédites:
- Entièrement multi-thread pour plus de performance;
- Supporte les servlets;
- File de messages (message queue) intégrée;
- Service timer (cron) intégré;
- "Persistence container" intégré et distribué (typiquement pour stocker les données de session).
Installation
Sur Ubuntu 14.04:
wget https://github.com/appserver-io/appserver/releases/download/1.0.6/appserver-dist_1.0.6-37.deb7_amd64.deb
wget https://github.com/appserver-io/appserver/releases/download/1.0.6/appserver-runtime_1.0.7-74.deb7_amd64.deb
sudo dpkg -i appserver-runtime_1.0.7-74.deb7_amd64.deb
sudo dpkg -i appserver-dist_1.0.6-37.deb7_amd64.deb
Et pour installer les éventuelles dépendances:
sudo apt-get install -f
appserver.io est maintenant installé dans /opt/appserver. La commande suivante permet de configurer le serveur pour le développement:
sudo /opt/appserver/server.php -s dev
sudo service appserver restart
Le serveur appserver.io est maintenant accessible à l'adresse http://localhost:9080
Servlets
L'utilisation des servlets est une fonctionnalité qu'on retrouve généralement dans les serveurs d'applications Java (Tomcat etc.).
Dans la plus-part des serveurs web PHP (Apache mod_php, PHP-FPM,...), l'entièreté du code nécessaire pour construire la page est évalué à chaque requête. Tous les les objets sont donc également instanciés puis détruits à chaque requête. Dans le cas d'applications complexes, cela représente un énorme gaspillage de ressources, et un énorme ralentissement.
Au contraire, dans le cas des servlets, un seul objet est instancié au démarrage du serveur. Lors de chaque requête, la méthode correspondante est appelée (généralement doGet pour les requêtes GET et doPost pour les requêtes POST). Typiquement, lors de l'instanciation de la servlet, on exécute toutes les tâches lourdes de configuration (bootstraping) qui sont communes à toutes les requêtes.
L'inconvénient: comme l'objet servlet est créé uniquement lors du démarrage du serveur, il faut redémarrer celui-ci après chaque modification du servlet.
Pour créer une servlet appserver.io:
cd /opt/appserver/webapps/
# Créer un dossier pour notre application
mkdir myapp
cd myapp
Les servlets doivent se trouver dans le dossier WEB-INF/classes et doivent suivre le standard PSR-0:
mkdir -p WEB-INF/classes/Me/MyApp
cd WEB-INF/classes/Me/MyApp
On peut enfin créer la servlet:
nano IndexServlet.php
<?php
namespace Me\MyApp;
// Doit correspondre au nom du répertoire !!
use AppserverIo\Psr\Servlet\Http\HttpServlet;
/**
* @Route(name="index", urlPattern={"/index.do", "/index.do*"})
*/
class IndexServlet extends HttpServlet {
// Le nom de la classe doit correspondre au nom du fichier!
protected $value;
public function init(ServletConfig $config) {
parent::init($config);
// Et ici, on initialise tout ce qui doit l'être
// Spécialement si c'est lourd à calculer!!
$this->value = "Hello";
}
public function doGet($servletRequest, $servletResponse) {
$servletResponse->appendBodyStream("Ceci était long à calculer " . $this->value);
}
}
Après avoir redémarré le serveur, la servlet sera visible à l'adresse
http://localhost:8090/myapp/index.do
Attention, en réalité ce n'est pas la même instance du servlet qui est utilisée à chaque requête, mais bien une copie. Les servlets ne peuvent donc pas être utilisées pour la communication entre les requêtes. L'exemple ci-dessous ne fonctionnera donc pas:
namespace Me\MyApp;
use AppserverIo\Psr\Servlet\Http\HttpServlet;
/**
* @Route(name="index", urlPattern={"/index.do", "/index.do*"})
*/
class IndexServlet extends HttpServlet {
protected $value = 0;
public function doGet($servletRequest, $servletResponse) {
$servletResponse->appendBodyStream("Nombre de visites: " . $this->value);
$this->value++;
}
}
Lors de chaque requête $this->value vaudra 0 car c'est une copie du servlet original qui est utilisée...
Templates
Les servlets sont donc extrêmement puissants pour le bootstrapping de l'application. Pour générer la page elle-même, mieux vaut utiliser des templates. Pour comparer avec le modèle MVC, la servlet sert alors de controller, et le template est la vue.
<?php
namespace Me\MyApp;
use AppserverIo\Psr\Servlet\Http\HttpServlet;
/**
* @Route(name="index", urlPattern={"/index.do", "/index.do*"})
*/
class IndexServlet extends HttpServlet
{
public function doGet($servletRequest, $servletResponse)
{
// récupérer les valeurs à afficher
$servletRequest->getContext()->setAttribute("NAMES",
array("Harry", "Hermione", "Ron"));
// calculer le chemin complet vers le template
$template = "templates/index.phtml";
$webappPath = $servletRequest->getContext()->getWebappPath();
$pathToTemplate = $webappPath . DIRECTORY_SEPARATOR . $template;
if (!file_exists($pathToTemplate)) {
throw new \Exception('Requested template not found: ' . $pathToTemplate);
}
// créer la page
ob_start();
require $pathToTemplate;
$servletResponse->appendBodyStream(ob_get_clean());
}
}
Et créer le template:
nano /opt/appserver/webapps/myapp/templates/index.phtml
<!DOCTYPE html>
<html lang="en">
<head>
<title>appserver.io exemple</title>
</head>
<body>
<h1>Example app</h1>
<table class="table table-hover">
<tr><th>Name</th></tr>
<?php foreach ($servletRequest->getContext()->getAttribute("NAMES") as $name): ?>
<tr><td><?php echo $name ?></td></tr>
<?php endforeach; ?>
</table>
</body>
</html>