Struts2

1,Struts2介绍和开发环境的搭建

    Stuts2是在webWork2的基础发展而来的。和stuts1一样,Sttuts2也属于MVC框架。

优点:

1,在软件设计上Sttuts2没有像Stuts1那样跟ServletAPI和strutsAPI有着紧密的耦合,Struts2的应用可以不依赖与ServletAPI和strutsAPI,

Struts2的这种设计属于无入侵式设计,而struts1属于入侵式设计。

2,Struts2提供了拦截器,利用拦截器可以进行AOP编程。实现如权限拦截等功能。

3,Struts2提供了类型转换器,我们可以把特殊的请求参数转换成需要的类型。在Struts1中,如果我们要实现同样的功能,就必须向Struts1

的底层实现BeanUtil注册类型转换器才行。

4,Struts2提供支持多种表现层技术,如jsp,freeMarker,velocity等。

5,Struts2的输入校验可以对指定方法进行校验,解决了Struts1的长久之痛。

6,提供了全局范围,包范围和Action范围国际化资源文件管理实现

开发环境的搭建

 1,找到开发Struts2应用需要使用到的jar文件

      

2,编写Struts2配置文件。

       Struts2默认的配置文件为struts.xml,该文件需要存放在web-inf/classes下,开发的时候,可以放到src目录下,该文件的配置模板如下:

       

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC    "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"    "http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
	
</struts>

       3,在web.xml中加入Struts2MVC框架启动配置。

  Struts2 1.6配置启动项    
<filter>
    <filter-name>struts2</filter-name>
    <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
 <!-- 自从Struts 2.1.3以后,下面的FilterDispatcher已经标注为过时
    <filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class> --> 
</filter>
<filter-mapping>
    <filter-name>struts2</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>


在StrutsPrepareAndExecuteFilter的init()方法中将会读取类路径下默认的配置文件struts.xml完成初始化操作。

注意:struts2读取到struts.xml的内容后,以javabean存放进内存中,以后struts2对用户的每次请求处理将使用内存中的数据,而不是每次

都读取struts.xml文件。

2,第一个struts应用

<package name="itcast" namespace="/test" extends="struts-default">

  <action name="helloworld" class="cn.itcast.action.HelloWorldAction" method="execute" >//名称作为访问action路径的一部分,class是action类,请求到来后,交给这个action来处理,交给那个方法处理,交给这个方法来指定

  <result name="success">/WEB-INF/page/hello.jsp</result>//视图的名称,路径

  </action>

 </package>

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也是Struts2默认配置文件。 Struts2每次都会自动加载 struts-default.xml文件。

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

例子中使用到的cn.itcast.action.HelloWorldAction类如下

package cn.itcast.action;

public class HelloWorldAction {
	private String message;

	public String getMessage() {
		return message;
	}

	public String execute() {
		message="我的第一个struts2应用";
		return "success";// 返回视图
	}
}

struts2方法签名的格式是public String ..返回值必须是string类型.处理完用户的请求,返回视图。请求到来之后,交给action处理,执行execute方法。返回视图
struts.xml配置如下:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC    "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"    "http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
	<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> 
</struts>

 

例子中使用到的/WEB-INF/page/hello.jsp如下:

为什么要把jsp放到web-info下面?

因为只供struts action使用,不希望用户通过浏览器访问这个jsp,所以放到web-inf,放到外面,用户访问是没有意义的。因为这个jsp要从action中获取属性。必须要经过action才能得到数据。

<%@ page language="java" pageEncoding="UTF-8"%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<html>

  <head>

    <title>第一个struts2应用</title>

  </head>

  <body>

   ${message } <br>

  </body>

</html>

EL表达式访问的是getMessage,而不是message,如果属性没有提供get方法是不行的。

可以使用EL表达式访问Action中的属性

 

