
Introduccion
Desde el primer lanzamiento, ha pasado mucho tiempo ( enlace al artículo anterior ). ¿Qué ha cambiado?
- estabilidad mejorada del sistema en su conjunto;
- implementado carga de componentes perezosa;
- Sistema de escucha básico incorporado
- soporte incorporado para programación orientada a aspectos (para problemas de resolución de dificultad media, de lo contrario, le aconsejo que use la biblioteca AspectJ para el resto)
- nuevo gestor de arranque RequestFactory
- trabajo integrado con caché basado en EhCache, Guava
- el trabajo con flujos está integrado (tanto la inicialización a través de la anotación @SimpleTask como el trabajo directo con el grupo)
** Módulos
- módulo para trabajar con la base de datos (ORM ligero con soporte para JPA, Transacciones, Controlador NO-SQL - Oriente, métodos Crud, sistema de repositorio y consultas autogeneradas desde la función de la clase de repositorio)
- Módulo de bozal web (mapeo de enlaces a través de anotaciones, soporte para productores / consumidores personalizados, página de representación de plantilla Velocity, solicitudes de seguridad básicas, sesiones, cookies, SSL) basado en Netty 4.1.30.
Estructura marco

"Esto, por supuesto, está todo bien", dices, "pero, de hecho, ¿todo funciona?"
"Sí, funciona. Pido un corte".
Ejemplo de proceso de implementación
Para implementar el ejemplo, usaré Maven 3 e Intelijj Idea 2018.2.
1) Conecte las dependencias:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <artifactId>example-webapp</artifactId> <groupId>org.ioc</groupId> <packaging>jar</packaging> <version>0.0.1</version> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.0</version> <configuration> <.source>1.8</source> <target>1.8</target> </configuration> <executions> <execution> <id>default-testCompile</id> <phase>test-compile</phase> <goals> <goal>testCompile</goal> </goals> </execution> </executions> </plugin> </plugins> </build> <dependencies> <dependency> <groupId>org.ioc</groupId> <artifactId>context-factory</artifactId> <version>2.2.4.STABLE</version> </dependency> <dependency> <groupId>org.ioc</groupId> <artifactId>orm-factory</artifactId> <version>2.2.4.STABLE</version> </dependency> <dependency> <groupId>org.ioc</groupId> <artifactId>web-factory</artifactId> <version>2.2.4.STABLE</version> </dependency> </dependencies> <repositories> <repository> <id>context</id> <url>https://raw.github.com/GenCloud/ioc_container/context</url> </repository> <repository> <id>cache</id> <url>https://raw.github.com/GenCloud/ioc_container/cache</url> </repository> <repository> <id>threading</id> <url>https://raw.github.com/GenCloud/ioc_container/threading</url> </repository> <repository> <id>orm</id> <url>https://raw.github.com/GenCloud/ioc_container/orm</url> </repository> <repository> <id>web</id> <url>https://raw.github.com/GenCloud/ioc_container/web</url> </repository> </repositories> </project>
** Todavía no se ha mudado a Maven Central, por desgracia.
Estructura del proyecto:

