Вы находитесь на странице: 1из 0

Curso: "Java EE y Frameworks" 2013

Apache Struts 2
Mdulo 6 / parte 1


Todos los logos y marcas utilizados en este
documento, estn registrados y pertenecen a
sus respectivos dueos.
AUTORES: andresguzf@gmail.com WEB: http://formacion-java.bolsadeideas.cl | | Apache Struts 2 1

Curso: "Java EE y Frameworks" 2013

Introduccin
Struts2 es un framework para desarrollar aplicaciones web basadas en Java. Surge de la unin de las
comunidades de Webwork y de Struts, en la que la base es de Webwork y el nombre lo pone Struts.
En su sitio web nos informa de que es ms simple y ms completo. Aqu podemos encontrar la ltima
versin disponible para descargar as como tutoriales, guas
Struts2 es una herramienta de soporte para el desarrollo de aplicaciones Web bajo el patrn MVC bajo
la plataforma J2EE (Java 2, Enterprise Edition). Struts se desarrollaba como parte del proyecto Jakarta de
la Apache Software Foundation, pero actualmente es un proyecto independiente conocido como
Apache Struts.
Struts2 permite reducir el tiempo de desarrollo. Su carcter de "software libre" y su compatibilidad con
todas las plataformas en que Java Entreprise est disponible, lo convierte en una herramienta altamente
disponible.
Struts2 se basa en el patrn del Modelo-Vista-Controlador (MVC) el cual se utiliza ampliamente y es
considerado de gran solidez. De acuerdo con este patrn, el procesamiento se separa en tres secciones
diferenciadas, llamadas el modelo, las vistas y el controlador.

Cuando se programan aplicaciones Web con el patrn MVC, siempre surge la duda de usar un solo
controlador o usar varios controladores, pues si consideramos mejor usar un solo controlador para tener
toda nuestra lgica en un mismo lugar, nos encontramos con un grave problema, ya que nuestro
controlador se convierte en lo que se conoce como "fat controller", es decir un controlador de
peticiones, Struts surge como la solucin a este problema ya que implementa un solo controlador
(ActionServlet) que evala las peticiones del usuario mediante un archivo configurable (struts.xml).

AUTORES: andresguzf@gmail.com WEB: http://formacion-java.bolsadeideas.cl | | Apache Struts 2 2

Curso: "Java EE y Frameworks" 2013

Herramientas necesarias
Necesitamos nuestras herramientas Java (JDK), un IDE (hoy por hoy Eclipse es el rey y netbeans el
principe) y un servidor de aplicaciones (Tomcat siempre es una buena eleccin).
Adems descargaremos la ltima distribucin 2.x de Struts. La distribucin contiene el cdigo, la
documentacin, y varias aplicaciones web de ejemplo (empaquetadas en formato .war), entre ellas
struts-blank-2.x.war, que es una aplicacin web vaca preparada para comenzar con Struts2, es decir,
algo as como el hola mundo que vamos a construir ms adelante.
Modelo Vista Controlador
Modelo Vista Controlador (MVC) es un patrn de arquitectura de software que separa los datos de una
aplicacin, la interfaz de usuario, y la lgica de control en tres componentes distintos. El patrn MVC se
ve frecuentemente en aplicaciones web, donde la vista es la pgina HTML y el cdigo que provee de
datos dinmicos a la pgina. El modelo es el Sistema de Gestin de Base de Datos y la Lgica de negocio,
y el controlador es el responsable de recibir los eventos de entrada desde la vista.
Componentes del modelo
Corresponden a la lgica del negocio con la cual se comunica la aplicacin web. Usualmente el modelo
comprende accesos a Bases de Datos o sistemas que funcionan independientemente de la aplicacin
web.
Esta es la representacin especfica de la informacin con la cual el sistema opera. La lgica de datos
asegura la integridad de estos y permite derivar nuevos datos; por ejemplo, no permitiendo comparar
un nmero de unidades negativo, calculando si hoy es el cumpleaos del usuario o los totales,
impuestos o importes en un carrito de la compra.
Componentes del control
Los componentes de control son los encargados de coordinar las actividades de la aplicacin, que van
desde la recepcin de datos del usuario, las verificaciones de forma y la seleccin de un componente del
modelo a ser llamado. Por su parte los componentes del modelo envan al control sus eventuales
resultados o errores de manera de poder continuar con otros pasos de la aplicacin.
En general este responde a eventos, usualmente acciones del usuario e invoca cambios en el modelo y
probablemente en la vista.
Componentes de vista
Tambin conocido como capa de presentacin, este presenta el modelo en un formato adecuado para
interactuar, usualmente la interfaz de usuario como por ejemplo contenidos XHTML dentro de un jsp.
Muchos sistemas informticos utilizan un Sistema de Gestin de Base de Datos para gestionar los datos:
en MVC corresponde al modelo. La unin entre capa de presentacin y capa de negocio conocido en el
paradigma de la Programacin por capas representara la integracin entre Vista y su correspondiente
Controlador de eventos y acceso a datos, MVC no pretende discriminar entre capa de negocio de capa
de presentacin pero si pretende separar la capa visual grfica de su correspondiente programacin y
acceso a datos algo que mejora el desarrollo y mantenimiento de la Vista y el Controlador en paralelo ya
que ambos cumplen ciclos de vida muy distintos entre s.
AUTORES: andresguzf@gmail.com WEB: http://formacion-java.bolsadeideas.cl | | Apache Struts 2 3