struts1中,通过<action path=“/test/helloworld”>节点的path属性指定访问该actionURL路径。在struts2中,情况就不是这样了,访问struts2actionURL路径由两部份组成:包的命名空间+action的名称,例如访问本例子HelloWorldActionURL路径为:/test/helloworld(注意:完整路径为:http://localhost:端口/内容路径/test/helloworld)。另外我们也可以加上.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>

3,action搜索顺序

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

2.首先寻找namespace/path1/path2/path3package,如果不存在这个package则执行步骤3;如果存在这个package,则在这个package中寻找名字为testaction,当在该package下寻找不到action时就会直接跑到默认namaspacepackage里面去寻找action(默认的命名空间为空字符串“” ) ,如果在默认namaspacepackage里面还寻找不到该action,页面提示找不到action

3.寻找namespace/path1/path2package,如果不存在这个package,则转至步骤4;如果存在这个package,则在这个package中寻找名字为testaction,当在该package中寻找不到action时就会直接跑到默认namaspacepackage里面去找名字为testaction,在默认namaspacepackage里面还寻找不到该action,页面提示找不到action

4.寻找namespace/path1package,如果不存在这个package则执行步骤5;如果存在这个package,则在这个package中寻找名字为testaction,当在该package中寻找不到action时就会直接跑到默认namaspacepackage里面去找名字为testaction,在默认namaspacepackage里面还寻找不到该action,页面提示找不到action

5.寻找namespace/package,如果存在这个package,则在这个package中寻找名字为testaction,当在package中寻找不到action或者不存在这个package时,都会去默认namaspacepackage里面寻找action,如果还是找不到,页面提示找不到action

3,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>如果没有指定resultname属性,默认值为success

4,Action中result的各种转发类型

 dispatcher(默认值) 内部请求转发定向到某一个jsp <result name="success">/WEB-INF/page/hello.jsp</result>

 redirect 重定向某个视图 如果采用浏览器重定向的方式定位到某一个jsp,那么这个jsp他不能够放到web-info目录下,所谓浏览器重定向就是引导用户的浏览器访问某一个路径,而用户不能访问web-inf下的jsp

<action name="redirect">
     <result type="redirect">/employeeAdd.jsp</result>
  </action>

地址栏发生变化

传递参数

<action name="list" class="cn.itcast.action.HelloWorldAction"
			method="execute">
			<result name="success" type="redirect">
				/employeeAdd.jsp?username=${username}
			</result>
		</action>
		<action name="redirect">
			<result type="redirect">/employeeAdd.jsp</result>
		</action>


如果传递的是中文出现乱码,怎么解决呢?

public String execute() throws Exception {
		this.username=URLEncoder.encode("州州", "UTF-8");  //用户传递过来的值,测试固定了
		message="我的第一个struts2应用";
		return "success";// 返回视图
	}


这时候,打印还是会出现乱码。传递过去的输入中文的编码,tomcat接受到中文之后,以iso8859-1存放。必须先得到iso-8859-1的字节数组,变成字符串

 <body>
  ${param.username}
  <%=URLDecoder.decode(new String(request.getParameter("username").getBytes("ISO8859-1"),"UTF-8"),"UTF-8")  %><%-- 这里是经过url编码的,所以要解码--%>
   <form action="/xxx">
   姓名:<input type="text" name="xxx"/>
   </form>
  </body>


redirectAction重定向某一个action

<action name="redirectAction">
    <result type="redirectAction">list</result>
  </action>

如果不在同一个包里面,该怎么做呢?

<action name="redirectAction">
			<result type="redirectAction">
			   <param name="actionName">xxx</param>
			   <param name="namespace">/test/department</param>
			</result>
		</action>

 

<package name="other" namespace="/test/department" extends="struts-default">
	   <action name="xxx">
	       <result>/WEB-INF/page/hello.jsp</result>
	   </action>
	</package>

plainText原样显示出视图的代码 像技术网站,可以浏览源代码

输出源代码把整个视图源代码显示到浏览器中,没有执行

<action name="plainText">
    <result type="plainText">/index.jsp</result>
  
  </action>

如果jsp含有中文的情况下会乱码什么原因呢?

是因为文件是utf-8,struts默认读取会以gbk读取,所以有乱码

必须要指定要以utf-8的编码方式读取文件

<action name="plainText">
    <result type="plainText">
   <param name="location">/index.jsp</param>
      <param name="charSet">UTF-8</param><!-- 指定读取文件的编码 -->

    </result>
   
  </action>

当多个action中都使用到了相同视图,这时我们应该把result定义为全局视图。struts1中提供了全局forward,struts2中也提供了相似功能:

<package ....>

  <global-results>

  <result name="message">/message.jsp</result>

  </global-results>

</package>

<?xml version1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC    "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"    "http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
	<package name="itcast" namespace="/test" extends="struts-default">
	<global-results>
	<result name="message">/WEB-INF/page/message.jsp</result>
	</global-results>
	<action name="manage" class="cn.itcast.action.HelloWorldAction"
			method="add">
			
		</action>
		<action name="list" class="cn.itcast.action.HelloWorldAction"
			method="execute">
			<result name="success" type="redirect">
				/employeeAdd.jsp?username=${username}
			</result>
		</action>
		
		<action name="redirect">
			<result type="redirect">/employeeAdd.jsp</result>
		</action>
		<action name="redirectAction">
			<result type="redirectAction">
				<param name="actionName">xxx</param>
				<param name="namespace">/test/department</param>
			</result>
		</action>
		<action name="plainText">
		  <result type="plainText">
		 <param name="location">/index.jsp</param>
	     <param name="charSet">UTF-8</param><!-- 指定读取文件的编码 -->

		  </result>
		  
		</action>
	</package>
	<package name="other" namespace="/test/department" extends="struts-default">
		<action name="xxx">
			<result>/WEB-INF/page/hello.jsp</result>
		</action>
	</package>

</struts>

public String add(){
   return "message";
 }

 

而目前的全局视图在这个包中的。也就是说只有在包中,需要所有包中的action都可以使用呢?

<package name="base" extends="struts-default">
		<global-results>
			<result name="message">/WEB-INF/page/message.jsp
			</result>
		</global-results>
	</package>

 

<package name="itcast" namespace="/test" extends="base">
		<action name="manage" class="cn.itcast.action.HelloWorldAction"
			method="add">

		</action>

5,指定需要Struts 2处理的请求后缀 

前面我们都是默认使用.action后缀访问Action。其实默认后缀是可以通过常量struts.action.extension进行修改的,例如:我们可以配置Struts 2只处理以.do为后缀的请求路径:

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE struts PUBLIC

    "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"

    "http://struts.apache.org/dtds/struts-2.0.dtd">

<struts>

    <constant name="struts.action.extension" value="do"/>

</struts>

如果用户需要指定多个请求后缀,则多个后缀之间以英文逗号(,)隔开。如:

 <constant name="struts.action.extension" value="do,go"/>

 6,细说常量定义

常量可以在struts.xmlstruts.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

struts.xml

struts.properties

web.xml  --------   init-param

如果在多个文件中配置了同一个常量则后一个文件中配置的常量值会覆盖前面文件中配置的常量值.

 

7,常用的常量介绍

<!-- 指定默认编码集,作用于HttpServletRequestsetCharacterEncoding方法 和freemarker 、velocity的输出 -->

    <constant name="struts.i18n.encoding" value="UTF-8"/>

    <!-- 该属性指定需要Struts 2处理的请求后缀,该属性的默认值是action,即所有匹配*.action的请求都由Struts2处理。

    如果用户需要指定多个请求后缀,则多个后缀之间以英文逗号(,)隔开。-->

    <constant name="struts.action.extension" value="do"/>

    <!-- 设置浏览器是否缓存静态内容,默认值为true(生产环境下使用),开发阶段最好关闭-->

    <constant name="struts.serve.static.browserCache" value="false"/>

    <!-- struts的配置文件修改后,系统是否自动重新加载该文件,默认值为false(生产环境下使用),开发阶段最好打开-->

    <constant name="struts.configuration.xml.reload" value="true"/>

    <!-- 开发模式下使用,这样可以打印出更详细的错误信息-->

    <constant name="struts.devMode" value="true" />

     <!-- 默认的视图主题-->

    <constant name="struts.ui.theme" value="simple" />

    <!– spring集成时,指定由spring负责action对象的创建-->

    <constant name="struts.objectFactory" value="spring" />

 <!–该属性设置Struts 2是否支持动态方法调用,该属性的默认值是true。如果需要关闭动态方法调用,则可设置该属性为false-->

<constant name="struts.enable.DynamicMethodInvocation" value="false"/>

 <!--上传文件的大小限制-->

<constant name="struts.multipart.maxSize" value=“10701096"/>

8,Struts2的处理流程

Struts2的处理流程

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

 

9,为应用指定多个struts配置文

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

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE struts PUBLIC

    "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"

    "http://struts.apache.org/dtds/struts-2.0.dtd">

<struts>

  <include file="struts-user.xml"/>

  <include file="struts-order.xml"/>

</struts>

10,动态方法调用

通过这种方式,我们就可以将Struts 2Action按模块添加在多个配置文件中

动态方法调用如果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";

  }

}

