Struts===

Struts2是在WebWork2基础上发展而来的,和struts1同样,struts2也属于MVC框架。不过有一点你们须要注意的是:尽管Struts2和Struts1在名字上的差异不是很大,可是Struts2和Struts1在代码风格上几乎是不同的。那么既然有Struts1,为什么还要推出Sturts2?java

  • 1>在软件设计上Struts2没有像Struts1那样个ServletApi跟SturtsApi有着紧密的耦合,Struts2的应用能够不依赖于ServletApi和StrutsApi,Struts2的这种设计属于无侵入式设计,而Struts1却属于侵入式设计。
  • public class OrderListAction extends Action
  • {
  • public ActionForward execute(ActionMapping mapping ,ActionForm form,HttpServletRequest request,HttpServletResponse response)throws Exception{
  • }
  • }
  • 2>Struts2提供了拦截器,利用拦截器能够进行AOP编程,实现如权限拦截功能
  • 3>Struts2提供了类型转换器,咱们能够把特殊的请求参数转换为须要的类型,在Struts1中,若是咱们要实现一样的功能,就必须向Struts1的底层实现BeanUtil注册类型转换器才行。
  • 4>Struts2提供支持多种表现层技术,如:JSP,freeMaiker,Velocity等等。
  • 5>Struts2的输入校验能够对指定的方法进行校验,解决了Struts1长久之痛。
  • 6>提供了全局范围,包范围和Action范围的国际化资源文件管理实现。

搭建Struts2开发环境
搭建Struts2环境时,咱们通常须要作一下几个步骤的工做web

  • 1》找到开发Struts2应用须要的jar文件
  • 2》编写Struts2的配置文件
  • 3》在web.xml中加入Sturts2 MVC 框架启动配置
  • 搭建Struts2开发环境--开发Struts2应用依赖的jar文件
  • struts1-core-2.x.x.jar:Struts2框架的核心类库
  • xwork-2.x.x.jar:xwork类库,Struts2在其构建
  • ognl-2.6.x.jar:对象图导航语言,struts2框架经过其读写对象的属性
  • freemarker-2.3.x.jar:struts2的UI标签的模板使用FreeMarker编写
  • commons-logging-1.1.x.jar:ASF出品的日志包,Struts2框架使用这个日志包支持Log4J和JDK1.4的日志记录
  • commons-fileupload-1.2.1.jar:文件上传组件,2.1.6版本后必须加入此文件

Struts2应用的配置文件
Struts2默认的配置文件为struts.xml,该文件须要存放在web-inf/classes下,该文件的配置模板以下:
Struts2在web中的启动配置
在struts1.x中,struts框架是经过Servlet启动的,在struts2中,struts框架是经过Filter启动的,他在web.xml中的配置以下
在strutsPrepareAndExecuteFilter的init()方法中将会读取类路径下默认的配置文件struts.xml,完成初始化操做。
注意,struts2读取到struts.xml的内容后,以javabean形式存放在内存中,之后struts2对用户的每次请求处理将使用内存中的数据,而不是每次都读取struts.xml文件
Struts.xml配置中的包的介绍
在struts2框架中使用包来管理Action,包的做用和java中的类包是很是类似的,它主要用于管理一组业务功能先关的action,在实际应用中,咱们应该把一组业务功能相关的action,在实际应用中,咱们应该把一组业务功能相关的Action放在同一个包下。
配置包时必须指定name属性,该name属性值能够任意取名,但必须惟一,他不对应java的类包,若是其余包要继承该包,必须经过该属性进行引用,包的namespace属性用于定义该包的命名空间,命名空间做为访问该包下Action的路径的一部分,如访问上面例子的Action,访问路径为:/test/helloworld.action。namespace属性能够不配置,对本例而言,若是不指定该属性,默认的命名空间为""。(空字符串)
一般每一个包都应该继承struts-default包,由于struts2不少核心的功能都是拦截器来实现的,如:从请求中把请求参数封装到action,文件上传和数据验证等等都是经过拦截器来实现的,能够这么说,当包继承了struts-default才能使用struts2提供的核心功能,struts-default包是在strust2-core-2.x.x.jar文件中的struts-default.xml中定义。struts-default.xml也是struts2默认配置文件。Struts2每次都会自动加载struts-default.xml文件。
包还能够经过abstract="true"定义为抽象包,抽象包中不能包含action。编程

