Struts2

来源:互联网 发布:网络安全法宣传图片 编辑:程序博客网 时间:2024/06/06 03:39
  1.  MVC 和  JSP Model 2 
    什么是MVC?
    1)  M-Model 模型
    模型(Model)的职责是负责业务逻辑。包含两部分:业务数据和业务处理逻辑。
    在之前学习的类中,比如实体类、DAO、Service都属于模型层。
    2)  V-View 视图
    视图(View)的职责是负责显示界面和用户交互(收集用户信息)。
    属于视图的类是不包含业务逻辑和控制逻辑的JSP(如果在JSP页面中有<%%>就不能算是视
    图层的类,或者JSP中有转发和或者重定向的控制逻辑也是不可以的)。
    3)  C-Controller 控制器
    控制器是模型层M和视图层V之间的桥梁,用于控制流程。
    比如我们之前项目中写的ActionServlet。 
  2. MVC JSP Model2
    之前我们写的模式被我们称之为JSP Model1,在其中我们有模型层(M),但是视图层(V)的
    JSP中包含了业务逻辑或控制逻辑。JSP Model2的不同之处在于将JSP中的业务逻辑和控制逻辑全部
    剔除,并全部放入控制层(C)中,JSP仅具有显示页面和用户交互的功能。

1)  所有的请求发给控制层的前端控制器(ActionServlet)
2)  前端控制器维护一个配置文件 (配置文件中指明了不同的请求和某个Action的对应关系)
3)  前端控制器可以根据请求的不同调用不同的Action
4)  控制层的Action调用Model,实现业务功能
5)  模型层DAO将请求中的数据从数据库中查出后绑定到Request对象上
6)  模型层DAO将请求转发给View层(JSP)JSP显示数据
3.拷贝Struts2的核心Jar包到WEB-INF/lib/下 
基本功能核心jar 包 5个(2.1.8)
   struts2-core-2.1.8.1.jar(*) 
Struts2核心包,是Struts 框架的“外衣”
 xwork-core-2.1.6.jar(*) 
Struts2核心包,是WebWork 内核。
ognl-2.7.3.jar
用来支持ognl表达式的,类似于EL表达式,功能比EL表达式强大的多。
freemarker-2.3.15.jar
freemarker 是比jsp更简单好用,功能更加强大的表现层技术,用来替代jsp的。
在Struts2中提倡使用 freemarker 模板,但实际项目中使用jsp也很多。
commons-fileupload-1.2.1.jar
用于实现文件上传功能的jar 包。 
4.在web.xml 中配置Struts2的前端控制器 
Struts2用Filter 实现的前端控制器(注意不是Servlet)
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4" 
xmlns="http://java.sun.com/xml/ns/j2ee"  
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee  
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
  <filter>
