一、文件上传
文件上传是WEB经常面对的问题,对于Java应用主要有以下三种上传文件的方式
- 文件流手工编程
- 基于commons-fileupload的组件
- 基于servlet3的文件上传
(一)单文件上传
1、创建应用导入jar包
- Spring MVC相关jar包
- commons-fileupload组件相关jar包
- JSTL的相关jar包
2、创建web.xml文件
配置DispatcherServlet和添加字符编码过滤器
<!--配置DispatcherServlet -->
<servlet>
<servlet-name>Springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- 避免中文乱码 -->
<filter>
<filter-name>characterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
3、创建文件上传页面
1、设置methon属性为post
2、 enctype属性为multipart/form-data,该编码方式表明服务器以二进制流的方式来处理表单数据,并将文件内容封装到请求参数里
3、表单属性multiple设置为multiple,可同时上传多个文件
<form action="${pageContext.request.contextPath }/onefile" method="post"
enctype="multipart/form-data">
选择文件:<input type="file" name="myfile" multiple="multiple"/><br>
文件描述:<input type="text" name="description"/><br>
<input type="submit" value="提交"/>
</form>
4、创建pojo类
领域模型中的属性名对应文件上传界面的file类型的表单参数名
public class FileDomain {
private String description;
private List<MultipartFile> myfile;
//省略getter和setter方法
}
5、创建控制器类
@Controller
public class FileUploadController {
private static final Log Logger = LogFactory.getLog(FileUploadController.class);
@RequestMapping("/onefile")
public String oneFileUpload(@ModelAttribute FileDomain fileDomain,HttpServletRequest request) {
// 指定文档上传的路径,本项目的发布路径是在tomcat下的webapps目录中
String realPath = request.getServletContext().getRealPath("/uploadfiles/");
// 如果文件夹不存在则创建
File targetDir = new File(realPath);
if(!targetDir.exists()) {
targetDir.mkdirs();
}
// 获得上传的文件集
List<MultipartFile> files = fileDomain.getMyfile();
for(MultipartFile file:files) {
String filename = file.getOriginalFilename();
File targetFile = new File(realPath,filename);
System.out.println("目标文件为:"+targetFile);
// 开始文件上传
try {
// 使用MultipartFile接口方法完成文件上传到指定位置
file.transferTo(targetFile);
Logger.info("文件上传成功!");
} catch (Exception e) {
e.printStackTrace();
}
}
return "showone";
}
}
6、创建springmvc-servlet.xml配置文件
1、添加扫描机制
2、配置视图解析器
3、使用spring的commonMultipartResolver,id必须为internalResourceViewResolver
<!-- 使用扫描机制扫描控制器类 -->
<context:component-scan base-package="Controller"></context:component-scan>
<!-- 配置视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
id="internalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver" >
<property name="defaultEncoding" value="UTF-8"></property>
<property name="maxUploadSize" value="5400000000"></property>
<property name="uploadTempDir" value="fileUpload/temp"></property>
</bean>
7、创建成功显示界面
运用JSTL的核心标签库,需要在报头上添加
<%@ taglib uri=“http://java.sun.com/jsp/jstl/core” prefix=“c” %>
<body>
${fileDomain.description }<br>
<!-- fileDomain.getMyfile().getOriginalFilename() -->
<c:forEach items="${fileDomain.myfile }" varStatus="loop">
文件名称:${fileDomain.myfile[loop.count-1].originalFilename }<br>
</c:forEach>
</body>
8、测试文件上传
因为本项目的发布路径是在Tomcat中,最后在Tomcat下的webapps中会有上传的文件,当Tomcat服务器关闭时,文件路径也会消失。
(二)多文件上传
多文件上传和单文件上传类似,只需要将文件上传页面改为多文件上传,如下:
<body>
<form action="${pageContext.request.contextPath }/multipFiles" method="post"
enctype="multipart/form-data">
选择文件1:<input type="file" name="myfile" multiple="multiple"/><br>
文件描述1:<input type="text" name="description"/><br>
选择文件2:<input type="file" name="myfile" multiple="multiple"/><br>
文件描述2:<input type="text" name="description"/><br>
选择文件3:<input type="file" name="myfile" multiple="multiple"/><br>
文件描述3:<input type="text" name="description"/><br>
<input type="submit" value="提交"/>
</form>
</body>
二、文件下载
(一)文件下载的实现方法
- 通过超链接下载
- 利用程序编码实现下载
1、利用超链接下载简单,但是暴露了下载文件的真实位置,并且只能下载存放在Web应用程序所在目录下的文件,具有一定的局限性
2、利用程序编码下载可以增加安全访问机制,还可以从任意位置提供下载的数据,即可以将文件存放在Web应用程序之外的目录中,也可以将文件保存到数据库。但实现较第一种下载略显困难。
利用程序实现下载需要设置两个报头:
response.setHeader("Content-Type", "application/x-msdownload");
response.setHeader("Content-Disposition", "attachment; filename="+filename);
(二)文件下载的实现过程
在执行文件下载时,需保证,对应的文件目录存在文件,否则会报错
1、编写控制器类
1、showDownloadFiles方法获取可下载的文件名称。
2、down方法执行下载功能。
3、toUTF8String方法是下载保存时中文文件字符编码转换,不出现乱码。
①showDownloadFiles方法
// 用于显示文件
private String showDownloadFiles(Model model,HttpServletRequest request) {
// 获得文档下载的路径
String realpath = request.getServletContext().getRealPath("/uploadfiles");
// 获取下载的文件
File dir = new File(realpath);
File file[] = dir.listFiles();
System.out.println(file);
ArrayList<String> filenames = new ArrayList<String>();
for(int i = 0;i<file.length;i++) {
filenames.add(file[i].getName());
}
model.addAttribute("files", filenames);
return "showDownloadFiles";
}
②down方法
@RequestMapping("down")
private String down(@RequestParam String filename,
HttpServletRequest request,HttpServletResponse response) {
String filepath = null;
InputStream in = null;
ServletOutputStream out = null;
try {
// 获得文件下载的路径
filepath = request.getServletContext().getRealPath("/uploadfiles");
// 设置文件下载时的报头
response.setHeader("Content-Type", "application/x-msdownload");
response.setHeader("Content-Disposition", "attachment; filename="+
toUTF8String(filename));
// 读入文件
in = new FileInputStream(filepath+"\\"+filename);
// 获得响应对象的输出流,用于向客户端输出二进制数据
out = response.getOutputStream();
out.flush();
int ahead = 0;
byte b[] = new byte[1024];
while ((ahead = in.read(b)) != -1 & in != null) {
out.write(b, 0, ahead);
}
out.flush();
in.close();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
logger.info("文件下载成功");
return null;
}
③toUTF8String方法
// 下载文件时中文文件字符编码的转换
private String toUTF8String(String str) {
StringBuffer sb = new StringBuffer();
int len = str.length();
for(int i = 0; i < len; i++){
//取出字符中的每个字符
char c = str.charAt(i);
//Unicode码值在0-255之间,不作处理
if(c >= 0 && c <= 255){
sb.append(c);
}else{//转换UTF-8编码
byte b[];
try {
b = Character.toString(c).getBytes("UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
b = null;
}
//转换为%HH的字符串形式
for(int j = 0; j < b.length; j ++){
int k = b[j];
if(k < 0){
k &= 255;
}
sb.append("%" + Integer.toHexString(k).toUpperCase());
}
}
}
return sb.toString();
}
2、创建文件列表显示页面
这里同样用到了JSTL标签库
<body>
<table>
<tr><td>可下载的文件名</td></tr>
<c:forEach var="filename" items="${files }">
<tr>
<td>
<a href="${pageContext.request.contextPath }/down?filename=${filename}">${filename}</a>
</td>
</tr>
</c:forEach>
</table>
</body>
三、总结
(一)文件上传遇到的坎儿
①显示上传空间不够,改一下配置文件中最大上传字节
②web.xml中若没有指定springmvc-servlet.xml的初始化位置,则需要将这两个文件统一放在webcontent/web-inf下,否则运行时会显示“这是一个不愿公开的资源”(重点,昨天没注意白花了两三个小时在找bug)
③若没有在配置文件中添加扫描包机制,也可能会出现上述问题
(二)文件下载遇到的坑
敲重点敲重点敲重点(重要的事情说三遍)
在文件下载之前一定要确定下载的路径中存在文件,否则会有空指针报错。
道阻且长,人生不易啊!笔落!!!