Action
Namespace(掌握)
在struts2中,在package元素中存在着namespace这么一个属性,该属性是可选的,代表定义该包的命名空间,当没有配置的时候,表示该包处于默认的包空间中。
Struts2之所以提供namespace的功能,主要是为了处理同一个Web应用中包含同名Action的情况。同一个namespace中不能存在相同名字的action,不同的namespace中可以存在相同名字的action。
当在namespace中指定了命名空间之后,在url地址上访问的时候也要记得加上对应的namespace。Struts2中,还可以指定根命名空间,主要是通过设置namespace=”/”来指定的,这样在url地址上输入的时候就可以不用进行输入。
要注意一点,根命名空间和默认空间是两回事,根命名空间下的action只处理根命名空间下的action请求,而默认命名空间,在指定的namespace中找不到action时,会到默认的命名空间去找,找到的话默认命名空间里的action也会处理用户请求。
命名空间只有一个级别,也就是说在指定的命名空间中找不到对应的action时,会直接到默认的命名空间里去查找,而不会到二级命名空间去寻找。就是说当你的url地址为:…/zqz/test/test.action,那么struts会直接到命名空间为zqz/test下面去查找是否存在名称为test的action,找不到的话会直接到默认命名空间去查找,而不会去/zqz命名空间去查找。
Path(掌握)
Struts2中的路径问题是根据action来指定的,而不是由jsp指定的,所以在开发中尽量不要使用相对路径,而是使用绝对路径。
在指定绝对路径的时候,记得要注意书写正确的namespace。
DMI(掌握)
DMI是 Dynamic Method Invocation,即动态方法调用。在实际开发中,一个action中不可能只存在一个execute()方法,也就是说,可以在一个action中存在很多个各式各样的方法,那么在调用这些方法的时候,就要使用到DMI。
使用DMI有两种配置:
一种是在配置action的时候指定method属性,表示调用该action的时候执行的时method指定的方法,而不是execute,但这种配置会使struts.xml的配置信息太长。
一种是在url上调用指定action的时候,用“!”来区别使用的是什么方法,格式为:test.action!add。表示的时调用的时test.action的add()方法。
在使用DMI的时候,要在struts2配置允许动态方法调用。即配置struts.enable.DynamicMethodInvocation来完成的,允许调态调用的话是将这个常量设置为true。因为在struts2-core-2.1.6.jar包下面的org.apache.struts2下面的default.properties已经把这个常量设置为true了,所以在这里是不需要配置的。
Wildcard(掌握)
在上面中可以发现,如果使用DMI的话也可以实现指定action里面不同的方法。但是这样的会使struts.xml中出现大量的配置。所以在这种情况下,Wildcard(通配符)就出现了,通配符是用“*”和“{num}”来指定的。
“*”可以匹配任何的字符,而“{num}”表示的是引用第num个*号。即如果在action中配置name为*Action时,class为cn.com.zqz.{1}Action,在url上输入的时testAction时,表示调用的是cn.com.zqz.testAction。而如果输入的是addAction的话,那么调用的就是cn.com.zqz.addAction。当然这些action一定要存在,并且符合开发使用的action的规则。
除了可以在class中指定“{num}”外,在method属性,result中都同样可以使用。
一般使用通配符的话,都是在action的name属性中设置*_*,然后第一个*与class相匹配,第二个*和method相匹配,这样就可以实现调用一个action的多个方法和多个action中的一个方法了。当然在对应result中按自己的实际情况去指定了。
还有一点,当在struts.xml中出现多个*号的时候,一定要注意优先级。如在struts.xml中的action的name属性有如下指定:LoginAction、*Action、*。那么在url上访问的时LoginAction的时候,首先匹配的肯定是LoginAction。而当不存在LoginAction的时候,如果*Action放在前面,就访问的时*Action指定的action。如果*放在前面的的话,访问的就是*指定的action。所以要注意,当要把action的name属性用*来指定是,一定要把这个action放在其他的action的后面,不然的话会拦截其他的action,使所有的action都是被*号指定的action匹配。
注意:使用通配符时不建议使用太多的*,因为指定太多的*的话会使逻辑出现混乱,所以一般不超过两个*,而*_*是最常用的。
接收参数(掌握前两种)
接收参数有三种方式
- 在action中声明,实现setter和getter方法。
- 封装到一个VO(ValueObject),或者称DO(DataObject),DTO(DataTransformObject)中,提供settet和getter方法,然后再指定的action中声明该vo,则在表单中进行传参的时候,要同时指定action中声明的属性和vo中的的属性。即假设把name属性封装到user中,在testAction声明user,并提供对应的setter和getter方法。那么在表单中传参时就应该这么做:…testAction?user.name=zhangsan,粗体部分表示传参,要注意的还有传递参数的时候不需要添加英文引号“”””。
- 实现modelDriven接口(不常用)
访问request等(掌握Map IoC)
在action中可以访问Request、Session、Application和HttpServletRequest、HttpSession和ServletContext。
访问上面两类对象的方法是类似的,都是有两种方式:
Request、Session、Application
- 建立一个Map对象,在构造方法中,将获取的request、session和application三个对象获取之后放在Map对象中。
Request=(Map)ActionContext.getContext().get(“request”);
Session=(Map)ActionContext.getContext().getSession();
Application=(Map)ActionContext.getContext().getApplication();
2. (常用,最重要)实现接口:requestAware、SessionAware、ApplicationAware,建立Map对象,实现接口的方法setRequest、setSession、setApplication,把接口中默认传递的方法赋值给自己创建的Map对象,获得request、session、application对象。
HttpServletRequest、HttpSession和ServletContext
3.同1,只是这里不建立Map对象,而是建立对应的HttpServletRequest、HttpSession和ServletContext。
HttpRequest对象通过ServletActionContext.getRequest();
HttpSession对象通过获取的request对象进一步获取,即request.getSession();
ServletCotext对象通过session对象获取,即session.ServletContext()
4.同2,不过只实现一个借口:ServletRequestAware,通过实现该接口的setServletRequest方法获取到HttpServletRequest的对象,再通过获取到的HttpServletRequest的对象来获取HttpSession,接着获取ServletContext对象。
简单数据验证(掌握addFieldError和<s:fieldError../>)
在进行数据的验证的时候,当发现验证通不过的时候,可以通过addFieldError把错误信息添加到Value Stack中,然后通过struts2的<s:fieldError../>来将错误信息获取出来,要注意的是这里获取的错误信息是带样式的。如果想要去掉该样式,可以自己重写一个css来覆盖之前的css。
在ActionSupport中,存在一个validate方法,这个方法是用来数据验证的。当此方法一旦发现有错误之后,就会自动跳转到input指定的路径中。
Result
结果类型(掌握四种,重点两种)
Result有如下几点类型:
1、 Dispatcher:forward到一个jsp页面
2、 Redirect:重定向到一个jsp页面
3、 Chain:forward到一个action
4、 redirectAction:重定向到一个action
5、 freemarker:用于指定使用FreeMarker模版作为视图的结果类型
6、 httpheader:用于控制特殊的HTTP行为的结果类型
7、 stream:用于向浏览器返回一个InputStream类型,一般用于文件下载
8、 velocity:用于指定使用velocity模版作为视图的结果类型
9、 xslt:用于与Xml/XSLT整合的结果类型
10、 paintText:用于显示某个页面的原始代码的结果类型,即显示页面源码
11、 tiles:
当result没有指定type时,表示使用默认的type类型,即dispatcher
Dispatcher和redirect的区别就像forward和redirect的区别,使用redirect会丢失参数,包括前一个action的处理结果
注意:在将result结果类型配置成chain或者redirectAction时,一定要配置actionName和namespace,不然无法完成配置。
全局结果(掌握)
当一个页面会被多次调用时,就像error.jsp页面,当该页面作为错误的信息返回时,那么这个result就不单单被某个action调用了,有可能被多个action进行映射,这个时候就可以把result设置成全局结果集。
全局结果集在package元素下进行配置:
<global-results>
<result>error.jsp</result>
</global-results>
注意:如果一个action里包含了与全局结果集里同名的结果,则action里的局部Result会覆盖掉全局结果集里的result。也就是说,当Action处理用户请求结束后,会首先在本action里的局部结果里搜索逻辑视图对应的结果,只有在action里的局部结果里找不到逻辑视图对应的结果,才会在全局结果集搜索。
动态结果(了解)
动态结果就是采用通配符的方式进行配置的,随着输入的action的不同,返回的结果视图也就不同。
使用动态结果集,还可以在对应的action中使用一个字符串来记录返回的jsp页面,然后在struts.xml中配置result的时候,用“${字符串}”的形式来进行动态的返回,这里的“${字符串}”是OGNL表达式,而不是EL表达式。
OGNL表达式(精通)
属性对象的取值
OGNL:Object Graph Navigation Language。
在使用OGNL进行传递参数的时候,系统会把数据放在Value Stack Contents和Stack Context中,使用OGNL将值获取出来的时候,访问Stack Context里的命名对象是需要在对象名之前添加“#”前缀;
假如系统的Stack Context中包含两个对象:foo对象,它在Context中的名字为foo;bar对象,它在Context中的名字为bar,并将foo对象设置成Context对象。
那么#foo.blah则表示返回foo的blah()方法值,#bar.blah表示返回bar的blah()方法值。而blah则表示返回的是foo的blah()方法值,因为foo在根目录。
如果想访问ValueStack里的属性,那么就可以使用“${属性}”来取值。
在Stack Context中,还存在如下的对象
- parameters:用于访问HTTP请求参数
- request:用于访问HttpServletRequest属性
- session:用于访问HttpSession属性
- application:用于访问ServletContext属性
- attr:该对象一次索搜如下对象:PageContext、HttpServletRequest、HttpSession和ServletContext中的属性。
只是上面的对象都不是在根目录中,所以在访问的时候要用“#”。
当系统建立了action实例之后,该action实例会被保存到ValueStack中,所以无需书写“#”就可以访问action属性。
当想查看Stack Context或者Value Stack Contents中有什么属性存在时,可以使用struts2的标签<s:debug/>就可以查看了。
在EL表达式中,当用${属性}的时候,会智能的从pageàrequestàsessionàapplication中查找,但是使用OGNL表达式则不会,所以需要用#request.属性表示request范围传递过来的属性,以此类推。
静态访问
在使用OGNL访问静态属性或者静态方法的时候,要在strust.xml中指定可以访问静态方法,进行如下配置
<constant name="struts.ognl.allowStaticMethodAccess" value="true"></constant>
具体访问静态属性和静态方法的时候,要用“@”来指定。
访问静态方法:<s:properties value=”@cn.com.zqz.Static@say()”/>
访问静态属性:<s:properties value=”@cn.com.zqz.Static@NAME”/>
如上,访问静态属性和静态方法,都要用“@”来指定,第一个@后面的是指定类的具体路径,而第二个@后面指定的时静态方法或属性,如果是静态属性的话,那么要全部大写。
当两个@同时出现的的时候,表示的时访问Math中的静态方法,如
访问Math中的静态方法: <s:properties value=”@@max(2,3)”/>
投影过滤
投影过滤只有三种方式:?#,^#,$#。
其中?#表示过滤条件,^#表示判断之后符合条件的第一个,$#表示判断之后符合的第二条。
Struts标签
struts标签中,常用的有如下标签:
property、set、bean、iterator、if…
struts2的标签有很多,在这里就不全部罗列出来了,详见leeGang234
property标签
在使用property标签的时候,要指定一个value属性,而value属性是动态加载的时候传递过来的,是一个OGNL表达式。当想直接输出value中内容是,可以在用英文单引号“’’”括起来。即<s:property value=”’name’”/>,这样会在页面中直接把name这个字段输出。
set标签
在使用set标签的时候,要对设置的内容存放到一个scope中,当不设置scope时,默认是action,即存放在ActionContext中和request中。但用debug标签检查的时候并未在request中发现,原因是request还未来得及加载,页面就显示出来了。而当在request中取值的时候是可以获取到的。
当然,也可以将scope设置为application、session、request、page和action。
一般来说,set标签只是为了将一个长度很长而又经常调用的属性设置到另一个变量中,那么在后面调用该属性的时候,就可以不用写那么冗长的名称了。
Bean标签
使用bean标签,可以为model类中的属性进行赋值。不过要注意,在使用bena标签的时候,要指定一个name,而这个name就是我们要设置的类的路径名称。可以使用<s:param/>为参数进行赋值,但是要注意,param标签要指定两个属性,一个是name属性,为String类型,对应的是model的属性名。一个是value属性,是OGNL表达式,当如果要为属性传递String类型的数值时,要在括号中再嵌套一个单引号。
在bean标签中,当不设置var时,会在ValueStack Contents中压入一个那么属性指定的类,而当bean标签结束的时候,栈顶的类也会被移除。
Iterator标签
Iterator标签式在开发中相对使用比较多的标签,可以遍历很多的格式,如collections、map、enumeration、iterator、array…
在使用iterator标签的时候,在中间可以使用<s:property/>标签将值显示出来。
在iterator标签中,可以指定三个属性:value、id、status。
- Value:是一个可选属性,一般都是用OGNL表达式指定。如果没有指定,那么久使用ValueStack栈顶的集合。
- Id:可选属性,指定集合里元素的ID。
- Status:可选属性,指定迭代式的IteratorStatus实例,通过该实例可判断当前迭代元素的属性。使用IteratorStatus的方法的时候要用“#”进行指引。
Status属性中指定的IteratorStatus实例,包含了如下方法:
- int getCount():返回当前迭代了几个元素
- int getIndex():返回当前迭代元素的索引
- boolean isEven():返回当前迭代元素的索引是否为偶数
- boolean isFirsrt():返回当前迭代元素是否为第一个元素
- boolean isLast():返回当前迭代元素是否为最后一个元素
- boolean isOdd():返回当前迭代元素是否为奇数
使用iterator迭代map集合的时候,自定义的map集合要以“#”开始,key和value之间以“:”隔开,如<s:iterator value=”#{1:’a’,2:’b’,3:’c’}”></ s:iterator>
取key值的时候直接是:<s:property value=”key”>,
取value值的时候是:<s:property value=”value”>
Map使用iterator输出的流程:
1、 通过Map中的entrySet()方法将Map集合的内容变为Set<Map.Entry>集合;
2、 通过Set集合的iterator()方法,取得Iterator<Map.Entry>的实例;
3、 进行迭代输出,并且通过Map.Entry进行key和value的分离。
If标签
If标签是指if/elseif/else三个标签一起使用,同我们一般使用的if语句是差不多的。
声明式异常处理(了解)
当捕获到异常的时候,不要对一场进行try…catch…,而是通过throw把异常抛出,这样就可以采用声明式异常进行处理了。
当用throw抛出一个异常之后,想要处理异常,还要在struts.xml中进行配置,配置的时候可以配置成局部和全局两种。
局部
配置局部异常,是在对应的action中,配置如下这么一个属性。
<exception-mapping result=”error” exception=”java.sql.SQLException”/>
上面的配置,表示配置了一个java.sql.SQLException的,当在调用某个具体方法的时候抛出SQLException异常的时候,在这里就会捕获到,并且转到result指定的jsp页面,所以除了以上的配置,还需要配置一个name为“error”的result对象。
当使用了如上配置之后,假设真的发生异常之后,在<s:debug/>里就会发现一个新的对象。在ValueStack里出现两个属性:exception、exceptionStack。
全局
当把一个异常声明成局部异常的时候,说明这个局部异常只能被某一个action使用,而当多个action要处理同一个异常的时候,就该把异常配置成全局异常了。
全局异常和局部异常的配置是差不多一样的。配置如下:
<global-exception-mappings/>,同样是要指定exception和result的,只是这里指定的result是全局结果集。在配置的时候,一定要记住,要把全局结果集配置在全局异常的前面,否则将会出现找不到result的错误。
I18N(了解)
I18N是在国际化操作的时候进行设置的。是把要显示的信息写在一个*.properties中
在配置国际化信息的时候,可以*.properties文件设置成三个级别。优先级分别为action-Package-App级别。
Action级别的时指把资源文件设置成只对某个action有效,命名规则为:***Action_zh_CN.properties、***Action_en_US.properties。
Package级别是指把资源文件设置成只对当前包有效,只能命名为package_zh_CN.properties和package_en_US.properties,是不可以修改的。
App级别是指把资源文件设置成整个项目都有效,命名为:***_zh_CN.properties。注意的是一定要放在根目录下面,而且要在struts.xml文件中进行配置
一般来说,设置的资源文件不单单是为某个action或者某个package使用,而应该作为整个项目的资源文件,所以一般都只使用第三种。
在一些网站上总是可以看到页面语言切换的功能,可以在地址栏中用地址重写的方式写:request_loacle=en_US或者request_locale=zh_CN或…
在资源文件中也可以使用占位符({1})的方式来进行传参,只需在使用<s:text/>的时候使用param标签进行传值就可以了。
国际化读取最重要的几个操作类:ResourceBundle、Locale
CRUD的过程(最重要的是设计和规划)(精通)
CRUD就是指对数据库的增删改查等操作,最主要的是了解设计和规划,还有逻辑。
freemarker
在jsp页面中,主要的功能就是对信息的显示,但是直接把jsp放在根目录下,是很不安全的,所以可以使用freemarker组件,使用这个组件的时候需要添加freemarker-2.3.13.jar,同时还需要在web.xml文件中配置一个servler:jspSupportServlet;这个class文件存放在org.apache.struts2.views.JspSupportServlet.class中,因此,需要把类名称和路径配置进去,同时配置一个load-on-startup节点,value是1,表示在启动服务器的时候就自动加载了该servlet。
在struts.xml文件中,配置一个type为freemarker的result节点,指定跳转的路径。如在WEB-INF/template/success.ftl。则需要在指定文件创建一个template文件夹和一个success.ftl文件。ftl文件中不再需要导入java的包和指定struts的标签。在用struts的标签的时候,在标签前面用一个”@“来指定,同时把”:”改成”.”,就可以完成struts标签的使用了。
当然,这样的操作不是完善的,在执行的过程中会发现出现乱码问题,这时候有两种解决方案:
1, 在把result节点配置问freemarker的后面配置一个param节点,name为contentType,value为text/html;charset=GBK表示把编码设置为中文GBK。
2, 如果第一种方式不可以的时候,还可以在src目录下添加一个freemarker.properties文件,文件中指定
a) default_encoding=GBK
b) locale=zh_CN
注意不能以”;“结束。