博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
浅谈STRUTS2
阅读量:4325 次
发布时间:2019-06-06

本文共 26444 字,大约阅读时间需要 88 分钟。

下载struts2

官网地址: 最新版本是struts2.2,我们下载使用struts2.2. 下载地址如下:

目录详细:src: 源代码docs: api文档lib: 依赖库apps: 官方例子(尤其注意:strut2-blank)

 

struts2简介

struts2是在webwork2基础上发展而来的。和struts1一样,struts2也属于MVC框架。不过有一点需要注意的是:struts2struts2虽然名字很相似,但是在两者在代码编写风格上几乎是不一样的。那么既然有了struts1,为什么还要推出struts2。主要的原因是struts2有以下优点:

 

1在软件设计上struts2没有像struts1那样跟servlet APIstruts API有着紧密的耦合,struts2的应用可以不依赖于servlet APIstruts APIstruts2的这种设计属于无侵入式设计,而struts1却属于侵入式设计,struts2提供了拦截器,利用拦截器可以进行AOP编程,实现如权限拦截等功能。

2struts2提供了类型转换器,可以把特殊的请求参数转化成需要的类型。在struts1中,如果我们要实现同样的功能,就必须向struts1的底层实现BeanUtil注册类型转换器才行。

3struts2提供支持多种表现层技术,如:jspfreemarkervelocity等。

4truts2的输入校验可以对指定的方法进行校验,解决了struts1长久之痛。

5提供了全局范围、包范围和Action范围的国际化资源文件实现。

 

Struts2作用

将请求与结果分开

 

struts2开发环境搭建

搭建struts2(这里使用的是2.3版的)的开发环境的时,一般都会按如下的步骤:

 

1.引入struts2需要的jar文件(一般需要commons-fileupload-1.2.1.jarcommons-logging-1.0.4.jarfreemarker-2.3.15.jarognl-2.7.3.jarstruts2-core-2.1.8.1.jarxwork-core-2.1.6.jar6jar文件,可以从struts2自带的示例项目中拷贝,粘贴到WebRoot/WEB-INF/lib下面)

2.编写struts2的配置文件(可以从struts2自带的示例项目中拷贝struts.xml,粘贴到src目录下,然后在这个基础上按照自己的需要来更改)

 

/WEB-INF/pages/input.jsp
/WEB-INF/pages/details.jsp
/index.jsp

 

3.web.xml中加入struts2框架启动配置,具体的方法是在web.xml中加入如下的代码:

 

