前言 文本


Struts2


Apache SoftWare Foundation Tomcat/Struts1/Struts2/Ibaitas/



MVC框架:Struts1/Struts2/JSF/WebWork


Struts2是由Apache软件基金会与webWork的研发团队合作开发

www.apache.org

Struts2是一个单控制器的开源免费的框架。


框架搭建


1.新建WEBproject导入JAR包 


antlr-2.7.2.jar  语法解析器

commons-beanutils-*.jar  commons项目下用来处理Bean的工具包

commons-chain-*.jar   commons项目下用来处理流程链的



commons-collections-*.jar commons项目下全部集合处理的工具包

commons-digester-*.jar 将xml解析成 java对象



commons-fileupload-*.jar 文件上传的

commons-io-*.jar处理IO流



commons-lang-*.jar处理普通java对象的



commons-logging-*.jarcommons项目下日志处理工具包



commons-logging-api-*.jar commons项目下日志处理工具包

commons-validator-*.jar   commons项目下处理验证

oro-*.jar 文本文件处理的



freemarker-*.jarfreemarker模版语言相关的



struts2-core-*.jarStruts2核心包



xwork-*.jar webwork核心包,包涵非常多command



ognl-*.jar  Struts2表达式语言


以上这些包在搭建Struts2框架时必须导入

其它jar包:


*-plugin-*.jar 以plugin结束的是其它框架与Struts2整合的插件包


2.拷贝配置文件


struts.xml  struts2的配置文件

web.xml 核心控制器的配置文件



在2.1.6版本号之前使用的核心控制器 FilterDispatcher

2.1.6版本号之后org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter



3.測试框架搭建




实现Action


1.实现Action接口实现接口中定义的全部方法


implements Action

Action接口中定义了五个字符串常数以及一个public String execute() throws Exception;



五个常数:

SUCCESS-->"success"

NONE-->"none"

INPUT-->"input"

ERROR-->"error"

LOGIN-->"login"


2.普通类,必须含有一个无參的返回值为String类型的execute方法


public class LoginAction2 {

public String execute(){

System.out.println("LoginAction2");

return "success";

}

}


*3.通过继承ActionSupport来实现自己定义Action


public class LoginAction3 extends ActionSupport{


@Override

public String execute() throws Exception {

System.out.println("LoginAction3--execute");

return SUCCESS;

}


}


Struts.xml中对于Action的配置


package标签用来管理Action

name属性:区分package

namespace:定义的是package中Action的訪问路径

extends:配置文件通过继承的方式实现其它配置文件里定义的属性


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

Action标签用来配置相应的Action实现

name属性:配置Action的訪问路径

class属性:配置当前Action标签相应的实现类

<action name="loginAction" class="" >

Result标签用来配置Action返回的页面

name属性:匹配Action的字符串返回值定位相应的返回页面

type属性:定义页面返回到浏览器的方式

<result>/success.jsp</result>

</action>

</package>




接收前台页面參数


1.接收单个參数