<filter-name>Struts2</filter-name>
<filter-class>    
org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter
</filter-class>
</filter>
<filter-mapping>
<filter-name>Struts2</filter-name>
<url-pattern>/*</url-pattern>  <!--/*表示所有的请求都要经过该过滤器  -->
</filter-mapping>
</web-app> 
5.Struts2提供的方便之处: 
 数据的自动的封装
根据页面组件的name属性,自动封装到Action中对应的 name属性中。
在Jsp页面<input name=’name’ type=’text’/>
在action中会自动给属性private String name 赋值
 数据的自动的传递
Action中得属性会在jsp页面可以直接用EL表达式拿到
Action中属性private String name;
在jsp页面上可以直接${name}的到对应的值
6.写struts2所需要的配置文件struts.xml 
struts.xml文件告诉Struts2\请求对应的Java类
注意:在编写时放在src中(编译后该文件位于WEB-INF/classes/下)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.1//EN"
"http://struts.apache.org/dtds/struts-2.1.dtd">
<struts>
<package name="helloworld" extends="struts-default"
  namespace="/day01">
  <action name="welcome"
   class="com.tarena.outman.WelcomeAction">
   <result name="success">/jsp/welcome.jsp</result>
   <result name="fail">/jsp/nameform.jsp</result>
  </action>
 </package>
</struts> 
注:
  •  <package> 
作用是为<action>分组,<struts>标签下可有多个<package>
 name="helloworld" 
唯一的标识,表示包名为helloworld
 extends="struts-default"  
继承的包的name,一般继承Struts2默认提供的struts-default包,该包中定义了很多
Struts2应用必须的组件(比如:拦截器);
该package声明的位置在struts2-core-2.1.8.jar/struts-default.xml文件中
namespace 
用来设置该包中的action的地址的命名空间
namespace="/" 表示没有命名空间(后续再讲解)
访问http://localhost:8080/outman/welcome.action即可
如果namespace="day01"之后,Action地址为:
http://localhost:8080/outman/day01/welcome.action
  •  <action> 
作用是指明每个请求对应的Action类之间的对应关系,<package>下可有多个<action>。
name="welcome"  
表示请求的名字为welcome(即welcome.do)
  class="com.tarena.outman.WelcomeAction"  
指定了对应的Action类
method="xxx"
用于指定在对应的类中要执行的方法名,该方法的返回值必须是String类型(规定)
public String xxx(){......}
如果没有method=""属性,默认执行execute()方法
  •  <result> 
name="success" 
该result的名称,Action返回哪一个result的name值,意味着要转发到哪一个result
所对应的JSP地址 
7.Action 的小结  
在Struts2框架中,我们写一个Action
class FooAction {}
一般情况下,在该类中有一个public String execute()方法
class FooAction {
public String execute() {}   
}

execute()方法通过返回不同的String决定转到哪个页面
class FooAction {
public String execute() {
    return "success";      //return "abc";亦可
     }   
}

我们为该Action添加成员变量 name
注意:
1)  只有当为成员变量添加get/set方法时,我们才称该成员变量是类的属性
2)  所有的属性都会被“带”到页面(在页面能够使用)
3)  在页面form表单中提交的信息可以赋值给属性
class FooAction {
     private String name;    //成员变量
     public String getName() {return name;}
     public void setName(String name) {this.name = name;}     
     public String execute() {
     return "success";      //return "abc";亦可
     }   
}
对与一般的Action有2种属性
1)  第1种,用来接收用户的提交 input属性
2)  第2种,用来把数据带给视图(JSP)output属性
public class ProjectListAction {
// input属性
private int page = 1;
// output属性
private List<Project> projectList;
public String execute() {
ProjectDao projectDao = new ProjectDao();
projectList = projectDao.findAll(page, 5);
return "success";
     }
public int getPage() {return page;}
public void setPage(int page) {this.page = page;}
public List<Project> getProjectList() {return projectList;}
public void setProjectList(List<Project> projectList) {
     this.projectList = projectList;
     }
}
8.El表达式翻译为Java代码的含义 
${foo.name}翻译为Java代码是out.print(foo.getName());
意味着调用foo的getName()方法,而非访问foo的成员变量name(同时注意成员变量一般是私
有的,不能直接访问)
9.EL表达式是干什么用的? 
EL表达式把数据从四个范围(pageContext、request、session、application)中取出来显示或者计算。
EL表达式解决了Java 代码和HTML的不匹配问题(让html页面中不再有java代码)。
EL表达式用字符串表达式替换Java代码,用来表示对数据的获取或计算。

OGNL 是干什么的?
OGNL和EL相似,但功能更加强大。

OGNL 是怎么工作的?
给ognl引擎一个字符串(OGNL表达式),可以让ognl引擎去读取和设置对象的属性。
OGNL 表达式  
1)  基本类型属性(包括String) 
例如: id,name
2)  数组和List
例如:arry[0], list[1]
3)  Map
例如:map['key'], map.key
4)  基本运算
5)  调用方法
6)  调用静态方法
7)  创建对象List,Map
创建List: {1,2,3,4,5}
创建Map:  #{'one':'java','two':'javajava'}
8)关联属性(不常用,理解即可)
empList[1].name
9)投影(不常用,理解即可)
empList.{name}
10)过滤(不常用,理解即可)
empList.{?#salary>10000} 
10.Ognl引擎访问对象的格式:
Ognl.getValue("OGNL表达式", root对象);  //root对象是Ognl要操作的对象 
11. OGNL 引擎的基本结构 
标准的Ognl 涉及到3个概念:Ognl 引擎、root对象、context对象 
 root对象:Ognl操作的对象
 context对象:就是一个Map,用于存放一个和整个系统都相关的公共数据
当有了Ognl引擎,我们就可以访问各种各样的root对象(比如Foo对象、Emp对象、Dept对
象等),在访问中有一些数据是每一次访问都需要用到的,这些数据就可以保存在context对象中
12. XWork中对OGNL 的扩展 
在之前讲的Ognl的应用是通用的,接下来讲解XWork 中对Ognl做的改动。
 OGNL引擎
 CompoundRoot对象:在XWork 中,root对象被改为类似“栈”一样的存储空间,
在该对象空间内可以存放多个root对象;
当取数据时符合“栈”的规则,如果OGNL表达式是“name“,
在CompoundRoot从栈顶开始依次看是否有name属性...
 Context(Map)对象 
13.ValueStack基本结构 
Struts2将之前讲的XWork 对Ognl的扩展这一套机制封装起来,这个对象叫ValueStack。 
Struts2在启动时,会创建一个ValueStrack 对象
当用户发送请求到对应的Action时,Struts2会把当前被请求的Action01放入CompoundRoot
对象的“栈空间”栈顶,请求结束,Action01会被清除。
(当下一次另一个请求到来时,Struts2会把该请求对应的Action02放入“栈顶”)
所以,我们可以通过Ognl表达式访问CompoundRoot对象栈顶的Action。
14.ValueStack核心概念
Struts2在请求到来时,首先会创建一个ValueStack;
然后,把当前的Action对象放入栈顶(CompoundRoot);
Struts2会把ValueStack 存放在request中,属性为”struts.valueStack“,
所以,标记库可以访问到ValueStack
Struts2的很多标记就是通过访问ValueStack 获得数据的:
 通过ognl从ValueStack 取数据,并且显示
<s:property value="ognl..."/> 
 省略value,取出ValueStack 的栈顶
<s:property />    
 通过ognl从ValueStack 取出集合,依次将集合中的对象置于栈顶,在循环中,ValueStack 栈
顶即为要显示的数据 
<s:iterator value="ognl...list">
<s:property value="name"/>
</s:iterator> 
15. Struts2 如何支持  EL 
Struts2通过StrutsRequestWrapper,重写了getAttribute方法。
设计模式
Sun公司提供了HttpServletRequest接口
HttpServletRequest
Sun提供的另一个类HttpServletRequestWrapper 继承了该接口;
在该类中有一个HttpServletRequest request属性,
同时提供一个getAttribute方法,可以访问到该属性,
public class HttpServletRequestWrapper implements HttpServletRequest{
private HttpServletRequest request;

public Object getAttribute(String name){
    return request.getAttribute(name);
     }
}
从上面来看,我们认为HttpServletRequestWrapper 和HttpServletRequest作用是一样的

方式1:如果我们写一个过滤器,在过滤器中使用HttpServletRequestWrapper 做包装
doFilter(request , response , chain){
    chain.doFilter(new HttpServletRequestWrapper(request) , response);
}
这和我们直接传request的效果是一样的,所以这样写意义也不大。

方式2:但是如果我们再写一个类,让该类继承HttpServletRequestWrapper。
在该类中重写了父类构造方法,同时重写getAttribute方法,在该方法中从valueStack 中取数据;
public class StrutsRequestWrapper extends HttpServletRequestWrapper{
public StrutsRequestWrapper(HttpServletRequest request){
    super(request);
}  
public Object getAttribute(String name){
    //从valueStack 中取数据
    //....
    return ....
     }
}
在过滤器中使用StrutsRequestWrapper 做包装。
doFilter(request , response , chain){
    chain.doFilter(new StrutsRequestWrapper(request) , response);
}

如此,在编程过程中,如果不使用getAttribute方法,request的使用和之前没有区别,如果调
用getAttribute方法,则会调用Struts2框架重写的方法。

类似的设计模式
Collections.synchronizedList方法是如何实现的? 
该方法的实现机制可以描述为:
首先,定义了一个包装类,在该包装类中有List list属性,
其次,新建synchroized 关键字的方法
private ListWrapper implements List{
List list;
public synchroized void add(){
    list.add();
     }
}
16.修改debug.jsp 
<%@page pageEncoding="utf-8"%>
<%@taglib uri="/struts-tags" prefix="s"%>

<%
Object obj = request.getAttribute("struts.valueStack");
out.println(obj);
%>

<!--  
s:debug标签用于看valueStack,用于调试-->
 
17.Struts Action 核心  * 
1.1. Action **
1)  Action基本原理 *
 每次請求都会创建一个新的Action的实例
因为每次请求都对应一个单独的Action,所以不需要考虑线程安全问题。
 Action对象将置于ValueStack 的栈顶
 Action的业务方法(默认为execute)根据输入算输出

2)  在Action中如何访问Session&Application
 使用ActionContext访问Session
ActionContext ctx = ActionContext.getContext();
Map session = ctx.getSession();
或者
Map application = ctx.getApplication();
   session, application 将存放在ValueStack 的Context中
<s:property value="#session..."/>
或者
<s:property value="#application..."/>
  
 通过实现SessionAware接口访问session (更好)
   首先,新建BaseAction implements SessionAware
   其次,所有需要session的XXXAction extends BaseAction
   类似的,还有:
   ServletRequestAware  
   ServletResponseAware 
   ServletContextAware
 
3)  使用通配符配置Action
<action name="*_*_*" class="com.tarena.outman.{1}Action" method="{2}">
<result name="success">/WEB-INF/jsp/day03/{3}.jsp</result>
</action>  
4)  给Action注入参数(属性注入)
<param name="rowsPerPage">5</param>

5)  在result的配置中使用OGNL 表达式
<result name="success" type="dispatcher">
/WEB-INF/jsp/day03/user.jsp?userId=${user.userId}
</result>
18.什么时候jsp用<%@taglib uri="/struts-tags" prefix="s"%> ,什么时候用<tr> </tr>,<td></td>,<h1></h1>,<tbody></tbody>
19.不推荐使用ActionContext访问Session的方式,因为这种方式的“侵入性”较强。
ActionContext是Struts2的API,如果使用其他框架代替目前的Struts2框架,而我们
实际项目中的Action的数量非常庞大,每个类都修改会很费劲。可以通过实现SessionAware接口访问session
package com.tarena.outman.day03;

import java.util.Map;
import org.apache.struts2.interceptor.SessionAware;

public class BaseAction implements SessionAware{
     //为了让子类也能使用,所以访问控制符为protected
protected Map<String, Object> session;

public void setSession(Map<String, Object> session) {
  this.session = session;
}
}

该类实现了SessionAware接口,表明Struts2在启动BaseAction时,
首先,创建出该Action的对象,放入“栈顶”
然后,会调用BaseAction的setSession方法,把session传入给BaseAction对象
(注意:如果是普通的Action,Struts2在启动时仅创建出该Action的对象,然后放入“栈顶”)

由此,我们定义了属性session,以便在之后其他的方法中使用。为了让子类也能使用,所以访问
控制符为protected。

按照这样的机制,我们可以让所有的Action(如LoginAction)继承实现了SessionAware接口
的BaseAction,当需要更换Struts2框架为其他框架时,只需要修改BaseAction即可(另外的
框架只要提供一个类似SessionAware接口的接口,由BaseAction继承) 
20. Struts2 核心标记库  
知识点
1)  UI标记 
常用UI标记
a.  form
b.  textfield  
c. password
d.  submit
e.  textarea
f. checkbox
g.  radio
h.  select

Struts2标记
a.  通用属性(所有标记都具备的属性)
   注:带”*“星号的属性表示在任意主题,如xhtml下才可以使用
 label (*)      
 labelposition(*)   
 required(*)    
 tooltip(*)
 tooltipIconPath(*)
-------html原来的属性--------
 cssClass(html中的class)   
 cssStyle(html中的sytle)
 name
 value
 ....
b.  <s:form><form>
 theme    主题 
 namespace   命名空间
 action  
 method
c.<s:textfield> && <s:password>
 maxLength
 size
 readonly
d.<s:textarea>
 cols
 rows
e.<s:checkbox>
 使用1个
<s:checkbox name="ok"/>
查看页面源代码,我们会发现生成这样的html
<input type="checkbox" name="ok" value="true"/>
<input type="hidden" name="_checkbox_ok" value="true"/>
使用多个
写在页面
<s:checkbox name="product" fieldValue="1"/>  
<s:checkbox name="product" fieldValue="2"/>
<s:checkbox name="product" fieldValue="3"/>
动态获得
<s:iterator value="products"> <!--products, Product类型的List-->
<s:checkbox name="product" fieldValue="%{id}"/>
</s:iterator>

<s:radio>
我们原来这么写
<input type="radio" name="abc" value="1"/>One
<input type="radio" name="abc" value="2"/>Two
<input type="radio" name="abc" value="3"/>Three
后来我们这么写
<s:radio list="productOptions" label="Radio" name="abc"
  listValue="label" listKey="value" />
属性含义:
 name
 label
 list OGNL--需要迭代的集合
 listValue 作用于每一个选项的提示 OGNL -- 
 listKey  作用于每一个要提交的值 OGNL -- 
g.  <select>
<select name="abc">
<option value="1">One</option>
<option value="2">Two</option>
<option value="3">Three</option>
</select>
Struts2标记
<s:select list="productOptions" label="Select" name="abc"
  listValue="label" listKey="value" />
属性含义:
 listValue 对应每一个Option的文本
 listKey 对应每一个Option提交的值
 headerValue 提示头的文字
 headerKey  提示头对应的提交值 
21.拦截器 
1)  在package 中定义拦截器
<interceptor name="" class="">
2)  在package 中定义拦截器栈
<interceptor-stack name="">
     <interceptor-ref name="">
</interceptor-stack>
3)  package中定义默认拦截器
<default-interceptor-ref name=""/>
4)  action定义拦截器
<action name="" class="">
          <!-- 表示访问该action前先调用这个拦截器-- >
<interceptor-ref name="">      
   <param name=""></param>
</interceptor-ref>
</action>
22.Struts2 结构图
图示流程说明
当HttpServletRequest请求到来
经过一些初始化的工作(这些仅先做了解):
1)  请求发送给ActionMapper,
2)  再发送给由ActionContextCleanUp、Other Filters、FilterDispatcher 组成的前端控制器
3)  再发送给ActionProxy
4)  ...
先调用拦截器,再调用Action、再是Result,
之后,还可以调用拦截器(拦截器前拦后堵)
 
23.Struts2 控制流程   
Struts2控制流程(面试可能会问到)
1)  请求到来
2)  创建ValueStack(Action放栈顶),进行初始化
3)  调用拦截器Interceptor,在拦截器中是可以访问ValueStack 的
4)  调用Action,执行execute()方法
5)  调用Result,Result负责把数据显示给用户
6)  最后到页面,通过标记库(Taglib)取出数据
24.自定义拦截器步骤 
1)  实现Interceptor 接口,实现intercept方法
2)  获取ValueStack
ValueStack stack = actionInvocation.getStack();
stack.findValue("ognl");
stack.setValue("ognl", obj);
3)获取Servlet API
HttpServletRequest request = ServletActionContext.getRequest();
HttpServletResponse response = ServletActionContext.getResponse();
ServletContext application = ServletActionContext.getServletContext();
4)调用Action
Action连Result一起调用
actionInvocation.invoke();
此后,intercept方法的返回值无意义
只调用Action,没有调用Result
actionInvocation.invokeActionOnly();
此后,由intercept方法的返回值来决定执行哪个Result
5)设置参数 
25.资源文件与国际化(i18n) 
之前我们学习了Struts2的五大组件(ValueStack、拦截器、Result、Action、标记库)。现在我
们开始关于这些组件的一些技巧的学习:国际化、错误处理、表单验证等等。

资源文件的国际化internationalization(又名i18n,来由是以i开头n结尾的中间共18个字母)。
国际化的核心:页面显示的文字是可配置的(如中文、英文、日文等,不能写死在页面中)。

1)  资源文件
资源文件一般是属性文件*.properties
2)  对于中文
 MyEclipse8.5可以方便的得到unicode编码
 使用JDK提供的命令工具native2ascii也可以
3)  资源文件的命名和位置(重要)
如果项目非常大,所有资源文件放入同一个目录下是不好的。资源文件需要分层和分类。
 包级资源文件
表示某资源文件是被一个包中所有Action所使用的,
 类级资源文件
表示某资源文件只能被指定类使用
4)  Action必须继承ActionSupport
ActionSupport类中已经封装了对资源文件的访问。
注意,在我们之前学习中,如果在配置文件中action没有class 属性,则调用的就是
ActionSupport类。
26.
0 0
原创粉丝点击