struts2
org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter
struts2
/*

 

4.建立包:并增加Action类,代码如下:

注:<action>标签中的class属性是表示action的对应的类(这个类是一个普通Java),当访问这个action时会创建这个类成为一个对象,然后执行这个对象中的execute方法()(execute方法返回类型为String)

 

第一种:Action 普通Java类public class IndexAction1 {    public String execute() {       return "success";    }}

 

<action>标签中class属性省略时,则默认执行com.opensymphony.xwork2.ActionSupport类中的execute方法,而这个方法返回一个字符串常量SUCCESS(常量值为:”success)

 

第二种:Action 实现com.opensymphony.xwork2.Action接口,这个接口中定义了一些常量和一个execute方法,我们重写execute()方法就可以了。

 

import com.opensymphony.xwork2.Action;public class IndexAction2 implements Action {    @Override    public String execute() {       //return "success";       return this.SUCCESS; //SUCCESS常量值为:"success"    }}

 

第三种:Action 继承com.opensymphony.xwork2.ActionSupport类,而这个类又实现了com.opensymphony.xwork2.Action接口,我们重写execute()方法就可以了。

 

import com.opensymphony.xwork2.ActionSupport;public class IndexAction3 extends ActionSupport {   private String msg;   public String getMsg() {        return msg;}  public void setMsg(String msg) {        this.msg = msg;    }    @Override    public String execute() {       //return "success";       return this.SUCCESS;//SUCCESS常量值为:"success"    }}

 

注:第三种Action是我们需要使用的方式,因为这个类不担实现了com.opensymphony.xwork2.Action接口,更重要的是它已经帮我封装了许多其它有用的方法。

 

注解配置

使用注解前必须保证 已经导入了 struts2-convention-plugin 的包。

 

在 Action 类上加上 @ParentPackage("struts-default") 在对应的方法上加上@Action(value = "hello", results = {           @Result(name = "success", location="/hello.jsp")})如下:@ParentPackage("struts-default")public class HelloAction extends ActionSupport {    @Action(value = "hello", results = {               @Result(name = "success", location="/hello.jsp")})    public String hello() throws Exception {        System.out.println("hello world!");        return SUCCESS;    }}

 

获取 Servlet Api

使用 ServletActionContext比如:ServletActionContext.getRequest();ServletActionContext.getResponse();

配置详解

struts2中使用包来管理action。包的作用和java中类包是非常类似的,它主要用于管理一组业务功能相关的action。在实际应用中,应该把一组业务功能相关的action放在同一个包下面。

配置包是必须指定name属性,该name可以随意取名,但是必须唯一,它不对应Java的类包,如果其他类要继承该包,必须使用该属性进行使用。包的namespace属性用于定义包的命名空间,命名空间作为该action路径的一部分,如访问上面的例子中的action的路径为:/upload/upload.actionnamespace属性可以不用配置,如果不指定该属性,默认的命名空间为“”(空字符串)。

通常每个包都必须继承struts-default包,因为struts很多核心的功能都是在这个包中定义的拦截器实现的,如:从请求中把请求参数封装到action、文件上传和数据验证等功能搜是通过拦截器实现的。struts-default包中定义了这些拦截器和result类型。换句话说,当包继承了strtus-default包才能使用struts提供的核心功能。struts-default包是在struts2-core-2.x.x.x.jar文件中的struts-default.xml中定义的。struts-default.xmlstruts2的默认配置文件,struts2每次都会自动加载struts-default.xml文件。

 

包还可以通过abstract=true”定义为抽象包,抽象包中不能包含action

注意,在配置文件struts.xml中没有提示的解决办法:window->preference->xml catalog中添加struts-2.0.dtd文件,key typeURIkeyhttp://struts.apache.org/dtds/struts-2.0.dtd

Action通配符(wildcard)的配置

使用通配符,将配置量降到最低, 不过,一定要遵守"约定优于配置"的原则

1、   通配符

星号(*)  表示所有

{

数字} 表示第几个通配符

例如:Student*  那么{1}代表第一个星号(*)

           *_*            那么{1}代表第一个星号(*) {2}代表第二个星号(*)

2、   实例

 

/Student{1}_success.jsp
/{1}_{2}_success.jsp

 

解释:

第一个Action的名称为name=Student*method={1},表示所有ActionStudent开始的都会执行这个Action,并且执行Student后字符为方法名的方法,例如:访问的ActionStudentadd,会执行这个Action(Student*),并且执行add的方法.因为{1}在这里代表add,并且返回/Studentadd_success.jsp页面。

第二个Action的名称name=*_*method={2}class=”…action.{1}Action” 表示所有Action中包含下划线(_)都会执行这个Action,例如:Teacher_add,那么会执行这个Action,并且Action对应的类为TeacherAction,且执行Action中的add方法,返回结果页面为/Teacher_add_success.jsp,因为在这里的{1}表示Teacher,{2}表示add

 

action名称的搜索顺序

1.获得请求的URI,例如uri:http://server/struts2/path1/path2/path3/test.action

 

2.首先寻找namesp/path1/path2/path3package,如果不存在这个package,就转第三步,如果存在这个package,则在这个package中寻找名字为testaction,当在该package中找不到action时就到默认namespacepackage中寻找(默认package的命名空间为空字符串“”),如果在默认的package中还找不到该action,页面提示找不到action

 

3.寻找namespace/path1/path2package,如果不存在这个package,则转第四步,如果存在这个package,则在这个package中寻找名字为testaction,当在该package中找不到action时就到默认namespacepackage中寻找(默认package的命名空间为空字符串“”),如果在默认的package中还找不到该action,页面提示找不到action

 

4.寻找namespace/path1package,如果不存在这个package,则转第五步,如果存在这个package,则在这个package中寻找名字为testaction,当在该package中找不到action时就到默认namespacepackage中寻找(默认package的命名空间为空字符串“”),如果在默认的package中还找不到该action,页面提示找不到action

 

5.寻找namespace/package,如果存在这个package,则在这个package中寻找名字为testaction,当在该package中找不到action或不存在这个package时就到默认namespacepackage中寻找(默认package的命名空间为空字符串“”),如果在默认的package中还找不到该action,页面提示找不到action

action配置中的默认值

department
/employeeAdd.jsp?username=${username}

 

1.如果没有为action指定class,默认的classActionSupport

2.如果没有为action指定method,默认执行action中的execute方法。

3.如果没有为result指定name属性,默认值为success

STRUTS2框架内部流程

1. 客户端发送请求的tomcat服务器。服务器接受,将HttpServletRequest传进来。

2. 请求经过一系列过滤器(如:ActionContextCleanUpSimeMesh)

3. FilterDispatcher被调用。FilterDispatcher调用ActionMapper来决定这个请求是否要调用某个Action

4. ActionMapper决定调用某个ActionFilterDispatcher把请求交给ActionProxy

5. ActionProxy通过Configuration Manager查看struts.xml,从而找到相应的Action

6. ActionProxy创建一个ActionInvocation对象

7. ActionInvocation对象回调Actionexecute方法

8. Action执行完毕后,ActionInvocation根据返回的字符串,找到对应的result。然后将Result内容通过HttpServletResponse返回给服务器。

StrutsPrepareAndExecuteFilterstruts2框架的核心控制器,它负责拦截由<url-pattern>/*</url-pattern>指定的所有用户请求,当用户请求到达时,该Filter会过滤用户请求。默认情况下,如果用户请求的路径不带后缀或是后缀是action,这时请求将被struts2框架处理,否则struts2将略过该请求。当请求转入struts2处理时会先经过一些列的拦截器,然后到action。与struts1不同,struts2对用户的每一个请求都会创建一个action,所以struts2是线程安全的。

 

为应用指定多个struts配置文件

 

在大部分应用里,随着应用规模的增加,系统中action的数量也会大量增加,导致struts.xml配置文件变的非常臃肿。为避免struts.xml文件过于庞大、臃肿,提高struts.xml文件的可读性,可以将一个struts.xml文件分解成过个配置文件,然后在struts.xml文件中包含其他的配置文件。下面的struts.xml文件通过include元素指定多个配置文件:

 

    
      
      
      
      
  
  

 

接收请求参数

1.采用基本类型接收参数(get/post)

action类中定义与请求参数同名的属性,并且该属性有setget方法,struts2就能自动接收请求参数并赋予同名属性。

请求路径:http://localhost:8080/struts2/product/view.action?id=1

public class ProductAction {     private int id;      public int getId() {         return id;     }     public void setId(int id) {
//通过反射技术调用与与请求参数同名的属性的setter方法来为该属性设置值 this.id=id; } } 2.采用复合类型接收参数 请求路径:http://localhost:8080/struts2/produ/view.action?produc.id=1public class ProductAction { private Product product; public Product getProduct() { return product; } public void setProduct(Product product) { this.product=product; } }

struts2首先通过反射技术调用Product的默认构造器创建product对象,然后再通过反射技术调用product中与请求参数同名的属性的setter方法来设置请求参数值。

struts2.1.6接收中文请求参数乱码的问题是个bug,原因是在获取并使用了请求参数后才调用HttpServletRequestsetCharacterEncoding()方法进行编码设置,导致应用使用的就是乱码参数。这个bugstruts2.1.8中已经被解决,如果使用的是struts2.1.6,要解决这个问题,可以采用下面的方法:

 

新建一个filter,把这个filter放在struts2filter前面,然后在doFilter()方法里添加如下的代码:

 

public void doFilter(ServletRequest request,ServletResponse response,FilterChain chain) throws java.io.IOException,ServletException {     HttpServletRequest req = (HttpServletRequest)request;      req.setCharacterEncoding("UTF-8");//根据实际使用的编码替换     chain.doFilter(request,response);  }

 

自定义类型转换器

1.定义类public class DateTypeConverter extends DefaultTypeConverter {      @Override      public Object convertValue(Map
context, Object value,Class toType) { SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd"); try { if(toType == Date.class) {
//字符串向date类型转换 String[] params = (String[])value; return sdf.parse(params[0]); } else if(toType == String.class) {
//date转换成string类型 Date date = (Date)value; return sdf.format(date); } } catch (ParseException e) { e.printStackTrace(); } return null; } }
2.将上面的类注册为局部类型转换器 在action所在的包下放置ActionClassName-conversion.properties文件,ActionClassName是action的类名,后面的-conversion.properties是固定写法,在本例中,文件名为HelloWorldAction-conversion.properties。该文件的内容为:属性名称=类型转换器的全类名就本例而言,HelloWorldAction-conversion.properties文件中的内容为:birthday=zhchljr.type.converter.DateTypeConverter
3.将上面的类注册为全局类型转换器 在WEB-INF/classes下放置xwork-conversion.properties文件。该文件中的内容为:待转换的类型=类型转换器的类全名对于本例而言,xwork-conversion.properties文件中的内容为:java.util.Date=zhchljr.type.converter.DateTypeConverter

访问或添加request/session/application属性

1.如果只是添加或访问request/session/application中的属性,就可以用ActionContext类来实现。如下代码所示:ActionContext ctx = ActionContext.getContext();  ctx.getApplication().put("app", "应用范围");//相当于往ServletContext中放入app  ctx.getSession().put("ses", "session应用范围");//相当于往session中加入ses  ctx.put("req", "request应用范围");//相当于往request中加入req   ctx.put("names", Arrays.asList("刘明","茫茫大海"));  获取HttpServletRequest/HttpSession/ServletContext/HttpServletResponse对象,可以有两种方法实现: (1)通过ServletActionContext直接获取:HttpServletRequest request = ServletActionContext.getRequest();  ServletContext context = ServletActionContext.getServletContext();  request.setAttribute("req", "请求范围属性");  request.getSession().setAttribute("ses", "会话范围属性");  context.setAttribute("app", "应用范围属性");  (2)实现指定接口,由struts2框架运行时注入:public class TestAction implements ServletRequestAware, ServletResponseAware,   ServletContextAware {     private HttpServletRequest request;     private HttpServletResponse response;     private ServletContext servletContext;          public void setServletRequest(HttpServletRequest request) {         this.request = request;     }       public void setServletResponse(HttpServletResponse response) {         this.response = response;     }      public void setServletContext(ServletContext context) {          this.servletContext = context;      }  }

文件上传

文件上传在项目中经常会用到,下面就来说说struts2中怎么上传文件的:1.引入相应的jar包(commons-fileupload-1.2.1.jar和commons-io-1.3.2.jar)2.把form的enctype设置为"multipart/form-data",如下所示:
文件1:
3.在action类中添加如下代码中注释的几个属性。public class HelloWorldAction { private File upload;//得到上传的文件 private String uploadContentType;//得到上传文件的扩展名 private String uploadFileName;//得到上传文件的名称 public File getUpload() { return upload; } public void setUpload(File upload) { this.upload = upload; } public String getUploadContentType() { return uploadContentType; } public void setUploadContentType(String uploadContentType) { this.uploadContentType = uploadContentType; } public String getUploadFileName() { return uploadFileName; } public void setUploadFileName(String uploadFileName) { this.uploadFileName = uploadFileName; } public String upload() throws IOException { String realpath = ServletActionContext.getServletContext().getRealPath("/upload"); if(upload != null) { File savefile = new File(realpath,uploadFileName); if(!savefile.getParentFile().exists()) { savefile.getParentFile().mkdirs(); } FileUtils.copyFile(upload, savefile); ActionContext.getContext().put("msg", "文件上传成功!"); } return "success"; } }

注意,如果在上传的过程中文件的大小超过了struts2默认的文件大小的话,就会上传失败,这时候,可以根据具体的情况设置struts.multipart.maxSize的值来满足上传的需求。

 

多文件上传

在实际的项目中,有时候可能会要求上传多个文件的情况,下面就来说说上传多个文件的情况。1.同上。2.form如下所示:
文件1:
文件2:
文件3:
3.action中添加的几个属性都是数组形式的。public class HelloWorldAction { private File[] upload;//得到上传的文件 private String[] uploadContentType;//得到上传文件的扩展名 private String[] uploadFileName;//得到上传文件的名称 public File[] getUpload() { return upload; } public void setUpload(File[] upload) { this.upload = upload; } public String[] getUploadContentType() { return uploadContentType; } public void setUploadContentType(String[] uploadContentType) { this.uploadContentType = uploadContentType; } public String[] getUploadFileName() { return uploadFileName; } public void setUploadFileName(String[] uploadFileName) { this.uploadFileName = uploadFileName; } public String upload() throws IOException { String realpath = ServletActionContext.getServletContext().getRealPath("/upload"); if(upload != null) { for(int i=0; i

 

自定义拦截器

自定义拦截器要实现com.opensymphony.xwork2.interceptor.Interceptor接口。下面是一个自定义拦截器的例子:public class PermissionInterceptor implements Interceptor {      public void destroy() {            }    public void init() {      }      public String intercept(ActionInvocation invocation) throws Exception {         Object user = ActionContext.getContext().getSession().get("user");          if(user != null) {              return invocation.invoke();          } else {              ActionContext.getContext().put("message", "你没有执行权限!");          }         return "success";      }  }
接下来,就要在配置文件中注册拦截器,具体的做法是:
为action指定拦截器,具体的做法是:

但是这样做了以后,就会出现一个问题,struts2中为一个action指定拦截器后,默认的defaultStack中的拦截器就不起作用了,也就是说struts2的众多核心功能都使用不了了(struts2的许多核心功能都是通过拦截器实现的),为了解决这个问题,引入拦截器栈,先使用系统默认的拦截器,然后再来使用自定义的拦截器,具体的做法是:

 

 

如果希望包下的所有action都使用自定义的拦截器,可以把拦截器设置为默认拦截器,具体的实现方式是:

 

 

注意:每个包中只能有一个默认的拦截器;一旦为包中的某个action指定了拦截器,则默认的拦截器就不起作用了。

 

输入校验

 

struts2中可以实现对action中的所有方法进行校验,也可以实现对指定的方法进行校验。可以用如下两种方式来实现输入校验。

 

1.采用手工编写代码实现:

 

<1>手工编写代码实现对action中的所有方法进行校验:通过编写validate()方法实现,validate()会校验action中所有与execute方法签名相同的方法。当某个数据校验失败时,应该采用addFieldError()方法往系统的filedErrors添加校验失败信息(为了使用该方法,action可以继承ActionSupport),如果系统的filedErrors包含失败信息,struts2会将请求发到名为inputresult,在input视图中可以通过<s:fielderror/>显示失败信息。具体的参见下面的例子:

 

用户名:
不能为空
手机号:
不能为空,并且要符合手机号的格式,1,3/5/8,后面是9个数字
页面中使用
来显示失败信息。public void validate() {//会对action中的所有方法进行校验 if(this.username == null || this.username.trim().equals("")) { this.addFieldError("username", "用户名不能为空!"); } if(this.mobile == null || this.mobile.trim().equals("")) { this.addFieldError("mobile", "手机号不能为空!"); } else { if(!Pattern.compile("^1[358]\\d{9}{1}quot;).matcher(this.mobile).matches()) { this.addFieldError("mobile", "手机号格式不正确!"); } } } <2>手工编写代码实现对action中的指定方法进行校验:通过编写validateXxx()方法实现,validateXxx()会校验action中方法名为xxx的方法。当某个数据校验失败时,应该采用addFieldError()方法往系统的filedErrors添加校验失败信息(为了使用该方法,action可以继承ActionSupport),如果系统的filedErrors包含失败信息,struts2会将请求发到名为input的result,在input视图中可以通过
显示失败信息。该校验方法示例如下:public void validateUpdate() {//会对action中的update方法进行校验 if(this.username == null || this.username.trim().equals("")) { this.addFieldError("username", "用户名不能为空!"); } if(this.mobile == null || this.mobile.trim().equals("")) { this.addFieldError("mobile", "手机号不能为空!"); } else { if(!Pattern.compile("^1[358]\\d{9}{1}quot;).matcher(this.mobile).matches()) { this.addFieldError("mobile", "手机号格式不正确!"); } } }

 

*.输入校验的流程:

 1)类型转换器对请求参数进行执行类型转换,并把转换后的值赋给action中的属性。

 2)如果在执行转换的过程中出现异常,系统会将异常信息保存到ActionContext中,conversionError拦截器将异常信息封装到fieldErrors中。不管类型转换是否异常,都会转入第3步。

 3)系统通过放射技术先调用action中的validateXxx()方法,xxx为方法名。

 4)再调用actionvalidate()方法。

 5)经过上面四步,如果系统中的fieldErrors存在错误信息(即存放错误信息的集合的size大于0),系统会将请求转发至名为input的视图。如果系统中的filedErrors中没有错误信息,系统将执行action中的处理方法。

2.基于xml配置方式来实现:

<1>基于xml配置方式实现对action中的所有方法进行校验:Action要继承ActionSupport,并且提供校验文件,校验文件和action类在同一个包下,文件的命名规则是:ActionClassName-validation.xml,其中的ActionClassNameaction的简单类名,-validation为固定写法。下面是一个校验文件(PersonAction-validation.xml)的例子:

 

true
用户名不能为空!
true
手机号不能为空!
手机格式不正确!

 

<2>基于xml配置方式实现对action中指定的方法进行校验:当校验文件名为ActionClassName-validation.xml时,会对action中的所有方法进行校验。如果要对action中的某一个方法进行校验,那么校验文件的名称为:ActionClassName-ActionName-validation.xml。其中ActionNamestruts.xml中的action的名称。配置文件如下:

 

/WEB-INF/page/message.jsp
/index.jsp

 

假设PersonAction中有save()update()两个方法。对save方法进行校验的文件名为PersonAction-manage_save-validation.xml,对update方法进行校验的文件名位PersonAction-manage_update-validation.xml

*.基于xml校验的一些特点:

 当为某个action提供了ActionClassName-validation.xmlActionClassName-ActionName-validation.xml两种规则的校验文件时,系统按下面的顺序寻找校验文件:

 1ActionClassName-validation.xml

 2ActionclassName-ActionName-validation.xml

系统搜索到第一个校验文件时,还会继续搜索后面的校验文件,当搜索到所有校验文件时,会把校验文件里的所有校验规则汇总,然后全部应用于action方法的校验。如果两个文件指定的校验规则冲突,则只使用后面文件中的校验规则。

action继承了另一个action时,父类action的校验文件会被先搜索到。还是按照上面的顺序,校验规则为四个文件的总和。

 

国际化

1.准备资源文件,资源文件的命名格式是:baseName_language_country.properties其中baseName为资源文件的基本名,可以自定义。但language和country必须是java支持的语言和国家。如: 中国大陆:baseName_zh_CN.properties 美国:baseName_en_US.properties现在为应用添加两个资源文件: 第一个存放中文:welcome_zh_CN.properties内容为:welcome=欢迎来到中国 第二个存放英文:welcome_en_US.properties内容为:welcome=welcome to china对于中文的属性文件,编写好后,应该使用jdk自带的native2ascii命令把文件转成unicode编码的文件,命令的使用方式如下:native2ascii src.properties dest.properties2.配置全局资源文件准备好资源文件后, 可以在struts.xml中通过struts.custom.i18n.resources把资源文件定义为全局资源文件,如下所示:
3.输出国际化信息1)在jsp页面中使用
标签输出国际化信息,如:
,name为资源文件中的key(2)在action类中,可以继承ActionSupport,使用getText()方法得到国际化信息,该方法的第一个参数用于指定资源文件中的key(3)在表单标签中,通过key属性指定资源文件中的key,如:
在jsp页面输出带占位符的国际化信息
liuming
study
在action类中获取带占位符的国际化信息,可以使用getText(String key,String[] args)或getText(String key,List args)在一个大型应用中,整个应用有大量的内容需要实现国际化,如果把国际化的内容都放置在全局资源文件属性中,会导致资源文件过于庞大、臃肿,不便于维护,这个时候可以针对不同模块,使用包范围来组织国际化文件。具体的做法如下:在java的包下放置package_language_country.properties资源文件,package为固定写法,处于该包及子包下的action都可以访问该资源。当查找指定key的消息时,系统会先从package资源文件中查找,当找不到对应的key时,才会从全局资源文件中找。5.action范围的资源文件可以为某个action单独指定资源文件,方法如下:在action类所在的路径,放置ActionClassName_language_country.properties资源文件,ActionClassName为action类的简单名称,当查找指定key的消息时,系统会先从ActionClassName_language_country.properties资源文件中查找,如果没有找到对应的key,然后沿着当前包向上查找基本名为package的资源文件,一直找到最顶层包。如果还没有找到指定的key,最后会从全局资源文件中查找。6.jsp中直接访问某个资源文件struts2提供了
标签,使用该标签可以在类路径下直接从某个资源文件中获取国际化数据,而无需任何配置。
如果要访问的资源在类路径的某个包下,可以这样访问:访问包zhchljr.action包下基本名为package的资源文件。
还可以访问action范围的资源文件:
liuming
study

 

OGNL表达式语言

OGNLObject Graphic Navigation Language(对象导航图语言)的缩写,它是一个开源项目。Struts2框架使用OGNL作为默认的表达式语言,相对于EL表达式,它提供了一些平时需要的功能。

1)支持对象方法调用,如xxx.save()

2)支持类静态方法调用和值访问,表达式的格式为@全类名(包括包路径)@方法名(参数),如:@java.lang.String@format('foo%s','bar')@java.util.Math@PI

3)操作集合对象

Ognl有一个上下文(Context)概念,说白了上下文就是一个Map结构,它实现了java.util.Map接口,在struts2context的实现为ActionContext,下面是它的结构示意图:

struts2接受一个请求时,会迅速创建出ActionContextValueStackaction,然后把action存放进ValueStack,所以action的实例变量可以被ognl访问。

访问上下文中的对象需要使用#标注命名空间,如#application#session等。

ognl有一个根对象(root对象),在struts2中根对象就是ValueStack,如果要访问根对象中对象的属性,则可以省略#命名空间,直接访问该对象的属性即可,struts2中,根对象ValueStack的实现为OgnlValueStack,该对象不是只存放单个值,而是存放一组对象。在OgnlValueStack中有一个List类型的root变量,就是使用它存放一组对象。

 

root变量中处于第一位的对象叫做栈顶对象。通常在OGNL表达式里面直接写上属性的名称即可访问root变量里对象的属性,搜索顺序是从栈顶对象开始,依次往下搜索,直到找到为止,需要注意的一点是,struts2ognl表达式要配合struts标签才可以使用。如:<s:property value="name"/>

 

由于ValueStackStruts2中的ognl的根对象,如果用户需要访问ValueStack中的对象,在jsp页面可以通过下面的EL表达式访问ValueStack中对象的属性。

 

${foo}//获得ValueStack中某个对象的foo属性

 

如果访问Context中的别的对象,由于它们不是根对象,所以在访问是需要添加#前缀。

 1application对象:用于访问ServletContext,例如#application.userName#application['userName'],相当于调用sessiongetAttribute("userName")

2session对象:用于访问HttpSession,例如#session.userName#session['userName'],相当于调用ServletContextgetAttribute("userName")

3request对象:用于访问HttpServletRequest对象,例如#request.userName#request['userName'],相当于调用requestgetAttribute("userName")

4parameters对象:用于访问Http的请求参数,例如#parameters.userName#parameters['userName'],相当于调用requestgetParameter("userName")

5)attr对象:用于按page->request->session->application的顺序访问其属性。

 

采用ognl表达式创建List/Map集合对象:如果需要一个集合元素的时候(例如listmap),可以使用ognl中通集合相关的表达式,使用如下代码可以直接生成一个list对象:

<s:set var="list" value="{'第一个','第二个','第三个'}"></s:set><!-- 默认放在OGNL context-->  

<!--s:iterator中有一个特点,会把当前迭代的对象放在栈顶中  -->  

<s:iterator value="#list">  

    <s:property/><br/>  

</s:iterator>  

 

set标签用于将某个值放入某个范围。

scope指定变量被放置的范围,该属性可以接受applicationsessionrequestpageaction。如果没有该属性,则默认放在OGNL context中。

value赋给变量的值,如果没有该属性,则将ValueStack栈顶的值放入赋给变量。

 

生成一个map对象:

<s:set var="maps" value="#{'key1':90,'key2':35,'key3':12}"></s:set>  

<s:iterator value="#maps">  

    <s:property value="key"/>=<s:property value="value"/><br/>  

</s:iterator>

 

采用ognl表达式判断对象是否在集合中:对于集合类型,ognl表达式可以使用innot in两个符号,其中in表示指定的元素是否在集合中,而not in表示指定的元素是否不再集合中。如下所示:

<s:if test="'foo' not in {'xxx','foo1','foo2'}">  

    不在  

</s:if>  

<s:else>  

      

</s:else>

 

OGNL表达式的投影功能:

 除了innot in外,ognl还允许使用某个规则获得集合对象的子集,常用的有以下三个操作符:

?:获得所有符合逻辑的元素

^:获得符合逻辑的第一个元素

$:获得符合逻辑的最后一个元素

 例如:

<s:iterator value="books.{?#this.price>60}">  

    <s:property value="name"/>,价格:<s:property value="price"/><br/>  

</s:iterator>

在上面的代码中,直接在集合后跟.{}运算符表明用于取出该集合的子集,{}内的表达式用于获取符合条件的元素,this表示为了从大集合books中筛选数据到小集合,需要对大集合books进行迭代,this代表当前迭代的元素。本例中用与获取集合中价格大于60的书的集合。

 

struts2中的标签

 

struts2标签库开始 可以支持EL表达式。但是从2.0.11开始,不再支持EL表达式。Struts推荐更为强大的OGNL语言。

 

常用数据标签

property 输出变量值property标签用于输出变量的值,输出OGNL表达式的结果。前面我们已经调用了多次!下面是示例代码:
set 设置变量值通过set标签,我们可以给指定的变量设值,或进行集合的初始化。
date 输出日期date标签用于格式化输出时间。类似于我们学的DateFormat类的作用。<% request.setAttribute("d",new Date(23432432L)); %>


 

什么是拦截器、拦截器栈?

Interceptor拦截器类似于我们前面学过的过滤器,是可以在action执行前后执行的代码。是我们做web开发时经常用的技术。比如:权限控制、日志等。我们也可以将多个Interceptor连在一起组成Interceptor栈。

Struts2拦截器,每个拦截器类只有一个对象实例,即采用单例模式,所有引用这个拦截器的Action都共享这一拦截器类的实例,因此,在拦截器中如果使用类变量,要注意同步问题。

•拦截器是在访问某个方法,字段之前或之后实施拦截。

•拦截器是AOP的一种实现(动态代理)

•拦截器栈(Interceptor Stack

–拦截器栈就是将拦截器按一定的顺序联结成一条链。

–在访问被拦截的方法或字段时,拦截器链中的拦截器就会按其之前定义的顺序被调用。

•实现原理

Struts2拦截器的实现原理相对简单,当请求struts2action时,Struts 2会查找配置文件,并根据其配置实例化相对应拦截器对象,然后串成一个列表,最后一个一个地调用列表中的拦截器。

 

默认拦截器说明

•alias:对于HTTP请求包含的参数设置别名。•autowiring:将某些JavaBean实例自动绑定到其他Bean对应的属性中。有点类似Spring的自动绑定,在Spring部分会详细说明。•chain:在Web项目开发中,以前使用Struts开发时候经常碰到两个Action互相传递参数或属性的情况。该拦截器就是让前一Action的参数可以在现有Action中使用。•conversionError:从ActionContext中将转化类型时候发生的错误添加到Action的值域错误中,在校验时候经常被使用到来显示类型转化错误的信息。•cookie:从Struts2.0.7版本开始,可以把cookie注入Action中可设置的名字或值中。•createSession:自动创建一个HTTP的Session,尤其是对需要HTTP的Session的拦截器特别有用。比如下面介绍的TokenInterceptor。•debugging:用来对在视图间传递的数据进行调试。•execAndWait:不显式执行Action,在视图上显示给用户的是一个正在等待的页面,但是Action其实是在“背后”正在执行着。该拦截器尤其在对进度条进行开发的时候特别有用。•exception:将异常和Action返回的result相映射。•fileUpload:支持文件上传功能的拦截器。•i18n:支持国际化的拦截器。        •logger:拥有日志功能的拦截器。•modelDriven:Action执行该拦截器时候,可以将getModel方法得到的result值放入值栈中。•scopedModelDrivenparams:将HTTP请求中包含的参数值设置到Action中。•prepare:假如Action继承了Preparabl:执行该拦截器时候,它可以从一个scope范围检索和存储model值,通过调用setModel方法去设置model值。•e接口,则会调用prepare方法。•staticParams:对于在struts.xml文件中Action中设置的参数设置到对应的Action中。•scope:在session或者application范围中设置Action的状态。•servletConfig:该拦截器提供访问包含HttpServletResquest和HttpServletResponse对象的Map的方法。•timer:输出Action的执行时间。•token:避免重复提交的校验拦截器。•tokenSession:和token拦截器类似,但它还能存储提交的数据到session里。•validation:运行在action-validation.xml(校验章节介绍)文件中定义的校验规则。•workflow:在Action中调用validate校验方法。如果Action有错误则返回到input视图。•store:执行校验功能时候,该拦截器提供存储和检索Action的所有错误和正确信息的功能。•checkbox:视图中如果有checkbox存在的情况,该拦截器自动将unchecked的checkbox当作一个参数(通常值为“false”)记录下来。这样可以用一个隐藏的表单值来记录所有未提交的checkbox,而且缺省unchecked的checkbox值是布尔类型的,如果视图中checkbox的值设置的不是布尔类型,它就会被覆盖成布尔类型的值。•profiling:通过参数来激活或不激活分析检测功能,前提是Web项目是在开发模式下。(涉及到调试和性能检验时使用)roles:进行权限配置的拦截器,如果登录用户拥有相应权限才去执行某一特定Action。

 

使用<s:token/>标签防止重复提交

使用
标签可以防止重复提交,具体的用户如下:1.在表单中加入
,例如:
姓名:
2.在action中配置token拦截器,如下所示:
/WEB-INF/page/message.jsp
/index.jsp
上面加入了token拦截器和invalid.token result,因为token拦截器在会话状态的token与请求状态的token不一致时,直接返回invalid.token result。计时拦截器timer拦截器能够统计每个action的执行时间。原理很简单:就是在执行action前纪录一个时间,执行action后纪录一个时间。两个时间纪录相减即可获得action的执行时间,timer拦截器使用方式非常简单:在action的配置中增加timer拦截器配置即可:
/ok.jsp
/testFormLabel.jsp
这样我们访问相应的action,控制台就会打印:2011-5-5 14:03:42 com.opensymphony.xwork2.util.logging.jdk.JdkLogger info信息: Executed action [//testValidate!execute] took 78 ms.注:使用默认拦截器,我们的
元素必须要有:extends="struts-default"

拦截器和过滤器的区别

1. 拦截器和过滤器的概念非常类似。

2. 过滤器隶属于web容器,可以过滤一切请求(包括actionservletjsphtml等等)

3. 而拦截器隶属于struts2框架,只能拦截action(无法拦截对jsp的请求)

4. 过滤器内部采用函数回调来实现。拦截器采用动态代理来实现!

 

开发模式的使用

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

转载于:https://www.cnblogs.com/pypua/articles/6874676.html

你可能感兴趣的文章
python的字符串内建函数
查看>>
Spring - DI
查看>>
微软自己的官网介绍 SSL 参数相关
查看>>
Composite UI Application Block (CAB) 概念和术语
查看>>
ajax跨域,携带cookie
查看>>
阶段3 2.Spring_01.Spring框架简介_03.spring概述
查看>>
阶段3 2.Spring_02.程序间耦合_1 编写jdbc的工程代码用于分析程序的耦合
查看>>
阶段3 2.Spring_01.Spring框架简介_04.spring发展历程
查看>>
阶段3 2.Spring_02.程序间耦合_3 程序的耦合和解耦的思路分析1
查看>>
阶段3 2.Spring_02.程序间耦合_5 编写工厂类和配置文件
查看>>
阶段3 2.Spring_01.Spring框架简介_05.spring的优势
查看>>
阶段3 2.Spring_02.程序间耦合_7 分析工厂模式中的问题并改造
查看>>
阶段3 2.Spring_02.程序间耦合_4 曾经代码中的问题分析
查看>>
阶段3 2.Spring_03.Spring的 IOC 和 DI_2 spring中的Ioc前期准备
查看>>
阶段3 2.Spring_03.Spring的 IOC 和 DI_4 ApplicationContext的三个实现类
查看>>
阶段3 2.Spring_02.程序间耦合_8 工厂模式解耦的升级版
查看>>
阶段3 2.Spring_03.Spring的 IOC 和 DI_6 spring中bean的细节之三种创建Bean对象的方式
查看>>
阶段3 2.Spring_04.Spring的常用注解_3 用于创建的Component注解
查看>>
阶段3 2.Spring_04.Spring的常用注解_2 常用IOC注解按照作用分类
查看>>
阶段3 2.Spring_09.JdbcTemplate的基本使用_5 JdbcTemplate在spring的ioc中使用
查看>>