java后台文件上传到资源服务器上

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java后台文件上传到资源服务器上相关的知识,希望对你有一定的参考价值。

在后台 生成了一个excel文件 由于项目做了负载均衡 不能将文件直接放在项目的根目录下 现在需要上传到资源服务器上 请问大神们怎么实现这个上传过程 谢谢!!!

package com.letv.dir.cloud.util;import com.letv.dir.cloud.controller.DirectorWatermarkController;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import java.io.*;import java.net.HttpURLConnection;import java.net.MalformedURLException;import java.net.URL;/** * Created by xijunge on 2016/11/24 0024. */public class HttpRequesterFile private static final Logger log = LoggerFactory.getLogger(HttpRequesterFile.class); private static final String TAG = "uploadFile"; private static final int TIME_OUT = 100 * 1000; // 超时时间 private static final String CHARSET = "utf-8"; // 设置编码 /** * 上传文件到服务器 * * @param file * 需要上传的文件 * @param RequestURL * 文件服务器的rul * @return 返回响应的内容 * */ public static String uploadFile(File file, String RequestURL) throws IOException
String result = null;
String BOUNDARY = "letv"; // 边界标识 随机生成 String PREFIX = "--", LINE_END = "\\r\\n";
String CONTENT_TYPE = "multipart/form-data"; // 内容类型 try
URL url = new URL(RequestURL);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setReadTimeout(TIME_OUT);
conn.setConnectTimeout(TIME_OUT);
conn.setDoInput(true); // 允许输入流 conn.setDoOutput(true); // 允许输出流 conn.setUseCaches(false); // 不允许使用缓存 conn.setRequestMethod("POST"); // 请求方式 conn.setRequestProperty("Charset", CHARSET); // 设置编码 conn.setRequestProperty("connection", "keep-alive");
conn.setRequestProperty("Content-Type", CONTENT_TYPE + ";boundary=" + BOUNDARY);
参考技术A 您好,common-fileupload是jakarta项目组开发的一个功能很强大的上传文件组件
下面先介绍上传文件到服务器(多文件上传):
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
import java.util.*;
import java.util.regex.*;
import org.apache.commons.fileupload.*;

public class upload extends HttpServlet
private static final String CONTENT_TYPE = "text/html; charset=GB2312";
//Process the HTTP Post request
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
response.setContentType(CONTENT_TYPE);
PrintWriter out=response.getWriter();
try
DiskFileUpload fu = new DiskFileUpload();
// 设置允许用户上传文件大小,单位:字节,这里设为2m
fu.setSizeMax(2*1024*1024);
// 设置最多只允许在内存中存储的数据,单位:字节
fu.setSizeThreshold(4096);
// 设置一旦文件大小超过getSizeThreshold()的值时数据存放在硬盘的目录
fu.setRepositoryPath("c://windows//temp");
//开始读取上传信息
List fileItems = fu.parseRequest(request);
// 依次处理每个上传的文件
Iterator iter = fileItems.iterator();
//正则匹配,过滤路径取文件名
String regExp=".+////(.+)$";
//过滤掉的文件类型
String[] errorType=".exe",".com",".cgi",".asp";
Pattern p = Pattern.compile(regExp);
while (iter.hasNext())
FileItem item = (FileItem)iter.next();
//忽略其他不是文件域的所有表单信息
if (!item.isFormField())
String name = item.getName();
long size = item.getSize();
if((name==null||name.equals("")) && size==0)
continue;
Matcher m = p.matcher(name);
boolean result = m.find();
if (result)
for (int temp=0;temp<ERRORTYPE.LENGTH;TEMP++)
if (m.group(1).endsWith(errorType[temp]))
throw new IOException(name+": wrong type");


try
//保存上传的文件到指定的目录
//在下文中上传文件至数据库时,将对这里改写
item.write(new File("d://" + m.group(1)));
out.print(name+" "+size+"");

catch(Exception e)
out.println(e);


else

throw new IOException("fail to upload");




catch (IOException e)
out.println(e);

catch (FileUploadException e)
out.println(e);




