通用上传Servlet

java判断文件类型参考: http://blog.csdn.net/shixing_11/article/details/5708145

目前使用的项目结构是:spring+springmvc+mybatis.

文件上传需要考虑两个地方:

1. 文件上传的安全性,脚本等文件是可以通过更改文件的后缀来提交的,这也是大多数网站通过上传渗入的方式.

2. 对非保存的文件删除,上传的文件,如果操作人没有进行保存或其他操作,需要清除文件.

本上传使用的包:

commons-fileupload
javax.servlet-api

我比较喜欢大段大段的上传,So,我就不客气啦~

package com.guoke.basic.servlet;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.log4j.Logger;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.*;

/**
 * 通用文件上传servlet
 */
@SuppressWarnings("serial")
@WebServlet(urlPatterns = "/upload")
public class UploadServlet extends HttpServlet {
    /**
     * LOG4j 日志
     */
    protected final Logger LOG = Logger.getLogger(this.getClass());

    /**
     * 文件类型
     */
    protected final static Map<String, String> FILE_TYPE = new HashMap<>();

    /**
     * 初始化文件头部信息
     */
    static {
        getFileType();
    }

    /**
     * 常见文件头十六进制
     */
    protected static void getFileType() {
        FILE_TYPE.put("jpg", "FFD8FF"); //JPEG (jpg)
        FILE_TYPE.put("png", "89504E47");  //PNG (png)
        FILE_TYPE.put("gif", "47494638");  //GIF (gif)
        FILE_TYPE.put("tif", "49492A00");  //TIFF (tif)
        FILE_TYPE.put("bmp", "424D"); //Windows Bitmap (bmp)
        FILE_TYPE.put("dwg", "41433130"); //CAD (dwg)
        FILE_TYPE.put("html", "68746D6C3E");  //HTML (html)
        FILE_TYPE.put("rtf", "7B5C727466");  //Rich Text Format (rtf)
        FILE_TYPE.put("xml", "3C3F786D6C");
        FILE_TYPE.put("zip", "504B0304");
        FILE_TYPE.put("rar", "52617221");
        FILE_TYPE.put("psd", "38425053");  //Photoshop (psd)
        FILE_TYPE.put("eml", "44656C69766572792D646174653A");  //Email [thorough only] (eml)
        FILE_TYPE.put("dbx", "CFAD12FEC5FD746F");  //Outlook Express (dbx)
        FILE_TYPE.put("pst", "2142444E");  //Outlook (pst)
        FILE_TYPE.put("xls", "D0CF11E0");  //MS Word
        FILE_TYPE.put("doc", "D0CF11E0");  //MS Excel 注意:word 和 excel的文件头一样
        FILE_TYPE.put("mdb", "5374616E64617264204A");  //MS Access (mdb)
        FILE_TYPE.put("wpd", "FF575043"); //WordPerfect (wpd)
        FILE_TYPE.put("eps", "252150532D41646F6265");
        FILE_TYPE.put("ps", "252150532D41646F6265");
        FILE_TYPE.put("pdf", "255044462D312E");  //Adobe Acrobat (pdf)
        FILE_TYPE.put("qdf", "AC9EBD8F");  //Quicken (qdf)
        FILE_TYPE.put("pwl", "E3828596");  //Windows Password (pwl)
        FILE_TYPE.put("wav", "57415645");  //Wave (wav)
        FILE_TYPE.put("avi", "41564920");
        FILE_TYPE.put("ram", "2E7261FD");  //Real Audio (ram)
        FILE_TYPE.put("rm", "2E524D46");  //Real Media (rm)
        FILE_TYPE.put("mpg", "000001BA");  //
        FILE_TYPE.put("mov", "6D6F6F76");  //Quicktime (mov)
        FILE_TYPE.put("asf", "3026B2758E66CF11"); //Windows Media (asf)
        FILE_TYPE.put("mid", "4D546864");  //MIDI (mid)
    }

