首页 > 代码库 > struts2简介

struts2简介

前言


正文


Struts2


Apache SoftWare Foundation 开发Tomcat/Struts1/Struts2/Ibaitas/


MVC框架:Struts1/Struts2/JSF/WebWork


Struts2是由Apache软件基金会与webWork的研发团队合作开发
www.apache.org
Struts2是一个单控制器的开源免费的框架。

框架搭建


1.新建WEB工程导入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
全局转换器:对工程Action中所有特定类型,将配置文件存储在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后台校验


有点: 校验不需要经过服务器,执行效率高安全
缺点: 不安全,容易被用户篡改校验必须连接服务器,执行效率低
建议:前台js校验和后台Struts2校验并用。


Struts2文件上传下载


文件上传:


1.前台jsp页面


<form action="" method="post" enctype="multipart/form-data">
    <input type="file" name="pic">

   </form>


   2.后台程序参照TestFileUploadAction

<script src="https://code.csdn.net/snippets/418623.js" type="text/javascript"></script>


文件下载


参照TestFileDownAction

<script src="https://code.csdn.net/snippets/418630.js" type="text/javascript"></script>


配置文件
<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=http://www.mamicode.com/"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=http://www.mamicode.com/"资源文件名称">

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.通过实现接口来实现自定义拦截器


<script src="https://code.csdn.net/snippets/418646.js" type="text/javascript"></script>

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.通过配置拦截器栈来引用
<script src="https://code.csdn.net/snippets/418649.js" type="text/javascript"></script>



表单重复提交


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

通过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>
  用户名:<input id="name" type="text" name="userName">
  年龄:<input id="age" type="text" name="age">
  <input type="submit" value=http://www.mamicode.com/"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=http://www.mamicode.com/"">
格式化日期
<s:date name="" format="">
向作用域设值
<s:set var="test" value=http://www.mamicode.com/"users[0]" scope="action">
设置路径
<s:url value=http://www.mamicode.com/"/testAction" >
创建对象
<s:bean name="com.zhongx.struts2.day1.User" var="uu">
设置参数
<s:param name="userName">testBean</s:param>
</s:bean>
将对象设置在root区,标签结束对象回收
<s:push value=http://www.mamicode.com/"users[0]">
<s:property value=http://www.mamicode.com/"userName"/>
<s:property value=http://www.mamicode.com/"age"/>
<s:property value=http://www.mamicode.com/"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=http://www.mamicode.com/"users.{$#this.age>1}" status="status">

<s:property value=http://www.mamicode.com/"#u.userName"/>
<!-- 循环下标 -->
<s:property value=http://www.mamicode.com/"#status.index"/>
<!-- 循环记录数 -->
<s:property value=http://www.mamicode.com/"#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=http://www.mamicode.com/"userName" >
<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=http://www.mamicode.com/"userName">
<s:textarea cols="5px" rows="5px"></s:textarea>
<s:submit value=http://www.mamicode.com/"submit">
<s:reset value=http://www.mamicode.com/"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

<script src="https://code.csdn.net/snippets/418660.js" type="text/javascript"></script>

  TestJsonAction2.java

<script src="https://code.csdn.net/snippets/418657.js" type="text/javascript"></script>



异常(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=http://www.mamicode.com/"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的线程安全方面不同

 
 
 



总结