Estrutura de Struts2
1. Por que usar estruturas?
(1) A estrutura completa automaticamente muitas tarefas triviais
Para o Struts2, nos ajuda a preencher facilmente a conversão do tipo de dados, verificação de dados, internacionalização, etc.
Tarefas comuns no desenvolvimento da Web. Existem também os modos de modelo que são amplamente utilizados na primavera, que estão tornando nosso processo de desenvolvimento mais automatizado e inteligente. O uso de uma estrutura é evitar reinventar a roda e re-copiar esses códigos de modelo.
A estrutura nos permite focar mais em questões de nível superior do que em fluxos de trabalho comuns e tarefas básicas.
(2) Usar uma estrutura significa herdar graciosamente a arquitetura por trás da estrutura
A arquitetura por trás da estrutura geralmente define uma série de fluxos de trabalho. O que precisamos fazer é anexar o código de um aplicativo específico a esse processo, para que possamos aproveitar os vários benefícios trazidos pela estrutura. Às vezes, também podemos resistir às regras arquitetônicas da estrutura, mas a estrutura geralmente fornece sua arquitetura de uma maneira difícil de rejeitar. É tão simples que você pode herdar uma excelente arquitetura graciosamente e é gratuita, então por que não fazer isso?
(3) É mais fácil encontrar pessoas bem treinadas usando a estrutura
Eu quase nunca usei nenhuma estrutura em todo o projeto da minha empresa antes e procurando serviços de serviço (semelhante ao JNDI)
Para o log de impressão (semelhante ao log4j) e depois ao pool de conexão do banco de dados (semelhante ao DBCP), todos eles são implementados pelo próprio pessoal interno. Em primeiro lugar, é porque o projeto é relativamente antigo e pode não haver nenhuma estrutura de código aberto para uso naquele momento. Em segundo lugar, é por causa da estratégia conservadora da empresa e está preocupada que o uso de uma estrutura de código aberto instável possa trazer riscos ao projeto. Isso pode ser verdade no ambiente naquela época, e a gerência sênior da empresa considerará naturalmente todo o projeto de uma perspectiva maior.
No entanto, quando o projeto gradualmente se torna maior e há mais e mais excelentes estruturas de código aberto no mundo, se algumas estruturas de código aberto maduro não puderem ser refatórias no tempo e introduzidas, o resultado final pode ser que os desenvolvedores recém -recrutados devem aprender esse sistema complexo a partir de scratch (todos os sistemas internos e não há ajuda na Internet) e ter cuidado de vários bugs nas estruturas internas.
O custo é realmente muito alto.
(4) A estrutura interna não pode acompanhar o desenvolvimento da indústria
O bug na estrutura interna mencionada anteriormente. Para estruturas de código aberto, pode haver uma equipe de fundadores -quadro, um grande número de entusiastas de código aberto,
Comunidade de código aberto para apoiá -lo. O poder do povo é infinito e a velocidade do reparo de insetos pode ser imaginada. Isso é do recente código aberto
O processo de correção de bugs do TextMate pode ser visto. Muitos insetos que foram arquivados há muito tempo foram rapidamente resolvidos por entusiastas depois de serem de código aberto, mas e a estrutura interna? Depois que as pessoas que o desenvolveram deixaram a empresa, ninguém leria seu código -fonte sem grandes insetos. A lacuna é evidente!
(5) É claro que usar uma estrutura não é um lucro enorme.
Como mencionado anteriormente, o uso de uma estrutura imaturo é arriscado e é melhor ser conservador para um projeto que não é tão radical.
(A menos que este seja um grupo de fanáticos por tecnologia gratuitos e irrestritos que possam decidir qual estrutura usar a seu próprio critério, isso é realmente uma bênção)
Assim como sequioa, o serviço de alta disponibilidade Java HA que usei antes, essa estrutura não é mais suportada pela empresa de desenvolvimento e o risco é ainda maior.
Além disso, ao usar algumas estruturas incomuns, você também deve prestar atenção ao protocolo de licença de código -fonte da estrutura e não o referenciar à vontade no projeto.
Modifique o código -fonte da estrutura para evitar disputas legais desnecessárias.
2. A arquitetura por trás do Struts2
Como já analisamos tantos benefícios da estrutura antes, naturalmente começaremos a aprender a usar o STRUTS2. Mas usando o Struts2
Que tipo de arquitetura elegante ele herdará? De fato, a partir de um nível mais alto de abstração, ainda é o modelo MVC com o qual estamos familiarizados.
De acordo com o exemplo anterior do Helloworld, o Controller C (FilterDispatcher) é o que declaramos em web.xml
Classe central do Struts2. E Modelo M é a nossa aula de ação de notícias. E o View V é naturalmente news.jsp. O conceito do modelo parece um pouco vago. O que é um modelo? De fato, esse conceito que soa muito substantivo contém dados de negócios transmitidos estaticamente do front-end da Web e a implementação da lógica de negócios.
Algumas pessoas podem dizer que essa arquitetura não é nova, existem muitas estruturas de MVC, qual é a diferença entre isso e outras estruturas? Vamos dissecar o Struts2 em um nível mais baixo de abstração e ver o que o torna único.
À primeira vista, parece muito complicado. Se apenas olharmos para ele da perspectiva do usuário, precisamos apenas implementar a parte amarela durante o desenvolvimento, ou seja, nós
struts.xml, NewsAction e News.jsp na instância de helloworld. Isso é tudo o que precisamos fazer, como mencionado anteriormente, só precisamos fazer muito poucas coisas e nos tornamos parte dessa excelente arquitetura.
Agora olhe para as outras partes. Filtrodispatcher é o filtro do servlet que configuramos no web.xml, que é o Struts2
Todos os aplicativos da Web STRUTS2 devem ser configurados dessa maneira. Em seguida, as partes azuis e verdes são o núcleo do Struts2. Pode -se dizer que essas classes são cuidadosamente projetadas pelos desenvolvedores do Struts2.
(1) O cliente envia uma solicitação e o contêiner J2EE analisa o pacote HTTP e o encapsula em um httpServletRequest.
(2) O FilterDispatcher intercepta essa solicitação e pesquisa o ActionMapper com base no caminho da solicitação para determinar qual ação chamar.
(3) De acordo com o resultado de retorno do ActionMapper, o FilterDispatcher confia o ActionProxy para encontrar essa ação no Struts.xml.
(4) O ActionProxy cria um ActionInvocation e inicia chamadas recursivas para o interceptador e a ação.
(5) Cada interceptador completa suas próprias tarefas
(6) O verdadeiro chamado à ação retorna o caminho do resultado
(7) O objeto de resultado produzirá os dados de retorno para o fluxo
(8) Retorne HttpServletResponse ao contêiner J2EE e o contêiner envia pacotes HTTP para o cliente.
Este é o processo de execução do Struts2. Os objetos principais são ActionInvocation e Interceptor, bem como o ActionContext que ainda não foi introduzido.
ActionInvocation é o agendamento total de todo o processo, que é muito semelhante ao objeto de invocação na Spring AOP. Muitos interceptores são incorporados em struts2. O mais importante é salvar os parâmetros de solicitação e passar os dados em primeiro plano para as variáveis do membro de ação.
ActionContext é o objeto de contexto global que salva esses dados, e o mais importante é o valor usado para salvar a instância de ação.
O chamado global significa que o ActionContext pode ser acessado em ação e resultado, mas na verdade é do tipo Threadlocal. Cada thread de solicitação terá sua própria instância de ação e ação -Context.
Pode -se dizer que o aprendizado de struts2 é principalmente sobre aprender:
(1) Deixe o interceptador e a ação cooperar para concluir a tarefa.
(2) Salve os dados de primeiro plano na ação.
(3) Resultado, obtém os dados de retorno da ação através da Valuestack.
3. As diferenças entre o Struts2 e o Struts1
No processo de execução acima, já podemos ver a enorme diferença entre o Struts1 e o 2.
(1) Para onde foi o ActionForm? A ação ainda é a mesma ação?
O mais óbvio é que não podemos ver o objeto Actionform em todo o processo e, embora a ação ainda seja chamada de nome, parece ser completamente diferente da ação no Struts1.
Primeiro de tudo, o ActionForm foi abandonado e os dados enviados da recepção poderiam ser salvos para qualquer pojo. O dia de economia no ActionForm primeiro e depois copiar para o objeto DTO acabou. Segundo, este pojo é na verdade uma variável de membro no objeto de ação. Isso está em struts1
É impossível compartilhar uma instância de ação para todas as solicitações neste caso. Agora o Struts2 criará uma instância de ação para cada solicitação, então isso funciona. Terceiro, embora isso seja viável, parece que a ação, como modelo M no MVC, salva dados e contém lógica de negócios. Este é um design ruim? Na verdade, se você pensa com cuidado, esse design é muito conveniente, já obtemos os dados.
Você pode operar diretamente a camada de serviço. A ação parece ter muitas responsabilidades, mas não muitas.
(2) Como o servlet front-end se tornou um filtro?
Sabemos que o MVC STRUTS1 e Spring são usados como entradas através de servlets front-end. Por que o Struts2 usa filtros de servlet?
Como o STRUTS2 é baseado no núcleo da web, é completamente diferente do Struts1. Pode -se dizer que reduz os aplicativos e J2EE
O acoplamento da API, como alterar o ACOLSERVLET para o filtro do servlet e o acesso direto ao httpServletRequest/Response.
Por exemplo, qualquer pojo pode servir como forma de ação, qualquer classe pode ser usada como ação sem implementar a interface de ação, etc.
Portanto, o Struts2 também herda esse excelente design não invasivo.
Isso é um pouco semelhante às idéias de design da Spring. Por exemplo, essas interfaces de ware não precisam ser implementadas, para minimizar o acoplamento entre o código do aplicativo e a estrutura. A invasão é realmente um fator importante a considerar ao projetar uma estrutura.
(3) Ognl entre filtro, ação e resultado
A figura a seguir pode mostrar claramente como o OGNL é integrado à estrutura do Struts2.
É tão conveniente acessar os dados em ação usando a tag STRUTS2 na página de entrada inputForm.html e retornar à página ResultPage.jsp
O OGNL faz acesso às propriedades das ações salvas no Valuestack tão conveniente quanto acessar as próprias propriedades da Valuestack.
O uso extensivo do OGNL é uma característica importante do Struts2. Incluindo a etiqueta de primeiro plano que passa por valores de ação, o resultado tomando valores de ação etc. usará o OGNL em grandes quantidades. No entanto, a reflexão é muito usada em Ognl. Eu acho que essa é uma das razões pelas quais o Struts2 não é tão bom quanto o Struts1. Afinal, é preciso um certo preço para obter uma arquitetura flexível e baixa.
(4) A força do interceptador é invencível
Outra característica poderosa no STRUTS2 é o interceptador interceptador. O STRUTS2 embutiu um grande número de interceptores, o que permite que uma grande quantidade de código seja reutilizada, automatizando o que chamamos de tarefas triviais anteriormente, permitindo assim que o STRUTS2 atinja um alto nível de separação de atenção. Este é realmente um modelo para a aplicação de idéias de AOP na estrutura!
Struts2 Três métodos de transferência de dados
O STRUTS2 fornece três maneiras de salvar parâmetros nas solicitações HTTP: Atributos Javabean, objetos Javabean e objetos Model -Driven. Vamos dar uma olhada nesses três métodos de transferência de dados através do exemplo de login mais comum. O código da página é muito simples. O formulário de envio contém o nome de usuário e a senha. Você pode obter esses dois parâmetros na ação para verificar se o usuário faz login com sucesso.
1. Propriedades do Javabean
< %@ página contenttype = "text/html; charset = utf-8" %> <html> <head> </head> <body> <h1> login página </h1> <forma action = "/cdai/login" method = "post"> <div> <bel para = "username"> name: </</"> </" <batin = "post"> <div> <bel para = "username"> name: </</"> </" <batin = "post"> <div> <bel para = "username"> name: </</" </div> <div> <gravadora para = "senha"> senha: </elabel> <entrada id = "senha" name = "senha" type = "senha"/> </div> <div> <gravador para = "lembrarMe"> <input id = "Remember" name = "Remember" Type = "Check"/>/////<bel <inputMe "type =" </body> </html>
pacote com.cdai.web.ssh.action; importar com.cdai.web.ssh.request.loginRequest; importar com.cdai.web.ssh.service.userService; importação com.opensymphony.xwork2.action; importação com.opensymphony.xwork2.modeldriven; classe pública LoginAction implementa ação {private string nome de usuário; senha de sequência privada; Usuários Service Service privado; @Override public String Execute () {System.out.println ("Login Action -" + request); sucesso de sucesso; } public string getUserName () {return request; } public void setUserName (string userName) {this.username = nome de usuário; } public string getPassword () {return request; } public void setPassword (string senha) {this.password = senha; }}Este método é relativamente simples, salve diretamente os parâmetros no formulário nas propriedades da ação. Ao verificar, a ação também pode precisar encapsular o nome de usuário e a senha no DTO para passar para a camada de serviço para verificação. Então, por que não dar um passo adiante e salvar o nome de usuário e a senha diretamente no DTO.
2. Objetos Javabean
< %@ página contentType = "text/html; charset = utf-8" %> <html> <head> </head> <body> <h1> página de login </h1> <formulário action = "/cdai/login" method = "post"> <div> <bel para = "username"> name: </</ladin "<bai> <input =" post "> <div> <bel para =" username "> name: </</> </" type = "textfield"/> </div> <div> <gravadora para = "senha"> senha: </cret> <input id = "senha" name = "request.password" type = "senha"/> </div> <div> <gravador para = "lembre -se"> <input id = "lembreMe" name = "MeMe "tipo =" Cheque "/"/ value = "login"> </sput> </div> </morm> </body> </html>
pacote com.cdai.web.ssh.action; importar com.cdai.web.ssh.request.loginRequest; importar com.cdai.web.ssh.service.userService; importação com.opensymphony.xwork2.action; importação com.opensymphony.xwork2.modeldriven; classe pública LoginAction implementa ação {Private LoginRequest Request; Usuários Service Service privado; @Override public String Execute () {System.out.println ("Login Action -" + request); sucesso de sucesso; } public LoginRequest getRequest () {return request; } public void setRequest (solicitação LoginRequest) {this.request = request; }} Isso facilita chamar a camada de serviço diretamente. Mas há uma pequena desvantagem de que isso aprofunda a profundidade do nome do parâmetro da página, adicionando apenas uma solicitação ao nome do parâmetro
O prefixo (o nome do atributo na ação) permite que o STRUTS2 salve corretamente os parâmetros no formulário no objeto Solicitação através do OGNL.
3. Objeto Model -Driven
< %@ página contenttype = "text/html; charset = utf-8" %> <html> <head> </head> <body> <h1> login página </h1> <forma action = "/cdai/login" method = "post"> <div> <bel para = "username"> name: </</"> </" <batin = "post"> <div> <bel para = "username"> name: </</"> </" <batin = "post"> <div> <bel para = "username"> name: </</" </div> <div> <gravadora para = "senha"> senha: </elabel> <entrada id = "senha" name = "senha" type = "senha"/> </div> <div> <gravador para = "lembrarMe"> <input id = "Remember" name = "Remember" Type = "Check"/>/////<bel <inputMe "type =" </body> </html>
pacote com.cdai.web.ssh.action; importar com.cdai.web.ssh.request.loginRequest; importar com.cdai.web.ssh.service.userService; importação com.opensymphony.xwork2.action; importação com.opensymphony.xwork2.modeldriven; classe pública LoginAction implementa ação, modeldriven <oginRequest> {private loginRequest request = new LoginRequest (); Usuários Service Service privado; @Override public String Execute () {System.out.println ("Login Action -" + request); sucesso de sucesso; } @Override public LoginRequest getModel () {Request Return; }} Dessa forma, é necessária mais uma interface do Modeldriven e os objetos fornecidos pelo Modeldriven são salvos para a Valuestack, para que a página de primeiro plano possa ser passada diretamente
Os nomes de atributos de nome de usuário e senha definem o nome do parâmetro do formulário.
Qual dos três métodos não deve ser generalizado? Depende das necessidades específicas do projeto e depois decida!