    /**
     * 处理post请求上传文件
     *
     * @param req HttpServletRequest对象
     * @param res HttpServletResponse 对象
     * @throws ServletException 异常处理
     * @throws IOException      异常处理
     */
    protected void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
        PrintWriter out = res.getWriter();//声明输出打印流
        // 上传的文件路径
        String uploadPath = this.getServletContext().getRealPath(File.separator);
        String isRename = "";// 是否重命名 true:重命名
        //存放文件上传的临时目录路径
        String _tempPath = req.getServletContext().getRealPath(File.separator) + "temp";
        createFolder(_tempPath);//创建文件夹
        File tempPath = new File(_tempPath); // 用于存放临时文件的目录
        // 允许上传文件大小,最大上传文件,单位:字节 1000000/1024=0.9M
        int maxSize = 1000000;
        // 默认允许上传文件,建议设置允许上传的文件,方便
        String allowedFile = ".jpg,.gif,.png,.zip";
//        String deniedFile = ".exe,.com,.cgi,.asp"; // 默认不允许上传的文件
        //FileItem 对象的工厂,设定缓冲区大小和存放临时文件目录
        DiskFileItemFactory factory = new DiskFileItemFactory();
        // 允许设置内存中存储数据的门限,单位:字节
        factory.setSizeThreshold(4096);
        // 如果文件大小大于SizeThreshold,则保存到临时目录
        factory.setRepository(tempPath);
        //处理表单数据,将数据封装到 FileItem 对象中。处理上传的文件的数据,
        // 优先保存在缓冲区,如果数据超过了缓冲区大小,则保存到硬盘上,
        // 存储在DiskFileItemFactory指定目录下的临时文件。数据都接收完后,
        // 它再在从临时文件中将数据写入到上传文件目录下的指定文件中,并删除临时文件。
        ServletFileUpload upload = new ServletFileUpload(factory);