Curso: "Java EE y Frameworks" 2013


Aunque se pueden encontrar diferentes implementaciones de MVC, el flujo que sigue el control
generalmente es el siguiente:
1. El usuario interacta con la interfaz de usuario de alguna forma (por ejemplo, el usuario pulsa
un botn, enlace, etc.)
2. El controlador recibe (por parte de los objetos de la interfaz-vista) la notificacin de la accin
solicitada por el usuario. El controlador gestiona el evento que llega, frecuentemente a travs de
un gestor de eventos (handler) o callback.
3. El controlador accede al modelo, actualizndolo, posiblemente modificndolo de forma
adecuada a la accin solicitada por el usuario (por ejemplo, el controlador actualiza el carro de
la compra del usuario). Los controladores complejos estn a menudo estructurados usando un
patrn de comando que encapsula las acciones y simplifica su extensin.
4. El controlador delega a los objetos de la vista la tarea de desplegar la interfaz de usuario. La
vista obtiene sus datos del modelo para generar la interfaz apropiada para el usuario donde se
refleja los cambios en el modelo (por ejemplo, produce un listado del contenido del carro de la
compra). El modelo no debe tener conocimiento directo sobre la vista. Sin embargo, el patrn
de observador puede ser utilizado para proveer cierta indireccin entre el modelo y la vista,
permitiendo al modelo notificar a los interesados de cualquier cambio. Un objeto vista puede
registrarse con el modelo y esperar a los cambios, pero aun as el modelo en s mismo sigue sin
saber nada de la vista. El controlador no pasa objetos de dominio (el modelo) a la vista aunque
puede dar la orden a la vista para que se actualice. Nota: En algunas implementaciones la vista
no tiene acceso directo al modelo, dejando que el controlador enve los datos del modelo a la
vista.
5. La interfaz de usuario espera nuevas interacciones del usuario, comenzando el ciclo
nuevamente.
Esta separacin simplifica enormemente la escritura tanto de vistas como de componentes del
modelo: Las pginas JSP no tienen que incluir manejo de errores, mientras que los elementos del control
simplemente deciden sobre el paso siguiente.

AUTORES: andresguzf@gmail.com WEB: http://formacion-java.bolsadeideas.cl | | Apache Struts 2 4

Curso: "Java EE y Frameworks" 2013

