我在学校时整理的笔记,我是个新手,请谅解我写不好的地方,在后面我会改,有问题可以留言,我们共同解决,共同进步,谢谢大家!
第一次课:Struts概念、运行流程
- J2EE应用体系结构、Java框架特点
- 概念:Struts2是在WebWork2基础发展而来的,和struts1一样,Struts2也属于MVC框架。要注意的是:Struts2与Struts1在代码编写风格上几乎是不一样的
Struts2主要有以下优点:
1) 在软件设计上Struts2没有像Struts1那样跟ServletAPI和StrutsAPI有着紧密的耦合,Strut2的应用可以不依赖于ServletAPI和StrutsAPI.Struts2的这种设计属于无侵入式设计,而Struts1却属于侵入式设计。
Public class OrderListAction extends Action{
Public ActionForward execute(ActionMapping mapping,ActionForm form,HttpServletRequest request,HttpServletResponse response)throwsException{}
}
2) Struts2提供了拦截器,利用拦截器可以进行AOP编程,实现如权限拦截等功能。
3) Struts2提供了类型转换器,我们可以把特殊的请求参数转换成需要的类型。在Struts1中,如果我们要实现同样的功能,就必须向Struts1的底层实现BeanUtil注册类型转换器才行。
4) Struts2提供支持多种表现层技术,如:Jsp、freeMarker、Velocity等
5) Struts2的输入校验可以对指定方法进行校验,解决了Struts1长久之痛。
6) 提供了全局范围、包范围和Action范围的国际化资源文件管理实现
- Struts2在web中的启动配置
在struts1.x中,struts框架是通过Servlet启动的。在struts2中,struts框架是通过Filter启动的。他在web.xml中的配置如下:
1 <filter> 2 <filter-name>struts2</filter-name> 3 <filter-class> 4 org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter 5 </filter-class> 6 <!--自从Struts2.1.3以后,下面的FilterDispatcher已经标注为过时 7 <filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class> --> 8 </filter> 9 <filter-mapping> 10 <filter-name>struts2</filter-name> 11 <url-pattern>*.action</url-pattern> 12 </filter-mapping>
在StrutsPrepareAndExecuteFilter的init()方法中将会读取类路径下默认的配置文件struts.xml完成初始化操作。
注意:struts2读取到struts.xml的内容后,以javabean形式放在内存中,以后struts2对用户的每次请求处理将使用内存中的数据,而不是每次都读取struts.xml文件
- Struts.xml配置中的包介绍
1 <package name=”itcast” namespace=”/test” extends=”struts-default”> 2 <action name=”helloworld” class=”cn.itcast.action.HelloWorldAction” method=”execute”> 3 <result name=”success”>/WEB-INF/page/hello.jsp</result> 4 </action> 5 </package>
1) 在struts2框架中使用包来管理Action,包的作用和java中的类包是非常类似的,它主要用于管理一组业务功能相关的action,在实际应用中,我们应该把一组业务功能相关的Action放在同一个包下。
2) 配置包时必须指定name属性,该name属性值可以任意取名,但必须唯一,他不对应java的类包,如果其他包要继承该包,必须通过该属性进行引用,包的namespace属性用于定义该包的命名空间,命名空间作为该包下Action的路径一部分,如访问上面例子的Action,访问路径为:/test/helloworld.action. namespace可以不配置,对本例而言,如果不指定该属性,默认的命名空间为””(空字符串).
3) 通常每个包都应该继承struts-default包,因为Struts2很多核心的功能都是拦截器来实现,如:从请求中把请求参数封装到action、文件上传和数据验证等等都是通过拦截器实现的。Struts-default.xml定义了这些拦截器和Result类型。可以这么说:当包继承了struts-default才能使用struts2提供的核心功能.struts-default包是在struts2-core-2.x.x.jar文件中的struts-default.xml中定义。Struts-default.xml也是struts2默认配置文件。Strutst每次都会自动加载struts-default.xml文件
4) 包还可以通过abstract=”true”定义为抽象包,抽象包中不能包含action
- A ction名称的搜索顺序
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
3) 寻找namespace为/path1/path2的package,如果不存在这个package,则转至步骤4;如果存在这个package,则在这个package中寻找名字为test的action,当在该package中寻找不到action时就会直接跑到默认namespace的package里面去找名字为test的action,在默认namaspace的package里面还寻找不到该action.页面提示找不到action
4) 寻找namespace为/path1的package,如果不存在这个package则执行步骤5;如果存在这个package,则在这个package中寻找名字为test的action,当在该package中寻找不到acton时就会直接跑到默认namespace的package里面去找名字为test的action,在默认namespace的package里面还寻找不到action,页面提示找不到action
5) 寻找namespace为/的package,如果存在这个package,则在这个package中寻找名字为test的action,当在package中寻找不到action或者不存在这个package时,都会去默认namespace的package里面寻找 action,如果还是找不到,页面提示找不到action
- Action配置中的各项默认值
1 <package name=”itcast” namespace=”/test” extends=”struts-default”> 2 <action name=”helloworld” class=”cn.itcast.action.HelloWorldAction” method=”execute”> 3 <result name=”success”>/WEB-INF/page/hello.jsp</result> 4 </action> 5 </package>
1) 如果没有为action指定的class,默认是ActionSupport.
2) 如果没有为action指定的method,默认执行action中的execute()方法
3) 如果没有指定result的name属性,默认值为success.
- Action中result的各种转发类型
<action name=”helloworld” class=”cn.itcast.action.HelloWorldAction” method=”execute”>
<result name=”success”>/WEB-INF/page/hello.jsp</result>
</action>
Result配置类似于struts1中的forward,但struts2中提供了多种结果类型,常用的类型有:dispatcher(默认值)、redirect(重定向,外部跳转)、redirectAction、plainText..
下面是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”>/xxx.jsp</param>
<param name=”charSet”>UTF-8</param><!--指定读取文件的编码-->
</result>
- Struts2运行流程分析
1) 在项目启动之初: Struts的过滤器会运行 此过滤器有两个目的:过滤*.action的请求, 加载Struts.xml struts-default.xml 配置文件
2) 如果前台的请求扩展名是action的.则会被StrutsPrepareAndExecuteFilter 过滤.此过滤器会去Strut.xml中找到相应的Action并且实例化,Action实例化之后会和前台页面的名字自动匹配(因为所有自定义的包都继承了extends="struts-default")
3) 到达Action到底要进去到哪个方法不再取决于隐藏域.而是配置文件中的method属性
- Action与Servlet的区别:
1) Action没有以来request reponse 是一个普通的Java类
2) Action声明一个全局变量用来方便的与前台表单数据匹配
3) Action是每一个请求都会实例化,一个Servlet处理所有的请求
4) Action:缺点:耗资源,优点:数据自动获取
第二次课:Struts2的验证框架
- 服务器端验证的必要:
a) 客户端验证更多起着提示作用
b) 服务端验证是数据完整性的有利保证
- 采用ActionSupport完成服务器端验证
a) 命名规范为: validate+方法名()
b) 验证流程:Action要继承ActionSuport类 此类可以实现基于代码和XML的验证
c) 验证方法的命名为: validate+方法名() 在调用方法之前,会自动进入validate验证方法
d) 如果验证成功则调转到目标方法,失败则跳转到Input指定的页面
e) 缺点:代码验证维护性不高.代码量大.
- 采用XML配置的方式完成服务器端验证
a) 命名规范为:Aciton名称-请求的名称- validation.xml
com.opensymphony.xwork2.validator.validators 下面有Struts已经实现的验证类,和验证类的
配置文件
例如:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <!DOCTYPE validators PUBLIC "-//OpenSymphony Group//XWork Validator 1.0.2//EN" 3 "http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd"> 4 <validators> 5 <field name="goods.sgname"> 6 <!—-非空验证--> 7 <field-validator type="requiredstring"> 8 <message>查询内容不能为空!</message> 9 </field-validator> 10 <!—-长度验证--> 11 <field-validator type="stringlength"> 12 <param name="minLength">4</param> 13 <param name="maxLength">16</param> 14 <param name="trim">true</param> 15 <message>字符长度在${minLength}-${maxLength}位</message> 16 </field-validator> 17 </field> 18 19 <field name="goods.sgprice"> 20 <!—-double范围之间的验证--> 21 <field-validator type="double"> 22 <param name="minExclusive">0.00</param> 23 <param name="maxExclusive">100.00</param> 24 <message>请输入${minExclusive}-${maxExclusive}之间的价钱</message> 25 </field-validator> 26 </field> 27 28 <field name="email"> 29 <field-validator type="requiredstring"> 30 <message>邮箱为必填项</message> 31 </field-validator> 32 <!—-邮箱验证--> 33 <field-validator type="email"> 34 <message>邮箱不正确!</message> 35 </field-validator> 36 </field> 37 38 <field name="phone"> 39 <!—-正则表达验证--> 40 <field-validator type="regex"> 41 <param name="expression"><![CDATA[1[358]\d{3}]]></param> 42 <message>手机号码不正确</message> 43 </field-validator> 44 </field> 45 </validators>
说明:struts2.1包各包的说明
commons-fileupload-1.2.1.jar:文件上传组件,2.1.6版本后必须加入些文件
commons-io-1.3.2.jar:文件操作包
commons-logging-1.1.jar:ASF出品的日志包,Struts2框架使用这个日志包来支持Log4J和JDK1.4+的日志记录
freemarker-2.3.13.jar:struts2的UI标签的模板使用FreeMarker编写
ognl-2.6.11.jar:对象图导航语言(Object Graph Navigation Language),Struts2框架通过其读写对象的属性
struts2-core-2.1.6.jar:Struts2框架的核心类库
xwork-2.1.2.jar:XWork类库,Struts2在其上构建,验证类
第三次课:Struts2自定义验证框架、文件上传
- Struts关于Double验证Bug问题解决
使用新版本Struts2
2.3.4必须包:
- Struts文件上传于原理解析
a) Form如果需要上传多媒体数据,则要post提交 而且表单指定为多媒体表单
enctype="multipart/form-data"
b) 编写一个文件上传的工具类:修改文件名,验证文件格式,实现文件上传功能
1 public class FileUploadUtil { 2 3 FileUploadUtil(){} 4 5 public static String getFileExt(String fileName) 6 { 7 //返回文件名称的后辍名 8 return fileName.substring(fileName.lastIndexOf(".")+1); 9 } 10 11 public static String updateFileName(String oldName) 12 { 13 //返回随机生成的32位数值+.后辍名 14 return UUID.randomUUID().toString()+"."+getFileExt(oldName); 15 } 16 17 public static void uploadFile(String filePath,File file) throws IOException 18 { 19 InputStream inputStream=new FileInputStream(file); 20 OutputStream outputStream=new FileOutputStream(filePath); 21 byte[] bytes=new byte[1024]; 22 while(inputStream.read(bytes)>0) 23 { 24 outputStream.write(bytes); 25 } 26 inputStream.close(); 27 outputStream.close(); 28 } 29 }
c) 在Struts的Action中.可以通过ServletActionContext 来对requst response session application进行获取
1 ServletActionContext.getRequest(); 2 ServletActionContext.getServletContext(); 3 ServletActionContext.getResponse(); 4 ServletActionContext.getRequest().getSession();
d) 在Action 调用上传文件的方法
1 public String saveGoods() throws IOException 2 { 3 //文件名入库 4 goods.setSgpic(FileUploadUtil.updateFileName(goodsFile.getGoodsImageFileName())); 5 //实现文件上传功能 6 String filePath=ServletActionContext.getServletContext().getRealPath("\\")+"image\\"+goods.getSgpic();//得到文件路径(包括文件名) 7 System.out.println(filePath); 8 FileUploadUtil.uploadFile(filePath, goodsFile.getGoodsImage()); 9 return "index"; 10 }
- 采用自定义验证规则验证文件格式
a) 自定验证类, 此类要继承FieldValidatorSupport类
如:
1 public class FileFormatValidate extends FieldValidatorSupport { 2 private String type = "jpg"; 3 public void validate(Object object) throws ValidationException { 4 // TODO Auto-generated method stub 5 String fieldName = getFieldName(); 6 Object value = this.getFieldValue(fieldName, object); 7 if (value instanceof String) { 8 String ext = FileUploadUtil.getFileExt((String) value); 9 for (String temp : type.split(",")) { 10 if (temp.equalsIgnoreCase(ext)) { 11 return; 12 } 13 } 14 } 15 //验证失败,添加错误消息 16 addFieldError(fieldName, object); 17 } 18 public String getType() { 19 return type; 20 } 21 22 public void setType(String type) { 23 System.out.println("====setType===="); 24 this.type = type; 25 } 26 }
b) 然后创建一个validators.xml 把自定义的验证类配置到此文件中
1 <?xml version="1.0" encoding="UTF-8"?> 2 <!DOCTYPE validators PUBLIC 3 "-//Apache Struts//XWork Validator Definition 1.0//EN" 4 "http://struts.apache.org/dtds/xwork-validator-definition-1.0.dtd"> 5 <validators> 6 <validator name="fileFormatValidate" class="it.shopping.util.FileFormatValidate" /> 7 </validators>
c) Struts先加载validators.xml 然后在加载系统default.xml的配置文件
第四次课:Struts拦截器的应用
- 文件大小设置、上传多个文件
d) <constant name="struts.multipart.maxSize" value="2097152" />
e) Action
1 public String saveGoods() throws IOException 2 { 3 4 String basePath=ServletActionContext.getServletContext().getRealPath("/")+"image/"; 5 StringBuffer sgpic=new StringBuffer(); 6 //获取第i个文件名 7 for(int i=0;i<goodsFile.getGoodsImage().length;i++) 8 { 9 String oldName=goodsFile.getGoodsImageFileName()[i]; 10 String newName=FileUploadUtil.updateFileName(oldName); 11 FileUploadUtil.uploadFile(basePath+newName,goodsFile.getGoodsImage()[i]); 12 sgpic.append(newName).append("?"); 13 } 14 goods.setSgpic(sgpic.substring(0,sgpic.length()-1)); 15 return "index"; 16 }
f) 自定义验证类,验证文件类型
1 public void validate(Object object) throws ValidationException { 2 String fieldName=getFieldName(); 3 Object value=this.getFieldValue(fieldName,object); 4 String[] types=type.split(","); 5 if(value instanceof String[]) 6 { 7 //把文件拿出来 8 for(String temp:(String[]) value) 9 { 10 //获取后辍名 11 String ext=FileUploadUtil.getFileExt(temp); 12 //ext与types判断,只要有一个ext不符合规整,则添加错误消息 13 int i=0; 14 for(;i<types.length;i++) 15 { 16 if(ext.equalsIgnoreCase(types[i])) 17 { 18 break; 19 } 20 } 21 //正常退出 22 if(i==types.length) 23 { 24 addFieldError(fieldName, object); 25 return; 26 } 27 } 28 } 29 }
- 拦截器的概念:AOP的一种实现,同过滤器
org.apache.struts2.interceptor 里面有Struts自定义的拦截类
- 过滤器类,在web.xml中配置了
1 <filter> 2 <filter-name>struts2</filter-name> 3 <filter-class> 4 org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter 5 </filter-class> 6 </filter> 7 <filter-mapping> 8 <filter-name>struts2</filter-name> 9 <url-pattern>*.action</url-pattern> 10 </filter-mapping>
则项目启动时过滤器加载,struts-dafault.xml,struts-plugin.xml,struts.xml在过滤器加载时初始化,在StrutsPrepareAndExecuteFilter初始化方法中,strutsPrepareAndExecuteFilter类中创建了ActionContext上下文对象
- ActionContext
在Struts中通过ServletActionContext来获取request response application 从而把数据存储到内置对象中.通过源码可以看出:ServletActionContext 继承了ActionContext类
Map requestMap = new RequestMap(request);
Map params = new HashMap(request.getParameterMap());
- 自定义拦截器实现”空字符”拦截
a) 定义一个StringTrimInterceptor类,实现从请求中参数去空格,要继承AbstractInterceptor
代码如下:
1 public class StringTrimInterceptor extends AbstractInterceptor { 2 3 private static final long serialVersionUID = 1L; 4 5 @Override 6 public String intercept(ActionInvocation invocation) throws Exception { 7 ActionContext context=invocation.getInvocationContext(); 8 //从ActionContext中获取客户端所有的参数名称和值 9 Map<String,Object> params=context.getParameters(); 10 for(String key:params.keySet()) 11 { 12 Object o=params.get(key); 13 //判断是否为String数组 14 if(o instanceof String[]) 15 { 16 String[] values=(String[]) o; 17 for(int i=0;i<values.length;i++) 18 { 19 values[i]=values[i].trim(); 20 } 21 params.put(key, values); 22 } 23 } 24 //跳转到下一个拦截器 25 return invocation.invoke(); 26 } 27 }
b) 在struts.xml配置文件中配置拦截器
1 <struts> 2 <package name="shopping" extends="struts-default"> 3 <!-- 配置拦截器 --> 4 <interceptors> 5 <!-- 配置拦截器,name:名字 class:对应的拦截器类 --> 6 <interceptor name="stringTrimInterceptor" class="it.shopping.util.StringTrimInterceptor" /> 7 <!-- 创建拦截器栈 (拦截器的集合) --> 8 <interceptor-stack name="shoppingStack"> 9 <interceptor-ref name="stringTrimInterceptor" /> 10 <!—-struts内容默认的拦截器—-> 11 <interceptor-ref name="defaultStack" /> 12 </interceptor-stack> 13 </interceptors> 14 <action name="goodsAction_*" class="it.shopping.action.GoodsAction" 15 method="{1}"> 16 <result name="index" type="redirect">/index.jsp</result> 17 <result name="input">/error.jsp</result> 18 <!—-调用拦截器栈--> 19 <interceptor-ref name="shoppingStack" /> 20 </action> 21 </package> 22 </struts>