现在介绍上传文件到服务器,下面只写出相关代码:
以sql2000为例,表结构如下:
字段名:name filecode
类型: varchar image
数据库插入代码为:PreparedStatement pstmt=conn.prepareStatement("insert into test values(?,?)");
代码如下:
。。。。。。
try
这段代码如果不去掉,将一同写入到服务器中
//item.write(new File("d://" + m.group(1)));

int byteread=0;
//读取输入流,也就是上传的文件内容
InputStream inStream=item.getInputStream();
pstmt.setString(1,m.group(1));
pstmt.setBinaryStream(2,inStream,(int)size);
pstmt.executeUpdate();
inStream.close();
out.println(name+" "+size+" ");

。。。。。。
这样就实现了上传文件至数据库。

java前后台开发之文件上传

入职java已经快2个月了。做了一个多月的改bug,6天的开发,刚做完一个文件上传,得好好整理下。

文件上传的大体思路其实是一样的,前端通过表单的方式上传,后端解析这个表单请求中的内容,得到文件部分的字段,再以流的形式读到内存中,后面怎么处理看业务了,比如保存到服务器等等。

一、前端
对于我这种前端ui等比较差的,果断选择了bootstrap为我撑撑场面。不会的可以搜一搜学一学,挺好用的。就是为你提供一些漂亮的样式,排版,自适应以及一些比较方便的插件。比如这个文件上传,基于bootstrap刚好有一个方便的fileinput。

先来秀一下效果

是不是挺漂亮的,实际上没有多少是靠我自己写的。

1)首先准备环境,你得有bootstrap环境,它依赖于jquery,这个你也是要的,有网络的童鞋可以直接使用cdn,没有的可以自行下载

<!-- 新 Bootstrap 核心 CSS 文件 -->
<link
    href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css"
    rel="stylesheet">
<script
    src="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap-theme.min.css"></script>
<script src="https://cdn.bootcss.com/jquery/2.1.1/jquery.min.js"></script>
<script
    src="https://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>

接着是file input插件的环境,我是下载下来用的,下载地址为https://github.com/kartik-v/bootstrap-fileinput/archive/v4.4.3.zip
只需要两个文件,大家对号入座

<script src="XXXXXXXXX/fileinput.min.js"></script>
    <link
    href="XXXXXXXXXX/fileinput.min.css"
    rel="stylesheet">

2)使用,外面那个遮罩和框使用的是bootstrap的模态框,这里不介绍了。只说中间文件上传部分。

<input id="uploadfile" type="file" class="file file-loading">

没了,简介明了,你只要声明好它的class就好,多简单。

然后你在javascript中可以对它进行定制,比如我的需求是这样的:

//上传组件初始化
    $("#uploadfile").fileinput(
        language: 'zh', //设置语言
        uploadUrl: "$ctx/dataModel/uploadModel", //上传的地址
        allowedFileExtensions: ['doc','docx'],//接收的文件后缀
        uploadAsync: true, //默认异步上传
        showUpload: true, //是否显示上传按钮

        showRemove : true, //显示移除按钮
        showPreview : true, //是否显示预览
        showCaption: true,//是否显示标题
        browseClass: "btn btn-primary", //按钮样式     
        dropZoneEnabled: false,//是否显示拖拽区域
        maxFileCount: 1, //表示允许同时上传的最大文件个数
        enctype: 'multipart/form-data',
        validateInitialCount:true,
        uploadExtraData: function(previewId, index)    //额外参数
            var obj = ;
            obj.modelId = select.id;
            return obj;
        
    );

同时上传完毕的回调

//异步上传返回结果处理
    $("#uploadfile").on("fileuploaded", function (event, data, previewId, index) 
            var response = data.response;
        //....
        );

前端到此结束

二、后端
后端你可以使用多种方式,我这使用的是SpringMVC,所以我的处理过程是写在Controller中的。

/**
     * 上传模型
     */
    @RequestMapping(value = "/uploadModel",method = RequestMethod.POST)
    @ResponseBody
    public Object uploadModel(HttpServletRequest request,HttpServletResponse response)