Patrón MVC estándar, ¿no?
Cree un punto de entrada a la aplicación:
package org.examples.webapp; import org.ioc.annotations.context.ScanPackage; import org.ioc.annotations.modules.CacheModule; import org.ioc.annotations.modules.DatabaseModule; import org.ioc.annotations.modules.ThreadingModule; import org.ioc.annotations.modules.WebModule; import org.ioc.context.starter.IoCStarter; @WebModule @CacheModule @ThreadingModule @DatabaseModule @ScanPackage(packages = {"org.examples.webapp"}) public class AppMain { public static void main(String[] args) { IoCStarter.start(AppMain.class); } }
** Explicaciones:
Anotación @ScanPackages : define paquetes contextuales para identificar componentes (en personas comunes: "contenedores").
Anotación @WebModule : sirve para conectar e inicializar una fábrica web.
Anotación @CacheModule : se usa para conectar e inicializar la fábrica de caché, se usa para que ORM funcione correctamente (en futuras versiones, no será necesaria una anotación).
Anotación @ThreadingModule : se utiliza para conectar e inicializar una fábrica de subprocesos, se utiliza para el funcionamiento correcto de una fábrica web (en versiones futuras, no se requerirá una anotación).
Anotación @DatabaseModule : se utiliza para conectar e inicializar una fábrica de ORM.
Todas las fábricas tienen configuradores predeterminados, que puede cambiar a los suyos al redefinir las funciones de la configuración utilizada por las fábricas (en cada anotación de módulo se redefine el configurador de clase - Clase <?> AutoConfigurationClass () predeterminado WebAutoConfiguration.class ), o deshabilitar cualquier configuración usando la anotación @Exclude en main aula
La utilidad IoCStarter es la clase principal de inicializador de contexto.
Bueno, todo parece estar listo, el contexto se inicializa, la web funciona en el puerto predeterminado 8081, pero no hay un enlace, y cuando vas al sitio realmente no nos da nada. Bueno, sigue adelante.
Creemos un archivo de configuración para nuestros módulos. Por defecto, todas las configuraciones se cargan desde {working_dir} /configs/default_settings.properties; lo crearemos a lo largo de la ruta adecuada.
# Threading ioc.threads.poolName=shared ioc.threads.availableProcessors=4 ioc.threads.threadTimeout=0 ioc.threads.threadAllowCoreTimeOut=true ioc.threads.threadPoolPriority=NORMAL # Event dispather # - () ( ) ioc.dispatcher.availableDescriptors=4 # Cache # (EhFactory|GuavaFactory) cache.factory=org.ioc.cache.impl.EhFactory # Datasource # (-, - ) #LOCAL, LOCAL_SERVER, REMOTE datasource.orient.database-type=LOCAL # datasource.orient.url=./database # ( ) datasource.orient.database=orient # datasource.orient.username=admin # datasource.orient.password=admin # (create, dropCreate, refresh, none) datasource.orient.ddl-auto=dropCreate # , datasource.orient.showSql=true # Web server # web.server.port=8081 # SSL web.server.ssl-enabled=false # in seconds # ( 7200 . = 2 ) web.server.security.session.timeout=300 # - web.server.velocity.input.encoding=UTF-8 web.server.velocity.output.encoding=UTF-8 # - web.server.velocity.resource.loader=file # web.server.velocity.resource.loader.class=org.apache.velocity.runtime.resource.loader.FileResourceLoader # - web.server.velocity.resource.loading.path=./public
A continuación, necesitamos una entidad de usuario y su repositorio de gestión:
Implementación de la entidad TblAccount:
package org.examples.webapp.domain.entity; import org.ioc.web.security.user.UserDetails; import javax.persistence.*; import java.util.Collections; import java.util.List; @Entity public class TblAccount implements UserDetails { @Id @GeneratedValue(strategy = GenerationType.SEQUENCE) private long id; @Column(name = "username") private String username; @Column(name = "password") private String password; @Transient private String repeatedPassword; public String getRepeatedPassword() { return repeatedPassword; } public void setRepeatedPassword(String repeatedPassword) { this.repeatedPassword = repeatedPassword; } @Override public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } @Override public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } @Override public List<String> getRoles() { return Collections.singletonList("ROLE_USER"); } }
** Explicaciones:
Todo es estándar como con todos los marcos compatibles con JPA. Asigne la entidad con @ .Entity , cree la Clave primaria con la anotación @ .Id , asigne las columnas con la anotación @Column. y herede de UserDetails para identificar la entidad en el módulo de Seguridad .
Implementación del repositorio de entidades TblAccountRepository:
package org.examples.webapp.domain.repository; import org.examples.webapp.domain.entity.TblAccount; import org.ioc.annotations.context.IoCRepository; import org.ioc.orm.repositories.CrudRepository; import javax.transaction.Transactional; @IoCRepository public interface TblAccountRepository extends CrudRepository<TblAccount, Long> { @Transactional TblAccount findByUsernameEq(String username); }
** Explicaciones:
Anotación @IoCRepository : sirve para determinar por contexto que la clase es un repositorio y debe procesarse de manera "diferente" .
Admite funciones CRUD estándar:
- Captura de entidad (ID de identificación) : obtiene una entidad de tipo Entidad de la base de datos o del caché mediante la Clave primaria;
- List fetchAll () - obtiene todas las entidades del tipo Entidad, precargándolas en el caché;
- guardar vacío (Entidad de entidad) : crea / actualiza una entidad de tipo Entidad tanto en la base de datos como en el caché;
- void delete (Entity entity) : elimina una entidad de tipo Entity de la base de datos y de la memoria caché;
- existe booleano (ID de ID) : comprueba si existe una entidad en la base de datos utilizando la clave primaria.
Todas las solicitudes CRUD ocurren en una transacción.
Admite la generación automática de consultas anulando funciones con palabras clave, como en la implementación anterior ( TblAccount findByUsernameEq (String username) ) y llamando consultas registradas ( NamedQuery )
Función findByUsernameEq (String username) : busca una entidad por su campo de nombre de usuario . Solicitud generada:
select * from tbl_account where username = 'username'
A continuación, necesitamos un nivel para gestionar la lógica empresarial.
Implementaciones de AccountService:
package org.examples.webapp.service; import org.examples.webapp.domain.entity.TblAccount; import org.examples.webapp.domain.repository.TblAccountRepository; import org.examples.webapp.responces.IMessage; import org.ioc.annotations.context.IoCComponent; import org.ioc.annotations.context.IoCDependency; import org.ioc.web.model.http.Request; import org.ioc.web.security.configuration.SecurityConfigureAdapter; import org.ioc.web.security.encoder.bcrypt.BCryptEncoder; import org.ioc.web.security.user.UserDetails; import org.ioc.web.security.user.UserDetailsProcessor; import java.util.Objects; import static org.examples.webapp.responces.IMessage.Type.ERROR; import static org.examples.webapp.responces.IMessage.Type.OK; @IoCComponent public class AccountService implements UserDetailsProcessor { @IoCDependency private TblAccountRepository tblAccountRepository; @IoCDependency private BCryptEncoder bCryptEncoder; @IoCDependency private SecurityConfigureAdapter securityConfigureAdapter; @Override public UserDetails loadUserByUsername(String username) { return tblAccountRepository.findByUsernameEq(username); } public void save(TblAccount tblAccount) { tblAccountRepository.save(tblAccount); } public void delete(TblAccount tblAccount) { tblAccountRepository.delete(tblAccount); } public IMessage tryCreateUser(String username, String password, String repeatedPassword) { if (username == null || username.isEmpty() || password == null || password.isEmpty() || repeatedPassword == null || repeatedPassword.isEmpty()) { return new IMessage(ERROR, "Invalid request parameters!"); } if (!Objects.equals(password, repeatedPassword)) { return new IMessage(ERROR, "Repeated password doesn't match!"); } final UserDetails userDetails = loadUserByUsername(username); if (userDetails != null) { return new IMessage(ERROR, "Account already exists!"); } final TblAccount account = new TblAccount(); account.setUsername(username); account.setPassword(bCryptEncoder.encode(password)); save(account); return new IMessage(OK, "Successfully created!"); } public IMessage tryAuthenticateUser(Request request, String username, String password) { if (username == null || username.isEmpty() || password == null || password.isEmpty()) { return new IMessage(ERROR, "Invalid request parameters!"); } final UserDetails userDetails = loadUserByUsername(username); if (userDetails == null) { return new IMessage(ERROR, "Account not found!"); } if (!bCryptEncoder.match(password, userDetails.getPassword())) { return new IMessage(ERROR, "Password does not match!"); } securityConfigureAdapter.getContext().authenticate(request, userDetails); return new IMessage(OK, "Successfully authenticated"); } public IMessage logout(Request request) { if (securityConfigureAdapter.getContext().removeAuthInformation(request)) { return new IMessage(OK, "/"); } return new IMessage(ERROR, "Credentials not found or not authenticated!"); } }
** Explicaciones:
Anotación @IoCComponent : sirve para inicializar una clase como componente.
Anotación @IoCDependency : se usa para inyectar dependencias en una instancia de una clase.
La utilidad BCryptEncoder es una implementación del códec BCrypt para el cifrado de contraseña (hasta ahora el único códec).
Instancia del sistema SecurityConfigureAdapter : se utiliza para trabajar con solicitudes de asignación y sesiones de usuario.
Función UserDetails loadUserByUsername : función heredada UserDetailsProcessor , sirve para cargar al usuario en la sesión y establecer el indicador de autenticación (en el futuro para la asignación estándar de autorización en Seguridad )
La función IMessage tryCreateUser es una función de creación de usuarios.
Función iMessage tryAuthenticateUser : función de autenticación de usuario.
La función de cierre de sesión de IMessage es una función para borrar una sesión de un usuario autorizado.
La clase IMessage es una clase de utilidad para mostrar la información que necesitamos en el navegador (respuesta json).
package org.examples.webapp.responces; public class IMessage { private final String message; private final Type type; public IMessage(String message) { this.message = message; type = Type.OK; } public IMessage(Type type, String message) { this.message = message; this.type = type; } public String getMessage() { return message; } public Type getType() { return type; } public enum Type { OK, ERROR } }
Ahora necesita la implementación del enlace en sí (mapeo de solicitud):
package org.examples.webapp.mapping; import org.examples.webapp.domain.entity.TblAccount; import org.examples.webapp.responces.IMessage; import org.examples.webapp.service.AccountService; import org.ioc.annotations.context.IoCDependency; import org.ioc.annotations.web.IoCController; import org.ioc.web.annotations.Credentials; import org.ioc.web.annotations.MappingMethod; import org.ioc.web.annotations.RequestParam; import org.ioc.web.annotations.UrlMapping; import org.ioc.web.model.ModelAndView; import org.ioc.web.model.http.Request; @IoCController @UrlMapping("/") public class MainMapping { @IoCDependency private AccountService accountService; @UrlMapping public ModelAndView index() { final ModelAndView modelAndView = new ModelAndView(); modelAndView.setView("index"); return modelAndView; } @UrlMapping(value = "signup", method = MappingMethod.POST) public IMessage createUser(@RequestParam("username") String username, @RequestParam("password") String password, @RequestParam("repeatedPassword") String repeatedPassword) { return accountService.tryCreateUser(username, password, repeatedPassword); } @UrlMapping(value = "signin", method = MappingMethod.POST) public IMessage auth(Request request, @RequestParam("username") String username, @RequestParam("password") String password) { return accountService.tryAuthenticateUser(request, username, password); } @UrlMapping("signout") public IMessage signout(Request request) { return accountService.logout(request); } @UrlMapping("loginPage") public ModelAndView authenticated(@Credentials TblAccount account) { final ModelAndView modelAndView = new ModelAndView(); modelAndView.setView("auth"); modelAndView.addAttribute("account", account); return modelAndView; } }
** Explicaciones:
Anotación @IoCController : sirve para identificar la clase en el contexto como un controlador (mapeador de solicitud del navegador)
Anotación @UrlMapping : indica que es necesario analizar una función / clase para detectar la presencia de solicitudes procesadas por los manejadores de canales.
Parámetros:
- valor : la solicitud que necesitamos;
- método : método http para el procesamiento (GET, POST, PUT, etc.);
- consume - tipo http mime para verificar un tipo específico de solicitud (opcional);
- produce - http content-type para devolver un tipo de contenido específico en la respuesta (Content-Type: text / html; charset = utf-8, Content-Type: multipart / form-data; boundary = something, etc. opcional;
Anotación @RequestParam : sirve para determinar el nombre del parámetro recibido a partir de la solicitud. Dado que es imposible obtener el nombre actual del parámetro del método de forma predeterminada mediante la reflexión, era demasiado vago para conectar una dependencia javaassist adicional, para chamán con asm. Por lo tanto, dicho método para determinar el nombre del parámetro para incrustar los valores de este parámetro obtenidos de la solicitud. Existe un análogo para el tipo GET , @PathVariable , el mismo principio de funcionamiento (no compatible con POST ).
Anotación @Credentials : sirve para insertar los datos actuales del usuario autorizado; de lo contrario, puede ser nulo si la información del usuario autorizado no está en la sesión.
El sistema de clase Solicitud es la información actual sobre una solicitud entrante, que contiene coca, encabezados y un canal de usuario, que luego puede enviarse a Push Message's ... que ya tiene algún tipo de fantasía al respecto.
La clase de utilidad ModelAndView es un modelo de página con el nombre del recurso sin una extensión y atributos para incrustar en el recurso.
Parece ser todo, pero no, definitivamente debe configurar la asignación de solicitudes disponible para los usuarios.
package org.examples.webapp.config; import org.ioc.annotations.configuration.Property; import org.ioc.annotations.configuration.PropertyFunction; import org.ioc.web.security.configuration.HttpContainer; import org.ioc.web.security.configuration.SecurityConfigureProcessor; import org.ioc.web.security.encoder.Encoder; import org.ioc.web.security.encoder.bcrypt.BCryptEncoder; import org.ioc.web.security.filter.CorsFilter; import org.ioc.web.security.filter.CsrfFilter; @Property public class SecurityConfig implements SecurityConfigureProcessor { @Override public void configure(HttpContainer httpContainer) { httpContainer. configureRequests(). anonymousRequests("/", "/signup", "/signin"). resourceRequests("/static/**"). authorizeRequests("/loginPage", "ROLE_USER"). authorizeRequests("/signout", "ROLE_USER"). and(). configureSession(). expiredPath("/"); } @PropertyFunction public CsrfFilter csrfFilter() { return new CsrfFilter(); } @PropertyFunction public CorsFilter corsFilter() { return new CorsFilter(); } @PropertyFunction public Encoder encoder() { return new BCryptEncoder(); } }
** Explicaciones:
Anotación @Property : indica al contexto que se trata de un archivo de configuración y que debe inicializarse.
Anotación @PropertyFunction : informa al analizador de configuración que esta función devuelve algún tipo y debe inicializarla como un componente (bin).
Interface SecurityConfigureProcessor : una utilidad utilizada para configurar la asignación de solicitudes.
La clase de modelo HttpContainer es una utilidad que almacena la asignación de solicitudes especificadas por el usuario.
La clase CsrfFilter es un filtro de solicitudes no válidas (implementaciones de la mecánica CSRF).
La clase CorsFilter es un filtro de intercambio de recursos de origen cruzado.
Función AnonymousRequests : acepta un conjunto ilimitado de solicitudes, no requiere usuarios autorizados y verificación de roles (ROLE_ANONYMOUS).
La función resourceRequests : toma una matriz ilimitada de solicitudes, específicamente sirve para determinar qué ruta será el archivo de recursos que no requiere un procesamiento complejo (css, js, imágenes, etc.).
Función authorizeRequests : acepta una variedad ilimitada de solicitudes, requiere un usuario autorizado y la función específica inherente al usuario.
Función ExpiredPath : cuando se borra una sesión que ha expirado a tiempo, el usuario es redirigido por esta asignación (enlace de redireccionamiento).
Bueno, había páginas, guiones y estilos de sitio (no voy a profundizar).
Encabezado de spoilerindex.vm - página principal
<html> <head> <meta charset="utf-8"/> <title>IoC Test</title> <link rel="stylesheet" href="/static/css/bootstrap.min.css"> <link rel="stylesheet" href="/static/css/style.css"/> <link rel="stylesheet" href="/static/css/pnotify.custom.min.css"/> <link rel="stylesheet" href="/static/css/pnotify.css"/> <link rel="stylesheet" href="/static/css/pnotify.buttons.css"/> </head> <body> <div class="container"> <h1>IoC Starter Test</h1> <br> <h4>Create user</h4> <br> <form id="creation"> <label for="username">Username: </label> <input type="text" id="username" name="username" class="color-input-field"/> <label for="password">Password: </label> <input type="password" id="password" name="password" class="color-input-field"/> <label for="repeatedPassword">Repeate: </label> <input type="password" id="repeatedPassword" name="repeatedPassword" class="color-input-field"/> <button type="button" class="btn btn-success btn-create">Sing up!</button> </form> <h4>Authenticate</h4> <br> <form id="auth"> <label for="username">Username: </label> <input type="text" id="username" name="username" class="color-input-field"/> <label for="password">Password: </label> <input type="password" id="password" name="password" class="color-input-field"/> <button type="button" class="btn btn-danger btn-auth">Sing in!</button> </form> </div> <script type="text/javascript" src="/static/js/jquery.js"></script> <script type="text/javascript" src="/static/js/bootstrap.min.js"></script> <script type="text/javascript" src="/static/js/scripts.js"></script> <script type="text/javascript" src="/static/js/pnotify.js"></script> <script type="text/javascript" src="/static/js/pnotify.buttons.js"></script> </body> </html>
auth.vm: para mostrar un usuario autorizado
<html> <head> <meta charset="utf-8"/> <title>IoC Test</title> <link rel="stylesheet" href="/static/css/bootstrap.min.css"> <link rel="stylesheet" href="/static/css/style.css"/> <link rel="stylesheet" href="/static/css/pnotify.custom.min.css"/> <link rel="stylesheet" href="/static/css/pnotify.css"/> <link rel="stylesheet" href="/static/css/pnotify.buttons.css"/> </head> <body> <div class="container"> <h1>Authorized page</h1> <br> <h4>Test auth data</h4> <div id="auth_data"> #if($!account) <h4>Hello @$!account.username, You successfully authenticated!</h4> <br> <button type="button" class="btn btn-success btn-logout">Logout!</button> #end </div> </div> <script type="text/javascript" src="/static/js/jquery.js"></script> <script type="text/javascript" src="/static/js/bootstrap.min.js"></script> <script type="text/javascript" src="/static/js/scripts.js"></script> <script type="text/javascript" src="/static/js/pnotify.js"></script> <script type="text/javascript" src="/static/js/pnotify.buttons.js"></script> </body> </html>
scripts.js - controlador, para enviar y recibir información de solicitud al servidor
$(function () { $(".btn-create").click(function () { var cooki = cookie(); document.cookie = 'CSRF-TOKEN=' + cooki; $.ajax({ url: "/signup", data: $('#creation').serialize(), headers: {'X-CSRF-TOKEN': cooki}, crossDomain: true, xhrFields: { withCredentials: true }, type: "POST" }).done(function (data) { switch (data.type) { case 'OK': new PNotify({ title: 'Success', text: data.message, type: 'success', hide: false }); break; case 'ERROR': new PNotify({ title: 'Error', text: data.message, type: 'error', hide: false }); break; } }); }); $(".btn-auth").click(function () { var cooki = cookie(); document.cookie = 'CSRF-TOKEN=' + cooki; $.ajax({ url: "/signin", data: $('#auth').serialize(), headers: {'X-CSRF-TOKEN': cooki}, crossDomain: true, xhrFields: { withCredentials: true }, type: "POST" }).done(function (data) { switch (data.type) { case 'OK': new PNotify({ title: 'Success', text: data.message, type: 'success', hide: false }); setTimeout(function () { window.location = "/loginPage"; }, 5000); break; case 'ERROR': new PNotify({ title: 'Error', text: data.message, type: 'error', hide: false }); break; } }); }); $(".btn-logout").click(function () { $.ajax({ url: "/signout", crossDomain: true, xhrFields: { withCredentials: true }, type: "GET" }).done(function (data) { switch (data.type) { case 'OK': new PNotify({ title: 'Success', text: 'Logouting...', type: 'success', hide: false }); setTimeout(function () { window.location = data.message; }, 5000); break; case 'ERROR': new PNotify({ title: 'Error', text: data.message, type: 'error', hide: false }); break; } }); }); }); function cookie(a) { return a
Compila, ejecuta todo lo que tenemos.
Si todo está correcto, veremos algo como esto al final de la descarga:
Registro[21.10.18 22: 29: 51: 990] INFO web.model.mapping.MappingContainer: Método mapeado [/], método = [GET], a [public org.ioc.web.model.ModelAndView org.examples.webapp .mapping.MainMapping.index ()]
[21.10.18 22: 29: 51: 993] INFO web.model.mapping.MappingContainer: Método mapeado [/ signup], method = [POST], a [public org.examples.webapp.responces.IMessage org.examples. webapp.mapping.MainMapping.createUser (java.lang.String, java.lang.String, java.lang.String)]
[21.10.18 22: 29: 51: 993] INFO web.model.mapping.MappingContainer: Método mapeado [/ signin], method = [POST], a [public org.examples.webapp.responces.IMessage org.examples. webapp.mapping.MainMapping.auth (org.ioc.web.model.http.Request, java.lang.String, java.lang.String)]
[21.10.18 22: 29: 51: 993] INFO web.model.mapping.MappingContainer: Método mapeado [/ signout], method = [GET], a [public org.examples.webapp.responces.IMessage org.examples. webapp.mapping.MainMapping.signout (org.ioc.web.model.http.Request)]
[21.10.18 22: 29: 51: 995] INFO web.model.mapping.MappingContainer: Método mapeado [/ loginPage], método = [GET], a [public org.ioc.web.model.ModelAndView org.examples. webapp.mapping.MainMapping.authenticated (org.examples.webapp.domain.entity.TblAccount)]
[21.10.18 22: 29: 51: 997] INFO ioc.web.factory.HttpInitializerFactory: El servidor HTTP se inició en el puerto (s): 8081 (http)
Resultado:
1) Página de inicio

2) registro

3) autenticación

4) La página con el resultado de la autorización (redirigir después de ingresar el nombre de usuario y contraseña correctamente)

5) Borrar información de autorización de la sesión y redirigir al usuario a la página de inicio

6) Un intento de un usuario no autorizado de llegar a la página con información de autenticación de sesión

El final
El proyecto se está desarrollando, los "contribuyentes" y las ideas originales son bienvenidas, ya que es difícil hacer este proyecto solo.
Repositorio de proyectos .
Contexto
Fábrica de ORM
Fábrica web
Ejemplos
Ejemplo actual del artículo
También en el repositorio hay ejemplos del uso de toda la funcionalidad en el módulo 'ejemplos' y, como dicen: "Buena suerte, diviértanse", gracias a todos por su atención.