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>

  

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

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

posted @ 2018-12-29 16:56  胡吃海喝的程序猿  阅读(1831)  评论(0编辑  收藏  举报