前言
文本
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-*.jar commons项目下日志处理工具包 commons-logging-api-*.jar commons项目下日志处理工具包 commons-validator-*.jar commons项目下处理验证 oro-*.jar 文本文件处理的 freemarker-*.jar freemarker模版语言相关的 struts2-core-*.jar Struts2核心包 xwork-*.jar webwork核心包,包涵非常多command ognl-*.jar Struts2表达式语言 以上这些包在搭建Struts2框架时必须导入 其它jar包:*-plugin-*.jar 以plugin结束的是其它框架与Struts2整合的插件包
2.拷贝配置文件
struts.xml struts2的配置文件 web.xml 核心控制器的配置文件 在2.1.6版本号之前使用的核心控制器 FilterDispatcher2.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 = userName2.将资源文件配置在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 Result2.配置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 RuntimeExceptionStruts2中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的线程安全方面不同
总结
版权声明:本文博客原创文章,博客,未经同意,不得转载。