Action名称的搜索顺序
1,得到请求路径的URI,例如url是:http://server/struts2/path1/path2/path3/test.action
2,首先寻找namespace为/path1/path2/path3的package,若是不存在这个package则执行步骤3:若是存在这个package,则在这个package中寻找名字为test的action,当该package下寻找不到action时就会直接跑到默认的namespace的package里面寻找action(默认的命名空间为空字符串),若是在默认namespace的package里面还寻找不到该action,页面提示找不到action。安全

 

<package name="itcast" namespace="/test" extends="struts-default">
<action name="helloworld" class="cn.itcast.action.HelloWorldAction" method="execute">
<result name="success">/WEB-INF/page/hello.jsp</result>
</action>
</package>
1》若是没有为action指定class,默认是ActionSupport。
2》若是没有为action指定method,默认执行action中的execute()方法。
3》若是没有指定result的name属性,默认值success。session

Action中result的各类转发类型
<action name="helleworld" class="cn.itcast.action.HelloWorldAction">
<result name="success">/WEB-INF/page/hello.jsp</result>
</action>
result配置相似于struts1中的forward,可是struts2中提供了多种结果类型,经常使用的类型有,dispatcher(默认值),redirect,plainText,redirectAction。
在result中还可使用${属性名}表达式访问action中的属性,表达式里的属性名对应action中的属性,以下
<result type="redirect">helloworld</result>
下面是redirectAction结果类型的例子,若是重定向的action中同一包下:
<result type="redirectAction">helloworld</result>
若是重定向的action在别的命名空间下:
<result type="redirectAction">
<param name="actionName">helloworld</param>
<param name="namespace">/test<param>
</result>
plaintext显示原始文本内容,例如,当咱们须要原样显示jsp文件源代码的时候,咱们可使用此类型,
<result name="source" type="plainText">
<param name="location">/xx.jsp</param>
<param name="charSet">UTF-8</param><!-- 指定读取文件的编码 -->
</result>
一个项目需求
使用重定向的技术,地址栏上面显示了用户名,经过编码的方法来显示
public String execute() throws Exception{
this.username = URLEncoder.encode("传智播客","UTF-8");
return "success";
}
in jsp write
<% URLDecoder.decode(new String(request.getParameter("username").getBytes(ISO8859-1),"UTF-8"),"UTF-8")%>
配置文件
<result name="success" type="reidirect">/employeeAdd.jsp?username=${username}</result>app

 

为Action属性注入值
为Action的属性注入值,若是要实现依赖注入,要实现setter and getter method
<action name="itcast" class="cn.itcast.action.HelloWorld">
<param name="savepath">/images</param>
</action>
经过这些信息的配置,能够实现给cn.itcast.action.HelloWorld这个类的savepath属性依赖注入值。
指定Struts2处理的请求后缀
前面咱们都是默认使用.action后缀名访问action。其实默认后缀名是能够经过常量"struts.action.extension"进行修改的,例如,咱们能够
配置Struts2只处理以.do为后缀的请求路径。
<struts>
<constant name="struts.action.extension" value="do,action,jsp"/>
</struts>
若是用户须要指定多个请求后缀,则多个后缀之间以英文逗号隔开,
细说常量定义
常量能够在struts.xml或struts.properties中配置,建议在struts.xml中配置,两种配置方式以下,在struts.xml文件中配置常量
<struts>
<constant name="struts.action.extension" value="do"/>
</struts>
在struts.properties中配置常量
struts.action.extension=do框架

由于常量能够在下面多个配置文件进行定义,因此咱们须要了解struts2加载常量的搜索顺序,
struts-default.xml
struts-plugin.xml
strus.xml
strus.properties
web.xml
若是在多个文件中配置了同一个常量,则后一个文件中配置的常量值会覆盖前面文件中配置的常量值。
常量能够在struts.xml
Struts2的处理流程与Action的管理方式
StrutsPrepareAndExecuteFilter是Struts2框架的核心控制器,他负责拦截由<url-pattern></url-pattern>指定的全部用户请求,当用户请求到达时,该Filter会过滤用户的请求,默认状况下,若是用户请求的路径不带后缀或者后缀以.action结尾,这时请求将被转入Struts2框架处理,不然Struts框架将略过该请求的处理,当请求转入Struts2框架处理时会先通过一系列的拦截器,而后再到Action,与Struts1不一样,Struts2对用户的每一次请求都会建立一个Action,因此Struts2中的Action是线程安全的。
为应用指定多个配置文件
在大部分应用里,随着应用规模的增长,系统中Action的数量也会大量增长,致使struts.xml配置文件变得很是臃肿,为了不struts.xml文件过于庞大,臃肿,提升struts.xml文件的可读性,咱们能够将一个struts.xml配置文件分解成多个配置文件,而后再struts.xml文件中包含其余配置文件。
<struts>
<include file="struts-user.xml"/>
<include file="struts-order.xml"/>
</struts>
经过这种方式,咱们就能够将struts2的Action按模块添加在多个配置文件中。jsp

