• 1. 01---Struts2开发环境的搭建 8/24/2011
  • 2. Struts2 Struts2是在WebWork2基础上发展而来的。和Struts1一样,Struts2也属于MVC框架。不过有一点大家需要注意的是:尽管Struts2和Struts1在名字上差别不是很大,但是Struts2和Struts1在代码编写风格上几乎是不一样的。那么既然有了Struts1,为何还要推出Struts2。主要是因为Struts2有以下优点: 一.在软件设计上,采用无侵入式设计,没有跟API有着紧密的耦合,可以不依赖于Servlet API和struts API。 二.Struts2提供了拦截器,利用拦截器可以进行AOP编程,实现如权限拦截等功能。 三.Struts2提供了类型转换器,我们可以把特殊的请求参数转换成需要的类型。 四.Struts2提供支持多种表现层技术。 五.Struts2的输入校验可以对指定方法进行校验。 六.提供了全局范围, 包范围和Action范围的国际化资源文件管理实现。public class OrderListAction extends Action{ public ActionForward execute(ActionMapping mapping,ActionForm form,HttpServletRequest request,HttpServletResponse response)throws Exception{ } }
  • 3. 搭建Struts2开发环境 搭建Struts2开发环境时,我们一般需要做以下几个步骤的工作: 找到开发Struts2应用需要使用到的jar文件; 编写Struts2的配置文件; 在web.xml中添加Struts2 MVC框架启动配置;1.创建一个web项目struts2; 2.将6个必须的jar文件放入lib包中; 3.编写struts.xml配置文件; 4.在web.xml配置文件中加入struts2 MVC框架的启动配置;
  • 4. 搭建Struts2开发环境—导入Struts应用依赖的jar文件大家可以到http://struts.apache.org下载struts-2.x.x-all.zip,目前最新版本为2.2.3。下载完后解压文件,开发struts2应用需要依赖的jar文件在解压目录的lib文件夹下。不同的应用需要的jar包是不同的,下面给出了开发struts2应用程序最少需要的jar。 1.struts2-core-2.x.x.jar:Struts2框架的核心类库。 2.xwork-2.x.x.jar:Xwork类库,Struts在其上构建。 3.ognl-2.6.x.jar:对象图导航语言,struts2框架通过其读写对象的属性。 4.freemarker-2.3.x.jar:Struts2的UI标签的模板使用FreeMarker编写。 5.commons-logging-1.1.x.jar:ASF出品的日志包,Struts2框架使用这个日志包来支持Log4j和JDK1.4+的日志记录。 6.commons-fileupload-1.2.1.jar:文件上传组件,2.1.6版本后必须加入此文件。 7. commons-io.jar commons-lang.jar javassist-3.7.ga.jar;注意:拷贝的时候不要全拷贝,因为jar包中有很多插件包,涉及到其它框架,那么如果你把它们放进来,由于其它jar包缺失,它们会报一个找不到相关类的错误。
  • 5. 搭建Struts2开发环境---Struts2应用的配置文件Struts2默认的配置文件为struts.xml,该文件需要放在web-inf/classes下,开发时放在src目录下面,该文件的配置模板如下(可以从例子下 struts-2.2.3\apps\struts2-blank\WEB-INF\classes拷贝):
  • 6. 搭建Struts2开发环境---Struts2在web中的启动配置在struts1中,struts框架是通过Servlet启动的,在Struts2中,struts框架是通过Filter启动的。它在web.xml中的配置如下,也可以从例子(struts-2.2.3\apps\struts2-blank\WEB-INF)中拷贝: struts2 org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter struts2 /* 在StrutsPrepareAndExecuteFilter的init()方法中将会读取类路径下默认的配置文件struts.xml完成初始化操作。 注意:struts2读取到struts.xml的内容后,以javaBean形式存放在内存中,以后struts2对用户的每次请求处理将使用内存中的数据,而不是每次都读取struts.xml文件。
  • 7. 搭建Struts2开发环境--下载时图片参考2018/10/227
  • 8. 搭建Struts2开发环境—下载时图片参考
  • 9. 搭建Struts2开发环境---Struts2应用的配置文件Struts2默认的配置文件为struts.xml,该文件需要放在web-inf/classes下,该文件的配置模板如下:
  • 10. 搭建Struts2开发环境---Struts2开发环境测试鼠标点击项目名,右键Run As如图所示:看看有无错误信息输出!!!
  • 11. 02---第一个Struts2应用开发 软件讲师:廖秀丽 8/24/2011
  • 12. 第一个Struts2应用---HelloWorld 在默认的配置文件Struts.xml中加入以下配置: /WEB-INF/page/hello.jsp 以上package标签的定义那段是什么意思呢?先看后面的讲解!
  • 13. Struts.xml配置中包的介绍 /WEB-INF/page/hello.jsp 在Struts2框架中使用包来管理Action,包的作用和java中的类包非常类似,它主要用于管理一组业务功能相关的action。在实际应用中,我们应该把一组业务功能相关的Action放在同一个包下。 配置包时必须制定name属性,该name属性可以任意取名,但必须唯一,他不对应java的类包,如果其他包要继承该包,必须通过该属性进行引用。包的namespace属性用于定义该包的命名空间,命名空间作为访问包下的Action路径的一部分,如访问上面例子的Action,访问路径为/test/helloworld.action。namespace属性可以不配置,如果不指定该属性,默认的命名空间为“”(空字符串)。 通常每一个包都应该继承struts-default包,因为Struts2很多核心的功能都是拦截器来实现的。如:从请求中把请求参数封装到action,文件上传和数据验证等等都是通过拦截器实现的。struts-default定义了这些拦截器和Result类型。可以这么说:当包继承了struts-default才能使用struts2提供的核心功能。struts-default包是在struts2-core-2.x.x.jar文件中的struts-default.xml中定义。Struts-default.xml也是Struts默认配置文件。Struts2每次都会自动加载struts-default.xml文件。 包还可以通过abstract=“true”定义为抽象包,抽象包中不能包含action。现在你明白了吧!接下来让我们把这个action建出来吧!
  • 14. 编写HelloWorldAction1.为什么要返回一个字符串? 2.为什么要定义一个message变量? 3.为什么要定义message变量的getMessage()方法? 4.为什么要定义一个execute()方法?
  • 15. 编写hello.jsp请大家思考以下问题,随着问题的解决,那么整个原理也就弄明白了: 1.在哪里创建hello.jsp页面,为什么? 2.在访问该应用,到达hello.jsp页面时,为什么能够拿到action传给页面的message变量值,是通过何种方式获取的?要注意什么? 3.访问该应用的url是什么? 4.如果我想往该页面传递一个name变量,应该怎么做? http://localhost:9080/struts2/test/helloworld屏蔽客户端的直接访问EL表达式中的名字与get方法中的名字保持一致。
  • 16. 第一步:? 第二步:? 第三步:? 大家再看看action的定义,HelloWorldAction有没有继承API中的哪个类,所以Struts2属于无侵入式设计。关于第一个Struts2应用的总结在struts.xml配置文件中添加一段package的配置信息,其中配置了一个Action。创建一个Action,并提供excute()方法,便于处理客户端请求。创建一个服务器端返回给客户端的视图:即jsp页面
  • 17. 03---Action名称的搜索顺序 8/24/2011
  • 18. 上次我们访问Action的url是: http://localhost:8080/struts2/test/helloworld.action 那么我把这段url改成: http://localhost:8080/struts2/test/a1/a2/a3/helloworld.action 还可以访问到这个action吗?
  • 19. Action名称的搜索顺序1.获得请求路径的url,例如url是:http://server/struts2/path1/path 2/path3/test.action 2.首先寻找namespace为/path1/path2/path3的package,如果不存在这个package则执行步骤3;如果存在这个package,则在这个package中寻找名字为test的action,当在该package下寻找不到action时就会直接跑到默认namespace的package里面去寻找action(默认的命名空间为空字符串“”),如果在默认namespace的package里面还寻找不到该action,页面提示找不到action。 3.寻找namespace为/path1/path2的package,如果不存在这个package则转至步骤4;如果存在这个package,则在这个package中寻找名字为test的action,当在该package下寻找不到action时就会直接跑到默认namespace的package里面去寻找action(默认的命名空间为空字符串“”),如果在默认namespace的package里面还寻找不到该action,页面提示找不到action。 4.寻找namespace为/path1的package,如果不存在这个package则转至步骤5;如果存在这个package,则在这个package中寻找名字为test的action,当在该package下寻找不到action时就会直接跑到默认namespace的package里面去寻找action,如果在默认namespace的package里面还寻找不到该action,页面提示找不到action。 5.寻找namespace为/的package,如果存在这个package,则在这个package中寻找名字为test的action,当不存在这个package或者在该package下寻找不到action时就会直接跑到默认namespace的package里面去寻找action,如果在默认namespace的package里 还寻找不到 该action,页面提示找不到action。
  • 20. Action名称搜索顺序测试如果包找得到,但是包下面没有这个action怎么办? 它会去默认的命名空间中找,那么什么叫做默认的命名空间呢? 如果一个包不指定namespace属性或者这个属性值为空,那么这个空间就是默认的命名空间。 我们试试吧,看看是不是真的这样,然后我们请同学总结一下规律!
  • 21. 04---Action配置的各项默认值 8/24/2011
  • 22. Action配置的各项默认值 /WEB-INF/page/hello.jsp 1)如果没有为action指定class,默认值是ActionSupport; 2)如果没有为action指定method,默认值是action中的execute()方法; 3)如果没有指定result的name属性,默认值为success; 如下图,我们在action的配置文件中再添加一个action的配置: /WEB-INF/page/employeeAdd.jsp
  • 23. Action配置的各项默认值接下来: 首先把刚才那个employeeAdd.jsp页面建好 然后利用:http://localhost:9080/<项目名>/<命名空间>/来访问该action。 看看结果如何? 这再一次说明了什么?
  • 24. 05---result配置的各种视图转发类型 软件讲师:廖秀丽 8/24/2011
  • 25. Struts1中的视图转发配置Struts1: /index.jsp /index.jsp> 让我们看看Struts2吧!
  • 26. Action中result的各种转发类型 /WEB-INF/page/hello.jsp result配置类似于Struts1中的forward,但struts2中提供了多种结果类型,常用的类型有:dispatcher(默认值)、redirect、redirectAction、plainText。 一.其中dispatcher相当于Struts1中的第一种forward,即内部请求转发。 二.Redirect相当与Struts1的第二种forward,即浏览器重定向,那么大家想一想:如果页面放在WEB-INF目录下面,浏览器能重定向到吗? 先配置一个action,内容如下: /employeeModify.jsp 然后在WebRoot目录下制作employeeModify.jsp页面; 然后部署项目,在浏览器中访问:http://localhost:8080/<项目名>/<命名空间>/ 大家看看: 访问后浏览器地址栏中的地址是否发生了变化?
  • 27. 带参数重定向当开发Struts应用时,如果遇到列表页面,那么在当前页面中有修改选项,你点修改时,它会用下面的url来到修改页面empModify.jsp?userID=1001。 可是用户在修改页面操作出项错误,这时浏览器需要重定向到修改页面,那么这个url后的(empModify.jsp?userID=1001)userID就会丢失,怎么办呢? 解决的办法很简单: /empAdd.jsp?userId=${userId} 当然有同学会说这个表达式中的UserId是哪里来的,它是action中定义的,并提供了set,get方法。 这里访问时要注意:? 第一步:在redirectTest这个action中定义这个属性。第二步:访问redirectTest那个action,把视图配置加上。
  • 28. 想想:如果刚才传递的是中文怎么办?可以像下面这样做: public String excute() throws Exception{ this.userName=URLEncoder.encode(“清华”,”UTF-8”); return “success”; } 可以测试:在jsp页面输出参数值${param.userName}但是乱码,应该这样: <%=URLDecoder.decode(new String(request.getParameter("userId").getBytes("ISO8859-1"),"UTF-8")) %> 现在大家想想:如果用户在页面添加某条记录后,他是不是想马上回到列表页面,这时我们就要重定向到某个action,那怎么做呢?
  • 29. 很简单: 我们在action的配置文件中,再添加一个action的配置, list 然后重新部署项目,访问就可以了,试试看: http://localhost:<端口号>/<项目名>/<命名空间>/ 如何重定向到一个action如果我重定向的action不在当前包中怎么办呢?
  • 30. 现在我们在action的配置文件中,再添加一个其它包的action的配置, /WEB-INF/page/hello.jsp 然后修改需要重定向的action的result视图类型, xxx /control/department 然后重新部署发布访问,就可以了…如何重定向到其它包中的action注意:查看该类型背后对应的java类
  • 31. plainText视图类型可以显示jsp页面的源代码; 例如:我们做了一个java技术网站,用户需要查看源文件代码,则可以使用此类型。 现在我们在action的配置文件中添加一个action的配置: /index.jsp 然后来访问它。。。 然后在jsp页面写一段中文看能否正常显示?这时该怎么办?看下面: /xxx.jsp UTF-8 plainText视图类型查看该类型背后对应的java类
  • 32. 在struts.xml配置文件中配置全局视图: 在标记中,有标记用来配置全局视图; 现在在action的配置文件中添加一段全局视图定义: /WEB-INF/page/message.jsp 然后再添加一个action的配置: 在action中定义一个add方法: public String add(){ return “message”; } 访问一下:。。。 提问:如何配置其它包中的action都能访问的全局视图? 很简单: /WEB-INF/page/message.jsp 然后让其它包继承这个包就可以了。 配置全局视图
  • 33. 06---Struts2配置文件无提示问题 8/24/2011
  • 34. Struts2配置文件无提示问题有时在配置文件中敲代码时,会发现工具不提示,那是为什么呢? 是因为dtd文件未导入,那么怎么办呢? 以上高亮度显示的部分是一个网络路径,由于机器未上网所以访问不到,有两种方法可以解决问题: 一种是机器上网就可以了。 另一种是在下载的源文件src包里搜索这个struts-2.0.dtd文件,然后点击开发工具:window-Preferences-MyEclipse Enterprise-Files And Editors-XML-XML Catalog-点击Add添加进去,注意三个参数的值。
  • 35. Action中result的各种转发类型 /WEB-INF/page/hello.jsp result配置类似于Struts1中的forward,但struts2中提供了多种结果类型,常用的类型有:dispatcher(默认值)、redirect、redirectAction、plainText。 一.其中dispatcher相当于Struts1中的第一种forward,即内部请求转发。 二.Redirect相当与Struts1的第二种forward,即浏览器重定向,那么大家想一想:如果页面放在WEB-INF目录下面,浏览器能重定向到吗? 先配置一个action,内容如下: /employeeModify.jsp 然后在webroot目录下制作employeeModify.jsp页面; 然后部署项目,在浏览器中访问:http://localhost:8080/<项目名>/<命名空间>/ 大家看看: 访问后浏览器地址栏中的地址是否发生了变化?
  • 36. 带参数重定向当开发Struts应用时,如果遇到列表页面,那么在当前页面中有修改选项,你点修改时,它会像这样来到修改页面empModify.jsp?userID=1001。 可是用户在修改页面操作出项错误,这时浏览器需要重定向到修改页面,那么这个url后的(empModify.jsp?userID=1001)userID就会丢失,怎么办呢? 解决的办法很简单: /empAdd.jsp?userName=${userName} 当然有同学会说这个表达式中的UserName是哪里来的,它是action中定义的,并提供了set,get方法。 这里访问时要注意:不能直接请求redirectTest这个action,因为这样就没有经过HelloWorldAction,也就拿不到值,所以大家想想可以怎么做? 第一种方法:在redirectTest这个action中定义这个属性。第二种方法:访问HelloWorld那个action,把视图配置加上。
  • 37. 想想:如果刚才传递的是中文怎么办?可以像下面这样做: public String excute() throws Exception{ this.userName=URLEncoder.encode(“清华”,”UTF-8”); return “success”; } 可以测试:在jsp页面输出参数值${param.userName}但是乱码,应该这样: <%=URLDecoder.decode(new String(request.getParameter("username").getBytes("ISO8859-1")),"utf-8") %> 现在大家想想:如果用户在页面添加某条记录后,他是不是想马上回到列表页面,这时我们就要重定向到某个action,那怎么做呢?
  • 38. 很简单: 我们在action的配置文件中,再添加一个action的配置, list 然后重新部署项目,访问: http://localhost:<端口号>/<项目名>/<命名空间>/ 如何重定向到一个action如果我重定向的action不在当前包中怎么办呢?
  • 39. 现在我们在action的配置文件中,再添加一个其它包的action的配置, /WEB-INF/page/hello.jsp 然后修改需要重定向的action的result视图类型, xxx /control/department 然后重新部署发布访问…如何重定向到其它包中的action
  • 40. plainText视图类型可以显示jsp页面的源代码; 例如:我们做了一个java技术网站,用户需要查看源文件代码,则可以使用此类型。 现在我们在action的配置文件中添加一个action的配置: /index.jsp 然后来访问它。。。 然后在jsp页面写一段中文看能否正常显示?这时该怎么办?看下面: /xxx.jsp UTF-8 plainText视图类型
  • 41. 在struts.xml配置文件中配置全局视图: 在标记中,有标记用来配置全局视图; 现在在actin的配置文件中添加一段全局视图定义: /WEB-INF/page/message.jsp 然后再添加一个action的配置: 在action中定义一个add方法: public String add(){ return “message”; } 访问一下:。。。 提问:如何配置其它包中的action都能访问的全局视图? 很简单: /WEB-INF/page/message.jsp 然后让其它包继承这个包就可以了。 配置全局视图
  • 42. 07---为Action的属性注入值 8/24/2011
  • 43. 为Action的属性注入值Struts2为Actin中的属性提供了依赖注入功能,在Struts2的配置文件中,我们可以很方便的为Action中的属性注入值。注意:属性必须提供setter方法。 public class HelloWorldAction{ private String savePath; public String getSavePath(){ return savePath; } public void setSavePath(String savePath){ this.savePath=savaPath; } … … } /images /WEB-INF/page/hello.jsp 上面通过节点为action的savePath属性注入值”/images”,需要在hello.jsp页面把这个属性取出来,看是否是/images。 下面我们可以访问一下这个action:。。。 给action中的savePath属性注入值,该属性必须提供set方法
  • 44. 为Action的属性注入值之原理和应用请同学们自己七嘴八舌讲一讲,好吗?
  • 45. 08---指定Struts2处理的请求后缀 软件讲师:廖秀丽 8/24/2011
  • 46. 指定需要Struts2处理的请求后缀这里我们定义了一个常量,那么常量究竟是怎么一回事呢?前面我们都是默认使用.action后缀访问Action。其实默认后缀是可以通过常量“struts.action.extension”进行修改的,例如:我们可以配置Struts2只处理以.do为后缀的请求路径: 如果用户需要指定多个请求后缀,则多个后缀之间以英文逗号(,)隔开,如:
  • 47. 细说常量的定义常量可以在struts.xml或struts.properties中配置,建议在struts.xml中配置,两种配置方式如下: 在struts.xml文件中配置常量: 在struts.properties中配置常量: struts.action.extension=do 因为常量可以在下面多个配置文件中进行定义,所以我们需要了解struts2加载常量的搜索顺序: struts-default.xml struts-plugin.xml struts.xml struts.properties web.xml 如果在多个文件中配置了同一个常量,则后一个文件中配置的常量值会覆盖前面文件中配置的常量值。现在你明白了吧!接下来让我们看看struts2有哪些常用的常量吧!最后加载
  • 48. 常用的常量介绍
  • 49. 09---Struts2的处理流程和Action的管理方式 软件讲师:廖秀丽 8/24/2011
  • 50. Struts2的处理流程StrutsPrepareAndExecuteFilter是Struts2框架的核心控制器,它负责拦截由/*指定的所有用户请求,当用户请求到达时,该Filter会过滤用户的请求。默认情况下,如果用户请求的路径不带后缀或者后缀以.action结尾,这时请求将被转入Struts2框架处理,否则Struts2框架将略过该请求的处理。当请求转入Struts2框架处理时会先经过一系列的拦截器,然后再到Action。与Struts1不同,Struts2对用户的每一次请求都会创建一个Action ,所以Struts2中的Action是线程安全的。Struts1与Struts2对Action的管理有什么不同: Struts1是单例模式,即在应用的生命周期内只会存在一个action,而Struts2则不同,对action的管理采用多线程,即每一个线程对应一个action实例。 这个在以后的面试中有可能遇到,请大家做好准备,本次期末考试会出一道相关的单选题。
  • 51. 10---为应用指定多个Struts配置文件 8/24/2011
  • 52. 为应用指定多个Struts配置文件在大部分应用里,随着应用规模的增加,系统中Action的数量也会大量增加,导致struts.xml配置文件变得非常臃肿。为了避免struts.xml文件过于庞大,臃肿,提高struts.xml文件的可读性,我们可以将一个struts.xml配置文件分解成多个配置文件,然后在struts.xml文件中包含其他配置文件,下面的struts.xml通过元素指定多个配置文件: 通过这种方式,我们就可以将Struts2的Action按模块添加在多个配置文件中。 需要注意的是: 1.在实际企业开发中,我们往往一个模块定义一个配置文件; 2.在strus.xml主配置文件中我们只是包含那些模块配置文件即可; 3.模块配置文件的组织结构与struts.xml是一样的。
  • 53. 11---动态方法调用和使用通配符定义 8/24/2011
  • 54. Struts1的动态方法调用Struts1: 在Struts1中如果想通过UI动态调用Action中的某个方法,可以使用下面的UI: /control/employee/manage?method=addUI 那么Struts2会怎么做呢?
  • 55. Struts2的动态方法调用Struts2: 如果Action中存在多个方法时,我们可以使用!+方法名调用指定方法。如下: public class HelloWorldAction{ private String message; … public String execute() throws Exception{ this.message=“我的第一个Struts2应用”; return “success”; } public String other() throws Exception{ this.message=“第二个方法”; return “success”; } } 假设访问上面action的URL路径为:/struts/test/helloworld.action 那么要访问action的other()方法,我们可以这样调用: /struts/test/helloworld!other.action 如果不想使用动态方法调用,我们可以通过常量struts.enable .DynamicMethodInvocation关闭动态方法调用。 注意:这种动态方法调用Struts2.1之后逐渐不支持。可以通过设置常量禁用它。大家再试一下。
  • 56. 使用通配符定义action WEB-INF/page/hello.jsp public class HelloWorldAction{ private String message; … public String execute() throws Exception{ this.message=“我的第一个Struts2应用”; return “success”; } public String other() throws Exception{ this.message=“第二个方法”; return “success”; } } 要想访问other()方法,可以通过这样的URL访问:/test/helloworld_other.action注意:通配符配置中的下划线可以去掉。{1}表示取第一个参数的值。想想:通配符在class属性中使用可以吗?在result配置中使用可以吗?
  • 57. 12---Struts2请求参数的接收 8/24/2011
  • 58. 接收请求参数采用基本类型接收请求参数(get/post) 在action类中定义与请求参数同名的属性,struts2便能自动接收请求参数并赋值给同名属性。 请求路径:http://localhost:8080/test/view.action?id=78 public class ProductAction{ private Integer id; public void setId(Integer id){//通过反射技术调用与请求参数同名的属性的setter方法来给请求参数赋值 this.id=id; } } 采用复合类型接收请求参数 请求路径:http://localhost:8080/test/view.action?id=78 public class ProductAction{ private Product product; public void setProduct(Product product){ this.product=product; } public Product getProduct(){ return product; } } Struts2通过反射技术调用Product的默认构造器创建product对象,然后再通过反射技术调用product中与请求参数同名的属性的setter方法来获取请求参数值。 做几个调试: 1.试验get方法接收请求参数; 2.试验post方法接收请求参数; 3.试验采用复合类型接收请求参数;想想:如果把复合类型的默认构造方法拿掉,还能收到请求参数吗?
  • 59. 关于Struts2.1.6接收中文请求参数乱码问题 Struts2.1.6版本中存在一个Bug,即接收到的中文请求参数为乱码(以post方式提交),原因是Struts2.1.6在获取并使用了请求参数后才调用HttpServletRequest的setCharacterEncoding()方法进行编码设置,导致应用使用的就是乱码请求参数。这个bug在Struts2.1.8中已经被解决,如果你使用的是Struts2.1.6,要解决这个问题,你可以这样做:新建一个Filter,把这个Filter放置在Struts2的Filter之前,然后在doFilter ()方法里添加以下代码: public void doFilter(){ HttpServletRequest req=(HttpServletRequest)request; req.setCharacterEncoding(“UTF-8”);//这里参数根据实际需要设置 filterchain.doFilter(request,response); }企业中开发新项目:尽量绕开这个版本!
  • 60. 13---自定义类型转换器 8/24/2011
  • 61. 自定义类型转换器试验一下如何接收Date类型的请求参数: 1.在action中定义一个Date属性 birthday,并提供set,get方法,见图1。 2.在配置文件的输出视图中取出该值,见图2。 3.在浏览器中通过get方法来访问该action: http://localhost:7777/struts2/control/employee/list_excute.action?birthday=2011-10-29 观察控制台有没有拿到该属性的值? 再观察页面有没有取到该值? 4.现在把birthday属性的值改为20111029,看看怎样? 这个时候我们发现控制台输出出错信息,这是为什么呢?因为此时它把日期20111029当做String来处理,所以说找不到这个方法。 那么如果程序非要接收这种类型的参数并且一定要使用setBirthday(Date birthday)方法,那么该怎么办呢?
  • 62. 自定义类型转换器java.util.Date类型的属性可以接收格式为2011-10-29的请求参数。但如果我们需要接收格式为20111029的请求参数,我们必须定义类型转换器,否则struts2无法自动完成类型转换。 import java.util.Date; public class HelloWorldAction{ private Date createtime; public Date getCreatetime(){ return createtime; } public void setCreatetime(Date createtime){ this.createtime=createtime; } } Struts 2有两种类型转换器:分别是局部类型转换器和全局类型转换器。局部是对某个Action起作用,全局是对整个应用起作用。
  • 63. 自定义类型转换器首先建立一个类,类名为TypeConverter,让它继承DefaultTypeConverter并重写converterValue()方法;(注意在继承的时候请选择适当的类) public class TypeConverter extends DefaultTypeConverter { @Override public Object convertValue(Map context, Object value, Class toType) { SimpleDateFormat sd = new SimpleDateFormat("yyyyMMdd"); try { if (toType == Date.class) { String[] params = (String[]) value; return sd.parse(params[0]); } else if (toType == String.class) { Date date = (Date) value; return sd.format(date); } } catch (ParseException e) { e.printStackTrace(); } return null; } } 首先建立一个类,类名为DateConverter,让它继承DefaultTypeConverter并重写converterValue()方法;(注意在继承的时候请选择适当的类) 然后将上面的类型转换器注册为局部类型转换器: 在Action类所在的包下放置ActionClassName-conversion.properties文件,ActionClassName是Action的类名,后面的-conversion.properties是固定写法,对于本例而言,文件的名称应为HelloWorldAction-conversion.properties。 在properties文件中的内容为: 属性名称=类型转换器的全类名 对于本例而言,HelloWorldAction-conversion.properties文件中的内容为: createtime=完整包名.类名
  • 64. 自定义类型转换器第二步:然后将前面的类型转换器注册为局部类型转换器: 在Action类所在的包下放置ActionClassName-conversion.properties文件,ActionClassName是Action的类名,后面的-conversion.properties是固定写法,对于本例而言,文件的名称应为HelloWorldAction-conversion.properties。 在properties文件中的内容为: 属性名称=类型转换器的全类名 对于本例而言,HelloWorldAction-conversion.properties文件中的内容为: createtime=完整包名.类型转换器类名 想想看:刚才我们自定义一个类型转换器做了哪几步?
  • 65. 14---全局类型转换器 8/24/2011
  • 66. 全局类型转换器将前面的类型转换器注册为全局类型转换器: 在WEB-INF/classes下放置xwork-conversion.properties文件。在properties文件中的内容为: 待转换的类型=类型转换器的全类名 注意: 第一步就是在src根目录下建一个xwork-conversion.properties文件; 第二步文件中的内容key值不能是birthday,而是java.util.Date,它会对所有的日期类型属性进行格式转换; 对于本例而言,xwork-conversion.properties文件中的内容为: java.util.Date=完整包名.类名讨论:如果应用中各个请求所使用的日期格式有不同的话,那么使用全局类型转换器合适吗?
  • 67. 15---访问或添加request/session/application属性 8/24/2011
  • 68. 访问或添加request/session/application属性public String scope() throws Exception{ ActionContext ctx=ActionContext.getContext(); ctx.getApplication().put(“app”,”应用范围”); //往servletContext里放入app ctx.getSession().put(“ses”,”session范围”); //往session里放入ses ctx.put(“req”,”request范围”); //往request里放入req return “scope”; } JSP: ${applicationScope.app}
    ${sessionScope.ses}
    ${requestScope.req}
    注意:Struts2为了杜绝对servletAPI的直接访问,所以通过ActionContext类来获取request,session和application对象。大家可以试着像上面一样做一下,看看能否在页面获取这些属性。
  • 69. 如果说非要得到request,session和application对象给怎么办?方法一:通过ServletActionContext类直接获取: public String rsa() throws Exception{ HttpServletRequest request=ServletActionContext.getRequest(); //能操作session和request ServletContext servletContext=ServletActionContext.getServletContext(); //能操作application request.setAttribute(“req”,”请求范围属性”); request.getSession().setAttribute(“ses”,”会话范围属性”); servletContext.setAttribute(“app”,”应用范围属性”); return “scope”; } 方法二:实现指定接口并实现接口中的方法,由Struts框架运行时注入相应的值: public class HelloWorldAction implements ServletRequestAware,ServletResponseAware,ServletContextAware{ private HttpServletRequest request; private ServletContext servletContext; private HttpServletResponse response; public void setServletRequest(HttpServletRequest req){ this.request=req; } public void setServletRequest(HttpServletResponse res){ this.response=req; } public void setServletContext(ServletContext ser){ this.servletContext=ser; } } }运行时struts框架帮你把值注入!
  • 70. 大家想想:什么情况下我们需要获取这三个对象,什么情况下不需要?如果我们想得到关于这个站点的相关参数,则需要获取这三个对象来操作,如果我们仅仅只是想往三个范围中放属性,则不需要。
  • 71. 16---文件上传 8/24/2011
  • 72. 文件上传第一步:在WEB-INF/lib下加入commons-fileupload-1.2.1.jar、commons-io-1.3.2.jar。这两个文件可以从http://commons.apache.org/下载。 第二步:把form表的enctype设置为:“multipart/form-data”,如下: 在项目的webroot目录下定义一个表单file.jsp:
    想想以上代码中的含义各是什么?
  • 73. 文件上传第三步:在Action类中添加以下三个属性,其中属性红色部分对应于表单中文件字段的名称: 把字段名称拷贝一下,在Action中添加这个属性,注意是File类型;另有两个属性是String类型;最后添加属性的set,get方法; private File uploadImage; // 临时文件路径 private String uploadImageFileName;// 文件名 private String uploadImageContentType;// 文件类型
  • 74. 文件上传public String execute() { // 想把文件保存在images目录下,这时定义一个变量存放images的文件路径 String realpath = ServletActionContext.getServletContext().getRealPath( "/images"); // 打印目标文件路径,方便一会查看 System.out.println(realpath); System.out.println("文件名称:"+uploadImageFileName + "临时文件路径:" + uploadImage + "文件类型:" + uploadImageContentType); // 加个判断,如果上传文件路径不为空,执行这段代码 if (uploadImage != null) { // 实例化一个文件对象,需要两个参数:文件目标路径和文件名 File savefile = new File(new File(realpath), uploadImageFileName); // 如果文件父目录不存在则创建 if (!savefile.getParentFile().exists()) savefile.getParentFile().mkdirs(); //复制文件,此时需捕获io异常 try { //将文件从临时路径复制到目标路径 FileUtils.copyFile(uploadImage, savefile); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } //向request范围放一个属性,在页面获取 ActionContext.getContext().put("ok", "ok"); } return "success"; } 表面上看代码很多,实际上核心代码只有不到四条。 当然最后还要建一个结果视图页面!
  • 75. 17—多文件上传 2011-08-24
  • 76. 多文件上传第一步:在WEB-INF/lib下加入commons-fileupload-1.2.1.jar、commons-io-1.3.2.jar。这两个文件可以从http://commons.apache.org/下载。 第二步:把form表单的enctype设置为:“multipart/form-data”,如下:
    文件1:
    文件2:
    文件3:
  • 77. 多文件上传第三步:在Actin中定义三个数组属性,分别是 private File [] uploadImage; // 临时文件路径 private String [] uploadImageFileName;// 文件名 private String [] uploadImageContentType;// 文件类型 并生成setter/getter方法; 定义处理方法: public String execute() throws Exception { String realpath = ServletActionContext.getServletContext().getRealPath( "/images"); if (uploadImage != null) { File savedir = new File(realpath); if (!savedir.exists()) savedir.mkdirs(); for (int i = 0; i < uploadImage.length; i++) { File savefile = new File(savedir, uploadImageFileName[i]); FileUtils.copyFile(uploadImage[i], savefile); } ActionContext.getContext().put("ok", "ok"); } return "success"; }想一想:跟刚才单个文件上传有什么不同?
  • 78. 18---自定义拦截器 8/24/2011
  • 79. 自定义拦截器一.需求: 如果用户登录则可以访问action中的所有方法; 如果用户没有登录则不能访问action中的所有方法,并且提示“你没有权限执行该操作”; 二.定义三个页面 user.jsp: <% request.getSession().setAttribute(“user”,”qinghua”); %> 用户已经登录! quit.jsp: <% request.getSession().removeAttribute(“user”); %> 用户已经退出! message.jsp: ${message}
  • 80. 自定义拦截器三.自定义一个拦截器,需要实现接口: com.opensymphony.xwork2.interceptor.Interceptor 并实现接口中的方法intercept,代码如下: public String intercept(ActionInvocation arg0) throws Exception { Object user = ActionContext.getContext().getSession().get("user"); if (user != null) return arg0.invoke(); //如果用户已登录,则执行用户所请求的方法 ActionContext.getContext().put("message", "你没有权限执行该操作!"); return "message"; }
  • 81. 自定义拦截器三.定义action public class HelloPremissAction { //定义一个变量便于显示测试信息 private String message; public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } //定义两个方法,其实一个方法也可以 public String meth1() { this.message = "meth1"; return "message"; } public String meth2() { this.message = "meth2"; return "message"; } }
  • 82. 自定义拦截器四.配置各组件,提醒这种配置不好 /message.jsp 此种配置屏蔽了Struts2给我们提供的拦截器的所有功能!
  • 83. 自定义拦截器五.正确的配置各组件 /message.jsp
  • 84. 自定义拦截器六.部署应用测试效果 1.试着访问action,此时session中没有用户存在,故应该输出“你没有执行该操作的权限”! 2.试着先访问user.jsp页面,此时会在session中存放“user”属性,再访问action,操作正常,访问的方法被调用! 注意1:因为struts2如文件上传,数据验证,封装请求参数到action等功能都是由系统默认的defaultStack的拦截器实现的,所以我们定义的拦截器需要引用系统默认的defaultStack,这样应用才可以使用struts2框架提供的众多功能。 如果希望包下的action都使用自定义拦截器,可以通过把拦截器定义为默认拦截器。 注意2:每个包只能指定一个默认拦截器。另外,一旦我们为该包中的action显式指定了某个拦截器,则默认拦截器不会起作用。
  • 85. 自定义拦截器假设我们要给包里的所有action都配置权限拦截,这个时候可以使用这样的配置: 注意:每个包只能指定一个默认拦截器,另外,一旦我们为该包中的某个action显式的指定了某个拦截器,则默认拦截器不会起作用。
  • 86. 19---对Action中所有方法进行输入验证 8/24/2011
  • 87. 对Action中所有方法进行输入校验输入校验 在Struts2中,我们可以实现对action的所有方法进行校验或者对action的指定方法进行校验。 对于输入校验Struts2 提供了两种实现方法: 1.采用手工编写代码实现。 2.基于XML配置方式实现。
  • 88. 对Action中所有方法进行输入校验第一步:创建一个web应用validate; 第二步:创建一个登录页面login.jsp:
    用户名: 用户名不能为空
    手机号: 手机号不能为空,并且符合相关规则
  • 89. 对Action中所有方法进行输入校验第三步:创建一个消息提示页面message.jsp: 主要代码:${message} 第四步:创建一个LoginAction: public class LoginAction { private String username; private String mobile; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getMobile() { return mobile; } public void setMobile(String mobile) { this.mobile = mobile; } public String update(){ ActionContext.getContext().put("message", "更新成功!"); return "message"; } public String save(){ ActionContext.getContext().put("message", "保存成功!"); return "message"; } }
  • 90. 对Action中所有方法进行输入校验第五步:在配置文件struts.xml中编写配置代码,该切图仅供参考:
  • 91. 对Action中所有方法进行输入校验第六步:手工编写代码实现对action中所有方法输入校验 通过重写validate()方法实现,validate()方法会校验action中所有与execute方法签名相同的方法。当某个数据校验失败时,我们应该调用addFieldError()方法往系统的fieldErrors添加校验失败信息(为了使用addFieldError()方法,action可以继承ActionSupport),如果系统的fieldErrors包含失败信息,struts2会将请求转发至input的result。在input视图中可以通过显示失败信息。 1.让LoginAction继承ActionSupport; 2.在LoginAction中重写validate方法:
  • 92. 对Action中所有方法进行输入校验3.在name为“input”的视图中导入struts标签库,然后使用标记显示出错信息: <%@ taglib uri="/struts-tags" prefix="s"%> 最后注意: 1.检查业务流程是否全部ok。 2.会敲代码还要会跑效果,看看不输入任何数据怎样,输错数据怎样,再试试对于action中的其它方法能否起效。
  • 93. 20---对Action指定方法进行校验 8/24/2011
  • 94. 对Action中指定方法进行输入校验只需要将前面action代码中的validate()方法名称改为validateUpdate(),则该校验将只对action中的update方法起作用,对于其它方法将不起作用,其作用原理同前面讲的“对action中所有方法进行输入校验”一致。 注意:改名时方法名字段首字母必须大写。
  • 95. 21---输入校验的流程 8/24/2011
  • 96. 输入校验的流程1.类型转换器对请求参数执行类型转换,并将转换后的值赋给action中的属性。 2.如果在执行类型转换的过程中出现异常,系统会将异常信息保存到ActionContext中,ConversionError拦截器将异常信息封装到fieldErrors里。不管类型转换是否出现异常,都会进入第3步。 3.系统通过反射技术先调用action中的validateXxx()方法,Xxx为方法名。 4.再调用action中的validate()方法。 5.经过上面四步,如果系统中的fieldErrors存在错误信息(即存放错误信息集合的size大于0),系统自动将请求转发至名称为input的视图中。如果系统中的fieldErrors没有任何错误信息,系统将执行action中的处理方法。认真观察:大家会发现,当类型转换失败时也会跳转到input视图,这里大家可以做个试验,给action添加一个日期字段,并提供set方法,然后validate方法什么也不做,在登录页面添加一个日期文本框,最后访问登录页面,随便输个日期,看系统有没有跳到input视图?
  • 97. 22---基于XML配置方式实现对Action的所有方法进行校验 8/24/2011
  • 98. 基于XML配置方式实现对Action的所有方法进行校验使用基于XML配置方式实现输入校验时,Action也要继承ActionSupport,并且提供校验文件,校验文件和action类放在同一个包下,文件的取名格式为:ActionClassName-validation.xml,其中ActionClassName为action的简单类名,-validation为固定写法,如果Action类为com .qinghua.UserAction,那么该文件的取名为:UserAction-validation.xml,下面是校验文件的模板: 用户名不能为空 手机号不能为空 手机号格式不正确 注意:把拷贝文件中的1.0.2改成1.0.3;
  • 99. 基于XML配置方式实现对Action的所有方法进行校验 指定action类要校验的属性,指定校验器,上面指定的校验器requiredstring是由系统提供的,系统提供了满足大部分验证需求的校验器,这些校验器的定义可以在xwork-2.X.jar中的com.opendymphony.xwork2.validator.validators包下的default.xml中找到。 为校验失败后的提示信息,如果需要国际化,可以为message指定key属性,key的值为资源文件中的key。 在这个校验文件中: 首先对actin中字符串类型userName属性进行校验,首先要求调用trim()方法去掉空格,然后判断用户名是否为空。 然后对字符串类型mobile属性进行校验,使用了两个校验器,一个是requiredstring(手机号必填),另一个是regex(根据param指定的格式要求输入手机号)。
  • 100. 基于XML配置方式实现对Action的所有方法进行校验 现在完成该效果: 第一步:创建login.jsp页面: 切图如下:大家想想: 1.根据请求递交的action属性值,你该创建一个怎样的action? 2.根据表单中两个输入框的name属性,你的action中是否也要定义相关变量,并提供…?
  • 101. 基于XML配置方式实现对Action的所有方法进行校验 第二步:创建ValiAction,要定义什么样的属性,定义几个方法,大家想想? 第三步:在struts.xml配置文件中配置该Action,提醒:这是参考代码: 想想: 1.action的name属性为什么那样定义: 2.为什么要定义input视图,为什么验证出错时返回到表单填写页面?
  • 102. 基于XML配置方式实现对Action的所有方法进行校验 第四步:编写针对action中属性的验证文件ValiAction-validation.xml: 其中含义大家还会解释吗?
  • 103. 基于XML配置方式实现对Action的所有方法进行校验 第五步:易错点: 1.Action类一定要继承ActionSupport类,否则验证的页面输出不ok; 2.input视图要导入struts的标签库,并且为了显示验证错误信息,一定要有标记; 3.验证文件中的属性名,表单中的属性名,action中的变量名要对应; 4.有同学会出现代码ok了,但是不会跑效果,注意我们这次验证对action中的所有方法都有效,你试试! 。。。。。大家比比谁悟性高?
  • 104. 23---基于XML配置方式------ 实现对action中指定方法进行校验 8/24/2011
  • 105. XML配置方式对指定action方法进行输入校验当校验文件的取名为ActionClassName-validation.xml时,会对action中的所有处理方法实施输入验证。如果你只需要对action中的某个action方法实施校验,那么,校验文件的取名应为:ActionClassName-ActionName-validation.xml, 其中ActionName为struts.xml中action的名称。例如:在实际应用中,常有以下配置: /index.jsp /message.jsp //ValidationAction中有两个处理方法 public String save(){ this.message="保存成功!"; return "message"; } public String update(){ this.message="更新成功!"; return "message"; } 要对save()方法实施验证,校验文件的取名为:ValidationAction-vali_save-validation.xml 要对update()方法实施验证,校验文件的取名为:ValidationAction-vali_update-validation.xml 大家想想:大致的实现步骤是什么? 1.Action类要继承ActionSupport类; 2.要有验证文件,注意取名; 3.要配置input视图,在视图中运用标记显示错误提示信息;
  • 106. 基于XML校验的一些特点当为某个action 提供了ActionClassName-validation.xml和ActionClassName-ActionName-validation.xml两种规则的校验文件时,系统按下面顺序寻找校验文件: ActionClassName-validation.xml ActionClassName-ActionName-validation.xml 系统寻找到第一个校验文件时还会继续搜索后面的校验文件,当搜索到所有校验文件时,会把校验文件里的规则汇总,然后全部应用于action方法的校验。如果两个校验文件中指定的校验规则冲突,则只使用后面文件中的校验规则。 当action类继承了另一个action,父类action的校验文件会先被搜索到。 假设UserAction继承BaseAction: 访问上面的action, 系统会先搜索父类的校验文件:BaseAction-validation.xml,BaseAction-base-validation.xml, 接着搜索子类的校验文件:UserAction-validation.xml,UserAction-user-validation.xml 应用于上面action的校验规则为这四个文件的总和。
  • 107. 24—配置国际化全局资源文件,输出国际化信息 8/24/2011
  • 108. 配置国际化全局资源文件,输出国际化信息准备资源文件,资源文件的命名格式如下: baseName_language_country.properties baseName_language.properties baseName.properties 其中baseName为资源文件的基本名,我们可以自定义,但language和country必须是java支持的语言和国家。如: 中国大陆:baseName_zh_CN.properties 美国:baseName_en_US.properties 现在我们为应用添加两个资源文件: 第一个存放中文:qinghua_zh_CN.properties 内容为:welcome=欢迎来到清华IT 第二个存放英语(美国):qinghua_en_US.properties 内容为:welcome =welcome to tsinghua 对于中文的属性文件,我们编写好后,应该使用jdk提供的native2ascii命令把文件转换为unicode编码的文件,命令的使用方式如下: native2ascii 源文件.properties 目标文件.properties首先大家要明白:Struts2对于国际化提供了三种范围的资源文件:全局范围,包范围和action范围。今天我们先学习如何定义全局范围的资源文件?
  • 109. 配置国际化全局资源文件,输出国际化信息当准备好资源文件后,我们可以在struts.xml中通过struts.custom.i18n.resources常量把资源文件定义为全局资源文件,如下: Qinghua为资源文件的基本名。 后面我们就可以在页面或在action中访问国际化信息: 在jsp页面中使用标签输出国际化信息: ,name为资源文件中的key 在Action类中,可以继承ActionSupport,使用getText()方法得到国际化信息,该方法的第一个参数用于指定资源文件中的key 在表单标签中,通过key属性指定资源文件中的key,如: 这些工作完成后,你还要会跑代码哟!注意:应先在jsp页面导入struts标签库。
  • 110. 25—输出带有占位符的国际化信息 8/24/2011
  • 111. 国际化---输出带有占位符的国际化信息资源文件的内容如下: welcome={0},欢迎来到清华IT{1} 在jsp页面中输出带占位符的国际化信息 liyuchun study 在Action类中获取带占位符的国际化信息,可以使用getText(String key,String [] args) 或getText(String aTextName,List args)方法。 在Action的某个方法中可以: ActionContext.getContext().put(“message”,this.getText (“welcome”,new String[]{“李宇春”,”参观”}));
  • 112. 26—配置包范围国际化资源文件 8/24/2011
  • 113. 国际化---包范围资源文件的配置在一些大型应用中,整个应用有大量的内容需要实现国际化。如果我们把国际化的内容都放置在全局资源属性文件中,显然会导致资源文件变的过于庞大,臃肿,不便于维护,这个时候我们可以针对不同模块,使用包范围来组织国际化文件。 方法如下: 在java的包下放置package_language_country.properties资源文件,package为固定写法,处于该包及子包下的action都可以访问该资源。当查找指定key的消息时,系统会先从package资源文件查找,当找不到对应的key时,才会从常量struts.custom.i18n.reaources指定的资源文件中寻找。
  • 114. 配置国际化全局资源文件,输出国际化信息当准备好资源文件后,我们可以在struts.xml中通过struts.custom.i18n.resources常量把资源文件定义为全局资源文件,如下: Qinghua为资源文件的基本名。 后面我们就可以在页面或在action中访问国际化信息: 在jsp页面中使用标签输出国际化信息: ,name为资源文件中的key 在Action类中,可以继承ActionSupport,使用getText()方法得到国际化信息,该方法的第一个参数用于指定资源文件中的key 在表单标签中,通过key属性指定资源文件中的key,如: 这些工作完成后,你还要会跑代码哟!
  • 115. 27—配置Action范围国际化资源文件 8/24/2011
  • 116. 国际化---Action范围资源文件我们可以为某个action单独指定资源文件,方法如下: 在Action类所在的路径,防止ActionClassName_language_country.properties资源文件,ActionClassName为action类的简单名称。 当查找指定key的消息时,系统会先从: ActionclassName_language_country.properties资源文件查找,如果没有找到对应的key,然后沿着当前包查找基本名为package的资源文件,一直找到最顶层包。如果还没有找到对应的key,最后会从常量struts.custom.i18n.resources指定的资源文件中寻找。
  • 117. 国际化---jsp中直接访问某个资源文件Struts2为我们提供了标签,使用标签我们可以在类路径下直接从某个资源文件中获取国际化数据,而无需任何配置: ----这种访问默认访问全局国际化资源配置文件 qinghua为类路径下资源文件的基本名。 如果要访问的某个资源在类路径的某个包下,可以这样访问: 李宇春 上面访问cn.qingua.action包下基本名为package的资源文件。 那如果我要访问基本名为某个action的配置文件呢? 基本名为qinghua基本名为package
  • 118. 28—ognl表达式 8/24/2011
  • 119. OGNL表达式语言OGNL是Object Graphic Navigation Language(对象图导航语言)的缩写,它是一个开源项目,Struts2框架使用OGNL作为默认的表达式语言。 相对EL表达式,它提供了平时我们需要的一些功能,如: 支持对象方法调用,如:xxx.sayHello(); 支持类静态方法调用和值访问,表达式的格式为@[类全名(包括包路径)]@[方法名|值名],例如:@java.lang.String@format()或者@qinghua.Constant@APP.NAME; 操作集合对象。 Ognl有一个上下文(Context)概念,说白了上下文就是一个MAP结构,它实现了java.utils.Map接口,在Struts2中上下文(Context)的实现为ActionContext,下面是上下文(Context)的结构示意图。
  • 120. OGNL表达式语言Struts2中的OGNL Context实现者为ActionContext,它结构示意图如下:当Struts2接受一个请求时,会迅速创建ActionContext,ValueStack,action,然后把action放进ValueStack,所以action的实例变量可以被OGNL访问。ValueStack(值栈,它是根对象)parametersrequestsessionapplicationattrOGNL Context
  • 121. OGNL表达式语言访问上下文(Context)中的对象需要使用#符号标注命名空间,如#application,#session 另外OGNL会设定一个根对象(root对象),在Struts中根对象就是ValueStack(值栈)。如果要访问根对象(即ValueStack)中对象的属性,则可以省略#命名空间,直接访问该对象的属性即可。 在Struts2中,根对象ValueStack的实现类为OgnlValueStack,该对象不是我们想象的只存放单个值,而是存放一组对象,在OgnlValueStack类里有一个List类型的root变量,就是使用它存放一组对象。 在root变量中处于第一位的对象叫栈顶对象。通常我们在OGNL表达式里直接写上属性的名称即可访问root变量里对象的属性,搜索顺序是从栈顶对象开始寻找,如果栈顶对象不存在该属性,就会从第二个对象寻找,如果没有就从第三个对象寻找,依次往下访问,直到找到为止。 大家注意:Struts2中,OGNL表达式需要配合Strut标签才可以使用: 如:
  • 122. OGNL表达式语言由于ValueStack(值栈)是Struts2中OGNL的根对象,如果用户需要访问值栈中的对象,在JSP页面可以直接通过下面的EL表达式访问ValueStack(值栈)中对象中的属性: ${name} //获得值栈中某个对象的name属性 如果访问其他Context中的对象,由于他们不是根对象,所以在访问时,需要加#前缀。 application对象:用于访问ServletContext,例如#application.username或者#application[‘username’],相当于调用ServletContext的的getAttribute(“username”); session对象:用来访问HttpSession,例如#session.username或者#session[‘username’],相当于调用session.getAttribute(“username”); request对象:用来访问HttpServletRequest属性(attribute)的Map,例如#request.username或者#request[‘username’],相当于调用request.getAttribute(“username”); parameters对象:用于访问HTTP的请求参数,例如#parameters.useranme或者 #parameters[‘username’],相当于调用request.getParameter(“username”); attr对象:用于按page->request->session->application顺序访问其属性。
  • 123. 采用OGNL表达式创建List/Map集合对象如果需要一个集合元素的时候(例如List对象或者Map对象),可以使用OGNL中同集合相关的表达式,使用如下代码直接生成一个List对象:
    set标签用于将某个值放入指定范围。 scope:指定变量被放置的范围,该属性可以接受application,session,request,page或action。如果没有设置该属性,则默认放置在OGNLContext中。 value:赋给变量的值如果没有设置该属性则将ValueStack栈顶的值赋给变量。 生成一个Map对象: =
  • 124. 采用OGNL表达式判断对象是否存在于集合中对于集合类型,OGNL表达式可以使用in和not in两个元素符号。其中,in表达式用来判断某个元素是否在指定的集合对象中,not in判断某个元素是否在指定的集合对象中,如下所示: in表达式: 不在 not in表达式: 不在
  • 125. OGNL表达式的投影功能除了in和not in之外,OGNL还允许使用某个规则获得集合对象的子集,常用的有以下3个操作符。 ?:获得所有符合逻辑的元素。 ^:获得符合逻辑的第一个元素。 $:获得符合逻辑的最后一个元素。 例如代码: 35}”> =$
    在上面代码中,直接在集合后跟紧.{}运算符表明取出该集合的子集,{}内的表达式用于获取符合条件的元素,this指的是为了从大集合books筛选数据到小集合,需要对大集合books进行迭代,this表示当前迭代的元素。本例的表达式用于获取集合中价格大于35的书集合。
  • 126. 29—struts2常用标签解说 8/24/2011
  • 127. property标签property标签用于输出指定值: default: 可选属性,如果需要输出的属性值为null,则显示该属性指定的值。 escape:可选属性,指定是否格式化HTML代码。 value:可选属性,指定需要输出的属性值,如果没有指定该属性,则默认输出valueStack栈顶的值。 Id:可选属性,指定该元素的标识。
  • 128. if/elseif/else标签 23 21 都不等 标签做了一个集合,此时未指定范围,所以默认是在OGNL上下文中,访问该集合需用#age方式,如果指定范围为scope=“request”,那么访问该集合就要使用#request.age这种方式了。大家可以试试。
  • 129. url标签 ">点击我吧 生成类似如下路径: /struts/test/helloworld_add.action?personid=23 当标签的属性值作为字符串类型处理时,“%”符号的用途是计算OGNL表达式的值。 第一种情况:
    第二种情况: 在实际应用中一般这样做: ”>超链接 输出结果: #myurl http://www.baidu.com 第一种情况的输出是把它当做字符串处理了,没有计算;第二种情况会计算。 大家想想:采用这种标签的好处是什么:很简单,不用硬编码,不用加上下文路径,不用加请求后缀。传参数
  • 130. iterator标签iterator标签用于对集合进行迭代,这里的集合包括List,Set和数组。 red blue>
    value:可选属性,指定被迭代的集合,如果没有设置该属性,则使用ValueStack栈顶的集合。 Id:可选属性,指定集合里的元素的id(已被标注为过时)。 status:可选属性,该属性指定迭代时的IteratorStatus实例,该实例包含如下几个方法: int getCount(),返回当前迭代了几个元素。 int getIndex(),返回当前迭代了几个元素。 boolean isEven(),返回当前被迭代元素的索引是否是偶数。 boolean isOdd(),返回当前被迭代元素的索引是否是奇数。 boolean isFirst(),返回当前被迭代元素是否是第一个元素。 boolean isLast(),返回当前被迭代元素是否是最后一个元素。
  • 131. 表单标签_checkboxlist复选框如果集合为list 生成如下HTML代码: 如果集合为MAP 生成如下HTML代码:
  • 132. 表单标签_checkboxlist复选框如果集合里存放的是javabean <% Person person1=new Person(1,”第一个”); Person person2=new Person(2,”第二个”); List list=new ArrayList(); list.add(person1); list.add(person2); request.setAttribute(“persons”,list); %> personid和name为person的属性
  • 133. 表单标签_radio单选框该标签的使用和checkboxlist复选框相同 如果集合里存放的是javabean(personid和name为Person的属性) 生成如下html代码: 如果集合为MAP 如果集合为list 生成如下html代码:
  • 134. 表单标签_select下拉选择框
  • 135. 30—使用标签防止表单重复提交 8/24/2011
  • 136. 标签防止重复提交标签防止重复提交,用法如下: 第一步:在表单中加入 第二步: /WEB-INF/page/message.jsp /WEB-INF/page/result.jsp 以上配置加入了“token拦截器”和“invalid.token”结果,因为“token”拦截器在会话的token与请求的token不一致时,将会直接返回“invalid.token”结果。 注意: 在debug状态下,控制台出现一些”严重”信息,是因为Action中没有struts.token和struts.token.name属性,我们不用关心这个错误。 可以返回提交页面在刷新
  • 137. 31—Struts2+Spring2.5+Hibernate3.3整合开发 8/24/2011
  • 138. Struts2+Spring2.5+Hibernate3.3整合开发1. 下面给出整合开发时Struts 2、 Hibernate、Spring需要的JAR。 <1> struts2-core-2.x.x.jar :Struts 2框架的核心类库 xwork-2.x.x.jar :XWork类库,Struts 2在其上构建 ognl-2.6.x.jar :对象图导航语言(Object Graph Navigation Language),struts2框架通过其读写对象的属性 freemarker-2.3.x.jar :Struts 2的UI标签的模板使用FreeMarker编写 commons-fileupload-1.2.x.jar 文件上传组件,2.1.6版本后需要加入此文件 struts2-spring-plugin-2.x.x.jar :用于struts2集成Spring的插件
  • 139. Struts2+Spring2.5+Hibernate3.3整合开发<2> hibernate核心安装包下的(下载路径:http://www.hibernate.org/,点击“Hibernate Core”右边的“Downloads”): hibernate3.jar lib\bytecode\cglib\hibernate-cglib-repack-2.1_3.jar lib\required\*.jar <3> hibernate 注解安装包下的(下载路径:www.hibernate.org,点击“Hibernate Annotations”右边的“Downloads”): hibernate-annotations.jar lib\ejb3-persistence.jar、hibernate-commons-annotations.jar
  • 140. Struts2+Spring2.5+Hibernate3.3整合开发<4> Hibernate针对JPA的实现包(下载路径:www.hibernate.org,点击“Hibernate Entitymanager”右边的“Downloads”): hibernate-entitymanager.jar lib\test\log4j.jar、slf4j-log4j12.jar <5> Spring安装包下的 dist\spring.jar lib\c3p0\c3p0-0.9.1.2.jar lib\aspectj\aspectjweaver.jar、aspectjrt.jar lib\cglib\cglib-nodep-2.1_3.jar lib\j2ee\common-annotations.jar lib\log4j\log4j-1.2.15.jar lib\jakarta-commons\commons-logging.jar <6> MYSQL数据库驱动jar或者Oracle数据库驱动jar等
  • 141. Struts2+Spring2.5+Hibernate3.3整合开发2.在源文件夹或者WEB-INF目录下新建Spring配置文件beans.xml : 注意讲解这些命名空间的作用,如果缺少某一个,则某些功能实现起来有困难。
  • 142. Struts2+Spring2.5+Hibernate3.3整合开发在配置文件中配置dbcp数据源数据源是单例模式
  • 143. Struts2+Spring2.5+Hibernate3.3整合开发 com/qinghua/www/entity/Person.hbm.xml hibernate.dialect=org.hibernate.dialect.Oracle9Dialect hibernate.hbm2ddl.auto=update???????????? //自动建表 hibernate.show_sql=false hibernate.format_sql=false create:表示启动的时候先drop,再create create-drop: 也表示创建,只不过再系统关闭前执行一下drop update: 这个操作启动的时候会去检查schema是否一致,如果不一致会做scheme更新 validate: 启动时验证现有schema与你配置hibernate是否一致,如果不一致就抛出异常,并不做更新 create:表示启动的时候先drop,再create create-drop: 也表示创建,只不过再系统关闭前执行一下drop update: 这个操作启动的时候会去检查schema是否一致,如果不一致会做scheme更新 validate: 启动时验证现有schema与你配置的hibernate是否一致,如果不一致就抛出异常,并不做更新
  • 144. Struts2+Spring2.5+Hibernate3.3整合开发3. 实体bean配置模版.hbm.xml SEQ_MARY 当然需要编写对应的实体bean,然后写测试类PersonTest---测试是否配置ok,也就是实例化spring容器时,看spring能否帮我们自动创建表!
  • 145. Struts2+Spring2.5+Hibernate3.3整合开发4. 在web容器中实例化spring容器和配置struts2 <1> contextConfigLocation classpath:beans.xml org.springframework.web.context.ContextLoaderListener
  • 146. Struts2+Spring2.5+Hibernate3.3整合开发<2> 配置struts2 struts2 org.apache.struts2.dispatcher.FilterDispatcher struts2 /*
  • 147. Struts2+Spring2.5+Hibernate3.3整合开发<3> struts2的配置文件模版struts.xml如下。常量struts.objectFactory=spring明确指出将由Spring负责创建Action实例。
  • 148. Struts2+Spring2.5+Hibernate3.3整合开发 /WEB-INF/page/message.jsp /WEB-INF/page/persons.jsp /WEB-INF/page/add_person.jsp /WEB-INF/page/edit_person.jsp 在struts.xml配置文件中添加一段包及action的配置。
  • 149. Struts2+Spring2.5+Hibernate3.3整合开发5. 为了能从spring容器中寻找到Action bean,要求action配置的class属性值和spring中bean的名称相同。如下: .....
  • 150. Struts2+Spring2.5+Hibernate3.3整合开发  C3P0拥有比DBCP更丰富的配置属性,通过这些属性,可以对数据源进行各种有效的控制:     acquireIncrement:当连接池中的连接用完时,C3P0一次性创建新连接的数目;     acquireRetryAttempts:定义在从数据库获取新连接失败后重复尝试获取的次数,默认为30;     acquireRetryDelay:两次连接中间隔时间,单位毫秒,默认为1000;     autoCommitOnClose:连接关闭时默认将所有未提交的操作回滚。默认为false;     automaticTestTable: C3P0将建一张名为Test的空表,并使用其自带的查询语句进行测试。如果定义了这个参数,那么属性preferredTestQuery将被忽略。你 不能在这张Test表上进行任何操作,它将中为C3P0测试所用,默认为null;     breakAfterAcquireFailure:获取连接失败将会引起所有等待获取连接的线程抛出异常。但是数据源仍有效保留,并在下次调   用getConnection()的时候继续尝试获取连接。如果设为true,那么在尝试获取连接失败后该数据源将申明已断开并永久关闭。默认为 false;     checkoutTimeout:当连接池用完时客户端调用getConnection()后等待获取新连接的时间,超时后将抛出 SQLException,如设为0则无限期等待。单位毫秒,默认为0;     connectionTesterClassName: 通过实现ConnectionTester或QueryConnectionTester的类来测试连接,类名需设置为全限定名。默认为 com.mchange.v2.C3P0.impl.DefaultConnectionTester;     idleConnectionTestPeriod:隔多少秒检查所有连接池中的空闲连接,默认为0表示不检查;     initialPoolSize:初始化时创建的连接数,应在minPoolSize与maxPoolSize之间取值。默认为3;   
  • 151. Struts2+Spring2.5+Hibernate3.3整合开发  maxIdleTime:最大空闲时间,超过空闲时间的连接将被丢弃。为0或负数则永不丢弃。默认为0;     maxPoolSize:连接池中保留的最大连接数。默认为15;     maxStatements:JDBC的标准参数,用以控制数据源内加载的PreparedStatement数量。但由于预缓存的Statement属 于单个Connection而不是整个连接池。所以设置这个参数需要考虑到多方面的因素,如果maxStatements与 maxStatementsPerConnection均为0,则缓存被关闭。默认为0;     maxStatementsPerConnection:连接池内单个连接所拥有的最大缓存Statement数。默认为0;     numHelperThreads:C3P0是异步操作的,缓慢的JDBC操作通过帮助进程完成。扩展这些操作可以有效的提升性能,通过多线程实现多个操作同时被执行。默认为3;     preferredTestQuery:定义所有连接测试都执行的测试语句。在使用连接测试的情况下这个参数能显著提高测试速度。测试的表必须在初始数据源的时候就存在。默认为null;     propertyCycle: 用户修改系统配置参数执行前最多等待的秒数。默认为300;     testConnectionOnCheckout:因性能消耗大请只在需要的时候使用它。如果设为true那么在每个connection提交的时候都 将校验其有效性。建议使用idleConnectionTestPeriod或automaticTestTable 等方法来提升连接测试的性能。默认为false;     testConnectionOnCheckin:如果设为true那么在取得连接的同时将校验连接的有效性。默认为false。
  • 152. Struts2+Spring2.5+Hibernate3.3整合开发 一、spring Bean的作用域:scope=singleton(默认,单例,生成一个实例)   //或不配             18     只生成一个对象,调用该bean时都是对该对象的引用     二、spring Bean的作用域:scope=prototype(多线程, 生成多个实例)               18     每次调用都生成新的对象,引用该bean时相当于 Bean4 bean= new Bean4();