Entre las caractersticas de Struts se pueden mencionar:
Configuracin del control centralizada.
Interrelaciones entre acciones y pgina u otras acciones se especifican por tablas XML en lugar
de codificarlas en los programas o pginas.
Componentes de aplicacin, que son el mecanismo para compartir informacin
bidireccionalmente entre el usuario de la aplicacin y las acciones del modelo.
Basado en POJOs
Conversin de Datos
Interceptores
Inyeccin de Dependencias
Flexible con etiquetas para Formularios GUI, y Ajax
Soporte OGNL
Testability.
Facilitar el deploy de aplicaciones.
Diseo mejorado.
Nuevos tags incorporados.
Mejora en la gestin de checkboxes.
Soporte para AJAX.
Integracin sencilla para Spring.
Resultados especializados.
Formularios POJO (nos olvidamos de los ActionForm).
Acciones POJO.
Aadir plugins fcilmente.
Integrar herramientas de profiling.
Reporte de errores ms preciso.
Acciones fciles de testear.
Valores por defecto para las configuraciones.
Controladores fciles de customizar.
Integracin de herramientas de debbuging.
Aadir nuevos tags fcilmente.
Validaciones, Struts2 contiene herramientas para validacin de campos de plantillas bajo varios
esquemas que van desde validaciones locales en la pgina (en javaScript) hasta las
validaciones de fondo hechas a nivel de las acciones.
Struts2 permite que el desarrollador se concentre en el diseo de aplicaciones complejas como una
serie simple de componentes del Modelo y de la vista intercomunicados por un control centralizado.
Diseando de esta manera puede obtenerse una aplicacin ms consistente y ms fcil de mantener.





AUTORES: andresguzf@gmail.com WEB: http://formacion-java.bolsadeideas.cl | | Apache Struts 2 5

Curso: "Java EE y Frameworks" 2013

As funciona Struts2 para una peticin del tipo Request:
1. Llega un Request a la aplicacin.
2. El Request es interpretador por el DispatcherFilter y determina que Action y que conjunto de
Interceptors invocar.
3. Cada Interceptor ejecuta sus acciones previas a la ejecucin del mtodo de Action a invocar
o Si el Interceptor I18nInterceptor intercepta el Action: Se ubicara en la session del
usuario un objeto Locale para utilizar i18n.
o Si el Interceptor ValidationInterceptor intercepta el Action: Se ejecutan la reglas de
validacin definidas sobre el Action
o Si el Interceptor AnnotationValidationInterceptor intercepta el Action: Se chequea en el
mtodo a invocar del Action si tiene la anotacin @SkipValidation, en cuyo caso no se
realizan validaciones
4. Es ejecutado el mtodo anotado con @Before en el Action
5. Es invocado el mtodo del Action.
6. Es ejecutado el mtodo anotado con @After en el Action
7. Es ejecutado el mtodo anotado con @BeforeResult en el Action
8. Cada Interceptor ejecuta sus acciones posteriores a la ejecucin del mtodo de Action a invocar
o Si el Interceptor ModelDrivenInterceptor intercepta el Action: Luego de la ejecucin del
Action se ubicara en el value stack el modelo que provee el Action.
o Si el Interceptor ParametersInterceptor intercepta elAction: Los parametros
provenientes del Request se ubican en el value stack
9. Se examina el resultado obtenido del Action y se determina el Result correspondiente.
10. Mediante el Result determinado se genera la vista, y segn la configuracin definida sober el se
invoca el proceso de generacin de la vista.
11. La vista generada retorna al cliente.


AUTORES: andresguzf@gmail.com WEB: http://formacion-java.bolsadeideas.cl | | Apache Struts 2 6

Curso: "Java EE y Frameworks" 2013







AUTORES: andresguzf@gmail.com WEB: http://formacion-java.bolsadeideas.cl | | Apache Struts 2 7

Curso: "Java EE y Frameworks" 2013

Ejercicio 1: Crear desde cero una aplicacin Hola Mundo con Struts2
Framework MVC

1. Iniciamos NetBeans IDE.
2. Crear el proyecto struts2-webmvc-hola-mundo.
Seleccionar File->New Project (Ctrl+Maysculas+N).