        try {
            //解析request请求
            List<FileItem> fileItems = upload.parseRequest(req);
            Iterator<FileItem> iterator = fileItems.iterator();
            String outPath = ""; //输出保存后的图片路径
            while (iterator.hasNext()) {
                //用来封装表单中的元素和数据。
                FileItem item = iterator.next();
                //获取name属性的值,是否存在上传路径
                if (item.getFieldName().equals("uploadPath")) {
                    outPath += item.getString();
                    uploadPath += outPath;
                    //获取name属性的值,是否重命名
                } else if (item.getFieldName().equals("isRename")) {
                    isRename = item.getString();
                    //获取最大上传文件大小
                } else if (item.getFieldName().equals("maxSize")) {
                    maxSize = Integer.parseInt(item.getString()) * 1048576;
                    //允许上传的文件类型
                } else if (item.getFieldName().equals("allowedFile")) {
                    allowedFile = item.getString();
//                } else if (item.getFieldName().equals("deniedFile")) {
//                    deniedFile = item.getString();
                } else if (!item.isFormField()) { // 忽略其他不是文件域的所有表单信息
                    String name = item.getName();//客户端的文件系统中的原始文件名
                    long size = item.getSize();//文件的大小,以字节为单位
                    //文件上传的类型
                    String fileTypeStr = name.substring(name.indexOf("."));
                    // 允许上传的文件类型
                    String[] allowFileType = allowedFile.split(",");
                    boolean isAllowFile = false;//是否是允许上传
                    for (String str : allowFileType) {
                        if (fileTypeStr.replaceAll("\\.", "").equals(str.replaceAll("\\.", ""))) {
                            isAllowFile = true;
                        }
                    }
                    if (!isAllowFile) {
                        //删除文件
                        tempPath.delete();
                    }

                    if ((name == null || name.equals("")) && size == 0)
                        continue;
                    try {
                        // 最大上传文件,单位:字节 1000000/1024=0.9M
                        upload.setSizeMax(maxSize);

                        // 保存上传的文件到指定的目录
                        // 在下文中上传文件至数据库时,将对这里改写
                        String fileName = System.currentTimeMillis() + fileTypeStr;
                        String savePath = uploadPath + File.separator;
                        //创建文件
                        createFolder(savePath);
                        // 重命名
                        if (isBlank(isRename) || Boolean.parseBoolean(isRename)) {
                            savePath += fileName;
                            outPath += fileName;
                        } else {
                            savePath += name;
                            outPath += name;
                        }
                        File newFile = new File(savePath);
                        item.write(newFile);//把上传的内容写到一个文件中
                        out.print(outPath.trim());
                        //对比文件上传类型是否和实际类型不相等
                        if (!getFileType(newFile).equals(fileTypeStr.replaceAll("\\.", ""))) {
                            //删除文件
                            newFile.delete();
                            LOG.debug("file is delete");
                        } else {
                            LOG.debug("upload file ok return path " + outPath);
                        }
                        out.flush();
                        out.close();
                    } catch (Exception e) {
                        this.LOG.debug(e);
                    }
                }
            }
        } catch (FileUploadException e) {
            this.LOG.debug(e);
        }
    }

    /**
     * 根据路径创建文件或文件夹
     * @param path 文件路径
     * @return 返回boolean值,true创建成功,false创建失败
     */
    public static boolean createFolder(String path) {
        File file = new File(path);
        return !file.exists() && file.mkdirs();
    }

    /**
     * 判断对象是否等于null,如果为字符串则还需要判断是否等于“”或“ ”
     * @param obj string
     * @return if is blank,return true, else ,return false
     */
    public static boolean isBlank(Object obj){
        //如果是字符串类型,则先清除前后空格符
        if(obj instanceof String){
            obj=((String) obj).trim();
        }
        //判断对象是否为null  hash判断 java7提供!
        return Objects.hash(obj) == 0;
    }

    /**
     * 获取文件头类型
     *
     * @param file 文件
     * @return 文件头部类型字符串
     */
    protected String getFileType(File file) {
        String fileType = null;
        byte[] b = new byte[50];
        if (file.exists()) {
            try {
                //
                InputStream is = new FileInputStream(file);
                //从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b 中。
                is.read(b);
                //获取文件类型
                fileType = getFileTypeByStream(b);
                is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return fileType;
    }

    /**
     * 从文件的数据流中对比文件头部信息
     *
     * @param b 字节数组
     * @return 文件头
     */
    protected String getFileTypeByStream(byte[] b) {
        //将字节数组转成字符串
        String filetypeHex = String.valueOf(getFileHexString(b));
        //迭代map
        Set<Map.Entry<String, String>> entrySet = FILE_TYPE.entrySet();
        for(Map.Entry<String, String> entry:entrySet){
            //判断字符串的开头是否包含对应的文件头
            if (filetypeHex.toUpperCase().startsWith(entry.getValue())) {
                return entry.getKey();
            }
        }
        return null;
    }

    /**
     * 将十六进制字节转成字符串
     *
     * @param byteArray 字节数组
     * @return 转换后的字符串
     */
    protected static String getFileHexString(byte[] byteArray) {
        //单线程比StringBuffer 要快
        StringBuilder stringBuilder = new StringBuilder();
        if (byteArray == null || byteArray.length <= 0) {
            return null;
        }
        for (byte b : byteArray) {
            int v = b & 0xFF; //将原来的负值变成正值
            //以十六进制(基数 16)无符号整数形式返回一个整数参数的字符串表示形式。
            String hv = Integer.toHexString(v);
            if (hv.length() < 2) {
                stringBuilder.append(0);
            }
            stringBuilder.append(hv);
        }
        return stringBuilder.toString();
    }

}
时间: 2024-08-26 00:56:29

通用上传Servlet的相关文章

文件上传 servlet 从HttpServletRequest.getInputStream()中获得消息内容

前段时间采用spring谢了文件上传,但是跟手机端调试时,发现他们的插件只能使用原生的数据流的形式上传文件,根据HTTP的规范看了下上传文件的消息体,写了如下的方法,供大家使用: @Note(note = "bigAnt:servlet上传文件", author = "zhangwenbo")    @RequestMapping("modifyPictureByStream2")    @ResponseBody    public Simpl

C# 通用上传文件类

1.Upfile.aspx: <%@ Page Language="C#" AutoEventWireup="true" CodeFile="Upfile.aspx.cs" Inherits="Inc_Upfile" %><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.or

当php懈垢windows通用上传缺陷

转自独自等待博客 早上逛乌云发现了PKAV大牛的一篇文章,针对php和windows文件上传的分析,思路很YD,果断转之与大家分享. 虽然此文可能有许多的限制条件,但是如果你认真阅读会发现,其实还是比较实用的. 另外一篇团长发的pdf中也涉及到了相关的文章,是国外的nosec发布的,英文的,感兴趣的同学在这里下载 点我下载 #1 实例介绍 本案例采用的实例是:U-Mail邮件系统. U-Mail邮件系统文件上传的地方代码是这样的: <?php if(ACTION =="attach-upl

pkav之当php懈垢windows通用上传缺陷

$pkav->publish{当php懈垢windows}剑心@xsser抛弃了我,但我却不能抛弃乌云..php懈垢windows,就像男人邂逅女人,早晚都会出问题的..感谢二哥@gainoverTips:本文讲述一种新型的文件上传方式(几个特性导致的漏洞),并给出相应的实例.. 详细说明: #1 实例介绍 本案例采用的实例是:U-Mail邮件系统. U-Mail邮件系统文件上传的地方代码是这样的: code 区域 <?php if(ACTION =="attach-upload&q

当php邂逅windows通用上传缺陷

早上逛乌云发现了PKAV大牛的一篇文章,针对php和windows文件上传的分析,思路很YD,果断转之与大家分享. 虽然此文可能有许多的限制条件,但是如果你认真阅读会发现,其实还是比较实用的. 另外一篇团长发的pdf中也涉及到了相关的文章,是国外的nosec发布的,英文的,感兴趣的同学在这里下载http://pan.baidu.com/s/1hqiQRbA 本案例采用的实例是:U-Mail邮件系统. U-Mail邮件系统文件上传的地方代码是这样的: <?php if(ACTION =="a

使用jsp/servlet简单实现文件上传与下载

使用JSP/Servlet简单实现文件上传与下载 通过学习黑马jsp教学视频,我学会了使用jsp与servlet简单地实现web的文件的上传与下载,首先感谢黑马.好了,下面来简单了解如何通过使用jsp与servlet实现文件上传与下载. 在写代码之前,我们需要导入两个额外的jar包,一个是common-io-2.2.jar,另一个是commons-fileupload-1.3.1.jar,将这个两个jar 包导入WEB-INF/lib目录里. 首先,想要在web端即网页上实现文件上传,必须要提供

Servlet方式实现文件的上传和下载

文件的上传和下载需要两个jar包  commons-fileupload-1.2.2.jar和commons-io-2.0.1.jar JSP页面 <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Trans

文件上传(Servlet/Struts2/SpringMVC)

文件上传 Servlet实现 要实现文件上传的功能,必须在form的表单中的添加 enctype="multipart/form-data" 表示以二进制流的方式将文件传给控制器. 需要导入的jar包有:commons-fileupload-1.2.1.jar.commons-io-1.4.jar 文件上传的步骤: (1)创建DiskFileItemFactory的对象. (2)创建ServletFileUpload的对象,需传入DiskFileItemFactory的对象.可以获得封

Spring MVC文件上传和下载

在Spring MVC中有两种实现上传文件的办法,第一种是Servlet3.0以下的版本通过commons-fileupload与commons-io完成的通用上传,第二种是Servlet3.0以上的版本的Spring内置标准上传,不需借助第3方组件.通用上传也兼容Servlet3.0以上的版本 Servlet3.0以下的通过commons-fileupload上传 1.添加上传依赖包 一个是文件上传的jar包,一个是其所依赖的IO包.这两个jar包,均在Spring支持库的org.apache