//      String dataPortalDir = request.getRealPath("");    //dataPortal路径
        String dataPortalDir = "/Users/cd/Downloads/dataPortalSt";    //dataPortal路径
        String cacheDir = "/files/cache";
        String htmlDir = "/files/html";
        Map<String, Object> json = new HashMap<String, Object>();
        ShiroHttpServletRequest shiroRequest = (ShiroHttpServletRequest) request;

        //转换为multipartrequest
        CommonsMultipartResolver commonsMultipartResolver = new CommonsMultipartResolver();  
        MultipartHttpServletRequest multipartRequest = commonsMultipartResolver.resolveMultipart((HttpServletRequest) shiroRequest.getRequest());  


        /** 页面控件的文件流* */
        MultipartFile multipartFile = null;
        Map map =multipartRequest.getFileMap();
         for (Iterator i = map.keySet().iterator(); i.hasNext();) 
                Object obj = i.next();
                multipartFile=(MultipartFile) map.get(obj);

               

          //获取额外参数
               String modelId =  multipartRequest.getParameter("modelId");

        /** 获取文件的后缀* */
        String filename = multipartFile.getOriginalFilename();

        //拷贝文件
        InputStream inputStream;
        String htmlUrl = "";
        try 

            inputStream = multipartFile.getInputStream();
            String tmpFilePath = dataPortalDir+cacheDir+File.separator+UUIDUtil.getUUID()+
                    filename.substring(filename.lastIndexOf("."));
                    //保存到服务器
            tmpFilePath = FileUtil.copyInputStreamToFile(inputStream, tmpFilePath,false);

            System.out.println("copy file to:"+tmpFilePath);



         catch (Exception e) 
            e.printStackTrace();
        
        json.put("code", 0);
        json.put("message", "上传成功");
        json.put("result", htmlUrl);
        return json;
    

这里有点小问题,就是一开始拿到的request并不是MultipartHttpServletRequest,而是ShiroHttpServletRequest。做了一次转换之后才可以。

第二个问题是额外参数,通过转换后是存放在MultipartHttpServletRequest的multiParam…中的,在后端获取的时候通过MultipartHttpServletRequest的getParameter(“modelId”);直接拿到。- -这个折腾了我一下午

2017.09.18
今天发现这个后台上传貌似还有点问题在里面,我们的request被搭框架的整了下,不再是ShiroHttpServletRequest,此时强转会发生错误。这里经过改写后的方法为:

    @ResponseBody
    @RequestMapping(value = "upload")
    public DataResult<?> uploadFile(@RequestParam("file_data") MultipartFile uploadfile, 
            @RequestParam("modelId") String modelId) 
      //....可以发现参数直接拿到MultipartFile和modelId
    

2017.09.20
今天发现file input在i.e.上兼容性不大好。ie9上都会出问题。没辙了,只能改写。改写过程中发现request不再是MultipartHttpServletRequest,有点泪奔,这是肿么了。
发现了一篇介绍的,看着挺完善的

SpringMVC默认是关闭fileupload功能的,开启该能够并验证文件上传,需要做如下几件事情:
第一:打开SpringMVC的文件上传功能:
***-servlet.xml中配置:
<bean id="multipartResolver"
    class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <property name="maxUploadSize" value="100000"/>
    <property name="maxInMemorySize" value="10240" />
</bean>
配置后,当SpringMVC接受到multipartRequest的时候,就会把HttpServletRequest转为MultipartHttpServletRequest类型,
第二步:创建上传文件的file.jsp:
<form action="dynamicFields.action?method=uploadFile" method="post" enctype="multipart/form-data"><input type="file" name="myfile" id="myfile" value="" /><br/><input type="submit" value="确认提交"></form>
一定不要漏掉enctype="multipart/form-data",否则web容器认为这不是一个MultipartRequest请求,会报错org.springframework.web.multipart.MultipartException: The current request is not a multipart request。
第三步:Controller层创建代码:
@RequestMapping(params = "method=uploadFile")
public ModelAndView uploadFile(@RequestParam("myfile") MultipartFile myfile,
                                  HttpServletRequest request, HttpServletResponse response) throws Exception 
    if(!myfile.isEmpty())
        logger.info(myfile.getName());
        byte[] bs= myfile.getBytes() ;
        logger.info(new String(bs));
    
    return null;

部署web应用运行后,能够看到控制台中打印出上传文件的内容,BINGO搞定(SpringMVC依赖common-fileupload.jar,需要加载该jar包)

