目录
前言
本篇会讲解在纯servlet下上传文件和框架下上传文件,以及各种上传文件的方式
纯servlet下使用upload插件上传文件
测试页面
我们选择图片提交后
<form action="UploadServlet" method="post" enctype="multipart/form-data">
帐号: <input type="text" name="username"/>
密码: <input type="text" name="password"/>
头像: <input type="file" name="userhead" />
<input type="submit"/>
</form>
图片是一串数据,并不能用reque.getParameter 来接受
导入upload的jar包
在servlet里
这里为了方便测试,把user放入session中,为了在页面中显示,实际情况中肯定不能这样
因为密码也通过populate给放入了
这个servlet的作用是,把上传到服务器文件,写到另一个地方,这个地方可以是专门存放图片的地方
还有就是要记得释放资源,不然页面显示不了,被jvm占用文件了
还有就是要注意,文件是不能存到tomcat下面的,因为重新发布的时候,文件会被清空
protected void doGet(HttpServletRequest request, HttpServletResponse response)
{
try
{
// 创建map集合来接收文件名,有对应的key,通过key找到value会非常快
Map<String, String> map = new HashMap<String, String>();
User user = new User();
// 利用request.getInputStream 获取请求体的全部数据,进行拆分和封装
//以下3行语句都是固定的
// 创建文件工厂
DiskFileItemFactory factory = new DiskFileItemFactory();
// 创建servlet上传对象
ServletFileUpload upload = new ServletFileUpload(factory);
//拆分request,把每份数据变成FileItem
List<FileItem> list = upload.parseRequest(request);
//遍历FileItem集合
for (FileItem fileItem : list)
{
//是否是普通的数据
if (fileItem.isFormField())
{
//如果是普通数据,那么直接put进去,普通数据就是username和password这些字符串
map.put(fileItem.getFieldName(), fileItem.getString());
}
//如果是文件数据,也就是二进制数据
else
{
//通过FileItem获取到输入流的对象,通过输入流可以获取到图片
InputStream is=fileItem.getInputStream();
//创建文件
File finalFile=new File("C:/Users/1/Desktop/","1.jpg");
System.out.println("finalFile====="+finalFile.getPath());
if (!finalFile.exists())
{
finalFile.createNewFile();
}
//将输入流拷贝到输出流中,这个输出流指定了finalFile文件对象
OutputStream os=new FileOutputStream(finalFile);
IOUtils.copy(is, os);
//然后把总的文件名放入map中
map.put("picture",finalFile.getPath());
//释放资源,必须释放,不然页面显示不了,因为文件被占用了
IOUtils.closeQuietly(is);
IOUtils.closeQuietly(os);
}
}
//利用BeanUtils把map中的数据填充到user上
BeanUtils.populate(user, map);
//将user的数据放到数据库中,这里就不写了
//跳转到显示图片页面
response.sendRedirect(request.getContextPath()+"/show.jsp");
} catch (Exception e)
{
e.printStackTrace();
}
}
重复文件名问题
我们上传到同一个文件夹的时候,如果有相同的文件名,原有的文件就会被覆盖,所以需要让每个文件名不同
如果是图片数据,那么就使用工具类重新获取文件名
工具类源码,看的懂就看,看不懂就用
public class UploadUtils {
/**
* 获取随机名称
* @param realName 真实名称
* @return uuid
*/
public static String getUUIDName(String realName){
//realname 可能是 1.jpg 也可能是 1
//获取后缀名,防止有的人故意把后缀改了,这样就异常了
int index = realName.lastIndexOf(".");
if(index==-1){
return UUID.randomUUID().toString().replace("-", "").toUpperCase();
}else{
return UUID.randomUUID().toString().replace("-", "").toUpperCase()+realName.substring(index);
}
}
/**
* 获取文件真实名称
* @param name
* @return
*/
public static String getRealName(String name){
// c:/upload/1.jpg 1.jpg
//获取最后一个"/"
int index = name.lastIndexOf("\\");
return name.substring(index+1);
}
/**
* 获取文件目录
* @param name 文件名称
* @return 目录
*/
public static String getDir(String name){
int i = name.hashCode();
String hex = Integer.toHexString(i);
int j=hex.length();
for(int k=0;k<8-j;k++){
hex="0"+hex;
}
//想要几层目录就写几个hex.charAt
return "/"+hex.charAt(0)+"/"+hex.charAt(1);
}
@SuppressWarnings("unused")
public static void main(String[] args) {
//String s="G:\\day17-基础加强\\resource\\1.jpg";
String s="1.jgp";
String realName = getRealName(s);
//System.out.println(realName);
String uuidName = getUUIDName(realName);
//System.out.println(uuidName);
String dir = getDir(realName);
System.out.println(dir);
}
}
多级目录的问题
上面通过工具类解决了重复文件名
但是还有一个新的文件,那么就是一个文件夹下如果有很多很多图片,那么是导致性能非常非常慢
你打开一个有几十万图片的文件夹,肯定会卡爆,所以应该分很多层目录