通常情况下,文件上传分为三种,
1,上传到tomcat服务器,也就是放入到tomcat项目里,这样会导致图片或者文件和项目高偶藕性,可能会有导致其他的一些错误。
2,上传到指定文件目录,添加服务器与真实目录的映射关系,从而解耦上传文件与tomcat的关系文件服务器。
3,在数据库表中建立二进制字段,将图片存储到数据库。这种方式如果是数据只有几千几万的情况下,是可以的,但是如果数据一多,数据库就会数据量大,从而影响读取速度。
所以一般情况下,都会选择第二种方式来进行文件上传。下面,我使用第二种方式来讲解。
配置文件
首先,在struts中要实现文件上传的第一步,就是在pom.xml里面配置
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
上传方法
配置好后,在web页面写方法。这里要写两个方法, preUpload()方法是跳转到页面选择文件进行上传, upload()则是进行上传操作。
在 upload()中, targetPath是你要存放的实际位置,severPath则是放到数据库中的地址,要让两者产生映射关系,则要在Servers项目中的server.xml里加一条映射关系。
/**
* 跳转页面
* @return
*/
public String preUpload() {
try {
Clazz c = this.clzDao.list(clz, null).get(0);
request.setAttribute("clz", c);
} catch (InstantiationException | IllegalAccessException | SQLException e) {
e.printStackTrace();
}
return "toUpload";
}
/**
* 实现上传
* @return
*/
public String upload() {
try {
//实际图片存储的位置
String targetPath = "D:/img";
//存到数据库中的地址
String severPath = "/upload";
FileUtils.copyFile(file, new File(targetPath+"/"+fileFileName));
clz.setPic(severPath+"/"+fileFileName);
this.clzDao.edit(clz);
} catch (Exception e) {
e.printStackTrace();
}
return "toList";
}
然后在配置文件中,配置好方法的路径。
就可以在jsp页面中调用了,
<a href="${pageContext.request.contextPath}/sy/clz_preUpload.action?cid=${c.cid}">图片上传</a>
当我点击这个按钮,则跳到选择文件页面。
这里因为要获取上传图片的是哪个,所以要隐藏域传参数过去。且表单也要设置成为多功能表单,再表单中添加一条属性
enctype="multipart/form-data"
在这里要注意的是图片路径的name,因为这里的name要和其他两个参数在web文件中set/get出来。
private File file;
private String fileContentType;
private String fileFileName;
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<form action="${pageContext.request.contextPath}/sy/clz_upload.action" method="post" enctype="multipart/form-data">
<input type="hidden" name="cid" value="${clz.cid} "/><br>
<input type="hidden" name="cname" value="${clz.cname} "/><br>
<input type="hidden" name="cteacher" value="${clz.cteacher} "/><br>
图片路径:<input type="file" name="file"/><br>
<input type="submit">
</form>
</body>
</html>
效果图:
当点击提交则运行upload()方法。
运行成功返回tolist重新刷新一次界面。
效果图:
完善上传方法
能实现文件上传最主要的则是upload()方法里的
FileUtils.copyFile(file, new File(targetPath+"/"+fileFileName));
这一句。
但他并不适用,所以我们可以改进一下,
/**
* 这是FileUtils.copyFile的底层,并且通过缓冲区进行了增强
* @param source
* @param target
*/
public void copyBufFile(File source,File target) {
try {
BufferedInputStream in = new BufferedInputStream(new FileInputStream(source));
BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(target));
byte[] bbuf = new byte[1024];
int leng = 0;
while((leng = in.read(bbuf))!=-1) {
out.write(bbuf,0,leng);
}
in.close();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
若没改进,在进行大文件上传的时候可能会文件丢失,等错误。
拦截器设置文件上传要求
而要设置上传文件的大小和格式的话,则要通过拦截器来设置,
要创建拦截器,
可以通过implements Interceptor和extends AbstractInterceptor
他们与filter的区别:先过filter再过interceptor。
这里我使用implements Interceptor。
然后要重写三个方法。我们只需写intercept就行了
public class OneInterceptor implements Interceptor{
@Override
public void destroy() {
// TODO Auto-generated method stub
}
@Override
public void init() {
// TODO Auto-generated method stub
}
@Override
public String intercept(ActionInvocation arg0) throws Exception {
return null;
}
}
写好拦截器,然后在配置文件中配置好路径。
<interceptors>
<interceptor name="one" class="com.zlk.crud.interceptor.OneInterceptor"></interceptor>
<interceptor name="two" class="com.zlk.crud.interceptor.TwoInterceptor"></interceptor>
</interceptors>
<interceptor-ref name="one"></interceptor-ref>
<interceptor-ref name="two"></interceptor-ref>
这样就可以了。