按理说应该是这样没跑了,可是我的还是有问题,明天继续改改看。request的类型变化真的好神奇- -。

2017.09.21上午
今天发现按照上面是对的。只不过这样是表单提交,表单提交会导致上传之后会发生页面跳转。禁止页面跳转的方式试了很多,网上说的那些都不大行,原因是他们是禁止了submit,相当于。这时候是不能上传的,要重新写上传。
经过多次查找资料,最后发现了一个好用的jquery-form,确实好用,官网http://malsup.com/jquery/form/.可以兼容到ie8,它的example中还提供了fileupload的例子http://malsup.com/jquery/form/progress.html
用法很简单,几个回调清晰明了,如下:

$('form').ajaxForm(
         beforeSend: function() 
             var percentVal = '0%';
             bar.width(percentVal)
             percent.html(percentVal);
         ,
         uploadProgress: function(event, position, total, percentComplete) 
             var percentVal = percentComplete + '%';
             bar.width(percentVal)
             percent.html(percentVal);
         ,
         success: function() 
             var percentVal = '100%';
             bar.width(percentVal)
             percent.html(percentVal);
         ,
        complete: function(xhr) 

        
     ); 

这样就完成了对ie9的兼容,当然上传界面只能自己写写了。

2017.09.21下午
发现这个上传里面的坑还不少。今天上传一个文档的时候出来这么一个异常:

org.springframework.web.multipart.MultipartException: Could not parse multipart servlet request; 
nested exception is java.io.IOException: 
org.apache.tomcat.util.http.fileupload.FileUploadBase$IOFileUploadException: Processing of multipart/form-data request failed. 
/upload_760aac73_045e_4c42_8f13_c36ad1041276_00000015.tmp (Permission denied)] with root cause
java.io.FileNotFoundException: /upload_760aac73_045e_4c42_8f13_c36ad1041276_00000015.tmp (Permission denied)

可以看出分成了两个tmp,目测是由于文件超过定义好的2M大小时,会被分成多块上传,上面两个则是分成的两个缓存文件。这个时候怎么处理?

经过多番查证这个问题是这样的,

参考1:http://blog.csdn.net/just4you/article/details/70233133
从Spring3.1开始,Spring提供了CommonsMultipartResolver
和StandardServletMultipartResolver处理multipart请求。

参考2:http://blog.csdn.net/hanger_liu/article/details/51970784
该文中使用CommonsMultipartResolver处理multipart请求,出现了跟我一样的问题。配置中的maxInMemorySIze 是文件上传的时候写到内存中的最大值,默认是10240字节,如果这里写大了,那么小于这个参数的文件则不会创建临时文件。

而我们使用了StandardServletMultipartResolver,以此类推在配置文件web.xml中

<multipart-config>
            <location>/</location>
            <max-file-size>20848820</max-file-size>
            <max-request-size>418018841</max-request-size>
            <file-size-threshold>1048576</file-size-threshold>
        </multipart-config>

由于这里的file-size-threshold是1M左右,当我的文件大于这个阀值,就会保存到临时文件upload_xxx.tmp中,而这个文件是存放在location中的。所以解决办法出来了,增大阀值必然是可以的,不过不是根本办法。根本解决办法是location配置到有权限的文件夹中。dalao支了一招,直接去掉location配置,使用默认的location就没有权限问题了。

2017.09.22凌晨
今天上班的时候碰到一个奇葩问题,关于表单提交的,以前好好的一个可以用的项目,突然在表单提交的时候后台取不到参数值了。entype采用的是默认的,如果采用multipart编码就可以拿到。由于很多地方都是这样的,没法一个个加,特别有的还是用ajax,jquery的load等方式。
终于在2点多的时候解决了。环境问题- -,全部换成现在用的javase-1.8就好了。无语,睡觉了。

以上是关于java后台文件上传到资源服务器上的主要内容,如果未能解决你的问题,请参考以下文章

求问我DEDE后台在上传文件的时候总是显示302是怎么了,请教?

java前后台开发之文件上传

java web图片上传和文件上传

springboot静态资源文件的映射

java base64位图片转码上传服务器,后台解码,后台保存文件路径不知道怎么写 求教(不是安卓)

PostMan上传文件到Java后台