基本介绍
我们项目当中很多都需要使用sftp
来实现文件上传功能。
步骤
一、引入依赖
<dependency>
<groupId>com.jcraft</groupId>
<artifactId>jsch</artifactId>
<version>0.1.53</version>
</dependency>
二、编写工具类
编写实现sftp
建立连接和关闭连接的工具类,简单代码如下:
/**
* @author: huangshuai
* @Description:用于sftp工具类
* @date 2021/12/3 15:58
*/
@Data
@ToString
@Component
@ConfigurationProperties(prefix = "sftp")
public class SftpClient {
private static final Logger logger = LoggerFactory.getLogger(SftpClient.class);
/**
* 主机地址
*/
private String host;
/**
* 主机端口号
*/
private int port;
/**
* 用户名
*/
private String username;
/**
* 密码
*/
private String password;
/**
* 文件路径
*/
private String basePath;
/**
* 超时时间
*/
private int timeout;
private ChannelSftp channel;
private Session session;
/**
* 建立sftp连接
*/
public ChannelSftp openConnect() {
try {
JSch jsch = new JSch();
//根据用户名,主机ip,端口获取一个Session对象
session = jsch.getSession(username, host, port);
//设置密码
session.setPassword(password);
//设置timeout时间
session.setTimeout(timeout);
Properties properties = new Properties();
properties.put("StrictHostKeyChecking", "no");
session.setConfig(properties);
//通过Session建立链接
session.connect();
//打开SFTP通道
channel = (ChannelSftp) session.openChannel("sftp");
logger.info("开始连接sftp服务器----------------->");
//建立SFTP通道的连接
channel.connect();
logger.info("连接sftp服务器成功----------------->");
} catch (Exception e) {
e.printStackTrace();
logger.info("连接sftp服务器失败!");
}
return channel;
}
/**
* 断开SFTP Channel、Session连接
*/
public void closeConnect() {
try {
logger.info("开始断开sftp服务器----------------->");
if (channel != null) {
channel.disconnect();
}
if (session != null) {
session.disconnect();
}
logger.info("已断开sftp服务器连接--------------->");
} catch (Exception e) {
logger.info("断开sftp服务器连接失败!");
}
}
}
三、配置SFTP连接信息
因为项目普遍都是SpringBoot
项目,所以可以直接在application.properties
配置配置文件中配置sftp
连接信息,如下:
##连接主机IP地址
sftp.host=xxx
##端口号
sftp.port=22
## 用户名
sftp.username=xxx
## 密码
sftp.password=xxx
## 文件上传到哪个目录下
sftp.basePath=/data/POD
## 连接超时时间
sftp.timeout=60000
四、上传文件业务代码
简单的实现文件上传代码如下:
@Service
public class MoveFileService {
private final static Logger log = LoggerFactory.getLogger(MoveFileService.class);
private final static String FILE_TYPE = ".pdf";
@Autowired
private SftpClient sftpClient;
@Autowired
private BackSignDetailDao backSignDetailDao;
@Value("${dalianda_down_file_prefix_url}")
private String downLoadUrl;
/**
* 移动指定格式的文件
*/
public void upLoadPatternFile() {
ChannelSftp sftp;
Map<String, String> headers = new HashMap<>();
ByteArrayOutputStream bos = null;
try {
//查询未上传过的文件信息
List<BackSignDetail> backSignDetailList = backSignDetailDao.qryBackSignDetailListByCond();
if (backSignDetailList != null && backSignDetailList.size() > 0) {
sftp = sftpClient.openConnect();
for (BackSignDetail backSignDetail : backSignDetailList) {
bos = new ByteArrayOutputStream();
if (StringUtils.hasText(backSignDetail.getFileName())
&& backSignDetail.getFileName().contains(".")
&& StringUtils.hasText(backSignDetail.getFileUrl())) {
String fileName = backSignDetail.getFileName();
log.info("当前处理的文件名:{}", fileName);
//从另一个地方下载需要上传的文件,转成输出流
HttpClientUtil.downloadFile(downLoadUrl + backSignDetail.getFileUrl(), bos, headers);
String curTime = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
//上传文件命名:DoNo_yyyyMMddHHmmss.pdf
String newFileName = fileName.substring(0, fileName.indexOf(".")) + "_" + curTime + FILE_TYPE;
if (bos != null) {
//切换到上传文件目录
sftp.cd(sftpClient.getBasePath());
//上传文件
sftp.put(new ByteArrayInputStream(bos.toByteArray()), newFileName);//上传文件
log.info("上传文件成功,文件名:{}", newFileName);
if (backSignDetailDao.updateBackSignDetailById(backSignDetail.getBackSignDetailOID())) {
log.info("更新backSignDetailOID:{}为已经上传过文件", backSignDetail.getBackSignDetailOID());
}
}
}
}
sftpClient.closeConnect();
}
} catch (Exception e) {
log.info("处理文件异常!");
e.printStackTrace();
} finally {
try {
if (bos != null) {
bos.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
@Slf4j
@SuppressWarnings("deprecation")
public class HttpClientUtil {
private final static RequestConfig defaultReqConfig;
private final static CloseableHttpClient defaultClient;
private final static CloseableHttpClient defaultSSLClient;
static {
defaultReqConfig = RequestConfig.custom()
.setConnectionRequestTimeout(10000)
.setConnectTimeout(10000)
.setSocketTimeout(30000) // 不能设为0,否则超时要等很久
.setCookieSpec(CookieSpecs.STANDARD)
.build();
defaultClient = HttpClients.createDefault();
defaultSSLClient = getSSLClientDefault();
}
private static void config(HttpRequestBase httpRequestBase) {
// 配置请求的超时设置
RequestConfig requestConfig = RequestConfig.custom()
.setConnectionRequestTimeout(1000)
.setConnectTimeout(10000)
.setSocketTimeout(0)
.build();
httpRequestBase.setConfig(requestConfig);
}
/**
* 绕过https安全验证
*
* @return
*/
private static CloseableHttpClient getSSLClientDefault() {
try {
SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
//信任所有
public boolean isTrusted(X509Certificate[] chain, String authType) {
return true;
}
}).build();
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext);
return HttpClients.custom().setSSLSocketFactory(sslsf).build();
} catch (Exception e) {
throw new RuntimeException("获取HTTPS client 出错", e);
}
}
public static CloseableHttpClient getHttpClient(String url) {
if (url.startsWith("https")) {
return defaultSSLClient;
} else {
return defaultClient;
}
}
private static HttpGet createHttpGet(String url, Map<String, String> headers) {
HttpGet get = new HttpGet(url);
if (headers != null) {
for (Map.Entry<String, String> header : headers.entrySet()) {
get.setHeader(header.getKey(), header.getValue());
}
}
return get;
}
/**
* 通过HTTP的Get请求下载文件,如下载PDF文件
* @param url 请求url
* @param out 文件输出流
* @param headers HTTP请求头
* @return 下载文件的大小
*/
public static int downloadFile(String url, OutputStream out, Map<String, String> headers) {
CloseableHttpClient client = getHttpClient(url);
HttpGet httpget = createHttpGet(url, headers);
httpget.setConfig(defaultReqConfig); // 设置超时时间
int byteCount = 0;
try (CloseableHttpResponse response = client.execute(httpget)) {
HttpEntity entity = response.getEntity();
InputStream is = entity.getContent();
byteCount = StreamUtils.copy(is, out);
} catch (IOException e) {
throw new RuntimeException(e);
}
return byteCount;
}
/**
* POST请求URL获取内容+请求头
* @param url
* @return
*/
public static String postAndHeader(String url, Map<String, Object> params) throws Exception {
HttpPost httpPost = new HttpPost(url);
config(httpPost);
setPostParams(httpPost, params);
HashMap<String, Object> headMap = new HashMap<>();
headMap.put("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
Set<String> keySet = headMap.keySet();
for (String key : keySet) {
httpPost.setHeader(key, headMap.get(key).toString());
}
CloseableHttpResponse response = null;
try {
response = getHttpClient(url).execute(httpPost,
HttpClientContext.create());
HttpEntity entity = response.getEntity();
String result = EntityUtils.toString(entity, "utf-8");
EntityUtils.consume(entity);
return result;
} catch (Exception e) {
// e.printStackTrace();
throw new Exception("HttpClientUtils.postAndHeader() exception. -->" + e.getMessage());
} finally {
try {
if (response != null)
response.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 发送post请求并加请求头--json格式
*/
public static String postStringEntityAndHeader(String url, String data, Map<String, Object> headMap) throws Exception {
HttpPost httpPost = new HttpPost(url);
httpPost.setHeader("Content-Type", "application/json");
Set<String> keySet = headMap.keySet();
for (String key : keySet) {
httpPost.setHeader(key, headMap.get(key).toString());
}
config(httpPost);
httpPost.setEntity(new StringEntity(data, "utf-8"));
CloseableHttpResponse response = null;
try {
response = getHttpClient(url).execute(httpPost,
HttpClientContext.create());
HttpEntity entity = response.getEntity();
String result = EntityUtils.toString(entity, "utf-8");
EntityUtils.consume(entity);
return result;
} catch (Exception e) {
e.printStackTrace();
throw new Exception("HttpClientUtils.postStringEntity() exception. -->" + e.getMessage());
} finally {
try {
if (response != null){
response.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
private static void setPostParams(HttpPost httpost,
Map<String, Object> params) {
List<NameValuePair> nvps = new ArrayList<NameValuePair>();
Set<String> keySet = params.keySet();
for (String key : keySet) {
nvps.add(new BasicNameValuePair(key, params.get(key).toString()));
}
try {
httpost.setEntity(new UrlEncodedFormEntity(nvps, "UTF-8"));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
/**
* GET请求URL获取内容
*
* @param url
* @return
*/
public static String get(String url) throws Exception{
HttpGet httpget = new HttpGet(url);
config(httpget);
CloseableHttpResponse response = null;
try {
response = getHttpClient(url).execute(httpget, HttpClientContext.create());
HttpEntity entity = response.getEntity();
String result = EntityUtils.toString(entity, "utf-8");
EntityUtils.consume(entity);
return result;
} catch (IOException e) {
log.error("GET请求URL获取内容失败!",e);
throw new Exception("HttpClientUtils.get() exception. -->"+e.getMessage());
} finally {
try {
if (response != null){
response.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}