在servlet中怎样上传文件?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在servlet中怎样上传文件?相关的知识,希望对你有一定的参考价值。

//新建一个Smartupload对象
SmartUpload su=new SmartUpload();
//上传初始化
su.initialize(pageContext);
//设定上传限度
//1.限定每个上传文件的最大长度
//su.setMaxFileSize(100000);
//2.限制总上传数据的长度。
//su.setTotalMaxFileSize(20000);
//3.设定允许上传的文件(通过扩展名限制),仅允许doc,txt文件。
//su.setAllowFilesList("doc,text");
//4.设定禁止上传的文件(通过扩展名限制),禁止上传带有exe,bat,jsp,htm,html扩展名的文件或没有扩展名的文件
//su.setDeniedDilesList("exe,bat,jsp,html,htm,,");
//上传文件
su.upload();
//将上传文件全部保存到指定目录
int count=su.save("/upload");
out.println(count+"个上传文件成功!<br>");
//利用Request对象获取参数之值
out.println("test="+su.getRequest().getParameter("test")+"<br><br>");
//逐一提取上传文件信息,同时可保存文件。
for(int i=0;i<su.getFiles().getCount();i++)

com.jspsmart.upload.File file=su.getFiles().getFile(i);
//若文件不存在则继续
if(file.isMissing())
continue;
//显示当前文件信息
out.println("<table border=1>");
out.println("<tr><td>表单项名(FiledName)</td><td>"+file.getFieldName()+"</tr></tr>");
out.println("<tr><td>文件长度(Size)</td><td>"+file.getSize()+"</td><td>");
out.println("<tr><td>文件名(FileName)</td><td>"+file.getFileName()+"</tr></tr>");
out.println("<tr><td>文件扩展名(FiledExt)</td><td>"+file.getFileExt()+"</tr></tr>");
out.println("<tr><td>文件全名(FiledPathName)</td><td>"+file.getFilePathName()+"</tr></tr>");
out.println("</table><br>");
//将文件另存
//file.saveAs("/upload/"+myFile.getFileName());
//另存到以web应用程序的根目录为文件根目录的目录下
//file.saveAs("/upload/"+myFile.getFileName(),su.SAVE_VIRTUAL);
//另存到操作系统的根目录为文件根目录的目录下
//file.safeAs("c://temp//"+myFile.getFileName(),su.SAVE_PHYSICAL);


上面就是了。。。。祝你好运哈!
参考技术A //新建一个Smartupload对象
SmartUpload su=new SmartUpload();
//上传初始化
su.initialize(pageContext);
//设定上传限度
//1.限定每个上传文件的最大长度
//su.setMaxFileSize(100000);
//2.限制总上传数据的长度。
//su.setTotalMaxFileSize(20000);
//3.设定允许上传的文件(通过扩展名限制),仅允许doc,txt文件。
//su.setAllowFilesList("doc,text");
//4.设定禁止上传的文件(通过扩展名限制),禁止上传带有exe,bat,jsp,htm,html扩展名的文件或没有扩展名的文件
//su.setDeniedDilesList("exe,bat,jsp,html,htm,,");
//上传文件
su.upload();
//将上传文件全部保存到指定目录
int count=su.save("/upload");
out.println(count+"个上传文件成功!<br>");
//利用Request对象获取参数之值
out.println("test="+su.getRequest().getParameter("test")+"<br><br>");
//逐一提取上传文件信息,同时可保存文件。
for(int i=0;i<su.getFiles().getCount();i++)

