基础知识在前面一篇,文件上传代码。耐心看到后面的重构,简洁多了
重构代码下载:http://download.csdn.net/detail/xiaozhegaa/9782629
(一) 开发思路:代码看起来有点乱,但是是有思路的
1:工厂–>对象设计模式。创建工厂—–>设置一下工厂的属性,其中涉及了临时文件,那么在源码第一二行先取得上传的真实路径和临时路径
2:得到对象,先设置上传文件的字符编码问题,然后判断是否是MIME协议提交
> 3.1:若不是MIME协议提交,抛异常,提示说要用MIME提交,若不然就收集不到数据哦
>> 3.2 : 若是MIME协议提交,则要把上传的内容转化成FileItemList。也就是用parseRequest()
4:取到list集合之后,循环遍历,判断是否是普通字段
>> 5:如果是普通字段的话,那么采用一般的bean装在就可以 //user.getUsername(“xxx”)
> > 6:否则就文件字段,那么对文件进行处理
7:这是扩展的功能:各种if
>>7.1 :if(fileItem.endWith(“jpg”)) //上传是jpg,给不给通过
>>7.2 :if(fileItem.getSize()==0) //空文件,给不给通过,还是抛异常
> >7.3 :if(fileItem.gizeSize() > 1024 * 200) //文件大于200k,给不给通过
> >7.4 :………等等
8:然后就读写数据,is.readLine(),os.write()。java基础固定写法
9:删除临时文件
10:显示上传成功页面
public class UploadServlet2 extends HttpServlet {
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//取得上传的真实路径和临时路径
String tempPath = this.getServletContext().getRealPath("/WEB-INF/temp");
String uploadPath = this.getServletContext().getRealPath("/WEB-INF/upload");
//使用第一个类u
//创建上传文件的工厂
DiskFileItemFactory fileItemFactory = new DiskFileItemFactory();
//设置内存中的缓冲区大小。10k
fileItemFactory.setSizeThreshold(1024*10);
//设置上传文件临时存放的目录
fileItemFactory.setRepository(new File(tempPath));
//使用第二个类
//创建上传文件的对象
ServletFileUpload servletFileUpload = new ServletFileUpload(fileItemFactory);
//设置上传文件名字的字符编码
servletFileUpload.setHeaderEncoding("UTF-8");
//判断客户端是否是采用那个了mime协议去上传文件
boolean flag = servletFileUpload.isMultipartContent(request);
if(!flag){
//也就是不是采用mime的协议上传文件,那么抛异常。这里也可以采用一般的方式去处理哦哦
throw new ServletException();
}else{
/*也就是说是采用了MIME的协议上传文件
* 解析request中的所有上传内容,并且把每个内容解析成fileItem对象
* fileItem代表的是普通字段跟文件字段两类
*/
try {
//使用第三个类
List<FileItem> fileItemList = servletFileUpload.parseRequest(request);
for(FileItem fileIem :fileItemList){
if(fileIem.isFormField()){
//如果说是普通的字段
String fileName = fileIem.getFieldName();
String fileValue = fileIem.getString("UTF-8");
System.out.println(fileName+"-----"+fileValue);
}else{
//这里是文件上传字段
String realFileName = fileIem.getName();
/*
* 对于ie浏览器的话上传路径是C:\Users\admin\Desktop\1.jpg,
* 而对于一些高级浏览器火狐之类的路径是1.jpg。
因此要对路径做一个处理。只需要1.jsp就可以
*/
int index = realFileName.lastIndexOf("\\");
if(index>=0){
//确实是ie浏览器
realFileName = realFileName.substring(index+1);
}
//通过真实的文件名换算出一个唯一的一个文件名
String makeUuidFileName = makeUuidFileName(realFileName);
//通过位运算换算出upload文件夹下面的子文件夹
String makeUuidFilePath = makeUuidFilePath(uploadPath,makeUuidFileName);
/*
*在读取文件之前可以先进行一系列判断,如果判断不通过,不给提交
*例如
*/
//如果无上传文件
if(fileItem.getSize()==0){
throw new NoUpfileException();
}
//只能上传JPG文件
if(!realFileName.endsWith("JPG")){
throw new UpfileTypeException();
}
//只有上传<=200K的文件
if(fileItem.getSize() > 200 * 1024){
throw new UpfileSizeException();
}
//等等各种限制条件,自己写
//获得到文件输入流
InputStream is = fileIem.getInputStream();
//取得文件输出流
OutputStream os = new FileOutputStream(makeUuidFilePath+"/"+makeUuidFileName);
byte[] buf = new byte[1024];
int len = 0;
while((len = is.read(buf)) > 0 ){
os.write(buf, 0, len);;
}
is.close();
os.close();
//将上传文件的临时文件删除
fileIem.delete();
request.setAttribute("message", "上传成功");
request.getRequestDispatcher("/WEB-INF/message.jsp").forward(request, response);
}
}
} catch (FileUploadException e) {
e.printStackTrace();
request.setAttribute("message","上传文件失败");
request.getRequestDispatcher("/WEB-INF/message.jsp").forward(request,response);
}
}
}
/**
*这个是防止说一个目录文件过多,采用&方式去推出二级目录之类的函数
*/
private String makeUuidFilePath(String uploadPath, String makeUuidFileName) {
String uuidFilePath = null;
int code = makeUuidFileName.hashCode(); //获得到文件的hascode码 8
int dir1 = code & 0xF; //3
int dir2 = code & 0xF; //8
File file = new File(uploadPath+"/"+dir1+"/"+dir2);
if(!file.exists()){
//如果说文件路径不存在的话,那么就一次创建多个目录
file.mkdirs();
}
uuidFilePath = file.getPath();
return uuidFilePath;
}
/**
*写一个算法,给每一张图片起一个唯一的名字,这样在上传同一张图片的时候就可以有多个
* @param fileName 图片的名字,最后加上文件的名字识别
* @return
*/
public String makeUuidFileName(String fileName){
return UUID.randomUUID().toString()+"_"+fileName;
}
</font>
(二) 第一种重构的方式比较简单:也就是把原代码中能够抽取出来的方法,全部抽取出来放在一个UploadUtil类中,然后再原来的方法中调用该静态方法就可以
注意:这里的源码没有列举出来,只是列举方法名而已。具体的实现源码我已经导成了一个jar包。如果有兴趣的可以下载该jar包研究一下啊。或者学习者自己重构
//取得上传的真实路径和临时路径
public static final String tempPath = "/WEB-INF/temp";
public static final String uploadPath ="/WEB-INF/upload";
/*
* 对于ie浏览器的话上传路径是C:\Users\admin\Desktop\1.jpg,
* 而对于一些高级浏览器火狐之类的路径是1.jpg。
因此要对路径做一个处理。只需要1.jsp就可以
*/
public static String getRealFileName(String realFileName){
//代码忽略了 return 1.jpg
return realFileName;
}
/**取得upload目录下面的子目录
* @param uploadPath :upload
* @param makeUuidFileName : a.jpg
* @return upload/8/8
*/
public static String makeUuidFilePath(String uploadPath, String makeUuidFileName) {
//代码忽略了 返回 upload/8/8
return uuidFilePath;
}
/**
* 取得文件的uuid名字
*写一个算法,给每一张图片起一个唯一的名字,这样在上传同一张图片的时候就可以有多个
* @param fileName 图片的名字,最后加上文件的名字识别
* @return
*/
public static String makeUuidFileName(String fileName){
return UUID.randomUUID().toString()+"_"+fileName;
}
/*
*文件保存,也就是Io流那个
*/
public static void doSave(InputStream is,String makeUuidFilePath ,String makeUuidFileName){
//代码忽略了 返回 true/false
return true/false
}
(三)第二种重构就更加的简洁了
只需要调用
UploadUtil.doUpload();
UploadUtil.doSave();
两个方法就可以实现保存。
这种简介的代码才是我们所追求的。
测试案例:
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws Exception {
try {
User user = UploadUtil.doUpload(request);
String uploadPath = this.getServletContext().getRealPath(UploadUtil.uploadPath);
UploadUtil.doSave(user,uploadPath);
request.setAttribute("message", "上传成功");
request.getRequestDispatcher("/WEB-INF/message.jsp").forward(request, response);
} catch (FileUploadException e) {
e.printStackTrace();
request.setAttribute("message", "上传失败");
request.getRequestDispatcher("/WEB-INF/message.jsp").forward(request, response);
}
}
//第二种封装方式,把上传文件分装成javaBean
public static User doUpload(HttpServletRequest request) throws Exception{
//代码忽略了
return user;
}
//javaBean的保存文件
public static void doSave(User user,String uploadPath) throws IOException{
//代码忽略了
}