Struts2의 구조
1. 왜 프레임 워크를 사용합니까?
(1) 프레임 워크는 많은 사소한 작업을 자동으로 완료합니다
Struts2의 경우 데이터 유형 변환, 데이터 검증, 국제화 등을 쉽게 완료하는 데 도움이됩니다.
웹 개발의 일반적인 작업. 봄에 널리 사용되는 템플릿 모드도 있으며, 이는 개발 프로세스를보다 자동화하고 지능적으로 만듭니다. 프레임 워크를 사용하는 것은 휠을 재창조하고 이러한 템플릿 코드를 다시 코피하는 것입니다.
프레임 워크를 통해 일반적인 워크 플로 및 기본 작업보다 높은 수준의 문제에 더 집중할 수 있습니다.
(2) 프레임 워크를 사용하는 것은 프레임 워크 뒤의 아키텍처를 우아하게 상속한다는 의미입니다.
프레임 워크 뒤에있는 아키텍처는 일반적으로 일련의 워크 플로를 정의합니다. 우리가해야 할 일은 특정 응용 프로그램의 코드를이 프로세스에 첨부하여 프레임 워크에서 가져 오는 다양한 이점을 누릴 수 있도록하는 것입니다. 때때로 우리는 프레임 워크의 건축 규칙에 저항 할 수 있지만 프레임 워크는 일반적으로 거부하기 어려운 방식으로 아키텍처를 제공합니다. 매우 간단하여 우수한 아키텍처를 우아하게 상속받을 수 있고 무료이므로 왜 그렇게하지 않겠습니까?
(3) 프레임 워크를 사용하여 잘 훈련 된 사람들을 찾는 것이 더 쉽습니다.
나는 이전에 회사 전체 프로젝트에서 어떤 프레임 워크를 사용하지 않았으며, 서비스 서비스를 찾고 있습니다 (JNDI와 유사)
로그 인쇄 (LOG4J와 유사) 및 데이터베이스 연결 풀 (DBCP와 유사)에 모든 내부 직원이 구현합니다. 첫째, 프로젝트가 상대적으로 오래 되었기 때문에 그 당시 사용하기위한 오픈 소스 프레임 워크가 없기 때문입니다. 둘째, 회사의 보수적 인 전략 때문이며 불안정한 오픈 소스 프레임 워크를 사용하면 프로젝트에 위험을 초래할 수 있다고 걱정하고 있습니다. 이는 당시 환경에서 사실 일 수 있으며 회사의 고위 경영진은 자연스럽게 전체 프로젝트를 더 큰 관점에서 고려할 것입니다.
그러나 프로젝트가 점차 커지고 세계에 점점 더 우수한 오픈 소스 프레임 워크가있을 때, 일부 성숙한 오픈 소스 프레임 워크가 제 시간에 리플렉션되어 소개 될 수 없다면, 최종 결과는 새로 모집 된 개발자가 처음 부터이 복잡한 시스템 (모든 내부 시스템, 인터넷에 도움이 없음) 에서이 복잡한 시스템을 배워야 할 수 있습니다.
비용이 너무 높습니다.
(4) 내부 프레임 워크는 업계의 발전을 따라갈 수 없습니다.
앞에서 언급 한 내부 프레임 워크의 버그. 오픈 소스 프레임 워크의 경우 프레임 워크 설립자 팀, 많은 오픈 소스 애호가가있을 수 있습니다.
그것을 지원하기위한 오픈 소스 커뮤니티. 사람들의 힘은 무한하며 버그 수리 속도를 상상할 수 있습니다. 이것은 최근 오픈 소스에서 나온 것입니다
텍스트 메이트의 버그 수정 과정을 볼 수 있습니다. 오픈 소스 후에 열광 자들에 의해 오랫동안 선반 된 많은 버그가 빠르게 해결되어 왔지만 내부 프레임 워크는 어떻습니까? 그를 개발 한 사람들이 회사를 떠난 후에는 아무도 큰 버그없이 소스 코드를 읽지도 않았습니다. 격차가 분명합니다!
(5) 물론 프레임 워크를 사용하는 것은 큰 이익이 아닙니다.
앞에서 언급했듯이 미성숙 프레임 워크를 사용하는 것은 위험하며, 그렇게 급진적이지 않은 프로젝트를 위해 보수적 인 것이 낫습니다.
(그렇지 않으면 이것이 자신의 재량에 따라 어떤 프레임 워크를 사용할 것인지 결정할 수있는 자유롭고 제한되지 않은 기술 광신자 그룹이 아니라면, 그것은 실제로 축복입니다).
이전에 사용한 Java Ha 고 가용성 서비스 인 Sequioa와 마찬가지로이 프레임 워크는 더 이상 개발 회사에서 지원하지 않으며 위험은 훨씬 더 큽니다.
또한, 드문 프레임 워크를 사용할 때 프레임 워크 소스 코드 라이센스 프로토콜에주의를 기울이고 프로젝트에서이를 참조하지 않아야합니다.
불필요한 법적 분쟁을 피하기 위해 프레임 워크의 소스 코드를 수정하십시오.
2. struts2의 건축물 2
우리는 이전에 프레임 워크의 많은 이점을 분석 했으므로 자연스럽게 struts2를 사용하는 법을 배우기 시작할 것입니다. 그러나 struts2를 사용합니다
어떤 종류의 우아한 건축물이 상속 될까요? 실제로, 더 높은 수준의 추상화에서도 여전히 우리가 익숙한 MVC 모델입니다.
이전 HelloWorld 예제에 따르면 컨트롤러 C (FilterDispatcher)는 Web.xml에서 선언 한 것입니다.
struts2 핵심 클래스. Model M은 뉴스 Action Action 클래스입니다. View V는 자연스럽게 News.jsp입니다. 모델의 개념은 약간 모호한 것 같습니다. 모델이란 무엇입니까? 실제로, 그 명사로 들리는이 개념에는 웹 프론트 엔드에서 정적으로 전송되는 비즈니스 데이터와 비즈니스 로직 구현이 포함됩니다.
어떤 사람들은이 아키텍처가 새로운 것이 아니며 많은 MVC 프레임 워크가 있다고 말할 수도 있습니다.이 프레임 워크와 다른 프레임 워크의 차이점은 무엇입니까? 더 낮은 수준의 추상화에서 struts2를 해부하고 그것을 독특하게 만드는 이유를 살펴 보겠습니다.
언뜻보기에는 매우 복잡해 보입니다. 사용자의 관점에서만 보면 개발 중에 노란색 부분 만 구현하면됩니다.
struts.xml, Helloworld 인스턴스의 뉴스 및 뉴스. 이것이 우리가해야 할 전부입니다. 앞에서 언급했듯이, 우리는 거의 일을 거의하지 않아도되며 우리는이 훌륭한 건축의 일부가됩니다.
이제 다른 부분을보십시오. FilterDispatcher는 Web.xml에서 구성하는 서블릿 필터입니다.
모든 struts2 웹 응용 프로그램은 이러한 방식으로 구성해야합니다. 다음으로, 파란색과 녹색 부분은 Struts2의 핵심입니다. 이 클래스는 Struts2 개발자가 신중하게 설계했다고 말할 수 있습니다.
(1) 클라이언트는 요청을 보내고 J2EE 컨테이너는 HTTP 패킷을 구문 분석하여 httpservletRequest로 캡슐화합니다.
(2) FilterDispatcher는이 요청을 가로 채고 요청 경로를 기반으로 ActionMapper를 검색하여 호출 할 작업을 결정합니다.
(3) ActionMapper의 반환 결과에 따르면 FilterDispatcher는 ActionProxy를 위임 하여이 작업을 struts.xml에서 찾습니다.
(4) ActionProxy는 ActionInvocation을 생성하고 인터셉터 및 작업에 대한 재귀적인 호출을 시작합니다.
(5) 각 인터셉터는 자체 작업을 완료합니다
(6) 실제 콜은 결과 경로를 반환합니다.
(7) 결과 객체는 리턴 데이터를 스트림에 출력합니다.
(8) httpservletResponse를 J2EE 컨테이너로 반환하면 컨테이너는 HTTP 패킷을 클라이언트에게 보냅니다.
이것은 struts2의 실행 프로세스입니다. 핵심 객체는 ActionInvocation 및 인터셉터뿐만 아니라 아직 도입되지 않은 ActionContext입니다.
ActionInvocation은 전체 프로세스의 총 스케줄링으로 스프링 AOP의 호출 객체와 매우 유사합니다. 많은 인터셉터가 Struts2에 내장되어 있습니다. 가장 중요한 것은 요청 매개 변수를 저장하고 전경 데이터를 ACTION 멤버 변수로 전달하는 것입니다.
ActionContext는 이러한 데이터를 저장하는 글로벌 컨텍스트 객체이며 가장 중요한 것은 작업 인스턴스를 저장하는 데 사용되는 Valuestack입니다.
소위 글로벌은 ActionContext에 액세스 할 수 있고 결과적으로 액세스 할 수 있지만 실제로는 ThreadLocal 유형입니다. 각 요청 스레드에는 자체 조치 인스턴스 및 ActionContext가 있습니다.
Struts2를 학습하는 것은 주로 학습에 관한 것이라고 말할 수 있습니다.
(1) 인터셉터와 행동이 협력하여 작업을 완료하도록하십시오.
(2) 전경 데이터를 동작에 저장합니다.
(3) 결과는 Valuestack을 통해 작업에서 반환 데이터를 가져옵니다.
3. struts2와 struts1의 차이
위의 실행 프로세스에서, 우리는 이미 struts1과 2의 큰 차이를 볼 수 있습니다.
(1) ActionForm은 어디로 갔습니까? 행동은 여전히 같은 행동입니까?
가장 분명한 점은 전체 프로세스에서 ActionForm 객체를 볼 수 없으며 액션을 여전히이 이름이라고 불렀지 만 Struts1의 동작과 완전히 다른 것 같습니다.
우선, ActionForm은 포기되었고 프론트 데스크에서 전송 된 데이터는 모든 POJO에 저장 될 수 있습니다. ActionForm에서 먼저 저장 한 다음 DTO 객체에 복사하는 날이 끝났습니다. 둘째,이 pojo는 실제로 액션 객체의 멤버 변수입니다. 이것은 struts1에 있습니다
이 경우 모든 요청에 대해 조치 인스턴스를 공유하는 것은 불가능합니다. 이제 struts2는 각 요청에 대한 작업 인스턴스를 생성하므로 작동합니다. 셋째, 이것은 가능하지만 MVC의 모델 M으로서의 행동은 데이터를 저장하고 비즈니스 로직을 포함하는 것으로 보입니다. 이것은 나쁜 디자인입니까? 실제로, 당신이 그것에 대해 신중하게 생각한다면,이 디자인은 매우 편리합니다. 우리는 이미 데이터를 얻었습니다.
서비스 계층을 직접 작동 할 수 있습니다. 행동에는 너무 많은 책임이 있지만 많지는 않습니다.
(2) 프론트 엔드 서블릿은 어떻게 필터가 되었습니까?
우리는 Struts1과 Spring MVC가 둘 다 프론트 엔드 서블릿을 통한 입구로 사용된다는 것을 알고 있습니다. struts2는 왜 서블릿 필터를 사용합니까?
struts2는 웹 워크 코어를 기반으로하기 때문에 struts1과 완전히 다릅니다. 웹 워크는 응용 프로그램과 J2EE를 줄이라고 할 수 있습니다
API 커플 링, 예를 들어 Actionservlet 변경 Servlet의 필터로 변경 및 httpservletrequest/response에 직접 액세스 할 수 있습니다.
예를 들어, 모든 pojo는 actionform 역할을 할 수 있으며 모든 클래스는 액션 인터페이스를 구현하지 않고 작업으로 사용할 수 있습니다.
따라서 Struts2는 또한이 우수한 비 침습적 디자인을 상속합니다.
이것은 Spring의 디자인 아이디어와 다소 유사합니다. 예를 들어, 해당웨어 인터페이스는 애플리케이션 코드와 프레임 워크 간의 결합을 최소화하기 위해 전혀 구현할 필요가 없습니다. 침습성은 실제로 프레임 워크를 설계 할 때 고려해야 할 중요한 요소입니다.
(3) 필터, 동작 및 결과 사이의 OGNL
다음 그림은 OGNL이 Struts2 프레임 워크에 어떻게 통합되는지 명확하게 보여줄 수 있습니다.
입력 페이지 inputform.html의 struts2 태그를 사용하여 작동중인 데이터에 액세스하고 페이지 resultpage.jsp로 돌아가는 것이 매우 편리합니다.
Ognl은 Valuestack의 자체 속성에 액세스하는 것만 큼 편리한 Valuestack에서 저장된 동작의 속성에 액세스합니다.
OGNL의 광범위한 사용은 Struts2의 주요 특징입니다. 전경 태그를 동작으로 전달하는 전경 태그를 포함하여, 동작 등으로부터 값을 취하는 결과는 OGNL을 대량으로 사용합니다. 그러나 반사는 Ognl에서 많이 사용됩니다. 나는 이것이 struts2가 struts1만큼 좋지 않은 이유 중 하나라고 생각합니다. 결국, 유연하고 저 커플 링 된 아키텍처를 얻으려면 특정 가격이 걸립니다.
(4) 인터셉터의 강도는 무적입니다
Struts2의 또 다른 강력한 기능은 인터셉터 인터셉터입니다. Struts2에는 많은 수의 인터셉터가 내장되어있어 많은 양의 코드를 재사용 할 수 있으며, 이전에 사소한 작업을 자동화하여 Struts2가 높은 수준의 관심에 도달 할 수 있습니다. 이것은 실제로 프레임 워크에서 AOP 아이디어를 적용하기위한 모델입니다!
Struts2 세 가지 데이터 전송 방법
struts2는 HTTP 요청에서 매개 변수를 저장하는 세 가지 방법을 제공합니다 : Javabean 속성, Javabean 객체 및 ModelDriven 객체. 가장 일반적인 로그인 예제를 통해이 세 가지 데이터 전송 방법을 살펴 보겠습니다. 페이지 코드는 매우 간단합니다. 제출 양식에는 사용자 이름과 비밀번호가 포함됩니다. 작업 에서이 두 매개 변수를 얻을 수있어 사용자가 성공적으로 로그인하는지 확인할 수 있습니다.
1. Javabean 속성
< %@ page contenttype = "text/html; charset = utf-8" %> <html> <head> </head> </head> <hoad> <h1> 로그인 페이지 </h1> <form action = "/cdai/login"method = "post"> <div> < "username"> name : </label "/> </div> <div> <label for = "password"> password : </label> </label> <입력 id = "password"name = "password"type = "type ="password "/</div> <div> <label for ="rememberme "> <input id ="remembe "name ="remember "type ="checkbox "/> remembe </div> </div> </div> </div> </div> <</input> </div> <input bype"name = "values"> </input> </body> </html>
패키지 com.cdai.web.ssh.action; com.cdai.web.ssh.request.loginrequest import; com.cdai.web.ssh.service.userservice import; com.opensymphony.xwork2.action import; com.opensymphony.xwork2.modeldriven import; 공개 클래스 로그인 action action {private String username; 개인 문자열 비밀번호; 개인 사용자 서비스 사용자 서비스; @override public string execute () {system.out.println ( "로그인 조치 -" + request); 반환 성공; } public String getUserName () {return request; } public void setusername (String username) {this.username = username; } public String getPassword () {return request; } public void setpassword (문자열 비밀번호) {this.password = password; }}이 방법은 비교적 간단하며 양식의 매개 변수를 동작의 속성에 직접 저장합니다. 확인할 때 동작은 사용자 이름과 비밀번호를 DTO로 캡슐화하여 검증을 위해 서비스 계층으로 전달해야 할 수도 있습니다. 따라서 한 걸음 더 나아가서 사용자 이름과 비밀번호를 DTO에 직접 저장하십시오.
2. Javabean 대상
< %@ page contenttype = "text/html; charset = utf-8" %> <html> <head> </head> </head> <hod> <h1> 로그인 페이지 </h1> <form action = "/cdai/login"method = "post"> <div> < "username"> name : </label> <input id = "username" "western" 유형 = "textfield"/> </div> <div> <label for = "password"> password : </label> <input id = "incute id ="possport "name ="requestword "type ="password "/> </div> <div> <레이블"rememberme "> <input id ="remember "name ="remember "="cheembbox "</label" 값 = "로그인"> </input> </div> </form> </body> </html>
패키지 com.cdai.web.ssh.action; com.cdai.web.ssh.request.loginrequest import; com.cdai.web.ssh.service.userservice import; com.opensymphony.xwork2.action import; com.opensymphony.xwork2.modeldriven import; 공개 클래스 로그인은 조치를 구현 {private loginrequest 요청; 개인 사용자 서비스 사용자 서비스; @override public string execute () {system.out.println ( "로그인 조치 -" + request); 반환 성공; } public loginRequest getRequest () {return request; } public void setRequest (loginRequest 요청) {this.request = request; }} 따라서 서비스 계층을 직접 호출 할 수 있습니다. 그러나 페이지 매개 변수 이름의 깊이를 심화시키는 작은 단점이 있으며 매개 변수 이름에 요청 만 추가합니다.
접두사 (동작의 속성 이름)를 사용하면 struts2가 양식의 매개 변수를 Ognl을 통해 요청 객체에 올바르게 저장할 수 있습니다.
3. 모델 드라이브 객체
< %@ page contenttype = "text/html; charset = utf-8" %> <html> <head> </head> </head> <hoad> <h1> 로그인 페이지 </h1> <form action = "/cdai/login"method = "post"> <div> < "username"> name : </label "/> </div> <div> <label for = "password"> password : </label> </label> <입력 id = "password"name = "password"type = "type ="password "/</div> <div> <label for ="rememberme "> <input id ="remembe "name ="remember "type ="checkbox "/> remembe </div> </div> </div> </div> </div> <</input> </div> <input bype"name = "values"> </input> </body> </html>
패키지 com.cdai.web.ssh.action; com.cdai.web.ssh.request.loginrequest import; com.cdai.web.ssh.service.userservice import; com.opensymphony.xwork2.action import; com.opensymphony.xwork2.modeldriven import; 공개 클래스 로그인은 조치, ModelDriven <loginRequest> {private loginRequest 요청 = new loginRequest (); 개인 사용자 서비스 사용자 서비스; @override public string execute () {system.out.println ( "로그인 조치 -" + request); 반환 성공; } @override public loginRequest getModel () {return request; }} 이런 식으로 ModelDriven 인터페이스가 하나 더 필요하고 ModelDriven에서 제공하는 객체는 Valuestack에 저장되어 전경 페이지를 직접 전달할 수 있습니다.
사용자 이름 및 비밀번호 속성 이름은 양식의 매개 변수 이름을 정의합니다.
세 가지 방법 중 어느 것이 일반화되지 않아야합니까? 그것은 프로젝트의 특정 요구에 따라 다르고 직접 결정합니다!