com.jspsmart.upload.File file=su.getFiles().getFile(i);
//若文件不存在则继续
if(file.isMissing())
continue;
//显示当前文件信息
out.println("<table border=1>");
out.println("<tr><td>表单项名(FiledName)</td><td>"+file.getFieldName()+"</tr></tr>");
out.println("<tr><td>文件长度(Size)</td><td>"+file.getSize()+"</td><td>");
out.println("<tr><td>文件名(FileName)</td><td>"+file.getFileName()+"</tr></tr>");
out.println("<tr><td>文件扩展名(FiledExt)</td><td>"+file.getFileExt()+"</tr></tr>");
out.println("<tr><td>文件全名(FiledPathName)</td><td>"+file.getFilePathName()+"</tr></tr>");
out.println("</table><br>");
//将文件另存
//file.saveAs("/upload/"+myFile.getFileName());
//另存到以web应用程序的根目录为文件根目录的目录下
//file.saveAs("/upload/"+myFile.getFileName(),su.SAVE_VIRTUAL);
//另存到操作系统的根目录为文件根目录的目录下
//file.safeAs("c://temp//"+myFile.getFileName(),su.SAVE_PHYSICAL);


上面就是了。。。。祝你好运哈!
参考技术B 编写一个文件上传类。
用到fileupload。
要是直接在页面上传文件,建议用smartfileupload.
参考技术C 你的意思说的不是很明白,是怎么样用servlet往服务器上传文件吗?如果是的话,只要写一个小工具,就是文件上传工具,主要方法的代码如下:
public String uploadFile(HttpServletRequest request)

try

DiskFileItemFactory factory= new DiskFileItemFactory();
ServletFileUpload upload= new ServletFileUpload(factory);
List<FileItem> list = upload.parseRequest(request);
String encoding=request.getCharacterEncoding();
upload.setHeaderEncoding(encoding);
upload.setFileSizeMax(fileMaxSize);
for(FileItem fileItem : list)
String fileName = fileItem.getFieldName();
if(fileItem.isFormField())
if("send".equals(fileName))
edto.setSend(fileItem.getString(encoding));

if("incept".equals(fileName))
edto.setIncept(fileItem.getString(encoding));

if("theme".equals(fileName))
edto.setTheme(fileItem.getString(encoding));

if("letter".equals(fileName))
edto.setLetter(fileItem.getString(encoding));


else
if("file".equals(fileName))
String sourceFilePath = fileItem.getName();
if(sourceFilePath!="")
if(fileItem.getSize()>fileMaxSize)
return "文件过大,不能上传!";

HttpSession session =request.getSession();
String serverPath = session.getServletContext().getRealPath("");
String savePath = serverPath + "\\userfile";
String saveFileName =GetSaveFileName.getFileName(edto.getIncept(),edto.getSend(),sourceFilePath);
InputStream in = fileItem.getInputStream();
edto.setSaveFileName(saveFileName);

this.saveFile(savePath,saveFileName, in);






保存上传的文件到服务器:
//保存文件到服务器
private void saveFile(String savePath,String saveFileName,InputStream in) throws IOException

File file=new File(savePath);

if(!file.exists())
file.mkdirs();


FileOutputStream out =new FileOutputStream(savePath+"\\"+saveFileName);

byte [] b =new byte[1024];

int len = in.read(b);

while(len!=-1)
out.write(b, 0, len);
out.flush();
len = in.read(b);

out.close();
in.close();

在 servlet 应用程序中保存上传文件的推荐方法

【中文标题】在 servlet 应用程序中保存上传文件的推荐方法【英文标题】:Recommended way to save uploaded files in a servlet application 【发布时间】:2022-01-08 17:19:31 【问题描述】:

我读到here 不应该将文件保存在服务器中,因为它不可移植、事务性且需要外部参数。但是,鉴于我需要一个用于 tomcat (7) 的 tmp 解决方案,并且我对我想知道的服务器机器具有(相对)控制权:

保存文件的最佳位置是什么?我应该将它保存在/WEB-INF/uploads(建议不要使用here)还是$CATALINA_BASE(见here)下的某个地方还是...? JavaEE 6 教程gets the path from the user (:wtf:)。注意:该文件不应以任何方式下载。

我应该像here那样设置一个配置参数吗?我会很感激一些代码(我宁愿给它一个相对路径 - 所以它至少是 Tomcat 可移植的) - Part.write() 看起来很有希望 - 但显然需要一个绝对路径