Aparece una Nueva Venta New Proyect
Seleccionar Proyecto->Choose Project -> Seleccionamos Java Web -> Web Application.
Clic en Next
AUTORES: andresguzf@gmail.com WEB: http://formacion-java.bolsadeideas.cl | | Apache Struts 2 8

Curso: "Java EE y Frameworks" 2013


Aparece una Nueva Venta New Web Application
En el Nombre (Proyect Name) escribimos struts2-webmvc-hola-mundo
Clic en Siguiente (Next)
El Servidor lo dejamos tal cual en Glassfish v3
Java EE versin lo dejamos en Java EE 5.
Next
AUTORES: andresguzf@gmail.com WEB: http://formacion-java.bolsadeideas.cl | | Apache Struts 2 9

Curso: "Java EE y Frameworks" 2013


Y clic en Finalizar (Finish)

AUTORES: andresguzf@gmail.com WEB: http://formacion-java.bolsadeideas.cl | | Apache Struts 2 10

Curso: "Java EE y Frameworks" 2013


3. Agregar las libreras de Struts2 en el proyecto creado en el paso anterior struts2-webmvc-hola-
mundo
Descargar el archivo struts-2-libs rar de la semana (ste viene como parte del
laboratorio de sta tercera semana como archivo de descarga):
Descomprimir el archivo struts-2-libs.rar bajo el directorio /curso/javaee/struts2 u
otro directorio a eleccin.
Agregamos las libreras al proyecto, con un clic derecho y Properties

Aparece la ventana de Proyect Properties, en la seccin de la izquierda seleccionamos
Libraries
Luego agregamos las libreras de struts2 descargadas y descomprimidas, clic en Add
JAR/Folder dentro de la ventana Proyect Properties
AUTORES: andresguzf@gmail.com WEB: http://formacion-java.bolsadeideas.cl | | Apache Struts 2 11

Curso: "Java EE y Frameworks" 2013


Aparece la ventana Add JAR/Folder
Buscar la carpeta donde descomprimimos las liberas
Seleccionamos todos los archives y clic Abrir (Open)
AUTORES: andresguzf@gmail.com WEB: http://formacion-java.bolsadeideas.cl | | Apache Struts 2 12

Curso: "Java EE y Frameworks" 2013


Observamos las libreras agregadas

AUTORES: andresguzf@gmail.com WEB: http://formacion-java.bolsadeideas.cl | | Apache Struts 2 13

Curso: "Java EE y Frameworks" 2013

Clic OK para cerrar la ventana Project Properties
4. Modificar el archivo web.xml generado por el IDE cuando creamos el proyecto.
Doble clic web.xml bajo struts2-webmvc-hola-mundo->Web Pages->WEB-INF para
abrir en el editor de Netbeans.
Clic pestaa XML para abrir en formato XML.

Remplazar el contenido del web.xml generado por el IDE con el contenido que se
muestra ms abajo. El fragmento de cdigo que necesita ser agregado est en negrita
de de color azul.
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-
instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">

<display-name>Struts2 Web MVC Hola Mundo</display-name>
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
</filter>
<filter-mapping>
AUTORES: andresguzf@gmail.com WEB: http://formacion-java.bolsadeideas.cl | | Apache Struts 2 14

Curso: "Java EE y Frameworks" 2013

<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

<session-config>
<session-timeout>
30
</session-timeout>
</session-config>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>

El resultado ser que todas las URLs invocadas dentro del contexto de nuestra aplicacin
web sern interceptadas y atendidas por el filtro de Struts2
org.apache.struts2.dispatcher.FilterDispatcher.
5. Crear el archivo de configuracin de Struts2, struts.xml
Clic derecho sobre Sources Packages bajo el proyecto struts2-webmvc-hola-mundo y
seleccionar New->Other

AUTORES: andresguzf@gmail.com WEB: http://formacion-java.bolsadeideas.cl | | Apache Struts 2 15

Curso: "Java EE y Frameworks" 2013

Observe que aparece la ventana New File.
Seleccionar XML bajo Categories (seccin de la izquierda) y XML Document bajo File
Types (seccin de la derecha).
Clic Next.

