Servlet做控制器存在的缺陷
- 接收请求参数需要书写大量的request.getParameter("");
- 如果需要的数据类型不是字符串,需要开发人员手动转化
- 业务方法参数需要的是一个Java对象时,需要手动将零散的数据封装成对象
- 如果需要向request作用域存数据,需要书写request.setAttribute("");
- 跳转的视图固定在程序中(硬编码),不利于未来项目的维护
Struts2
框架概述
- 解决项目开发中通用问题的技术,对现有项目开发中一些普遍存在的开发效率的问题进行优化,也会对线程安全性问题进行处理
- 开发人员需要按照框架的规范加入一些逻辑完成软件的开发
- 使用框架可以提升开发效率
- SSH:Struts2 + Spring + Hibernate,逐渐被淘汰
- SSM:SpringMVC + Spring + Mybatis 现在的主流
Struts2框架
- 针对于Web应用开发中控制器层的问题,是一个典型的基于MVC设计思想的框架产品
- Struts2框架集成了Struts1和webwork框架,本质上Struts2更多的使用了webwork框架的设计理念和开发方式,2013年左右Struts1出现安全漏洞,所以出现Struts2
- Struts2配置文件
struts2.xml
<action name="url-pattern" class="servlet-class"> //url-pattern没有斜杠
<result name="返回值">/返回值.jsp</result> //跳转到哪个文件
</action>
-
获取Struts2:可以到官网下载,Struts2是apache开源组织开发的一款开源框架
-
解压包文件:
- apps:struts2案例项目
- docs:struts2学习使用文档
- lib:struts2的功能 jar包
- src:struts2源码
-
jar:java application resource
-
war:web application resource
-
使用Struts开发
-
搭建开发环境
- 引入jar包:struts2-core-2.3.16.jar和xwork-core-2.3.16.jar为struts2框架的核心jar包
- 引入配置文件:
- struts.xml核心配置文件必须放在根目录src下
- src下引入log4j.properties日志管理文件,查看Struts2的运行过程
- 初始化配置:编写web.xml文件,配置一个Struts2的核心过滤器,开启Struts2框架的功能
<!-- strtus2核心入口过滤器 --> <filter> <filter-name>struts</filter-name> <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class> </filter> <filter-mapping> <filter-name>struts</filter-name> <!-- 过滤范围是所有,代表所有来自客户端的请求先进入过滤器,才能使用Struts2框架功能--> <url-pattern>/*</url-pattern> </filter-mapping>
- 配置struts.xml
<!-- name属性全局唯一即可 extends:struts-default 使用Struts2框架的功能 namespace:是未来请求action路径的一部分,必须以 / 开头,且多个package不冲突 --> <package name="p1" extends="struts-default" namespace="/p1"> <!-- name属性值为请求action路径的一部分,唯一 class属性值指定action实现类的全限定名 访问当前action路径:http://localhost/项目名/p1/helloWorld --> <action name="helloWorld" class="com.hang.action.HelloAction"> <result name="success">/success.jsp</result> </action> </package>
-
Struts2中的跳转控制
- action —> jsp
- 请求转发:type=“dispatcher” 默认值,代表请求转发的方式跳转到jsp
- 请求重定向:type=“redirect” 代表请求重定向方式跳转到jsp
<action name="jump1" class="com.hang.action.JumpAction1">
<!-- 通过type属性值控制跳转方式
type="dispatcher" 默认值,代表请求转发的方式跳转到jsp
type="redirect" 代表请求重定向方式跳转到jsp-->
<result name="success" type="redirect">/success.jsp</result>
</action>
- action —> action
- 请求转发:type=“chain” 代表请求转发跳转到action
- 请求重定向:type=“redirectAction” 代表请求重定向到action
- 在struts中,action到action请求重定向跳转时地址栏会默认加 . action
<action name="jump2" class="com.hang.action.JumpAction2">
<!-- type="chain" 代表请求转发跳转到action
type="redirectAction" 代表请求重定向到action -->
<result name="success" type="chain">jump1</result>
</action>
- action跳转到另一个package下的action,其中name为固定值
<!-- 跳转到另一个package的action -->
<action name="jumpA" class="com.hang.action.JumpActionA">
<result name="success" type="chain">
<!-- 指定目标action的namespace -->
<param name="namespace">/p2</param>
<!-- 指定目标action的名字 -->
<param name="actionName">jumpB</param>
</result>
</action>
- 全局跳转:
- 如果当前action的配置内没有对应的result匹配视图,则去全局视图跳转位置匹配,如果全局的位置也没匹配到,则抛出异常
- 当全局视图配置与局部冲突时,局部优先
- 全局视图跳转的配置主要是解决跳转视图配置冗余。通常在项目后期优化使用
- 全局视图配置只在当前package内有效
<!-- 全局视图跳转配置 -->
<package name="p3" extends="struts-default" namespace="/p3">
<!-- 配置全局跳转的视图 -->
<global-results>
<result name="success">/success.jsp</result>
</global-results>
<action name="global1" class="com.hang.action.GlobalAction1">
<result name="success">/error.jsp</result>
</action>
<action name="global2" class="com.hang.action.GlobalAction2">
</action>
<action name="global3" class="com.hang.action.GlobalAction3">
</action>
</package>
获取原生的ServletAPI
- 获取request、session、response、application
//使用Struts2提供的工具类获取原生ServletAPI
HttpServletRequest request = ServletActionContext.getRequest();
HttpSession session = request.getSession();
HttpServletResponse response = ServletActionContext.getResponse();
ServletContext application = ServletActionContext.getServletContext();
Struts2的action实现类创建
Struts2的实现类action | Servlet的实现类service |
---|---|
实现类是多例的,每次请求都会创建一个新的对象 | 实现类是单例的,在tomcat中只会创建一个对象,在并发时不安全 |
允许定义成员变量,并且成员变量接收请求参数 | 不允许定义成员变量 |
Struts2中的收参机制
- 通过成员变量接收客户端请求参数
- 同一个参数可以接收参数同时传递参数
- 接收八种基本数据类型和字符串
- 请求参数的key与action中的成员变量名对应
- 提供对应成员变量的公开的getter / setter方法
- 成员变量的数据类型声明为需要的类型,Struts2框架会根据需要自动完成数据类型的转换
- 对于日期格式,必须是yyyy-MM-dd格式
<form action="${path }/ceshi/paramAction" method="post">
username:<input type="text" name="username"><br>
password:<input type="text" name="password"><br>
age:<input type="text" name="age"><br>
score:<input type="text" name="score"><br>
birthday:<input type="text" name="birthday"><br>
<input type="submit">
</form>
//需要提供公开的getter/setter方法
public class ParamAction implements Action{
private String username;
private String password;
private Integer age;
private Double score;
private java.util.Date birthday;
public java.util.Date getBirthday() { return birthday; }
public void setBirthday(java.util.Date birthday) { this.birthday = birthday; }
public Double getScore() { return score; }
public void setScore(Double score) { this.score = score; }
public Integer getAge() { return age; }
public void setAge(Integer age) { this.age = age; }
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
public String getPassword() { return password; }
public void setPassword(String password) { this.password = password; }
@Override
public String execute() throws Exception {
System.out.println("username:"+username);
System.out.println("password:"+password);
System.out.println("age:"+age);
System.out.println("score:"+score);
System.out.println("birthday:"+birthday);
return SUCCESS;
}
}
<package name="ceshi" extends="struts-default" namespace="/ceshi">
<action name="paramAction" class="com.yuan.action.ParamAction">
<result name="success">/success.jsp</result>
</action>
</package>
- 接收自定义对象类型的参数
- 在action实现类声明一个自定义类型的对象,接收请求参数
- jsp中请求参数的key需要加把自定义类型参数名作为前缀
action中的自定义对象变量名 . 自定义对象类型中的属性名 - 给自定义成员变量提供getter / setter方法
<form action="${path }/ceshi/paramObjAction" method="post">
id:<input type="text" name="employee.id"><br>
name:<input type="text" name="employee.name"><br>
salary:<input type="text" name="employee.salary"><br>
age:<input type="text" name="employee.age"><br>
<input type="submit">
</form>
public class ParamObjAction implements Action {
private Employee employee;
public Employee getEmployee() { return employee; }
public void setEmployee(Employee employee) { this.employee = employee; }
@Override
public String execute() throws Exception {
System.out.println(employee);
return SUCCESS;
}
}
-
接收list集合类型:
- 泛型为String时,key与集合名字对应
<form action="${path }/ceshi/paramListAction" method="post"> 爱好: <input type="checkbox" name="hobby" value="eat">吃饭 <input type="checkbox" name="hobby" value="study">学习 <input type="checkbox" name="hobby" value="sleep">睡觉<br> <input type="submit"> </form> public class ParamListAction implements Action{ private List<String> hobby; public List<String> getHobby() { return hobby; } public void setHobby(List<String> hobby) { this.hobby = hobby; } @Override public String execute() throws Exception { for(String str:hobby) System.out.println(str); return SUCCESS; } }
- 泛型为自定义类型时,不常用
- key为action变量名[数组下标] . 自定义对象类型中的属性名
<form action="${path }/ceshi/paramListAction" method="post"> id:<input type="text" name="employees[0].id"> name:<input type="text" name="employees[0].name"> salary:<input type="text" name="employees[0].salary"> age:<input type="text" name="employees[0].age"><br> <br> id:<input type="text" name="employees[1].id"> name:<input type="text" name="employees[1].name"> salary:<input type="text" name="employees[1].salary"> age:<input type="text" name="employees[1].age"><br> <input type="submit"> </form> public class ParamListAction implements Action{ private List<Employee> employees; public List<Employee> getEmployees() { return employees; } public void setEmployees(List<Employee> employees) { this.employees = employees; } @Override public String execute() throws Exception { for(Employee employee:employees){ System.out.println(employee); } return SUCCESS; } }
使用成员变量替换request作用域
- Struts2会自动将成员变量作为命名属性放入request作用域,命名属性就是变量名
public class RequestScopeAction implements Action{
private String name;
private List<String> strList;
public List<String> getStrList() { return strList; }
public void setStrList(List<String> strList) { this.strList = strList; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
@Override
public String execute() throws Exception {
//向Struts2中的一个action发送请求时,这个action的成员变量会自动存入request作用域
name = "yuan"; //放入request作用域 名字为成员变量名,值通常在execute方法中
strList = new ArrayList<String>();
strList.add("hang");
strList.add("yaun");
return SUCCESS;
}
}
Struts2的action另外两种开发方式
-
继承ActionSupport,需要使用ActionSupport类的一些功能,则必须通过继承ActionSupport编写控制器
- 底层ActionSupport实现了Action接口,不过是空实现
//底层代码 public class ActionSupport implements Action,...., { ...... public String execute() throws Exception { return SUCCESS; //返回值是父类Action中的 //public static final String SUCCESS = "success"; } ....... }
- 继承ActionSupport开发
public class SecondAction extends ActionSupport{ @Override public String execute()throws Exception{ System.out.println("action第二种开发方式"); return SUCCESS; } } <action name="secondAction" class="com.yuan.action.SecondAction"> <result name="success">/success.jsp</result> </action>
-
直接通过一个JavaBean作为action
public class ThirdAction { public String execute(){ System.out.println("第三种Action开发方式"); return "success"; } } <action name="thirdAction" class="com.yuan.action.ThirdAction"> <result name="success">/success.jsp</result> </action>
DMI开发
-
Dynamic Method Invocation,动态方法调用
-
可以在一个action实现类中定义多个方法,每一个方法都可以处理一个客户端的请求
-
可以减少项目中控制器类的数量,提高项目的可维护性
-
实际开发中,通常将针对于同一张表的操作,定义在一个action实现类中。
public class EmployeeAction extends ActionSupport{ public String addEmployee(){ System.out.println("this is addEmployee"); return "addEmp"; } public String queryEmployee(){ System.out.println("this is queryEmployee"); return "queryEmp"; } } <!-- 第一种DMI配置方式 --> <package name="emp" extends="struts-default" namespace="/emp"> <!-- method指定当请求这个action的时候调用哪个方法处理请求 method属性值:目标调用方法的名字,默认值为execute--> <action name="addEmp" class="com.yuan.action.EmployeeAction" method="addEmployee"> <result name="addEmp">/success.jsp</result> </action> <action name="queryEmp" class="com.yuan.action.EmployeeAction" method="queryEmployee"> <result name="queryEmp">/success.jsp</result> </action> </package> <!-- 第二种DMI配置方式 ,简化配置文件 name值中的 * 称为通配符,用于匹配请求路径的值,method={1}表示取name属性值第一个 * 匹配到的值,作为目标调用方法的名字 --> <!-- 第二种DMI配置 调用:直接调用方法名即可,method通配符会自动调用方法,然后对应返回值到跳转 http://localhost:8989/upStruts2_day3/emp/emp_addEmployee http://localhost:8989/upStruts2_day3/emp/emp_queryEmployee --> <action name="emp_*" class="com.yuan.action.EmployeeAction" method="{1}"> <result name="addEmp">/success.jsp</result> <result name="queryEmp">/success.jsp</result> </action>
Struts2配置文件中的默认值
- 在配置文件中通常只有一个package中namespace是默认值
<!-- namespace默认值:/ -->
<package name="order" extends="struts-default">
<!-- method默认值:execute -->
<action name="orderAction" class="com.yuan.action.OrderAction">
<!-- name属性默认值success type 属性默认值:dispatcher -->
<result>/success.jsp</result>
</action>
</package>
拦截器 interceptor
-
可以在请求到达指定action之前,进行拦截请求
-
编写拦截器
- 实现Interceptor接口
public class MyInterceptor1 implements Interceptor{ //销毁拦截器时调用 public void destroy() { } //初始化拦截器调用 public void init() { } /*核心实现的方法 ActionInvocation:可以获取到目标的action对象 返回值:与Action实现类方法中的返回值作用一样,可以代表一个跳转的视图*/ public String intercept(ActionInvocation ai) throws Exception { System.out.println("this is MyInterceptor1"); HttpServletRequest request = ServletActionContext.getRequest(); String name = request.getParameter("name"); //获取目标action对象,然后通过反射的方式将接收到的值设置给action对应的属性上 Object obj = ai.getAction(); System.out.println(obj.getClass()); if(name!=null){ //让请求继续向下执行 ai.invoke(); //返回值为null等同于不做任何跳转 return null; }else{ //进行重定向跳转 return "error"; //代表一个跳转的视图 } } }
- 编写struts.xml
<!-- 拦截器声明配置 --> <interceptors> <!-- 声明创建一个拦截器 name是拦截器的别名,也是未来使用拦截器的依据 class是拦截器实现类的全限定名 --> <interceptor name="myInterceptor1" class="com.hang.interceptor.MyInterceptor1"></interceptor> </interceptors> <!-- 使用拦截器 --> <action name="target1" class="com.yuan.action.HelloAction"> <!-- 指定使用的拦截器 --> <interceptor-ref name="myInterceptor1"></interceptor-ref> <result name="success">/success.jsp</result> </action>
-
拦截器的使用技巧
- 拦截器进行重定向
<!-- 拦截器声明配置 --> <interceptors> </interceptors> <!-- 全局视图跳转配置 --> <global-results> <!-- 如果拦截器中的返回值表示要跳转,则使用全局视图跳转配置简化代码 --> <result name="error" type="redirect">/error.jsp</result> </global-results> <action name="target1" class="com.yuan.action.HelloAction" method="target1"> <!-- 指定使用的拦截器 --> <interceptor-ref name="myInterceptor1"></interceptor-ref> <result name="success">/success.jsp</result> <!-- 使用拦截器进行跳转,冗余代码 --> <result name="error" type="redirect">/error.jsp</result> </action>
- 多个拦截器的执行顺序,根据在action配置中的引用顺序一致
- 拦截器栈:简化配置文件
<!-- 拦截器声明配置 --> <interceptors> <interceptor name="myInterceptor1" class="com.hang.interceptor.MyInterceptor1"></interceptor> <interceptor name="myInterceptor2" class="com.hang.interceptor.MyInterceptor2"></interceptor> <!-- 配置拦截器栈 name为拦截器栈的名字,是引用拦截器栈的依据--> <interceptor-stack name="myDefaultStack"> <interceptor-ref name="myInterceptor1"></interceptor-ref> <interceptor-ref name="myInterceptor3"></interceptor-ref> </interceptor-stack> </interceptors> <!-- 引用使用的拦截器栈 --> <action name="target1" class="com.yuan.action.HelloAction" method="target1"> <!-- 指定使用的拦截栈,相当于使用了拦截器栈中拦截器的功能 --> <interceptor-ref name="myDefaultStack"></interceptor-ref> <result name="success">/success.jsp</result> </action>
- default-interceptor-ref 默认使用拦截器或拦截器栈
<!-- 写在 interceptors 标签后 --> <!-- 指定当前package内所有的action默认引用的拦截器或拦截器栈 --> <default-interceptor-ref name="myDefaultStack"></default-interceptor-ref>
- 通常书写的package都继承了系统的struts-default package,即继承了struts-default里面的功能,当自己设置了默认的拦截器栈后,会覆盖系统拦截器栈道引用
- 如果覆盖掉系统的拦截器栈,则会失去系统拦截器栈提供的功能;所有在使用自己的拦截器栈时,必须手动引入系统的默认拦截器栈
<!-- 配置拦截器栈 name为拦截器栈的名字,是引用拦截器栈的依据--> <interceptor-stack name="myDefaultStack"> <interceptor-ref name="myInterceptor"></interceptor-ref> <!-- 引用系统的默认拦截器栈 --> <interceptor-ref name="defaultStack"></interceptor-ref> </interceptor-stack>
-
方法拦截器
- 针对action实现类中的方法制定拦截规则,使用时和普通拦截器一样
<!-- 配置拦截器 --> <interceptors> <interceptor name="myMethodInterceptor" class="com.hang.interceptor.MyMethodInterceptor"> <!-- 配置方法的拦截规则:只根据方法名来判断是否拦截 name="includeMethods" 包含哪些方法拦截 name="excludeMethods" 不拦截哪些方法 方法拦截规则是针对于方法的配置,与方法在哪个类没有直接关系--> <param name="excludeMethods">mb,mc</param> <!-- 方法名的配置支持通配符 ,拦截以m开头的方法 --> <param name="includeMethods">m*</param> </interceptor> <interceptor-stack name="myDefaultStack"> <interceptor-ref name="defaultStack"></interceptor-ref> <interceptor-ref name="myMethodInterceptor"></interceptor-ref> </interceptor-stack> </interceptors> <action name="emp_*" class="com.hang.action.EmpAction" method="{1}"> <!-- 引用拦截器 --> <interceptor-ref name="myDefaultStack"></interceptor-ref> <result name="ma">/success.jsp</result> <result name="mb">/success.jsp</result> <result name="mc">/success.jsp</result> </action>
拦截器使用的标准流程
-
实现Interceptor接口
-
编写配置文件,默认拦截器有效范围在当前的package内,也可以通过package的继承扩大拦截器的使用范围
<package name="employee" extends="struts-default" namespace="/employee"> <!-- 拦截器配置 --> <interceptors> <!-- 拦截器声明配置 --> <interceptor name="myInterceptor" class="com.hang.interceptor.MyInterceptor"></interceptor> <!-- 拦截器栈配置 --> <interceptor-stack name="myDefaultStack"> <!-- 引用系统默认的拦截器栈 --> <interceptor-ref name="defaultStack"></interceptor-ref> <interceptor-ref name="myInterceptor"></interceptor-ref> </interceptor-stack> </interceptors> <action name="findAll" class="com.hang.action.FindAllEmployeesAction"> <!-- 拦截器引用 --> <intercepter-ref name="myDefaultStack"></intercepter-ref> <result name="emplist">/emplist.jsp</result> </action> </package>
Struts2中POST方式请求中文的编码处理
-
Struts2默认已经处理了POST请求提交数据的中文乱码,默认编码为UTF-8,默认的以键值对存储
- 自定义编码格式,只针对POST请求 i18n是资源国际化的缩写
<!-- constant标签用于自定义Struts2的一些初始化配置 --> 在struts.xml中覆盖<constant></constant>标签,用于覆盖struts2默认配置,以key-value存储 <!-- 自定义编码格式 --> <constant name="struts.i18n.encoding" value="iso-8859-1"> </constant>
- 在struts2中的struts.xml中进行GET方式拼接传参
<action name="login" class="com.yuan.action.LoginAction" > <result name="success">/success.jsp</result> <result name="login" type="redirect"> <!-- 重定向跳转get拼接传参 --> <param name="location">/login.jsp</param> <!-- login.jsp?errorMsg=验证账户信息失败 --> <param name="errorMsg">验证用户信息失败</param> </result> </action>
验证码
-
编码实现
- 生成验证码随机数
- 将随机数绘制到验证码图片上
public class CaptchaAction { public String execute() throws IOException{ //生成验证码随机数 String securityCode = SecurityCode.getSecurityCode(); //将随机数存入session,做验证使用 HttpSession session = ServletActionContext.getRequest().getSession(); session.setAttribute("securityCode", securityCode); //绘制生成验证码图片 BufferedImage image = SecurityImage.createImage(securityCode); //使用IO流响应结果到客户端 HttpServletResponse response = ServletActionContext.getResponse(); OutputStream out = response.getOutputStream(); /* ImageIO工具类,写验证码图片使用 * 第一个参数:指定验证码图片对象 * 第二个参数:指定图片的格式 * 第三个参数:指定输出流 */ ImageIO.write(image, "png", out); return null;//返回null代表不做跳转 } } <!-- 验证码配置 --> <action name="captcha" class="com.yuan.action.CaptchaAction"> <!-- type=stream 代表以IO流的方式响应结果 --> <result type="stream">image/png</result> </action>
- 使用验证码,并从session中获取服务器端生成的验证码随机数,与客户端提交的进行对比
验证码: <input type="text" name="captchaCode"><br> <!-- 用户输入 --> <img src="${pageContext.request.contextPath }/p1/captcha"/> <!-- 验证码图片 -->
文件上传
-
客户端HTML编写
-
服务器编写代码接收
//客户端浏览器 <!-- 将选择的文件,以二进制流的形式提交到服务器 并且必须以POST方式提交数据 --> <form action="${path }/p1/uploadAction" methed="post" enctype="multipart/form-data" > <input type="file" name="upload"> <input type="submit" value="upload"> </form> /* 服务器端 1,接收上传文件 .File 2,将上传的文件保存,保存在服务器的某个位置 */ class UploadAction{ private File upload; //上传文件的key+FileName,获取上传文件的原始文件名 private String uploadFileName; getter/setter public String execute(){ //使用IO流处理上传文件的保存,保存到服务器端 } }
-
文件上传实现:Struts2把文件封装
- 第一版
public String execute() throws IOException{ System.out.println("文件名:"+uploadFileName); InputStream in = new FileInputStream(upload); OutputStream out = new FileOutputStream("C:\\Learn\\upStruts2\\upStruts2_day4\\WebRoot\\upload\\"+uploadFileName); //缓冲区 byte[] buffer = new byte[1024]; int len = 0; while(true){ //每次读取的放到缓冲区中 len = in.read(buffer); if(len==-1) break; //写到服务器指定位置保存 out.write(buffer, 0, len); } //释放资源 out.close(); in.close(); return "success"; } }
- 获取上传文件的原始类型
//获取上传文件原始类型,指文件的互联网类型MIME类型 //格式:父类型 / 子类型 //变量名:上传文件的key+ContentType private String uploadContentType;
- 第二版,使用工具类
public String execute() throws IOException{ System.out.println("文件名:"+uploadFileName); //根据相对路径,获取保存文件的真实路径 ServletContext servletContext = ServletActionContext.getServletContext(); String realPath = servletContext.getRealPath("upload"); System.out.println("保存上传文件的真实路径:"+realPath); System.out.println("上传文件原始文件类型:"+uploadContentType); //将上传的文件保存到realPath下 //参数1:上传过来的文件对象 //参数2:目标保存上传文件的文件对象 FileUtils.copyFile(upload, new File(realPath+"\\"+uploadFileName)); return "success"; }
- 保证上传到服务器的文件,保存的名字唯一
- UUID是一个全球唯一的字符串序列,32位,可以使用UUID作为上传的文件名
UUID uuid = UUID.randomUUID(); System.out.println(uuid); public String execute() throws IOException{ //根据相对路径,获取保存文件的真实路径 ServletContext servletContext = ServletActionContext.getServletContext(); String realPath = servletContext.getRealPath("upload"); System.out.println("文件名:"+uploadFileName); System.out.println("保存上传文件的真实路径:"+realPath); System.out.println("上传文件原始文件类型:"+uploadContentType); //使用UUID实现保存文件的名字 UUID uuid = UUID.randomUUID(); //获取上传文件的后缀 String extension = FilenameUtils.getExtension(uploadFileName); System.out.println("文件的后缀:"+extension); //组成新的文件名 String saveFileName = uuid.toString()+"."+extension; //将上传的文件保存到realPath下 //参数1:上传过来的文件对象 //参数2:目标保存上传文件的文件对象 FileUtils.copyFile(upload, new File(realPath+"/"+saveFileName)); return "success"; }
- 修改上传文件大小的限制
Struts2默认大小struts.multipart.maxSize=2097152 <!-- 设置上传文件的大小,在配置文件中覆盖struts2默认属性 --> <constant name="struts.multipart.maxSize" value="15728640"> </constant>
-
文件下载
/*提供一个读取服务器文件的输入流 Struts2框架会自动调用这个方法,然后把输入流读取到的文件下载到客户端 */ public class DownLoadAction extends ActionSupport{ /*提供一个读取服务器文件的输入流 Struts2框架会自动调用这个方法,然后把输入流读取到的文件下载到客户端 */ //默认调用execute方法,所以可以写空实现或者继承ActionSupport public InputStream getInputString() throws FileNotFoundException{ String filePath = "C:\\apache-tomcat-7.0.79\\webapps\\upStruts2_day4\\upload\\wallhaven-2eex5x.jpg"; return new FileInputStream(filePath); } } <!-- 文件下载第一版 --> <action name="download" class="com.yuan.action.DownLoadAction"> <!-- type="stream"表示使用IO流相应结果 --> <result type="stream"> <!-- 设置下载文件的类型,要互联网类型 --> <param name="contentType">image/jpeg</param> <!-- 设置下载文件的保存方式,两种 一是以附件的形式保存到磁盘 attachment 二是直接在客户端浏览器打开,inline 浏览器必须支持这种文件类型 --> <param name="contentDisposition">inline;filename=x.jpg</param> <!-- 设置下载文件的缓冲区大小,面向缓冲区操作,提高读写效率 --> <param name="buffer">1024</param> </result> </action>
- 优化下载名字:使用action的成员变量给struts.xml传参
<!-- 文件下载第二版 --> public class DownLoadAction extends ActionSupport{ private String filename; public String getFilename() { return filename; } public void setFilename(String filename) { this.filename = filename; } /*提供一个读取服务器文件的输入流 Struts2框架会自动调用这个方法,然后把输入流读取到的文件下载到客户端 */ public InputStream getInputStream() throws FileNotFoundException{ ServletContext servletContext = ServletActionContext.getServletContext(); String realPath = servletContext.getRealPath("/upload"); return new FileInputStream(realPath+"/wallhaven-2eex5x.jpg"); } public String execute(){ filename="3546.jpg"; //对下载文件重命名 return "success"; } } <!-- 文件下载 --> <action name="download" class="com.yuan.action.DownLoadAction"> <!-- type="stream"表示使用IO流相应结果 --> <result type="stream"> <!-- 设置下载文件的类型,要互联网类型 --> <param name="contentType">image/jpeg</param> <!-- 设置下载文件的保存方式,两种 一是以附件的形式保存到磁盘 attachment 二是直接在客户端浏览器打开,inline 浏览器必须支持这种文件类型 --> <!-- 使用OJNL表达式动态获取名字 --> <param name="contentDisposition">attachment;filename=${filename}</param> <!-- 设置下载文件的缓冲区大小,面向缓冲区操作,提高读写效率 --> <param name="buffer">1024</param> </result> </action>
Struts2配置文件拆分
<!-- 主配置文件struts.xml -->
<include file="com/hang/conf/struts-user.xml"></include>
<!-- 副配置文件struts-user.xml -->
<!-- 如果当前配置文件中跳转到另一个配置文件的某个action,则需要将其包含 -->
<include file="com/hang/conf/struts-emp.xml"></include>
DTO
- data transfer object,数据传输对象
- 主要用于数据的传递
MainDTO{
private List<Book> list;
private List<Book> list1;
private List<Book> list2;
getter / setter
}