我想了解一下这种方法与数据库/JCR 存储库相比的缺点

不幸的是,@BalusC 的FileServlet 专注于下载文件,而他的answer 上传文件则跳过了保存文件的部分。

更可取的是可轻松转换为使用 DB 或 JCR 实现的解决方案(如 jackrabbit)。

【问题讨论】:

关于我的最终方法,请参阅answer below 【参考方案1】:

将其存储在 IDE 项目文件夹(即服务器的部署文件夹)的可访问位置 除了 的任何位置,原因在Uploaded image only available after refreshing the page 的答案中提到:

    IDE 项目文件夹中的更改不会立即反映在服务器的工作文件夹中。 IDE 中有一种后台作业,它负责服务器的工作文件夹与上次更新同步(这在 IDE 术语中称为“发布”)。这是您看到的问题的主要原因。

    在现实世界的代码中,有时将上传的文件存储在 webapp 的部署文件夹中根本不起作用。一些服务器(默认情况下或通过配置)不会将部署的 WAR 文件扩展至本地磁盘文件系统,而是完全扩展至内存中。如果不基本上编辑已部署的 WAR 文件并重新部署它,则无法在内存中创建新文件。

    即使服务器将部署的 WAR 文件扩展至本地磁盘文件系统,所有新创建的文件在重新部署甚至简单重启时都会丢失,这仅仅是因为这些新文件不是原始 WAR 文件的一部分。

只要你do not ever use getRealPath() method,它将被保存在本地磁盘文件系统的哪个位置对我或其他任何人来说都无关紧要。使用该方法在任何情况下都会令人担忧。

存储位置的路径又可以通过多种方式定义。您必须自己全部完成。也许这就是造成您困惑的地方,因为您以某种方式期望服务器会自动执行所有操作。请注意,@MultipartConfig(location) 确实没有指定最终上传目的地,但案例文件大小的临时存储位置超过了内存存储阈值。

因此,最终存储位置的路径可以通过以下任一方式定义:

硬编码:

  File uploads = new File("/path/to/uploads");

环境变量通过SET UPLOAD_LOCATION=/path/to/uploads:

  File uploads = new File(System.getenv("UPLOAD_LOCATION"));

服务器启动期间的VM参数通过-Dupload.location="/path/to/uploads"

  File uploads = new File(System.getProperty("upload.location"));

*.properties 文件条目为upload.location=/path/to/uploads:

  File uploads = new File(properties.getProperty("upload.location"));

web.xml&lt;context-param&gt;,名称为upload.location,值为/path/to/uploads

  File uploads = new File(getServletContext().getInitParameter("upload.location"));

如果有,请使用服务器提供的位置,例如在JBoss AS/WildFly:

  File uploads = new File(System.getProperty("jboss.server.data.dir"), "uploads");

无论哪种方式,您都可以轻松引用并保存文件,如下所示:

File file = new File(uploads, "somefilename.ext");

try (InputStream input = part.getInputStream()) 
    Files.copy(input, file.toPath());

或者,当您想要自动生成唯一的文件名以防止用户覆盖具有相同名称的现有文件时:

File file = File.createTempFile("somefilename-", ".ext", uploads);

try (InputStream input = part.getInputStream()) 
    Files.copy(input, file.toPath(), StandardCopyOption.REPLACE_EXISTING);

如何在JSP/Servlet中获得part在How to upload files to server using JSP/Servlet?中回答,如何在JSF中获得part在How to upload file using JSF 2.2 <h:inputFile>? Where is the saved File?中回答

注意:不要使用Part#write(),因为它会解释相对于@MultipartConfig(location) 中定义的临时存储位置的路径。还要确保您不会通过错误地使用Reader/Writer 而不是InputStream/OutputStream,在读/写期间将字节转换为字符来损坏二进制文件,例如PDF文件或图像文件。

另见:

How to save uploaded file in JSF(针对JSF,但原理差不多) Simplest way to serve static data from outside the application server in a Java web application(如果你想把它送回去) How to save generated file temporarily in servlet based web application