Para el nombre del archivo (File Name), ingresamos struts.
Clic Browse.
AUTORES: andresguzf@gmail.com WEB: http://formacion-java.bolsadeideas.cl | | Apache Struts 2 16

Curso: "Java EE y Frameworks" 2013


Expandir struts2-webmvc-hola-mundo->src.
Escoger java.
Clic en Select Folder.

AUTORES: andresguzf@gmail.com WEB: http://formacion-java.bolsadeideas.cl | | Apache Struts 2 17

Curso: "Java EE y Frameworks" 2013

Clic Next
Clic Finish
Observe que el IDE genera el archive XML struts.xml y ste es desplegado en el editor
de cdigo de Netbeans
Remplace el contenido generado de struts.xml con el que se muestra a continuacin
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">

<struts>
<constant name="struts.enable.DynamicMethodInvocation" value="false" />
<constant name="struts.devMode" value="false" />

<package name="controllers" namespace="/" extends="struts-default">

<action name="saludo" class="controllers.SaludoController">
<result>/views/saludo.jsp</result>
</action>

<action name="*" class="controllers.SaludoController">
<result>/views/saludo.jsp</result>
</action>

<!-- Add actions here -->
</package>
</struts>

package: simboliza una unidad de trabajo, es exactamente el mismo concepto que
paquetes en UML y en Java.
action: la accin propiamente dicha, aqu mapeamos el controlador a un PATH URL
result: el resultado posible. Si no incluimos un nombre, ser utilizado por defecto
cuando la accin resulte en SUCCESS, se refiere a la vista que cargaremos o alguna
redireccin a otra accin.
6. Ahora creamos la clase Controladora de struts SaludoController
Clic derecho sobre el proyecto y seleccionar New->Java Class
AUTORES: andresguzf@gmail.com WEB: http://formacion-java.bolsadeideas.cl | | Apache Struts 2 18

Curso: "Java EE y Frameworks" 2013


Para el nombre de clase (Class Name), ingresar SaludoController.
Para el Package, ingresar controllers.
Clic Finish.
AUTORES: andresguzf@gmail.com WEB: http://formacion-java.bolsadeideas.cl | | Apache Struts 2 19

Curso: "Java EE y Frameworks" 2013



AUTORES: andresguzf@gmail.com WEB: http://formacion-java.bolsadeideas.cl | | Apache Struts 2 20

Curso: "Java EE y Frameworks" 2013

Modificar la clase SaludoController con el siguiente cdigo:
package controllers;

import com.opensymphony.xwork2.ActionSupport;
import java.util.Date;

/**
*
* @author Andrs Guzmn F
*/
public class SaludoController extends ActionSupport {

public static final String MESSAGE = "Bienvenido usuario al sistema usando Struts2!";
private String saludo;

@Override
public String execute() throws Exception {
setSaludo(MESSAGE);
return SUCCESS;
}

public String getSaludo() {
return saludo;
}

public void setSaludo(String saludo) {
this.saludo = saludo;
}

public Date getFecha() {
return new Date();
}
}
Struts 2 utiliza el patrn Dependency Injection para rellenar los atributos que se
necesiten, por esa razn, tenemos que tener en cuenta los mtods getter/setter para
cada componente de presentacin que queramos tratar.
Los mtodos setter se utilizan para los parmetros del request, los nombres de los
atributos de la clase controladora (en ste caso SaludoController) deben coincidir con
los nombre de los parmetros de la peticin.
Los mtodos getter se utilizan para pasar datos y/o atributos a la vista, mediante los
getter el controlador le pasa los parmetros a la vista.
Con respecto al mtodo execute(), aqu se maneja/controla la peticin, no recibe
parmetros y retorna un String representando el resultado de la accin (error, xito o
cualquier otro string).
7. Ya teniendo creado nuestro controlador, ahora creamos su vista (presentacin)
Creamos la carpeta views bajo struts2-webmvc-hola-mundo ->Web Pages
o Clic derecho sobre struts2-webmvc-hola-mundo ->Web Pages y seleccionar
New->Folder
o En Folder Name Ingresar views y clic en Finish
AUTORES: andresguzf@gmail.com WEB: http://formacion-java.bolsadeideas.cl | | Apache Struts 2 21

