struts2框架
struts2是一种基于MVC模式的框架,是在struts1的基础上融合了xwork的功能。
struts2框架预处理了一些功能:
>请求数据自动封装,
>文件上传的功能
>对国际化功能的简化
>数据校验功能
使用struts2框架开发的流程:
1.引入jar文件
>commons-fileupload-1.2.2.jar 【文件上传相关包】
>commons-io-2.0.1.jar
>struts2-core-2.3.4.1.jar 【struts2核心功能包】
>xwork-core-2.3.4.1.jar 【Xwork核心包】
>ognl-3.0.5.jar 【Ognl表达式功能支持表】
>commons-lang3-3.1.jar 【struts对java.lang包的扩展】
>freemarker-2.3.19.jar 【struts的标签模板库jar文件】
>javassist-3.11.0.GA.jar 【struts对字节码的处理相关jar】
2.配置web.xml
Tomcat启动时,会加载所有项目的web.xml,通过web.xml中引入过滤器,而struts的核心功能
的初始化,是通过过滤器完成的
<!--引入核心过滤器-->
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
StrutsPrepareAndExecuteFilter就是核心过滤器,位于struts2的核心功能包中,使用struts版本不同,核心过滤器类是不一样的
3.配置struts.xml
struts2的执行流程
1.服务器启动
>加载web.xml
>创建struts核心过滤器对象,执行filter-->init()
·struts-default.xml, 核心功能的初始化
·struts-plugin.xml, struts相关插件
·struts.xml 用户编写的配置文件
2.用户访问
>用户访问action,服务器根据路径名称,找对应的action配置,创建action对象
>执行默认拦截器栈中定义的18个拦截器
>执行action的业务处理方法
struts-default.xml详解
1.位于struts2-core-2.3.jar包中,
2.bean节点指定了struts在运行时候创建的对象类型
3.指定struts-default包,用户写的struts.xml文件中package一定要继承此包,struts-default包定义了:
>跳转的结果类型:dispatcher,redirect,redirectAction,stream
>定义了所有拦截器,一共32个拦截器,为了拦截器引用方便,可以通过定义栈的方式引用拦截器,默认的栈中包含了初始化18个拦截器
>默认执行的拦截器栈、默认执行的action
拦截器和过滤器比较:
相似:功能相似
区别: 过滤器,拦截器所有资源都可以; (/index.jsp/servlet/img/css/js)
拦截器,只拦截action请求。
拦截器是struts的概念,只能在struts中用。
过滤器是servlet的概念,可以在struts项目、servlet项目用
注意:拦截器什么时候执行,先执行Action类创建,还是先执行拦截器
答:拦截器在访问时执行,先创建Action类对象,再按顺序执行18个拦截器,最后执行Action类的业务处理方法
Action开发
Action开发有三种方式:
1.继承ActionSupport类,如果用struts的数据校验功能,必须继承此类
2.实现Action接口,重写execute方法
3.不继承任何类,不实现任何接口
struts中路径匹配原则:
localhost:访问到哪一台机器
8080:找到Tomcat
mystruts:找到项目名
/user/a/b:查找是否有此名称空间,没有则向下
/user/a:查找是否有此名称空间,没有则向下
/user:查找是否有此名称空间,没有则向下
/:查找是否有此名称空间,没有则报错
例如:<action name="login" class="..." method="..."></action>,项目名称后面可以有/a/b这些无用的分层,只要最后为login以及名称空间正确照样能访问
struts中的常量
>struts中的常量定义了默认访问后缀等配置,文件名为default.propertities
>位于struts核心包中
>能够在struts.xml中通过<constant name="key" value="value"></coonstant>修改默认常量配置
struts中对数据操作(三种方式)
1.直接拿到servletAPI,进行操作,核心类:ServletActionContext提供的静态方法
HttpServletRequest request = ServletActionContext.getRequest();
HttpSession session = request.getSession();
ServletContext application = ServletActionContext.getServletContext();
2.通过ActionContext类获取(代表request,session,application)map
1 ActionContext ac = ActionContext.getContext(); 2 //struts对HttpServletRequest进行了封装,封装成一个map 3 4 //拿到表示request对象的map 5 Map<String, Object> request = ac.getContextMap(); 6 7 //拿到session对象的map 8 Map<String, Object> session = ac.getSession(); 9 10 //拿到表示ServletContext对象的map 11 Map<String, Object> application = ac.getApplication();
3.实现接口的方式:(requestAware/sessionAware/applicationAware)
1 public class DataAction2 extends ActionSupport implements RequestAware, 2 SessionAware, ApplicationAware { 3 Map<String, Object> request; 4 Map<String, Object> session; 5 Map<String, Object> application; 6 7 // struts运行时,会把代表request的map对象注入 8 @Override 9 public void setRequest(Map<String, Object> request) { 10 this.request = request; 11 } 12 13 // struts运行时,会把代表session的map对象注入 14 @Override 15 public void setSession(Map<String, Object> session) { 16 this.session = session; 17 } 18 19 // struts运行时,会把代表application的map对象注入 20 @Override 21 public void setApplication(Map<String, Object> application) { 22 this.application = application; 23 } 24 25 @Override 26 public String execute() throws Exception { 27 request.put("request_data", "request_actionAware"); 28 session.put("session_data", "session_actionAware"); 29 application.put("application_data", "application_actionAware"); 30 31 return SUCCESS; 32 } 33 }
区别:第二种方式由于不用引进servlet包,是解耦的方式实现对数据的操作,所以推荐使用第二种方式
但是,第二种方式每个事务方法都要获取ActionContext,因为ActionContext可以获取struts的数据或者对象,而这一过程
是通过拦截器完成的,而拦截器在创建Action对象之后运行,所以无法把ActionContext对象在全局变量中获取,第二种和第三种
方式原理一样,不过第三种方式通过接口则解决了第二种方式的不足,但实现起来较麻烦,业务方法比较多的时候应该优先考虑。
第一种方式可以在二三种方式无法实现需求是使用比如获取request.getContextPath()等。
struts2中请求数据自动封装(两种方式)
实现原理:参数拦截器,用户访问时,创建了Action对象,因此拦截器能够拿到action对象和属性
<interceptor name="params" class="com.opensymphony.xwork2.interceptor.ParametersInterceptor"/>
1.jsp表单数据填充到action中的属性,需要给出属性的set方法
2.jsp表单数据填充到action的对象中的属性:一定要给出对象的set和get方法
1 // 第一种方式 2 /* 3 * private String username;// 请求数据封装,必须给出set方法 4 * private String password; 5 * private int age; 6 * private Date birth; 7 * 8 * public void setUsername(String username) { this.username = username; } 9 * 10 * public void setPassword(String password) { this.password = password; } 11 * 12 * public void setAge(int age) { this.age = age; } 13 * 14 * public void setBirth(Date birth) { this.birth = birth; } 15 */ 16 17 // 第二种方式 18 private User user; 19 20 public void setUser(User user) { 21 this.user = user; 22 } 23 24 // 处理注册请求 25 public String regist() { 26 System.out.println("username:" + user.getUsername() + ",password:" 27 + user.getPassword() + ",age:" + user.getAge() + ",birth:" 28 + user.getBirth()); 29 return SUCCESS; 30 }
数据类型转换
struts中jsp提交的数据,会自动转换为action中的属性的类型
对于基本类型以及日期类型会自动转换,日期类型只支持yyyy-MM-dd格式
如果是其他格式,需要自定义类型转换器
自定义类型转换器:
struts中转换器API
|--TypeConverter 转换器接口
|--DefaultTypeConverter 默认类型转换器(yyyy-MM-dd就是在这里定义的)
|--StrutsTypeConverter 用户编写的类型转换器,继承此类即可
局部转换器开发步骤:
1.写转换器类,重写父类的抽象方法
2.配置转换器类(告诉struts使用自定义的转换器类)
-->在同包的action目录下,新建一个properties文件
-->命名规则:ActionClassName-conversion.properties
举例:cn.electhuang.d_type/UserAction-conversion.properties
-->配置文件内容:user.birth=转换器类全路径(cn.electhuang.d_type.MyConverter)
总结:转换器(转换器类和配置文件)不能给其他Action用
全局类型转换器
需要写一个转换器给所有的action用
配置:
-->在src目录下,新建一个properties文件
-->命名规则:xwork-conversion.properties
-->内容:类型全名=转换器类(java.util.Date=cn.electhuang.d_type.MyConverter)
转换器类代码示例:
1 public class MyConverter extends StrutsTypeConverter { 2 // 要求支持三种Date格式 3 // 先定义格式 4 DateFormat[] df = { new SimpleDateFormat("yyyy-MM-dd"), 5 new SimpleDateFormat("yyyyMMdd"), 6 new SimpleDateFormat("yyyy年MM月dd日") }; 7 8 /** 9 * 把String转换为指定类型 10 * 11 * @param context 12 * 当前上下文环境 13 * @param values 14 * jsp提交的字符串值 15 * @param toClass 16 * 要转换的目标类型 17 * @return the converted object 18 */ 19 @Override 20 public Object convertFromString(Map context, String[] values, Class toClass) { 21 22 if (values == null || values.length == 0) { 23 return null; 24 } 25 System.out.println("1111"); 26 if (Date.class != toClass) { 27 return null; 28 } 29 System.out.println("2222"); 30 for (int i = 0; i < df.length; i++) { 31 try { 32 return df[i].parse(values[0]); 33 } catch (ParseException e) { 34 continue; 35 } 36 } 37 System.out.println("3333"); 38 return null; 39 } 40 41 @Override 42 public String convertToString(Map context, Object o) { 43 return null; 44 } 45 46 }
struts文件上传
1.回顾采用servlet文件上传
前台:
-->提交方式必须为POST
-->表单类型:multipart/form-data
-->input type="file"
后台:
-->Apache提供的FileUpload组件
-->核心类:
①FileItemFactory FileItem的工厂
②ServletFileUpload servlet中文件上传的核心类
③FileItem 封装了上传的表单文件项的信息
总结:文件上传使用比较多,但处理比较麻烦!
2.struts的文件上传
文件上传拦截器帮助完成文件上传的功能
<interceptor name="fileUpload" class="org.apache.struts2.interceptor.FileUploadInterceptor"/>
代码示例:
1 public class FileUpload extends ActionSupport { 2 private File file1;// 对应表单的name 3 private String File1FileName;// 文件名 4 private String file1ContentType;// 文件类型 5 6 public void setFile1(File file1) { 7 this.file1 = file1; 8 } 9 10 public void setFile1FileName(String file1FileName) { 11 File1FileName = file1FileName; 12 } 13 14 public void setFile1ContentType(String file1ContentType) { 15 this.file1ContentType = file1ContentType; 16 } 17 18 @Override 19 public String execute() throws Exception { 20 // 拿到上传文件进行处理 21 // 把文件上传到upload目录 22 // 获取上传的目录路径 23 String path = ServletActionContext.getServletContext().getRealPath( 24 "/upload"); 25 26 // 创建目标文件对象 27 File destFile = new File(path, File1FileName); 28 29 // 把上传的文件拷贝到目标文件对象中 30 FileUtils.copyFile(file1, destFile); 31 32 return SUCCESS; 33 } 34 35 }
重要:文件上传细节处理
-->文件大小限制:struts2默认支持上传最大是2M,可通过常量修改
当文件上传出现错误时,struts内部会返回input视图(错误视图),所以需要在struts.xml中配置input视图对应的错误页面
<!-- 4. 修改上传文件的最大大小为30M -->
<constant name="struts.multipart.maxSize" value="31457280"/>
-->限制上传文件的运行类型
拦截器注入参数从而限制文件上传类型
<!-- 限制上传文件的类型 -->
<interceptor-ref name="defaultStack">
<!-- 限制文件扩展名 -->
<param name="fileUpload.allowedExtensions">txt,jpg</param>
</interceptor-ref>
struts文件下载(2种方式)
1.通过response对象向浏览器写入字节流数据,设置下载的响应头
2.struts的方式
代码示例:
1 public class DownAction extends ActionSupport { 2 // 显示所有要下载的文件列表 3 public String list() { 4 // 得到upload目录 5 String path = ServletActionContext.getServletContext().getRealPath( 6 "/upload"); 7 // 创建目录对象 8 File file = new File(path); 9 // 得到所有文件名 10 String[] fileNames = file.list(); 11 // 保存 12 ActionContext ac = ActionContext.getContext(); 13 Map<String, Object> request = ac.getContextMap(); 14 request.put("fileNames", fileNames); 15 return "list"; 16 } 17 18 /* 19 * 文件下载 20 */ 21 // 1.获取要下载的文件名 22 private String fileName; 23 24 public void setFileName(String fileName) { 25 try { 26 // 处理传入参数中文乱码问题 27 fileName = new String(fileName.getBytes("ISO8859-1"), "utf-8"); 28 } catch (UnsupportedEncodingException e) { 29 throw new RuntimeException(e); 30 } 31 // 把处理好的文件名赋给fileName 32 this.fileName = fileName; 33 } 34 35 // 2.下载提交的业务方法,需要在struts.xml中配置返回stream 36 public String down() { 37 return "download"; 38 } 39 40 // 3.返回流 41 public InputStream getAttrInputStream() { 42 43 return ServletActionContext.getServletContext().getResourceAsStream( 44 "/upload/" + fileName); 45 } 46 47 // 下载显示的文件名 48 public String getDownFileName() { 49 // 需要中文编码 50 try { 51 fileName = URLEncoder.encode(fileName, "utf-8"); 52 } catch (UnsupportedEncodingException e) { 53 throw new RuntimeException(e); 54 } 55 return fileName; 56 } 57 }
配置文件配置方法:
1 <struts> 2 <package name="fileupload_" namespace="/" extends="struts-default" abstract="flase"> 3 <!-- action的名称不要用FileUpload --> 4 <action name="fileUpload_" class="cn.electhuang.e_fileupload.FileUpload" method="execute"> 5 <result name="success">/e/success.jsp</result> 6 7 <!-- 配置错误视图 --> 8 <result name="input">/e/error.jsp</result> 9 10 <!-- 限制上传文件的类型 --> 11 <interceptor-ref name="defaultStack"> 12 <!-- 限制文件扩展名 --> 13 <param name="fileUpload.allowedExtensions">txt,jpg</param> 14 </interceptor-ref> 15 </action> 16 17 <action name="down_*" class="cn.electhuang.e_fileupload.DownAction" method="{1}"> 18 <!-- 列表展示 --> 19 <result name="list">/e/list.jsp</result> 20 21 <!-- 下载操作 --> 22 <result name="download" type="stream"> 23 <!-- 允许下载的文件类型,指定为所有的二进制文件类型 --> 24 <param name="contentType">application/octet-stream</param> 25 26 <!-- 对应action中的属性,返回流的属性 ,其实就是找到getArrrInputStream方法--> 27 <param name="inputName">attrInputStream</param> 28 29 <!-- 下载头,包括浏览器显示的文件,其实就是找到getDownFileName方法 --> 30 <param name="contentDisposition">attachment;filename=${downFileName}</param> 31 32 <!-- 缓冲区大小设置 --> 33 <param name="bufferSize">1024</param> 34 </result> 35 </action> 36 37 </package> 38 </struts>