zoukankan      html  css  js  c++  java
  • SFTP文件上传下载以及如何处理异常,页面展现

    首先需要一个第三方包,网上有很多种方式,我这里用的是ChannelSftp 

    API地址 http://epaul.github.io/jsch-documentation/javadoc/com/jcraft/jsch/ChannelSftp.html

    1.工具类

    /**
     * 
     * @author Caicaizi
     *
     */
    public class SFTPUtils {
    
    	private static final Logger LOG = LoggerFactory.getLogger(SFTPUtils.class);
    
    	/**
    	 * 打开ssh会话
    	 * 
    	 * @param username
    	 * @param host
    	 * @param port
    	 * @param pwd
    	 * @return
    	 * @throws JSchException
    	 */
    	private static Session openSession(String username, String host, int port, String pwd) throws JSchException {
    		JSch jsch = new JSch();
    		Session session = jsch.getSession(username, host, port);
    		session.setPassword(pwd);
    		Properties config = new Properties();
    		config.put("StrictHostKeyChecking", "no");
    		config.put("PreferredAuthentications", "password");
    		int timeout = 3000;
    		session.setServerAliveInterval(timeout); //
    		session.setConfig(config); // 为Session对象设置properties
    		session.setTimeout(timeout); // 设置timeout时间
    		session.connect(); // 通过Session建立连接
    		LOG.info("Session connected.");
    		return session;
    	}
    
    	/**
    	 * 获取文件
    	 * 
    	 * @param filePath
    	 *            文件路径
    	 * @param out
    	 *            输出流
    	 * @param username
    	 * @param host
    	 * @param port
    	 * @param pwd
    	 */
    	public static void getFile(String filePath, OutputStream out, String username, String host, int port, String pwd) {
    		ChannelSftp channel = null;
    		Session session = null;
    		try {
    			session = openSession(username, host, port, pwd);
    			LOG.info("Opening channel");
    			channel = (ChannelSftp) session.openChannel("sftp");
    			channel.connect();
    			channel.get(filePath, out);
    		} catch (JSchException e) {
    			LOG.error("连接服务器失败", e);
    		} catch (SftpException e) {
    			LOG.error("文件获取失败", e);
    		} finally {
    			close(channel, session);
    		}
    	}
    
    	public static void uploadFile(InputStream input, String filename, String path, String username, String host,
    			int port, String pwd) {
    		ChannelSftp channel = null;
    		Session session = null;
    		try {
    			session = openSession(username, host, port, pwd);
    			channel = (ChannelSftp) session.openChannel("sftp");
    			channel.connect();
    			SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd");
    			String date = format.format(new Date());
    			channel.cd(path);
    			// 查看日期对应的目录状态
    			try {
    				channel.stat(date);
    			} catch (Exception e) {
    				LOG.info("目录不存在,创建目录:" + path + "/" + date);
    				channel.mkdir(date);
    			}
    			channel.put(input,path+"/"+date+"/"+filename);
    			
    		} catch (JSchException e) {
    			LOG.error("连接服务器失败", e);
    		} catch (SftpException e) {
    			LOG.error("文件上传失败", e);
    		} finally{
    			close(channel, session);
    		}
    
    	}
    
    	/**
    	 * 释放sftp连接资源
    	 * 
    	 * @param channel
    	 * @param session
    	 */
    	private static void close(ChannelSftp channel, Session session) {
    		if (channel != null) {
    			channel.quit();
    			channel.disconnect();
    		}
    		if (session != null) {
    			session.disconnect();
    		}
    
    	}
    }
    

      我们所需要的参数必须:IP,PORT,路径,文件名,以及账号密码;

    上传文件可以直接调用:uploadFile,下载:getFile。
    注意:下载时用户只需要有读权限,但进行文件上传用户必须有文件夹写的权限

    2.servlet
    先考虑发生的错误:文件没下载下来,1.可能是文件服务器挂了,2.也可能是文件路径有问题(博主的文件服务器是由系统管理员在应用中配置的,并不固定也有可能填错);
    考虑到上面的错误,需要在页面给用户错误提示
    public class FileServlet extends HttpServlet {
    
    	/**
    	 * post方式下载
    	 */
    	@Override
    	protected void doPost(HttpServletRequest request, HttpServletResponse response)
    			throws ServletException, IOException {
    		// 编码
    		response.setCharacterEncoding("UTF-8");
    		response.setContentType("text/html;charset=utf-8");
    		// 要下载的文件名
    		String filename = request.getParameter("filename");
    		// 最终相应输出流
    		OutputStream out = response.getOutputStream();
    		// 临时输出流
    		FileOutputStream outputStream = null;
    		// 输入流
    		FileInputStream inputStream = null;
    		// 临时文件
    		File file = null;
    		// 临时文件名称,用UUID,输出到浏览器后,删掉这个临时文件
    		try {
    			String uuid = UUIDGenerator.generate();
    			File fileDir = new File("./tmp");
    			if (!fileDir.exists()) {
    				fileDir.mkdirs();
    			}
    			file = new File(fileDir, uuid);
    			outputStream = new FileOutputStream(file);
    			// 用工具类把文件到输出到临时文件
    			SFTPUtils.getFile(filename, outputStream, "username", "host", 80, "pwd");
    			// 设置下面两个响应头,在web端返回的就是下载结果
    			// URLEncoder.encode(filename, "UTF-8")解决中文乱码的问题
    			response.addHeader("Content-type", "application/octet-stream");
    			response.addHeader("Content-Disposition", "attachment:filename=" + URLEncoder.encode(filename, "UTF-8"));
    			// 把临时文件copy到response的相应中
    			inputStream = new FileInputStream(fileDir);
    			// 这里用了apache.commoms.io的工具类
    			IOUtils.copy(inputStream, out);
    		} catch (JSchException e) {
    			Log.error("FTP连接失败",e);
    		}catch(SftpException e){
    			Log.error("配置路径错误,文件未找到",e);
    		}finally{
    			// 关闭流,删除临时文件
    			IOUtils.closeQuietly(inputStream);
    			IOUtils.closeQuietly(outputStream);
    			if(file.exists()){
    				file.delete();
    			}
    		}
    
    	}
    
    }
    

      

    3。页面
    为什么不直接用<a>标签?
    老大就要在页面上挂个中文,用a在后台会乱码,我也尝试过在后台转码,好几种方式,但是都失败了,另外一个就是错误提示了,下载失败怎么搞?所以用了form表单,用post的方式进行提交

    通过js document.getElementId('file_form').submit()进行表单提交
     
    <span id='file'>下载一个中文文件</span>
    <form method='post' action='FileServlet' target="_blank" id='file_form'>
    <input type='hidden' name='filename' value='一个中文文件.pdf'>
    </form>
    

      

    人比较懒,目前只有下载需求,上传直接往文件服务器丢,后续会完善上传的部分代码。

    遇到的坑:
    为什么不直接输出文件,要用一个临时文件:核心原因就是我们的服务器地址、用户密码都是由管理员在系统中进行设置,而不是配置文件。而且文件服务器宕机,这里也需要给出一些错误信息。
    不用临时文件这些错误是捕获不到的。我们用临时文件,一切正常之后再把临时文件瞧瞧删掉~

  • 相关阅读:
    arcgis增大缩放级别
    arcgis地图窗口操作
    arcgis访问百度地图
    内存溢出和内存泄漏的区别、产生原因以及解决方案
    多线程之sleep和wait的区别
    java技术-重点方向
    技术思维VS管理思维
    几个问题
    写完百行代码,一次运行全部案例通过 是什么体验?
    分布式开放消息系统(RocketMQ)的原理与实践
  • 原文地址:https://www.cnblogs.com/chylcblog/p/10196601.html
Copyright © 2011-2022 走看看