Curso: "Java EE y Frameworks" 2013

Sobre la carpeta views que se encuentra bajo struts2-webmvc-hola-mundo ->Web
Pages botn derecho del mouse Clic en New -> JSP.


AUTORES: andresguzf@gmail.com WEB: http://formacion-java.bolsadeideas.cl | | Apache Struts 2 22

Curso: "Java EE y Frameworks" 2013

Para el nombre de archivo del JSP (File Name), ingresar saludo.
Para el directorio (Folder), revisar que se encuentre en views.

Observe que Netbeans genera la JSP saludo.jsp y lo abre en el editor.
Modificamos el contenido generado por el que se muestra a continuacin.
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Pgina de Saludo</title>
</head>
<body>
<h1><s:property value="saludo" /></h1>
<p>Hoy da es <s:property value="fecha" /></p>
</body>
</html>

Las etiquetas de struts se agregan en el JSP mediante el taglib /struts-tags, con el prefijo
s.
Las etiquetas property muestra una propiedad de la clase Controladora (que hereda de
ActionSupport)
o default: Valor a mostrar en caso de que el valor pedido sea nulo.
o escape: Determina si queremos que se escape el HTML. Por defecto es true.
o value: Valor a mostrar

AUTORES: andresguzf@gmail.com WEB: http://formacion-java.bolsadeideas.cl | | Apache Struts 2 23

Curso: "Java EE y Frameworks" 2013

8. Construir y ejecutar el proyecto struts2-webmvc-hola-mundo:
Clic-derecho en proyecto struts2-webmvc-hola-mundo y seleccionar Run.
El navegador se abre, mostrando una pantalla por defecto.
En el navegador escribimos la siguiente direccin web: http://localhost:8080/struts2-
webmvc-hola-mundo/saludo

Finalmente se abre nuestro navegador con el mensaje de saludo y la fecha y hora del
servidor.

AUTORES: andresguzf@gmail.com WEB: http://formacion-java.bolsadeideas.cl | | Apache Struts 2 24

Curso: "Java EE y Frameworks" 2013

9. Dando formato a la fecha para que tenga una salida ms acorde a nuestro lenguaje y localidad:
Doble clic en saludo.jsp bajo struts2-webmvc-hola-mundo ->Web Pages ->views para
abrir y agregar el nuevo cdigo.
Dado lo anterior modificamos el archivo saludo.jsp, tal como se muestra en el cdigo de
abajo. El fragmento de cdigo que necesita ser agregado est en azul y negrita.
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Pgina de Saludo</title>
</head>
<body>
<h1><s:property value="saludo" /></h1>
<p>Hoy da es <s:date name="fecha" format="d 'de' MMMM 'de' yyyy" /></p>
</body>
</html>
Guardamos el archivo modificado y refrescamos recargamos la pgina del navegador
con la direccin URL del saludo (http://localhost:8080/struts2-webmvc-hola-
mundo/saludo)
Se muestra el nuevo formato de fecha en nuestro sistema

AUTORES: andresguzf@gmail.com WEB: http://formacion-java.bolsadeideas.cl | | Apache Struts 2 25

Curso: "Java EE y Frameworks" 2013

Resumen
En este workshop de laboratorio, hemos aprendido a utilizar e implementar las funciones bsicas de
Struts2 Framework, implementando MVC mediante la herencia de la clase ActionSupport de Struts2 en
nuestros controladores, tambin vimos algunas etiquetas de vistas.
Enva tus consultas a los foros!
Aqu es cuando debes sacarte todas las dudas
haciendo consultas en los foros
correspondientes
AUTORES: andresguzf@gmail.com WEB: http://formacion-java.bolsadeideas.cl | | Apache Struts 2 26

Вам также может понравиться