【讨论】:

@MultipartConfig(location) 指定当文件大小超过内存存储阈值时服务器应使用的 临时 存储位置,而不是您最终的永久存储位置喜欢它被存储。此值默认为由java.io.tmpdir 系统属性标识的路径。另请参阅对失败的 JSF 尝试的相关答案:***.com/questions/18478154/… 谢谢-希望我听起来不是白痴,但是 Part.write >> This allows a particular implementation to use, for example, file renaming, where possible, rather than copying all of the underlying data, thus gaining a significant performance benefit 的这句话加上一些未知的“剪切”(相对于复制)方法从说一些 apache lib 可以节省我自己编写字节的麻烦 - 并重新创建一个已经存在的文件(另见here) 是的,如果你已经在使用 Servlet 3.0,你可以使用Part#write()。我用它更新了答案。 非常感谢您更新帖子 - Tomcat 是否有 "jboss.server.data.dir" 这样的属性? 不,它没有。【参考方案2】:

我根据接受的答案发布我的最终方法:

@SuppressWarnings("serial")
@WebServlet("/")
@MultipartConfig
public final class DataCollectionServlet extends Controller 

    private static final String UPLOAD_LOCATION_PROPERTY_KEY="upload.location";
    private String uploadsDirName;

    @Override
    public void init() throws ServletException 
        super.init();
        uploadsDirName = property(UPLOAD_LOCATION_PROPERTY_KEY);
    

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException 
        // ...
    

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException 
        Collection<Part> parts = req.getParts();
        for (Part part : parts) 
            File save = new File(uploadsDirName, getFilename(part) + "_"
                + System.currentTimeMillis());
            final String absolutePath = save.getAbsolutePath();
            log.debug(absolutePath);
            part.write(absolutePath);
            sc.getRequestDispatcher(DATA_COLLECTION_JSP).forward(req, resp);
        
    

    // helpers
    private static String getFilename(Part part) 
        // courtesy of BalusC : http://***.com/a/2424824/281545
        for (String cd : part.getHeader("content-disposition").split(";")) 
            if (cd.trim().startsWith("filename")) 
                String filename = cd.substring(cd.indexOf('=') + 1).trim()
                        .replace("\"", "");
                return filename.substring(filename.lastIndexOf('/') + 1)
                        .substring(filename.lastIndexOf('\\') + 1); // MSIE fix.
            
        
        return null;
    

在哪里:

@SuppressWarnings("serial")
class Controller extends HttpServlet 

    static final String DATA_COLLECTION_JSP="/WEB-INF/jsp/data_collection.jsp";
    static ServletContext sc;
    Logger log;
    // private
    // "/WEB-INF/app.properties" also works...
    private static final String PROPERTIES_PATH = "WEB-INF/app.properties";
    private Properties properties;

    @Override
    public void init() throws ServletException 
        super.init();
        // synchronize !
        if (sc == null) sc = getServletContext();
        log = LoggerFactory.getLogger(this.getClass());
        try 
            loadProperties();
         catch (IOException e) 
            throw new RuntimeException("Can't load properties file", e);
        
    

    private void loadProperties() throws IOException 
        try(InputStream is= sc.getResourceAsStream(PROPERTIES_PATH)) 
                if (is == null)
                    throw new RuntimeException("Can't locate properties file");
                properties = new Properties();
                properties.load(is);
        
    

    String property(final String key) 
        return properties.getProperty(key);
    

和 /WEB-INF/app.properties :

upload.location=C:/_/

HTH,如果您发现错误,请告诉我

【讨论】:

如果我想要一个在 (win/ux) 情况下都适用的 SO 独立解决方案怎么办?我必须设置不同的 upload.location 路径还是有其他提示?

以上是关于在servlet中怎样上传文件?的主要内容,如果未能解决你的问题,请参考以下文章

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

使用Servlet上传文件

基于Servlet+smartUpload的文件上传

Servlet文件上传下载使用详解

Servlet中服务器端接收上传文件操作

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