Estructura de Struts2
1. ¿Por qué usar marcos?
(1) El marco completa automáticamente muchas tareas triviales
Para Struts2, nos ayuda a completar fácilmente la conversión de tipo de datos, verificación de datos, internacionalización, etc.
Tareas comunes en el desarrollo web. También están los modos de plantilla que se usan ampliamente en Spring, que hacen que nuestro proceso de desarrollo sea más automatizado e inteligente. Usar un marco es evitar reinventar la rueda y volver a copiar estos códigos de plantilla.
El marco nos permite centrarnos más en problemas de nivel superior que en flujos de trabajo comunes y tareas básicas.
(2) usar un marco significa heredar con gracia la arquitectura detrás del marco
La arquitectura detrás del marco generalmente define una serie de flujos de trabajo. Lo que debemos hacer es adjuntar el código de una aplicación específica a este proceso, para que podamos disfrutar de los diversos beneficios traídos por el marco. A veces también podemos resistir las reglas arquitectónicas del marco, pero el marco generalmente proporciona su arquitectura de una manera que es difícil de rechazar. Es tan simple que puedes heredar una excelente arquitectura con gracia y es gratis, entonces, ¿por qué no hacerlo?
(3) Es más fácil encontrar personas bien capacitadas que usan el marco
Casi nunca he usado ningún marco en todo el proyecto de mi empresa antes y buscando servicios de servicio (similar a JNDI)
Para registrar la impresión (similar a LOG4J), y luego al grupo de conexión de base de datos (similar a DBCP), todos ellos son implementados por el personal interno. En primer lugar, se debe a que el proyecto es relativamente antiguo, y puede que no haya ningún marco de código abierto para su uso en ese momento. En segundo lugar, se debe a la estrategia conservadora de la compañía, y está preocupado que el uso de un marco de código abierto inestable pueda traer riesgos al proyecto. Esto puede ser cierto en el medio ambiente en ese momento, y la alta gerencia de la compañía considerará naturalmente todo el proyecto desde una perspectiva más amplia.
Sin embargo, cuando el proyecto se hace gradualmente más grande y hay más y más excelentes marcos de código abierto en el mundo, si algunos marcos de código abierto maduros no pueden refactorizarse en el tiempo e introducido, el resultado final puede ser que los desarrolladores recién reclutados deben aprender este complejo sistema desde cero (todos los sistemas internos, y no hay ayuda en Internet) y tener cuidado de varios errores en el marco interno.
El costo es realmente demasiado alto.
(4) El marco interno no puede mantenerse al día con el desarrollo de la industria
El error en el marco interno mencionado anteriormente. Para los marcos de código abierto, puede haber un equipo de fundadores de marco, una gran cantidad de entusiastas de código abierto,
Comunidad de código abierto para apoyarlo. El poder de la gente es infinito, y se puede imaginar la velocidad de la reparación de errores. Esto es del reciente código abierto
Se puede ver el proceso de corrección de errores de TextMate. Los entusiastas han resuelto rápidamente muchos errores que han sido archivados durante mucho tiempo después de que son de código abierto, pero ¿qué pasa con el marco interno? Después de que las personas que lo desarrollaron dejaron la compañía, nadie leería su código fuente sin errores importantes. ¡La brecha es evidente!
(5) Por supuesto, usar un marco no es una gran ganancia.
Como se mencionó anteriormente, el uso de un marco inmaduro es arriesgado, y es mejor ser conservador para un proyecto que no es tan radical.
(A menos que este sea un grupo de fanáticos tecnológicos gratuitos y sin restricciones que pueden decidir qué marco usar a su propia discreción, eso es realmente una bendición)
Al igual que Sequioa, el servicio de alta disponibilidad de Java HA que utilicé antes, este marco ya no es compatible con la compañía de desarrollo, y el riesgo es aún mayor.
Además, cuando use algunos marcos poco comunes, también debe prestar atención al protocolo de licencia del código fuente del marco, y no hacer referencia a su voluntad en el proyecto.
Modifique el código fuente del marco para evitar disputas legales innecesarias.
2. La arquitectura detrás de Struts2
Como hemos analizado tantos beneficios del marco antes, naturalmente comenzaremos a aprender a usar Struts2. Pero usando Struts2
¿Qué tipo de arquitectura elegante heredará? De hecho, desde un mayor nivel de abstracción, sigue siendo el modelo MVC con el que estamos familiarizados.
Según el ejemplo anterior de Helloworld, el controlador C (FilterDispatcher) es lo que declaramos en Web.xml
Struts2 Core Clase. Y el modelo M es nuestra clase de acción de periódico. Y la vista V es naturalmente News.jsp. El concepto del modelo parece un poco vago. ¿Qué es un modelo? De hecho, este concepto que suena muy sustantivo contiene datos comerciales transmitidos estáticamente desde el front-end web y la implementación de la lógica empresarial.
Algunas personas pueden decir que esta arquitectura no es nueva, hay muchos marcos de MVC, ¿cuál es la diferencia entre este y otros marcos? Disegaremos Struts2 en un nivel más bajo de abstracción y veamos qué lo hace único.
A primera vista, parece muy complicado. Si solo lo miramos desde la perspectiva del usuario, solo necesitamos implementar la parte amarilla durante el desarrollo, es decir, nosotros
Struts.xml, NewsAction y News.jsp en la instancia de Helloworld. Esto es todo lo que tenemos que hacer, como se mencionó anteriormente, solo necesitamos hacer muy pocas cosas y nos convirtemos en parte de esta excelente arquitectura.
Ahora mira las otras partes. FilterDispatcher es el filtro de servlet que configuramos en Web.xml, que es Struts2
Todas las aplicaciones web Struts2 deben configurarse de esta manera. A continuación, las partes azules y verdes son el núcleo de Struts2. Se puede decir que estas clases están cuidadosamente diseñadas por los desarrolladores de Struts2.
(1) El cliente envía una solicitud, y el contenedor J2EE analiza el paquete HTTP y lo encapsula en una HTTPservletRequest.
(2) FilterDispatcher intercepta esta solicitud y busca el ActionMapper en función de la ruta de solicitud para determinar qué acción llamar.
(3) Según el resultado de retorno de ActionMapper, FilterDispatcher confía ActionProxy para encontrar esta acción en Struts.xml.
(4) ActionProxy crea una información de acción y comienza las llamadas recursivas al interceptor y la acción.
(5) Cada interceptor completa sus propias tareas
(6) El llamado real a la acción devuelve la ruta de los resultados
(7) El objeto de resultado emitirá los datos de retorno a la transmisión
(8) Devuelva httpservletResponse al contenedor J2EE, y el contenedor envía paquetes HTTP al cliente.
Este es el proceso de ejecución de Struts2. Los objetos centrales son ActionInvocation e Interceptor, así como el ActionContext que aún no se ha introducido.
ActionInvocation es la programación total de todo el proceso, que es muy similar al objeto de invocación en Spring AOP. Muchos interceptores están integrados en Struts2. Lo más importante es guardar los parámetros de solicitud y pasar los datos de primer plano a las variables del miembro de la acción.
ActionContext es el objeto de contexto global que guarda estos datos, y lo más importante es la valuación utilizada para guardar la instancia de acción.
El llamado Global significa que se puede acceder a ActionContext en acción y resultado, pero en realidad es de tipo Threadlocal. Cada hilo de solicitud tendrá su propia instancia de acción y acciónContext.
Se puede decir que aprender Struts2 se trata principalmente de aprender:
(1) Deje que el interceptor y la acción cooperen para completar la tarea.
(2) Guarde los datos de primer plano en la acción.
(3) El resultado obtiene los datos de retorno de la acción a través de ValueStack.
3. Las diferencias entre Struts2 y Struts1
En el proceso de ejecución anterior, ya podemos ver la gran diferencia entre Struts1 y 2.
(1) ¿A dónde fue ActionForm? ¿La acción sigue siendo la misma acción?
Lo más obvio es que no podemos ver el objeto ActionForm en todo el proceso, y aunque la acción todavía se llama este nombre, parece ser completamente diferente de la acción en Struts1.
En primer lugar, ActionForm fue abandonado, y los datos enviados desde la recepción se pueden guardar en cualquier POJO. El día de guardar en ActionForm primero y luego copiar al objeto DTO ha terminado. En segundo lugar, este POJO es en realidad una variable miembro en el objeto de acción. Esto está en Struts1
Es imposible compartir una instancia de acción para todas las solicitudes en este caso. Ahora Struts2 creará una instancia de acción para cada solicitud, por lo que esto funciona. Tercero, aunque esto es factible, parece que la acción, como modelo M en MVC, guarda datos y contiene lógica comercial. ¿Es este un mal diseño? En realidad, si lo piensa cuidadosamente, este diseño es muy conveniente, ya hemos obtenido los datos.
Puede operar directamente la capa de servicio. La acción parece tener demasiadas responsabilidades, pero no muchas.
(2) ¿Cómo se convirtió el servlet delantero en un filtro?
Sabemos que Struts1 y Spring MVC se usan como entradas a través de servlets frontales. ¿Por qué Struts2 usa filtros de servlet?
Debido a que Struts2 se basa en el núcleo de la webwork, es completamente diferente de Struts1. Se puede decir que la obra web reduce las aplicaciones y J2EE
El acoplamiento API, como cambiar ActionServlet al filtro de servlet y el acceso directo a HttpservletRequest/respuesta.
Por ejemplo, cualquier POJO puede servir como formulario de acción, cualquier clase puede usarse como acción sin implementar la interfaz de acción, etc.
Por lo tanto, Struts2 también hereda este excelente diseño no invasivo.
Esto es algo similar a las ideas de diseño de Spring. Por ejemplo, esas interfaces de Ware no necesitan implementarse en absoluto, para minimizar el acoplamiento entre el código de aplicación y el marco. La invasividad es un factor importante a considerar al diseñar un marco.
(3) OGNL entre filtro, acción y resultado
La siguiente figura puede mostrar claramente cómo se integra OGNL en el marco Struts2.
Es muy conveniente acceder a los datos en acción utilizando la etiqueta Struts2 en la página de entrada inputForm.html y volver a la página ResultPage.jsp
OGNL hace que el acceso a las propiedades de las acciones guardadas en ValueStack sea tan conveniente como acceder a las propias propiedades de ValueStack.
El uso extenso de OGNL es una característica importante de Struts2. Incluyendo los valores de pase de la etiqueta de primer plano a la acción, los resultados que toman valores de la acción, etc., utilizarán OGNL en grandes cantidades. Sin embargo, la reflexión se usa mucho en OGNL. Creo que esta es una de las razones por las cuales Struts2 no es tan bueno como Struts1. Después de todo, se necesita un cierto precio para obtener una arquitectura flexible y de bajo acoplamiento.
(4) La fuerza del interceptor es invencible
Otra característica poderosa en Struts2 es el interceptor interceptor. Struts2 ha incorporado una gran cantidad de interceptores, que permiten reutilizar una gran cantidad de código, automatizando lo que anteriormente llamamos tareas triviales, lo que permite a Struts2 alcanzar un alto nivel de separación de atención. ¡Este es realmente un modelo para la aplicación de ideas AOP en el marco!
Struts2 tres métodos de transferencia de datos
STRUTS2 proporciona tres formas de guardar parámetros en las solicitudes HTTP: atributos de Javabean, objetos de Javabean y objetos de ModelDriven. Echemos un vistazo a estos tres métodos de transferencia de datos a través del ejemplo de inicio de sesión más común. El código de página es muy simple. El formulario de envío contiene el nombre de usuario y la contraseña. Puede obtener estos dos parámetros en la acción para verificar si el usuario inicia sesión correctamente.
1. Propiedades de Javabean
< %@ página contentType = "text/html; charset = utf-8" %> <html> <fead> </head> <body> <h1> Página de inicio de sesión </h1> <form de action = "/cdai/login" método = "post"> <iv> <label for = "username"> name: </etiqueta> <input id = "username" name = "name =" name = "type" type "" </div> <div> <etiqueta for = "contraseña"> contraseña: </etiqueta> <input id = "contraseña" name = "contraseña" type = "contraseña"/> </div> <div> <etiqueta for = "recordme"> <input id = "recordMe" name = "recordMe" type = "checkbox"/> recuerda mi </label> <input type = "Subt" Value = "Login" </Input> </Inpy </Input </Input </Input </Input> </Inpy </Input> </Inpy </Input> </Incuming </Input> </Input> </Input> </Input> </Input> </<///<///<//<////<///</itio </html>
paquete com.cdai.web.ssh.action; import com.cdai.web.ssh.request.loginrequest; import com.cdai.web.ssh.service.userservice; import com.opensymphony.xwork2.action; import com.opensymphony.xwork2.modeldriven; La clase pública LoginAction implementa acción {Nombre de usuario de cadena privada; contraseña de cadena privada; servicio de usuarios de usuarios privados; @Override public String Execute () {System.out.println ("Acción de inicio de sesión -" + solicitud); devolver el éxito; } public String getUsername () {solicitud de retorno; } public void setUsername (String UserName) {this.Username = username; } public String getPassword () {requería return; } public void setPassword (String Password) {this.password = contraseña; }}Este método es relativamente simple, guarde directamente los parámetros en el formulario a las propiedades de la acción. Al verificar, la acción también puede necesitar encapsular el nombre de usuario y la contraseña en DTO para pasarlo a la capa de servicio para su verificación. Entonces, ¿por qué no ir un paso más allá y guardar el nombre de usuario y la contraseña directamente en DTO?
2. Objetos de Javabean
< %@ página contentType = "text/html; charset = utf-8" %> <html> <fead> </head> <body> <h1> página de inicio de sesión </h1> <form de accion = "/cdai/login" método = "post"> <iv> <label for = "userName"> nombre: </etiqueta> <input id = "username" name = "request.useMeNeMe" </div> <div> <etiqueta for = "contraseña"> contraseña: </etiqueta> <input id = "contraseña" name = "request.password" type = "contraseña"/> </div> <div> <etiqueta for = "recordMe"> <input ID = "RememberMe" name = "RememberMe" type = "checkbox"/> recordar yo </etiqueta> <input type = "Subsit" Value = "Login" </inputing <inputing </inputing " </body> </html>
paquete com.cdai.web.ssh.action; import com.cdai.web.ssh.request.loginrequest; import com.cdai.web.ssh.service.userservice; import com.opensymphony.xwork2.action; import com.opensymphony.xwork2.modeldriven; Public Class LoginAction implementa Acción {solicitud privada de LoginRequest; servicio de usuarios de usuarios privados; @Override public String Execute () {System.out.println ("Acción de inicio de sesión -" + solicitud); devolver el éxito; } public LoginRequest getRequest () {Revolt solicitud; } public void setRequest (solicitud de LoginRequest) {this.request = request; }} Esto facilita llamar directamente a la capa de servicio. Pero existe una pequeña desventaja de que esto profundiza la profundidad del nombre del parámetro de la página, solo agrega una solicitud al nombre del parámetro
El prefijo (el nombre del atributo en la acción) permite a Struts2 guardar correctamente los parámetros en el formulario al objeto de solicitud a través de OGNL.
3. Objeto impulsado por el modelo
< %@ página contentType = "text/html; charset = utf-8" %> <html> <fead> </head> <body> <h1> Página de inicio de sesión </h1> <form de action = "/cdai/login" método = "post"> <iv> <label for = "username"> name: </etiqueta> <input id = "username" name = "name =" name = "type" type "" </div> <div> <etiqueta for = "contraseña"> contraseña: </etiqueta> <input id = "contraseña" name = "contraseña" type = "contraseña"/> </div> <div> <etiqueta for = "recordme"> <input id = "recordMe" name = "recordMe" type = "checkbox"/> recuerda mi </label> <input type = "Subt" Value = "Login" </Input> </Inpy </Input </Input </Input </Input> </Inpy </Input> </Inpy </Input> </Incuming </Input> </Input> </Input> </Input> </Input> </<///<///<//<////<///</itio </html>
paquete com.cdai.web.ssh.action; import com.cdai.web.ssh.request.loginrequest; import com.cdai.web.ssh.service.userservice; import com.opensymphony.xwork2.action; import com.opensymphony.xwork2.modeldriven; Public Class LoginAction implementa acción, ModelDriven <RoginRequest> {private LoginRequest solicitud = new LoginRequest (); servicio de usuarios de usuarios privados; @Override public String Execute () {System.out.println ("Acción de inicio de sesión -" + solicitud); devolver el éxito; } @Override public LoginRequest getModel () {solicitud de retorno; }} De esta manera, se requiere una interfaz más modelada, y los objetos proporcionados por ModelDiven se guardan en ValueStack, de modo que la página de primer plano se puede pasar directamente
El nombre de usuario y los nombres de los atributos de contraseña definen el nombre del parámetro del formulario.
¿Cuál de los tres métodos no debe ser generalizado? ¡Depende de las necesidades específicas del proyecto y luego lo decide usted mismo!