public class LoginAction3 extends ActionSupport{

//定义一个參数成员变量

private String userName;

//提供getter/setter

public String getUserName() {

return userName;

}


public void setUserName(String userName) {

this.userName = userName;

}


JSP页面:


<input type="text" name="userName">

name属性的值必须和Action中成员变量的名称同样


2.通过对象接收參数


public class LoginAction2 {

private User user;

public User getUser() {

return user;

}

public void setUser(User user) {

this.user = user;

}


JSP页面:

<input type="text" name="user.userName">


3.ModelDriven接收參数


public class LoginAction implements Action,ModelDriven{

private User user = new User();

public User getUser() {

return user;

}

public void setUser(User user) {

this.user = user;

}

public Object getModel() {

return user;

}

}


JSP页面:

<input type="text" name="userName">

name属性的值必须和Action中对象的属性名同样


关于參数接收:

通常通过继承ActionSupport方式来实现Action

在接收參数方面,经常使用普通成员变量和对象类型两种

假设通过Action接收方式接收对象类型參数。必须在创建相应引用时初始化


Action中使用作用域


1.通过ActionContext来设置作用域 


ActionContext对象所表示的是当前Action对象的执行环境

//通过静态方法获得对象,ActionContext为线程单例

ActionContext context = ActionContext.getContext();

//request.setAttribute();

context.put("requestScope", "req");

//session

Map session = context.getSession();

session.put("sessionScope", "session");

//ServletContext

Map app = context.getApplication();

app.put("app", "application");


2.通过ServletActionContext对象来设置作用域


//通过ServletActionContext来获得request对象

//ServletActionContext单例

HttpServletRequest request = ServletActionContext.getRequest();

request.setAttribute("requestScope", "requestScope");

HttpSession session = request.getSession();

session.setAttribute("sess", "sessionScope");

ServletContext context = session.getServletContext();

context.setAttribute("app", "app");


3.通过实现ServletRequestAware接口来设置作用域


//设置HttpServletRequest成员变量接收接口中传递的request參数

public class TestServletRequest extends ActionSupport implements ServletRequestAware{

private HttpServletRequest request;

public void setServletRequest(HttpServletRequest request) {

this.request = request;

}


參数接收过程中的类型转换


1.自己定义类型转换


a.參数类型转换类。必须继承StrutsTypeConverter


public class DateConverter extends StrutsTypeConverter{

/**

* 将String类型的參数转换成特定对象类型

* @param Map context ActionContext 对象

* @param String[] values 參数数组

* @param Class toClass

*/

@Override

public Object convertFromString(Map context, String[] values, Class toClass) {


/**

* 将特定对象类型转换成String类型

* @param Map context ActionContext 对象

* @param Object o 目标对象

*/

@Override

public String convertToString(Map context, Object o) {


b.配置參数接收过程中的配置文件


局部转换器:针对特定Action,配置文件放置在相应Action同样文件夹下


Action类名-conversion.properties

TestParametersAction-conversion.properties

配置内容:

Action类中特定对象类型的成员变量名称 = 转换类的全限定名

birthday = com.zhongx.struts2.day2.DateConverter

全局转换器:对projectAction中全部特定类型,将配置文件存储在SRC下

xwork-conversion.properties

配置内容:

特定转换的对象类型 = 转换类的全限定名

java.util.Date = com.zhongx.struts2.day2.DateConverter


后台验证


通过继承ActionSupport重写validate方法来实现


validate方法会在运行execute方法之前先被调用进行输入參数格式校验

//通过validate方法进行校验

@Override

public void validate() {

System.out.println("validate");

String name = users.get(0).getUserName();

int age = users.get(0).getAge();

if(name==null || "".equals(name)){

//将错误提示信息设置到错误信息域中

this.addFieldError("error", "name is null");

}else if(age>200||age<0){

this.addFieldError("error", "age is error");

}else{

System.out.println("ok");

}

}


一旦错误信息域中有错误提示。那么Struts2默认会查找相应Action配置中

<result name="input"> 所相应的jsp返回

<result name="input">/error.jsp</result>

那么在错误页面:

通过struts2标签来获取错误信息:

   <s:fielderror><s:param>error</s:param></s:fielderror>


前台JS校验Struts2后台校验


有点: 校验不须要经过server,运行效率高安全



缺点: 不安全。easy被用户篡改校验必须连接server,运行效率低



建议:前台js校验和后台Struts2校验并用。



Struts2文件上传下载


文件上传:


1.前台jsp页面


<form action="" method="post" enctype="multipart/form-data">

    <input type="file" name="pic">

   </form>


   2.后台程序參照TestFileUploadAction



文件下载


參照TestFileDownAction



配置文件

<action name="fileDownAction" class="com.zhongx.struts2.day3.TestFileDownAction">

<result name="down">/list.jsp</result>

配置下载结果类型 type = stream

<result name="fileDown" type="stream">

stream类型的结果类型接收两个參数

inputName 名称的參数是Action中的输入流

<param name="inputName">downFileInput</param>

contentDisposition 參数设置文件的展示方式以及下载 时的默认文件名

<param name="contentDisposition">attachment;fileName=${file}</param>

</result>

</action>



Action中方法的动态调用


1.通过。+方法名称显示调用

调用dynaMethodAction中的相应的add方法

dynaMethodAction!add

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

2.通过配置文件设置调用的方法名称

通过method属性设置默认调用的方法

<action name="dynaMethodAction" class="com.zhongx.struts2.day4.TestDynaMethodAction" method="delete">

</action>

3.通过*通配符匹配调用方法

//method中通过动态获得调用的方法的方法名

//调用过程中dynaMethodAction_方法名称

<action name="dynaMethodAction_*" method="{1}" class="com.zhongx.struts2.day4.TestDynaMethodAction">

<result name="ok">{1}_success.jsp</result>


Struts2的国际化


Internationalization(i18n)


1.在src文件夹下新建资源文件


资源文件名_语言简写_国别简写.properties

appRes_zh_CN.properties

文件内容:

key = value  //user=\u7528\u6237\u540D

//user = userName

 

2.将资源文件配置在Struts.xml中


<constant name="struts.custom.i18n.resources" value="资源文件名"></constant>


3.获得匹配国家的语言


占位符

<s:text name="key"></s:text>

// <s:text name="user"></s:text>

 

在浏览器显示时依据浏览器的国别设置获得相应的语言显示


在书写资源文件时,假设相应国家的语言是非拉丁语系的语言,那么资源文件必须经过Unicode编码

user=\u7528\u6237\u540D

手动将资源文件转换成Unicode编码

native2ascii  命令转换

native2ascii -encoding gbk 输入文件   输出文件



Struts2的result type


<result name="" type="xxxx">

type = dispatcher 默认,从Action到前台页面的转发

  chain     从Action到Action的转发



  redirect      从Action到前台页面的重定向



  redirectAction  从Action到Action的重定向

  stream     向浏览器输出一个InputStream类型的流,一般用作文件下载



  freemarker 向浏览器输出freemarker模版



  velocity 向浏览器输出velocity模版



  xslt 向浏览器输出xml/xslt模版



  plainText 向浏览器原样输出(输出源文件)



  httpheader 控制特定HTTP协议的输出



  

自己定义的Result type类型


1.定义type实现类


public class TestResult implements Result


2.配置Result type类型


a.定义type类型而且绑定实现类


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

<result-types>

<result-type name="type名称" class="实现类的全限定名称"></result-type>

</result-types>

b.使用自己定义的type


<action name="" class="">

<result name="" type="自己定义type名称" ></result>


还能够通过继承StrutsResultSupport来实现自己定义result类型

实现doExecute方法


拦截器(Interceptor)



认识拦截器

struts-default.xml

标签

<interceptors>

<interceptor name="拦截器名称" class="拦截器的实现类"></interceptor>

</interceptors>


Action中应用拦截器

<action>

<interceptor-ref name="引入拦截器的名称"></interceptor-ref>

</action>


默认Struts.xml中

<package name="" namespace="" extends="struts-default">

默认当前包中的 Action继承struts-default中使用的拦截器

struts-default默认使用

拦截器栈 defaultStack

拦截器栈中引入18个经常使用拦截器

比方 :

i18n

fileUpload

params

workflow等

</package>


自己定义的拦截器


a.通过实现接口来实现自己定义拦截器



b.通过继承AbstractInterceptor来实现拦截器


//通过继承父类的形式来实现拦截器

public class MyInterceptor3 extends AbstractInterceptor{

@Override

public String intercept(ActionInvocation invocation) throws Exception {

String path = invocation.invoke();

return path;

}

}



配置自己定义拦截器


a.直接引用

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

<!-- 配置自己定义的拦截器以及功能实现类 -->

<interceptors>

<interceptor name="myInte1" class="com.zhongx.struts2.day5.MyInterceptor1"></interceptor>

</interceptors>

<action name="testIntercepter" class="com.zhongx.struts2.day5.TestInterceptorAction">

<!-- 使用自己定义的拦截器 -->

<interceptor-ref name="myInte1"></interceptor-ref>

<result name="ok">/success.jsp</result>

<result name="success">/index.jsp</result>

</action>

</package>

b.通过配置拦截器栈来引用




表单反复提交


问题:同一个表单携带同样的数据被提交多次


通过Struts2的拦截器   token来处理多次提交问题


<interceptors>

<interceptor-stack name="my_stack">

<interceptor-ref name="token"></interceptor-ref>

<interceptor-ref name="defaultStack"></interceptor-ref>

</interceptor-stack>

</interceptors>


在Action中使用自己定义的拦截器栈

<action name="testToken" class="com.zhongx.struts2.day4.TestTokenAction">

<interceptor-ref name="my_stack"></interceptor-ref>


<result name="ok">/success.jsp</result>

<!-- 一旦反复提交。那么token拦截器会返回invalid.token 来查找相应的返回结果-->

<result name="invalid.token">/error.jsp</result>


</action>


在JSP页面


表单中增加<s:token></s:token>标签来标识是否为同一表单

<form action="testToken">

  <s:token></s:token>

  username:<input id="name" type="text" name="userName">

  年龄:<input id="age" type="text" name="age">

  <input type="submit" value="submit">

   </form>


方法级别的拦截器


 继承MethodFilterInterceptor来实现拦截器

String doIntercept(ActionInvocation)



配置文件

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

<!--配置拦截器实现类-->

<interceptors>

<interceptor name="methods" class="com.zhongx.struts2.day6.TestMethodInterceptor"></interceptor>

</interceptors>


<action name="testMethod" class="com.zhongx.struts2.day6.TestMethodInterceptorAction">

<!--引入拦截器-->

<interceptor-ref name="methods">

<!-- 不被拦截的方法  -->

<param name="excludeMethods">login</param>

<!-- 被拦截的方法 -->

<param name="includeMethods">add,delete,execute</param>

</interceptor-ref>


<result name="exe">/success.jsp</result>

<result name="delete">/delete_success.jsp</result>

<result name="add">/add_success.jsp</result>

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

</action>

</package>



OGNL和值栈以及Struts2标签


OGNL(Object Graphic Navigation Language,对象图导航语言)

方便开发者查找对象,高速的获得对象的属性和相应的值

OGNL从值栈中获取对象方便,可以高速从复杂类型对象(树形文件夹结构非常深)中获取属性

在没有Struts2前webWork框架中已经採用了OGNL来获取属性

使用OGNL必须 导入OGNL.jar




Action对象,其它对象

(root区)


ValueStack (context,context用OGNL訪问必须加#号)

paramters 包涵HTTP请求參数的对象 

request  HTTP请求对象



session   HTTP会话对象

application  当前应用对象

attr 包涵作用域对象


OGNL訪问属性必须结合Struts2标签使用


基本标签


获取属性值

<s:property value="">

格式化日期

<s:date name="" format="">

向作用域设值

<s:set var="test" value="users[0]" scope="action"></s:set>

设置路径

<s:url value="/testAction" ></s:url>

创建对象

<s:bean name="com.zhongx.struts2.day1.User" var="uu">

设置參数

<s:param name="userName">testBean</s:param>

</s:bean>

将对象设置在root区,标签结束对象回收

<s:push value="users[0]">

<s:property value="userName"/>

<s:property value="age"/>

<s:property value="address.street"/>

</s:push>

分支控制

<s:if test="users[0].age>0">

</s:if>

<s:elseif>

</s:elseif>

<s:else>

</s:else>


迭代标签

<!-- 

?

表示选出符合条件的全部对象

^表示符合条件的第一个对象

$表示符合条件的最后一个对象

users.{$#this.age>1}

-->

<s:iterator var="u" value="users.{$#this.age>1}" status="status"><br>

<s:property value="#u.userName"/>

<!-- 循环下标 -->

<s:property value="#status.index"/>

<!-- 循环记录数 -->

<s:property value="#status.count"/>


</s:iterator>


获得值栈

<s:debug></s:debug>


UI标签


<s:head/>

<s:form>

<s:textField>

<s:password>

<s:select>

<s:radio>

<s:checkboxlist>

<s:textarea>

<s:submit>

<s:reset>


<s:form action="">

<s:textfield name="name"></s:textfield>

<s:password name="password"></s:password>

<s:select name="city" list="{'北京','上海','广州'}" ></s:select>

<s:select name="city" list="users" listKey="age" listValue="userName" ></s:select>

<s:radio name="sex" list="#{'m':'男','n':'女'}"></s:radio>

<s:checkboxlist  name="in" list="{'beij','shangh'}" ></s:checkboxlist>

<s:checkboxlist  name="in" list="users" listKey="age" listValue="userName"></s:checkboxlist>

<s:textarea cols="5px" rows="5px"></s:textarea>

<s:submit value="submit"></s:submit>

<s:reset value="reset"></s:reset>

</s:form>


Struts2中使用Json


1.从Action中传递一个Json对象到前台JS中


a.导入Json相应的依赖库

json-lib-*.jar

struts2-json-plugin-*.jar

b.通过Ajax发送请求到处理Action

action中提供一个返回对象类型的成员变量而且提供getter/setter方法

private User user;

c.配置Action

通过继承json-default来继承result type="json"

<package name="json" namespace="/" extends="json-default">

<action name="testJsonAction" class="com.zhongx.struts2.day6.TestJsonAction">

<result type="json"></result>

</action>

</package>


通过这样的方式会将对象类型的成员变量以Json形式返回给页面的回调函数


2.从前台JS传递一个Json类型的字符串到后台Action

參照testJson2.jsp


  TestJsonAction2.java




异常(Exception)


何为异常:

怎么处理异常

try{}catch(){}

当前方法中能解决的,就捕获解决

throw

当前方法解决不了,交给调用者处理


JavaEE中处理异常


throw DAO---->DaoException

ClassNotFoundException

IOException

SQLException

NetWorkAdapterException

throw Biz---->DaoException

业务异常

UserNotExistException

UserOrPasswordException



try{}catch(){}Action--->DaoException



 UserNotExistException

 UserOrPasswordException



UI   提供友好提示


异常分类


两大类

check Exception

编译时,编译器会检查程序

 ClassNotFoundException

 IOException

 SQLException

 

RuntimeException

执行过程中。检查的异常 

NullPointerException

ClassCastException

IndexOutOFboundsException


检查异常是在程序中必须处理




自己定义异常


extends Exception

採用

extends RuntimeException


Struts2中Action的异常处理


1.在Action中trycatch

try{

//调用biz处理业务

User user = userBiz.queryUserByName(name, password);

}catch(DaoException e){

依据不同异常返回不同页面

return "error";

}catch(UserNotExistException e){

this.addFieldError("message", "user not exist");

依据不同异常返回不同页面

return "input";

}catch(PasswordErrorException e){

this.addFieldError("message", "password is error");

return "input";

}


2.声明式异常处理


将全部异常配置在Struts.xml中,Action中不做不论什么处理

<action name="loginAction" class="com.zhongx.bank.action.LoginAction">

配置异常对象以及发生异常跳转的 相应页面

exception属性:配置异常的全限定名称

result:配置异常发生时相应跳转的result结果

<exception-mapping 

exception="com.zhongx.bank.exception.DaoException"

result="error"

></exception-mapping>

<exception-mapping 

exception="com.zhongx.bank.exception.UserNotExistException"

result="input"

></exception-mapping>

<exception-mapping 

exception="com.zhongx.bank.exception.PasswordErrorException"

result="input"

></exception-mapping>


<result name="success">/manager.jsp</result>

<result name="input">/login.jsp</result>

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

</action>


页面获取异常信息


从值栈中获取,异常信息存放在值栈中Action对象中

<s:property value="exception.message" s:property/>

重定向不能获取到异常信息


Filter与Interceptor 差别?


1.Filter在运行流程时,採用方法回调来实现流程调用

 Interceptor在运行流程中採用的是反射实现

2.拦截目标不同。Filter拦截全部请求,Interceptor拦截特定Action的请求

3.Filter在运行目标Action之前拦截。Interceptor在Action运行前后都拦截


自己定义Struts1


commons-digester.jar解析XML

实现XML标签到对象的转换

1.依据目标XML的结构定义解析规则文件

參照rule.xml

2.创建集合对象接收封装解析的XML

ModelConfig config = new ModelConfig();

Digester digester = DigesterLoader.

createDigester(ActionServlet.class.getClassLoader().getResource("com/zhongx/struts/rule.xml"));

//将存储集合对象传入

digester.push(config);

//解析目标 XML

digester.parse(ActionServlet.class.

getClassLoader().getResourceAsStream("mystruts.xml"));


Struts1和Struts2差别


1.核心控制器实现不同


2.Action的实现方式不同


3.參数接收方式不同


4.后台验证实现不同


5.Action中绑定值到视图的实现方式不同


6.框架支持的页面显示技术不同


7.页面运行的表达式语言不同


8.Action运行流程不同


9.Action的线程安全方面不同

 

 

 




总结











版权声明:本文博客原创文章,博客,未经同意,不得转载。