假设访问上面actionURL路径为: /struts/test/helloworld.action

要访问actionother()方法,我们可以这样调用:

/struts/test/helloworld!other.action

如果不想使用动态方法调用,我们可以通过常量struts.enable.DynamicMethodInvocation关闭动态方法调用。

<constant name="struts.enable.DynamicMethodInvocation" value="false"/>

使用通配符定义action<package name="itcast" namespace="/test" extends="struts-default">

 

11,使用通配符定义action 

 <action name="helloworld_*_*" class="cn.itcast.action.HelloWorldAction" method="{1}

          >

  <result name="success">/WEB-INF/page/{2}.jsp</result>

  </action>

</package>

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

 

12,接受请求参数

 

采用基本类型接收请求参数(get/post)

Action类中定义与请求参数同名的属性,struts2便能自动接收请求参数并赋予给同名属性。

请求路径: http://localhost:8080/test/view.action?id=78

public class ProductAction {

      private Integer id;

      public void setId(Integer id) {//struts2通过反射技术调用与请求参数同名的属性的setter方法来获取请求参数值

             this.id = id;

      }

      public Integer getId() {return id;}

  }

首页form提交

 <form action="<%=request.getContextPath()%>/test/list_execute_message" method="post">
               编号:<input type="text" name="id"/><br />
                 姓名:<input type="text" name="name"/><br/>
               <input type="submit" value="提交"/>

