{"id":348,"date":"2013-11-19T00:12:27","date_gmt":"2013-11-19T03:12:27","guid":{"rendered":"https:\/\/www.erudio.com.br\/blog\/?p=348"},"modified":"2022-12-20T23:32:19","modified_gmt":"2022-12-21T02:32:19","slug":"iniciando-se-no-jsf-03-a-arquitetura-da-aplicacao","status":"publish","type":"post","link":"https:\/\/www.erudio.com.br\/blog\/iniciando-se-no-jsf-03-a-arquitetura-da-aplicacao\/","title":{"rendered":"Iniciando Se No JSF &#8211; 03 &#8211; A Arquitetura Da Aplica\u00e7\u00e3o"},"content":{"rendered":"<p>Bom a imagem abaixo representa a estrutura de pacotes em que se divide nossa aplica\u00e7\u00e3o. De cima para baixo temos as pastas <strong>META-INF<\/strong> e <strong>WEB-INF<\/strong> a primeira delas n\u00e3o tem muita relev\u00e2ncia nesse caso j\u00e1 a segunda \u00e9 repons\u00e1vel por armazenar os arquivos de configura\u00e7\u00e3o de nossa aplica\u00e7\u00e3o como <strong>faces.config.xml<\/strong> que armazena as configura\u00e7\u00f5es do JSF, o <strong>web.xml<\/strong> que mapeia listeners, servlets e demais configura\u00e7\u00f5es da aplica\u00e7\u00e3o e por fim temos o <strong>spring-security.xml<\/strong> que armazena as configura\u00e7\u00f5es de seguran\u00e7a de nossa aplica\u00e7\u00e3o. Um pouco abaixo temos as pastas <strong>public<\/strong>, <strong>restrict<\/strong> e <strong>resources<\/strong>. A pasta <strong>public<\/strong> no nosso projeto conter\u00e1 as p\u00e1ginas que poder\u00e3o ser acessadas sem a necessidade de autentica\u00e7\u00e3o por parte do usu\u00e1rio a <strong>restrict<\/strong> por sua vez armazena as p\u00e1ginas que s\u00f3 ser\u00e3o acessadas por usu\u00e1rios autenticados e autorizados. A pasta <strong>resources<\/strong> cont\u00e9m outras duas pastas <strong>public<\/strong> e <strong>restrict<\/strong> onde s\u00e3o armazenados arquivos de css, javascript e templates Facelets correspondentes as p\u00e1ginas publicas e restritas.<br \/>\nLogo abaixo temos nossa estrutura de pacotes. Inicialmente temos o pacote <strong>br.com.semeru.controller<\/strong> que armazena as classes da camada de controle de nossa aplica\u00e7\u00e3o. Logo abaixo temos o pacote <strong>br.com.semeru.conversores<\/strong> que armazena as classes respons\u00e1veis por converter dados, como por exemplo criptografar uma senha. Logo abaixo temos o pacote <strong>br.com.semeru.exceptions<\/strong> que armazena as classes respons\u00e1veis por tratar as exce\u00e7\u00f5es ocorridas na aplica\u00e7\u00e3o. Logo abaixo temos o pacote <strong>br.com.semeru.i18n<\/strong> que \u00e9 respons\u00e1vel por prover internacionaliza\u00e7\u00e3o da aplica\u00e7\u00e3o, entretanto isso ainda n\u00e3o foi aplicado no projeto atual. Mais abaixo temos o pacote <strong>br.com.semeru.dao<\/strong> que armazena a uma interface do DAO e uma classe de DAO Gen\u00e9rico que \u00e9 respons\u00e1vel por acessar os a base de dados. Um pouco mais abaixo temos o pacote <strong>br.com.semeru.entities<\/strong> que armazena as entidades que representam as tabelas do banco de dados da nossa aplica\u00e7\u00e3o. Vale destacar que nossa arquitetura segue o padr\u00e3o MVC onde as p\u00e1ginas representam a camada de vis\u00e3o (V) os DAO&#8217;s e as Entidades representam o modelo (M) e o controle \u00e9 representado pelos nossos ManagedBeans. Logo abaixo temos o pacote <strong>br.com.semeru.suport <\/strong> que armazena os BackingBeans de nossa aplica\u00e7\u00e3o essas classes s\u00e3o repons\u00e1veis por oferecer suporte \u00e0 p\u00e1gina n\u00e3o processando nada e raramente contendo regras de neg\u00f3cio. Por fim temos o pacote <strong>br.com.semeru.validators<\/strong> que armazena as classes respons\u00e1veis por realizar valida\u00e7\u00f5es de dados no projeto.<br \/>\nTemos ainda no pacote default o arquivo <strong>hibernate.cfg.xml<\/strong>, a fim de manter o projeto levemente mais simples vamos mant\u00ea-lo no pacote default. Pouco depois temos o pacote ScriptsSQL que contem o backup de alguns dados do nosso banco e depois o arquivo <strong>pom.xml<\/strong> que \u00e9 o respons\u00e1vel por armazenar as configura\u00e7\u00f5es do Maven. N\u00e3o irei me aprofundar muito em explica\u00e7\u00f5es do Maven para entender melhor sobre o maven acesse <a href=\"https:\/\/www.erudio.com.br\/blog\/entendendo-o-apache-maven\/\">este link, <\/a><a href=\"https:\/\/www.erudio.com.br\/blog\/entendendo-o-pom-do-maven\/\"> este e <\/a><a href=\"https:\/\/www.erudio.com.br\/blog\/gerando-um-jar-com-as-dependencias-em-um-projeto-maven\/\">este.<\/p>\n<p><\/a><\/p>\n<p><a href=\"https:\/\/www.erudio.com.br\/blog\/iniciando-se-no-jsf-03-a-arquitetura-da-aplicacao\/arquiteturasemeru\/\" rel=\"attachment wp-att-428\"><img decoding=\"async\" loading=\"lazy\" class=\"aligncenter size-full wp-image-428\" src=\"https:\/\/www.erudio.com.br\/blog\/wp-content\/uploads\/2013\/02\/ArquiteturaSemeru.png\" alt=\"ArquiteturaSemeru\" width=\"348\" height=\"1155\" srcset=\"https:\/\/www.erudio.com.br\/blog\/wp-content\/uploads\/2013\/02\/ArquiteturaSemeru.png 348w, https:\/\/www.erudio.com.br\/blog\/wp-content\/uploads\/2013\/02\/ArquiteturaSemeru-90x300.png 90w\" sizes=\"(max-width: 348px) 100vw, 348px\" \/><\/a><\/p>\n<p><strong>05 &#8211; Curso De JSF Do Zero \u00c0 Nuvem &#8211; Definindo A Estrutura De Pacotes<\/strong><\/p>\n<p>Nesse v\u00eddeo iremos montar toda a estrutura de pacotes onde \u00e9 explicado com mais detalhe todo o projeto.<\/p>\n<figure class=\"wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\">\n<div class=\"wp-block-embed__wrapper\"><iframe loading=\"lazy\" src=\"https:\/\/www.youtube.com\/embed\/et_z0GcHvoc\" width=\"648\" height=\"365\" frameborder=\"0\" allowfullscreen=\"allowfullscreen\"><br \/>\n<\/iframe><\/div>\n<\/figure>\n<p>Aqui temos a classe HibernateUtil que \u00e9 respons\u00e1vel por criar a SessionFactory que nos permitir\u00e1 acessar a base de dados. Inicialmente declaramos uma inst\u00e2ncia de SessionFactory e depois uma constante com a sess\u00e3o do Hibernate. Logo abaixo temos um bloco est\u00e1tico que \u00e9 respons\u00e1vel por tentar criar uma SessionFactory. Inicialmente declaramos uma inst\u00e2ncia de Configuration. Posteriormente tentamos registrar uma SessionFactory para isso passamos como par\u00e2metro no m\u00e9todo applySettings as informa\u00e7\u00f5es do nosso hibernate.cfg.xml se mudarmos esse arquivo para um pacote diferente do default deveremos passar sua localiza\u00e7\u00e3o como par\u00e2metro configuration.getProperties, caso contr\u00e1rio o Hibernate n\u00e3o saber\u00e1 se localizar. Caso ocorra alguma falha nesse processo uma exception ser\u00e1 lan\u00e7ada. Por fim temos o o m\u00e9todo getSessionFactory que \u00e9 o respons\u00e1vel por permitir a obten\u00e7\u00e3o da SessionFactory pelo nosso PhaseListener, que ser\u00e1 abordado mais abaixo.<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\npackage br.com.semeru.util;\n\nimport org.hibernate.SessionFactory;\nimport org.hibernate.cfg.Configuration;\nimport org.hibernate.service.ServiceRegistry;\nimport org.hibernate.service.ServiceRegistryBuilder;\n\npublic class HibernateUtil {\n\n    private static final SessionFactory sessionFactory;\n    public static final String HIBERNATE_SESSION = &quot;hibernate_session&quot;;\n\n    static{\n\n        try {\n            Configuration configuration = new Configuration().configure();\n\n            ServiceRegistry serviceRegistry = new ServiceRegistryBuilder().\n                applySettings(configuration.getProperties()).buildServiceRegistry();\n            sessionFactory = configuration.buildSessionFactory(serviceRegistry);\n        } catch (Exception ex) {\n            throw new ExceptionInInitializerError(ex);\n        }\n    }\n\n    public static SessionFactory getSessionFactory() {\n        return sessionFactory;\n    }\n\n}\n<\/pre>\n<p><strong>06 &#8211; Curso De JSF Do Zero \u00c0 Nuvem &#8211; Criando A Classe HibernateUtil<\/strong><\/p>\n<p>Aqui temos o processo de cria\u00e7\u00e3o da classe HibernateUtil que detalha um pouco mais essas informa\u00e7\u00f5es.<\/p>\n<figure class=\"wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\">\n<div class=\"wp-block-embed__wrapper\"><iframe loading=\"lazy\" src=\"https:\/\/www.youtube.com\/embed\/z5v8Hxd9TOY\" width=\"648\" height=\"365\" frameborder=\"0\" allowfullscreen=\"allowfullscreen\"><br \/>\n<\/iframe><\/div>\n<\/figure>\n<p><strong>07 &#8211; Curso De JSF Do Zero \u00c0 Nuvem &#8211; Removendo Depend\u00eancia Duplicada E slf4j<\/strong><\/p>\n<p>Nesse v\u00eddeo removemos uma depend\u00eancia duplicada e o slf4j que estavam impedindo a execu\u00e7\u00e3o de nosso projeto.<\/p>\n<figure class=\"wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\">\n<div class=\"wp-block-embed__wrapper\"><iframe loading=\"lazy\" src=\"https:\/\/www.youtube.com\/embed\/BygizO8VqRg\" width=\"648\" height=\"365\" frameborder=\"0\" allowfullscreen=\"allowfullscreen\"><br \/>\n<\/iframe><\/div>\n<\/figure>\n<p>Aqui temos as nossa InterfaceDAO que define os m\u00e9todos que o nosso DAO gen\u00e9rico dever\u00e1 implementar. S\u00e3o eles save, update, remove, merge respons\u00e1veis por salvar, atualizar, remover e tanto salvar quanto atualizar respectivamente. Temos tamb\u00e9m os m\u00e9todos de leitura como por exemplo o getEntity que obt\u00e9m um objeto no banco, o getEntityByDetachedCriteria que obt\u00e9m um objeto no banco atrav\u00e9s de uma DetachedCriteria, o getEntities que obt\u00e9m uma lista de objetos no banco e getListByDetachedCriteria que obt\u00e9m uma lista de objetos no banco atrav\u00e9s de uma DetachedCriteria.<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\npackage br.com.semeru.model.dao;\n\nimport java.io.Serializable;\nimport java.util.List;\nimport org.hibernate.criterion.DetachedCriteria;\n\npublic interface InterfaceDAO&lt;t&gt; {\n\n    void save (T entity);\n    void update (T entity);\n    void remove (T entity);\n    void merge (T entity);\n    T getEntity(Serializable id);\n    T getEntityByDetachedCriteria(DetachedCriteria criteria);\n    List&lt;t&gt; getEntities();\n    List&lt;t&gt; getListByDetachedCriteria(DetachedCriteria criteria);    \n\n}\n<\/pre>\n<p>Aqui temos a nossa classe HibernateDAO que \u00e9 de tipagem gen\u00e9rica, o que siginfica que o nosso DAO possibilitar\u00e1 a persistencia de todas as entidades da nossa aplica\u00e7\u00e3o. No nosso construtor obrigamos a sempre passar o tipo da entidade que queremos persistir e a sess\u00e3o do hibernate para que o DAO fa\u00e7a o servi\u00e7o. Al\u00e9m disso toda a implementa\u00e7\u00e3o \u00e9 bastante simples, sendo necess\u00e1rio apenas usar a session do hibernate e executar seus m\u00e9todos passando a entidade envolvida como par\u00e2metro.<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\npackage br.com.semeru.model.dao;\n\nimport java.io.Serializable;\nimport java.util.List;\nimport org.hibernate.Criteria;\nimport org.hibernate.Session;\nimport org.hibernate.criterion.DetachedCriteria;\n\npublic class HibernateDAO&lt;t&gt; implements InterfaceDAO&lt;t&gt;, Serializable {\n\n    private static final long serialVersionUID = 1L;\n\n    private Class&lt;t&gt; classe;\n    private Session session;\n\n    public HibernateDAO(Class&lt;t&gt; classe, Session session) {\n        super();\n        this.classe = classe;\n        this.session = session;\n    }\n\n    @Override\n    public void save(T entity) {\n        session.save(entity);\n    }\n\n    @Override\n    public void update(T entity) {\n        session.update(entity);\n    }\n\n    @Override\n    public void remove(T entity) {\n        session.delete(entity);\n    }\n\n    @Override\n    public void merge(T entity) {\n        session.merge(entity);\n    }\n\n    @Override\n    public T getEntity(Serializable id) {\n        T entity = (T)session.get(classe, id);\n        return entity;\n    }\n\n    @Override\n    public T getEntityByDetachedCriteria(DetachedCriteria criteria) {\n        T entity = (T)criteria.getExecutableCriteria(session).uniqueResult();\n        return entity;\n    }\n\n    @Override\n    public List&lt;t&gt; getListByDetachedCriteria(DetachedCriteria criteria) {\n        return criteria.getExecutableCriteria(session).list();\n    }\n\n    @Override\n    public List&lt;t&gt; getEntities() {\n        List&lt;t&gt; enties = (List&lt;t&gt;) session.createCriteria(classe).list();\n        return enties;\n    }    \n\n}\n<\/pre>\n<p><strong>08 &#8211; Curso De JSF Do Zero \u00c0 Nuvem &#8211; Cria\u00e7\u00e3o Do DAO Gen\u00e9rico<\/strong><\/p>\n<p>Nesse v\u00eddeo n\u00f3s criamos a interface e o DAO gen\u00e9rico, neles voc\u00ea ter\u00e1 informa\u00e7\u00f5es com maiores detalhes.<\/p>\n<figure class=\"wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\">\n<div class=\"wp-block-embed__wrapper\"><iframe loading=\"lazy\" src=\"https:\/\/www.youtube.com\/embed\/aYjeNxf28mg\" width=\"648\" height=\"365\" frameborder=\"0\" allowfullscreen=\"allowfullscreen\"><br \/>\n<\/iframe><\/div>\n<\/figure>\n<p>Aqui temos a classe FacesContextUtil que \u00e9 respons\u00e1vel por colocar na sess\u00e3o do usu\u00e1rio (FacesContext) do JSF, a sess\u00e3o do Hibernate. Como se pode perceber ela possui um atributo est\u00e1tico que \u00e9 a chave da sess\u00e3o do Hibernate e dois m\u00e9todos set e get. O primeiro deles captura o RequestMap do FacesContext e atribui a ele a sess\u00e3o do Hibernate. O segundo m\u00e9todo obt\u00e9m de volta a sess\u00e3o do Hibernate para que o PhaseListenerSemeru possa realizar o commit na transa\u00e7\u00e3o como ser\u00e1 explicado mais abaixo.<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\npackage br.com.semeru.util;\n\nimport javax.faces.context.FacesContext;\nimport org.hibernate.Session;\n\npublic class FacesContextUtil {\n\n    private static final String HIBERNATE_SESSION = &quot;hibernate_session&quot;;\n\n    public static void setRequestSession(Session session){\n        FacesContext.getCurrentInstance().getExternalContext().getRequestMap().put(HIBERNATE_SESSION, session);\n    }\n\n    public static Session getRequestSession() {\n        return (Session)FacesContext.getCurrentInstance().getExternalContext().getRequestMap().get(HIBERNATE_SESSION);\n    }\n\n}\n<\/pre>\n<p>Antes de partir para a pr\u00f3xima etapa recomendo que voc\u00ea leia <a href=\"https:\/\/www.erudio.com.br\/blog\/o-ciclo-de-vida-das-requisicoes-no-javaserver-faces\">este post<\/a> que explica como funciona o ciclo de vida do JSF. Agora aproveite para assistir tamb\u00e9m a parte te\u00f3rica do video abaixo em que isso \u00e9 abordado com mais detalhes.<\/p>\n<p><strong>09 &#8211; Curso De JSF Do Zero \u00c0 Nuvem &#8211; O Ciclo De Vida De Uma Request No JSF E O FacesContextUtil<\/strong><\/p>\n<figure class=\"wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\">\n<div class=\"wp-block-embed__wrapper\"><iframe loading=\"lazy\" src=\"https:\/\/www.youtube.com\/embed\/hWe7qZ3JqUM\" width=\"648\" height=\"365\" frameborder=\"0\" allowfullscreen=\"allowfullscreen\"><br \/>\n<\/iframe><\/div>\n<\/figure>\n<p>Atuando junto \u00e0 classe FacesContextUtil temos a classe PhaseListenerSemeru \u00e9 a respons\u00e1vel por auxiliar o sistema de login e por implementar o padr\u00e3o Open Session in View do Hibernate. Open Session in View consiste em iniciar a transa\u00e7\u00e3o quando \u00e9 feita uma requisi\u00e7\u00e3o e encerr\u00e1-la quando a p\u00e1gina \u00e9 renderizada. O PhaseListenerSemeru implementa a interface PhaseListener do JSF e possui tr\u00eas m\u00e9todos beforePhase, afterPhase e getPhaseId. O m\u00e9todo beforePhase verifica se a fase est\u00e1 antes da Restore View (Restaurar a Vis\u00e3o), se estiver ele abre a sess\u00e3o do Hibernate e coloca-a na requisi\u00e7\u00e3o do usu\u00e1rio passando-a para o FacesContext. O segundo m\u00e9todo, verifica se a fase Render Response (Renderizar a Resposta) foi executada, se sim, ele tenta commitar a transa\u00e7\u00e3o. Se ocorrer algum erro ele imprime uma mensagem no log, nesse momento, caso a sess\u00e3o ainda esteja ativa ele executa um rollback e finalmente fecha a sess\u00e3o. Caso n\u00e3o ocorram erros ele encerra a transa\u00e7\u00e3o e fecha a sess\u00e3o. J\u00e1 o terceiro m\u00e9todo, o getPhaseId \u00e9 respons\u00e1vel por especificar em que fase o PhaseListener deve ser acionado, no nosso exemplo ele \u00e9 acionado em todas as fases. Dessa forma, a classe PhaseListenerSemeru implementa o Open Session in View de forma transparente para o desenvolvedor. Essa abordagem torna desnecess\u00e1rio, ao desenvolvedor, se preocupar com abrir e fechar a sess\u00e3o. Toda a responsabilidade pelo controle de sess\u00e3o passa a ser feito pelo PhaseListenerSemeru atrav\u00e9s da verifica\u00e7\u00e3o das fases da requisi\u00e7\u00e3o no FacesContext, do JSF.<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\npackage br.com.semeru.util;\n\nimport javax.faces.event.PhaseEvent;\nimport javax.faces.event.PhaseId;\nimport javax.faces.event.PhaseListener;\nimport org.hibernate.Session;\n\npublic class PhaseListenerSemeru implements PhaseListener {\n\n    \/\/Antes da Fase\n    @Override\n    public void beforePhase(PhaseEvent fase) {\n        System.out.println(&quot;Antes da fase: &quot;+ fase.getPhaseId());\n        if (fase.getPhaseId().equals(PhaseId.RESTORE_VIEW)) {\n            Session session = HibernateUtil.getSessionFactory().openSession();\n            session.beginTransaction();\n            FacesContextUtil.setRequestSession(session);\n        }\n    }\n\n    \/\/Depois da Fase\n    @Override\n    public void afterPhase(PhaseEvent fase) {\n        System.out.println(&quot;Depois da fase: &quot;+ fase.getPhaseId());\n        if (fase.getPhaseId().equals(PhaseId.RENDER_RESPONSE)) {\n            Session session = FacesContextUtil.getRequestSession();\n            try {\n                session.getTransaction().commit();\n            } catch (Exception e) {\n                if (session.getTransaction().isActive()) {\n                    session.getTransaction().rollback();\n                }\n            } finally{\n                session.close();\n            }\n        }\n    }\n\n    @Override\n    public PhaseId getPhaseId() {\n        return PhaseId.ANY_PHASE;\n    }\n\n}\n<\/pre>\n<p>Para refor\u00e7ar os conceitos sobre o PhaseListener assista mais essa v\u00eddeo aula.<\/p>\n<p><strong>10 &#8211; Curso De JSF Do Zero \u00c0 Nuvem &#8211; O PhaseListener<\/strong><\/p>\n<figure class=\"wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\">\n<div class=\"wp-block-embed__wrapper\"><iframe loading=\"lazy\" src=\"https:\/\/www.youtube.com\/embed\/ZghqMGl5KrE\" width=\"648\" height=\"365\" frameborder=\"0\" allowfullscreen=\"allowfullscreen\"><br \/>\n<\/iframe><\/div>\n<\/figure>\n<p>Agora que temos uma vis\u00e3o geral mais clara botaremos para quebrar nos pr\u00f3ximos posts. Lembrando que os coment\u00e1rios s\u00e3o importantes para que eu possa ir melhorando gradativamente os posts. Quero destacar tamb\u00e9m que os fontes desse curso podem ser baixados do <a href=\"https:\/\/github.com\/leandrocgsi\/semeru_jsf_maven\"><strong>GitHub<\/strong><\/a>. Ser\u00e3o feitos posts correspondentes \u00e0s demais v\u00eddeo aulas e assim que poss\u00edvel irei realizando posts para complementar o que foi falado nos v\u00eddeos. \u00c9 isso a\u00ed bons estudos.<\/p>\n<h2>Treinamentos relacionados com este post<\/h2>\n<p><a href=\"https:\/\/pub.erudio.com.br\/kr\/blog_rest_spring_java\" target=\"_blank\" rel=\"noopener\"><br \/><img decoding=\"async\" style=\"max-width: 100%;\" title=\"REST API's RESTFul do 0 \u00e0  AWS com Spring Boot 3, Java e Docker\" src=\"https:\/\/raw.githubusercontent.com\/leandrocgsi\/blog-images\/main\/07-rest-spring-java.png\" \/><br \/><\/a><\/p>\n<p><a href=\"https:\/\/pub.erudio.com.br\/kr\/blog_microservices_java\" target=\"_blank\" rel=\"noopener\"> <img decoding=\"async\" style=\"max-width: 100%;\" title=\"Microservices do 0 com Spring Cloud, Spring Boot e Docker\" src=\"https:\/\/raw.githubusercontent.com\/leandrocgsi\/blog-images\/main\/14-microservices-java.png\" \/><br \/><\/a><\/p>\n<p><a href=\"https:\/\/pub.erudio.com.br\/kr\/blog_rest_spring_kotlin\" target=\"_blank\" rel=\"noopener\"> <img decoding=\"async\" style=\"max-width: 100%;\" title=\"REST API's RESTFul do 0 \u00e0 AWS com Spring Boot 3, Kotlin e Docker\" src=\"https:\/\/raw.githubusercontent.com\/leandrocgsi\/blog-images\/main\/18-rest-spring-kotlin.png\" \/><br \/><\/a><\/p>\n<p><a href=\"https:\/\/pub.erudio.com.br\/kr\/blog_ms_kotlin\" target=\"_blank\" rel=\"noopener\"> <img decoding=\"async\" style=\"max-width: 100%;\" title=\"Microsservi\u00e7os do 0 com Spring Cloud, Kotlin e Docker\" src=\"https:\/\/raw.githubusercontent.com\/leandrocgsi\/blog-images\/main\/22-ms-kotlin.png\" \/><br \/><\/a><\/p>\n<p><a href=\"https:\/\/pub.erudio.com.br\/kr\/blog_docker\" target=\"_blank\" rel=\"noopener\"> <img decoding=\"async\" style=\"max-width: 100%;\" title=\"Docker do 0 \u00e0 Maestria: Cont\u00eaineres Desmistificados mais 3 B\u00d4NUS\" src=\"https:\/\/raw.githubusercontent.com\/leandrocgsi\/blog-images\/main\/09-docker.png\" \/><br \/><\/a><\/p>\n<p><a href=\"https:\/\/pub.erudio.com.br\/kr\/blog_docker_para_aws\" target=\"_blank\" rel=\"noopener\"> <img decoding=\"async\" style=\"max-width: 100%;\" title=\"Docker para Amazon AWS Implante Apps Java e .NET com Travis CI\" src=\"https:\/\/raw.githubusercontent.com\/leandrocgsi\/blog-images\/main\/10-docker-to-aws.png\" \/><br \/><\/a><\/p>\n<p><a href=\"https:\/\/pub.erudio.com.br\/kr\/blog_kotlin\" target=\"_blank\" rel=\"noopener\"> <img decoding=\"async\" style=\"max-width: 100%;\" title=\"Kotlin para DEVs Java: Aprenda a Linguagem Padr\u00e3o do Android\" src=\"https:\/\/raw.githubusercontent.com\/leandrocgsi\/blog-images\/main\/20-kotlin.png\" \/><br \/><\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Bom a imagem abaixo representa a estrutura de pacotes em que se divide nossa aplica\u00e7\u00e3o. De cima para baixo temos as pastas META-INF e WEB-INF a primeira delas n\u00e3o tem muita relev\u00e2ncia nesse caso j\u00e1 a segunda \u00e9 repons\u00e1vel por armazenar os arquivos de configura\u00e7\u00e3o de nossa aplica\u00e7\u00e3o como faces.config.xml que armazena as configura\u00e7\u00f5es do [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[10,45,49,82],"tags":[131,172,176],"_links":{"self":[{"href":"https:\/\/www.erudio.com.br\/blog\/wp-json\/wp\/v2\/posts\/348"}],"collection":[{"href":"https:\/\/www.erudio.com.br\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.erudio.com.br\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.erudio.com.br\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.erudio.com.br\/blog\/wp-json\/wp\/v2\/comments?post=348"}],"version-history":[{"count":4,"href":"https:\/\/www.erudio.com.br\/blog\/wp-json\/wp\/v2\/posts\/348\/revisions"}],"predecessor-version":[{"id":1472,"href":"https:\/\/www.erudio.com.br\/blog\/wp-json\/wp\/v2\/posts\/348\/revisions\/1472"}],"wp:attachment":[{"href":"https:\/\/www.erudio.com.br\/blog\/wp-json\/wp\/v2\/media?parent=348"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.erudio.com.br\/blog\/wp-json\/wp\/v2\/categories?post=348"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.erudio.com.br\/blog\/wp-json\/wp\/v2\/tags?post=348"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}