如何接收请求参数
在学习中我发现一个知识要点,那就是在Action中定义一个方法,
public String test()
{
return "success";
}
在返回success的时候,也就是返回一个success页面的时候,会把这个Action的参数也给带过去。因此,假如说,这个"success"对应的是一个页面,那么这个页面可使用到该Action里面的属性。
接收请求参数
采用基本类型接收请求参数(get/post)
requestPath:http://localhost:8080/test/view.action?id=78
public class Production{post

private Integer id;
public void setId(Integer id){this.id = id;}
public Integer getId(){return this.id;}学习

}
采用复合类型接收请求参数
requestPath:http://localhost:8080/test/view.action?product.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方法来获取请求参数值。
若是使用符合类型了接收参数的话,注意必定要给一个默认的构造器,such as
public class Person{
public Person(){}
}
自定义类型转换器

 

动态方法调用
若是Action中存在多个方法时,咱们可使用!+方法名调用指定方法,以下:
public class HelloWorld{

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/hellowrold.action
若是咱们不想使用动态方法调用,咱们能够经过常量struts.enable.DynamicMethodinvocation关闭动态方法调用。
<constant name="struts.enable.DynamicMethodinvocation" value="false">

使用通配符定义action
<packge name="itcast" namespace="/test" extends="struts-default">
<action name="helloworld_*" class="cn.itcast.action.HelloWorldAction" method="{1}">
<result name="success">/WEB-INF/page/hello.jsp</result>
</action>
</package>

public class HelloworldAction extends ActionSupport{

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.actoin

Struts也能够实现AOP的编程
这个功能的实现是经过拦截器来实现的,下面是一个案例
若是用户登陆后能够访问action的全部方法,若是,用户没有登陆不容许访问action的全部方法,并显示用户没有访问权限。
1,在jsp页面中经过session来设置用户的登陆状态。
2,拦截器跟Filter很相像,自定义的拦截器要实现Interceptor接口。该接口一共有三个方法
public void init()
public void destroy()
public String intercept(ActionInvocation invocation)throws Exception()
3,注册拦截器,在struts.xml中定义一个拦截器
<interceptors>
<interceptor name="permiession"class="cn.itcast.interceptor.PermissInterceptor"/>
</inpterceptors>

<action name="list_*" class="cn.itcast.action.HelloworldAction" method="{1}">
<interceptor-ref name="permission"/>
</action>
//采用上述的方法能够得到一个拦截器的使用permiession,可是却失去了struts定义好的全部默认的拦截器。因此采用下面的方法
<interceptors><!-- 注意这个struts提供给咱们的defaultStack栈是要放在前面的 -->
<interceptor name="permiession"class="cn.itcast.interceptor.PermissInterceptor"/>
<interceptor-stack name="permiessionStack">
<interceptor-ref name="defaultStack"/>
<interceptor-ref name="permiession"/>
</interceptor-stack>

</inpterceptors>

<action name="list_*" class="cn.itcast.action.HelloworldAction" method="{1}">
<interceptor-ref name="permiessionStack"/>
</action>


//struts-default.xml定义了一个拦截器栈<interceptor name="defaultStack">,这个栈里面放置一些经常使用的拦截器,
上面我配置的拦截器只能做用于一个action,若是想做用于整个包底下的action,我能够这样定义

<interceptors>
<interceptor name="permiession"class="cn.itcast.interceptor.PermissInterceptor"/>
<interceptor-stack name="permiessionStack">
<interceptor-ref name="defaultStack"/>
<interceptor-ref name="permiession"/>
</interceptor-stack>
</inpterceptors>
<default-interceptor-ref name="permiessionStack"/>
<action name="list_*" class="cn.itcast.action.HelloworldAction" method="{1}">
</action>
//经过<default-inpterceptor-ref>来声明一个全局的拦截器做用于整个包下
//注意若是这个时候在action中再定义一个拦截器的话,那么<default-interceptor-ref>定义的拦截器将不会做用在该action中。

 

由于struts2中如文件上传,数据验证,封装验证,封装请求参数到action等功能都是系统默认的defaultStack中的拦截器实现的,因此咱们定义的拦截器须要引用系统默认的defaultStack,这样应用才可使用struts2框架提供的众多功能。
若是但愿包下的全部action都使用自定义的拦截器,能够经过<default-interceptor-ref name="permiessionStack"/>把拦截器定义为默认拦截器,注意,每一个包只能指定一个默认拦截器,另外,一旦咱们为该包中的某个action显示指定了某个拦截器,则默认拦截器不会起什么做用。

对Action中全部的方法进行输入校验
在struts2中,咱们能够实现对action的全部方法进行校验或者对action的指定方法进行校验。
对于输入校验struts2提供了两种实现方法:
1,采用手工编写代码实现
2,基于XML配置方式实现
手工编写代码实现对action中全部的方法输入校验
经过重写validate()方法实现,validate()中全部与execute方法签名相同的方法,当某个数据校验失败时,咱们应该调用addFieldError()方法往系统的fieldError添加失败信息,(为了使用addFieldError方法,action能够继承ActionSupport),若是系统的fieldError包含失败信息,struts2会将请求转发到名为input的result视图,在input视图中能够经过<s:fielderror/>显示失败信息。
validate()使用例子
public void validate(){  if(this.mobile==null||"".equals(this.mobile.trim()){this.addFieldError("username","手机号不能为空!");}

  else if(Pattern.compile("^1[358]\\d{9}").matcher(this.mobile.trim().matches()){
  this.addFieldError("mobile","手机号格式不正确!");
}
}
验证失败后,请求转发到input视图
  <result name="input">/WEB-INF/page/addUser.jsp</result>
在addUser.jsp页面中使用<s:fielderror/>显示失败信息。


项目需求,一个是用户名不能为空,另外一个是手机号的长度为符合手机号的格式,1,开始,3,5,8为第二个,后面一共有九个数字。
1,定义一个jsp页面
  用户名:<input type="text" name="username"/>
  手机号:<input type="text" name="tel"/>
  <input type="submit" value="提交"/>
2,定义一个action,
public PersonAction extends ActionSupport
{
  private String username ;
  private String mobile ;
  ...setter and getter method
  public String save()throws Exception(){return "success";}
  public Stirng add() throws Exception(){return "fail";}

}
//重写validate方法
public void validate()
{
  if(this.username==null&&"".equals(this.username.trim())){
}

}

手工编写代码实现actioin指定方法输入校验
经过重写validateXxxx()方法实现,validateXxxx()只会校验action中方法名为Xxx的方法,其中Xxx的第一个字母要大写,当某个数据校验失败时,咱们应该调用addFieldError()方法往系统中fieldError添加校验失败信息(为了使用addFieldError方法,action能够继承ActionSupport,若是系统的fieldError包含失败信息,struts2会将请求转发到名为input的result,在input视图中能够经过<s:fielderror/>显示失败信息
validateXxx()方法使用例子
public String add()throws Exception {return "success";}
public void validateAdd(){if..............this.addFieldError(''''}

 

输入校验的流程
  1,类型转换器对请求参数执行类型转换,并把转换后的值赋予action中的属性。
  2,若是在执行类型转换的过程当中出现异常,系统会将异常信息保存到ActionContext,conversionError拦截器将异常信息封装到fieldError里,无论类型转换是否出现异常,都会进入第三步。
  3,系统经过反射技术先调用acion中的validateXxx方法,Xxx为方法名。
  4,在调用action中的validate方法。
  5,通过上面四步,若是系统中的fieldError存在错误信息,(即存在错误信息的集合的size大于0),系统自动将请求转发至名称input的视图,若是系统中的fieldError没有任何错误信息,系统将执行action的处理方法。

注://这里有一个须要说明的是当我把validate或者validateXxx方法里面的代码所有清空,结果,发现系统仍是执行input方法,那么,这个时候就要注意了,多是在类型转换的时候出现了错误,这时候,要检查类型转换器。

相关文章
相关标签/搜索