采用复合类型接收请求参数

请求路径: 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方法来获取请求参数值

首页form提交

 <form action="<%=request.getContextPath()%>/test/list_execute_message" method="post">
               编号:<input type="text" name="person.id"/><br />
                 姓名:<input type="text" name="person.name"/><br/>
               <input type="submit" value="提交"/>
     </form>

action中

private Person person;
    public Person getPerson() {
		return person;
	}
	public void setPerson(Person person) {
		this.person = person;
	}


视图中

 ${person.id}<br />
 ${person.name }<br />


当Struts2的拦截器接受到了请求参数之后,根据参数名称,访问对应的属性
如果对象为空,会调用这个对象的默认构造器方法。

如果没有默认构造器,会抱错。

关于struts2.1.6接收中文请求参数乱码问题

struts2.1.6版本中存在一个Bug,即接收到的中文请求参数为乱码(post方式提交),原因是struts2.1.6在获取并使用了请求参数后才调用HttpServletRequestsetCharacterEncoding()方法进行编码设置 ,导致应用使用的就是乱码请求参数。这个bugstruts2.1.8中已经被解决,如果你使用的是struts2.1.6,要解决这个问题,你可以这样做:新建一个Filter,把这个Filter放置在Struts2Filter之前,然后在doFilter()方法里添加以下代码

public void doFilter(...){

  HttpServletRequestreq = (HttpServletRequest) request;

  req.setCharacterEncoding("UTF-8");//应根据你使用的编码替换UTF-8

  filterchain.doFilter(request, response);

}

13自定义类型转换器

java.util.Date类型的属性可以接收格式为2009-07-20的请求参数值。但如果我们需要接收格式为20091221的请求参数,我们必须定义类型转换器,否则struts2无法自动完成类型转换。

import java.util.Date;

public class HelloWorldAction {

  private Date createtime;

  public Date getCreatetime() {

  return createtime;

  }

  public void setCreatetime(Date createtime) {

  this.createtime = createtime;

  }

}

Struts2里面有个拦截器,一旦检测出类型转换出错。通过el表达式获取这个值的时候,在栈里面取得原始的。

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

public class DateConverter extends DefaultTypeConverter {

                @Override  public Object convertValue(Map context, Object value, Class toType) {

  SimpleDateFormatdateFormat = new SimpleDateFormat("yyyyMMdd");

  try {

  if(toType == Date.class){//当字符串向Date类型转换时

  String[] params = (String[]) value;// Request.getParameterValues()

  return dateFormat.parse(params[0]);

  }else if(toType == String.class){//Date转换成字符串时

  Date date = (Date) value;

  return dateFormat.format(date);

  }

  } catch (ParseException e) {}

  return null;

  }

}

将上面的类型转换器注册为局部类型转换器

Action类所在的包下放置ActionClassName-conversion.properties文件,ActionClassNameAction的类名,后面的-conversion.properties是固定写法,对于本例而言,文件的名称应为HelloWorldAction-conversion.properties。在properties文件中的内容为:

属性名称=类型转换器的全类名

对于本例而言,HelloWorldAction-conversion.properties文件中的内容为:

createtime= cn.itcast.conversion.DateConverter

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值