58 KiB
SFTP文件管理系统 - 开发文档
🎨 UI设计系统概览
完整设计系统文档请参考:
UI设计系统.md
核心设计原则
- 现代简约:界面清晰,层次分明
- 专业高效:减少操作步骤,提升工作效率
- 一致性:统一的视觉语言和交互模式
- 可访问性:符合WCAG 2.1 AA标准
关键设计令牌
颜色系统:
- 主色:
#0d6efd(操作按钮、选中状态) - 成功:
#198754(连接成功状态) - 危险:
#dc3545(删除操作、错误提示) - 深灰:
#212529(导航栏背景) - 浅灰:
#e9ecef(工具栏背景)
字体系统:
- 字体族:系统字体栈(-apple-system, Segoe UI, Roboto等)
- 正文:14px,行高1.5
- 标题:20-32px,行高1.2-1.4
- 小号文字:12px(文件大小、日期等)
间距系统:
- 基础单位:8px
- 标准间距:16px(1rem)
- 组件内边距:8px-16px
组件规范:
- 导航栏:高度48px,深色背景
- 工具栏:浅灰背景,按钮间距8px
- 文件项:最小高度44px,悬停效果150ms
- 按钮:圆角4px,过渡150ms
交互规范:
- 悬停效果:150ms过渡
- 触摸目标:最小44x44px
- 键盘导航:Tab、Enter、Delete、F2、F5、Esc
- 焦点状态:2px蓝色轮廓
响应式断点:
- 移动端:< 768px(双面板垂直排列)
- 平板:768px - 1024px
- 桌面:> 1024px(标准布局)
项目概述
1.1 项目目标
开发一个基于Spring Boot的Web版SFTP文件管理系统,支持左右双分屏界面,实现本地文件和远程SFTP服务器的文件管理功能。
1.2 技术选型
- 后端框架:Spring Boot 2.7.x
- SFTP客户端:JSch 0.1.55
- 前端技术:HTML5 + Bootstrap 5 + jQuery
- 数据库:H2嵌入式数据库(存储连接配置)
- JDK版本:JDK 8+
- 构建工具:Maven
1.3 核心功能特性
- ✅ 支持多SFTP服务器连接管理
- ✅ 左右双面板文件浏览
- ✅ 本地文件系统与SFTP服务器文件切换
- ✅ 支持双SFTP模式(左右均为SFTP连接)
- ✅ 文件上传下载
- ✅ 文件/文件夹删除
- ✅ 文件重命名
- ✅ 新建文件夹
- ✅ 连接配置持久化
1.4 架构设计
┌─────────────────────────────────────────────────────────┐
│ 浏览器前端 │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ 左侧面板 │ │ 右侧面板 │ │
│ │ (本地/SFTP) │ │ (本地/SFTP) │ │
│ └──────────────┘ └──────────────┘ │
└────────────────────┬────────────────────────────────────┘
│ REST API
┌────────────────────┴────────────────────────────────────┐
│ Spring Boot 后端 │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Controller │ │ Service │ │ Model │ │
│ │ (API接口) │ │ (业务逻辑) │ │ (数据模型) │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
└────────────────────┬────────────────────────────────────┘
│
┌───────────┴───────────┐
│ │
┌────────▼────────┐ ┌────────▼────────┐
│ 本地文件系统 │ │ SFTP服务器 │
└─────────────────┘ └─────────────────┘
模块01:项目初始化与基础配置
1.1 项目结构创建
sftp-manager/
├── README.md # 项目说明文档
├── pom.xml # Maven配置文件
└── src/
├── main/
│ ├── java/com/sftp/manager/
│ │ ├── SftpManagerApplication.java # Spring Boot主类
│ │ ├── config/
│ │ │ └── WebConfig.java # Web配置(CORS等)
│ │ ├── controller/
│ │ │ ├── FileController.java # 文件操作API
│ │ │ └── ConnectionController.java # 连接管理API
│ │ ├── service/
│ │ │ ├── SftpService.java # SFTP操作服务
│ │ │ ├── LocalFileService.java # 本地文件操作服务
│ │ │ └── ConnectionService.java # 连接配置服务
│ │ ├── model/
│ │ │ ├── Connection.java # 连接实体类
│ │ │ └── FileInfo.java # 文件信息实体类
│ │ └── dto/
│ │ ├── ConnectionRequest.java # 连接请求DTO
│ │ ├── FileOperationRequest.java # 文件操作请求DTO
│ │ └── ApiResponse.java # API统一响应DTO
│ └── resources/
│ ├── application.yml # 应用配置文件
│ ├── static/
│ │ ├── css/
│ │ │ └── style.css # 自定义样式
│ │ └── js/
│ │ └── app.js # 前端业务逻辑
│ └── templates/
│ └── index.html # 主页面(双面板UI)
└── test/ # 测试代码
1.2 Maven依赖配置(pom.xml)
核心依赖列表:
<dependencies>
<!-- Spring Boot Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- JSch for SFTP -->
<dependency>
<groupId>com.jcraft</groupId>
<artifactId>jsch</artifactId>
<version>0.1.55</version>
</dependency>
<!-- H2 Database (嵌入式数据库) -->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<!-- JPA for Data Persistence -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- Lombok (简化实体类代码) -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- Spring Boot DevTools (热部署) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
1.3 应用配置文件(application.yml)
配置项说明:
server:
port: 8080 # 服务端口
servlet:
context-path: /sftp-manager # 应用上下文路径
spring:
application:
name: sftp-manager
# H2数据库配置
h2:
console:
enabled: true # 启用H2控制台
path: /h2-console # 控制台访问路径
datasource:
url: jdbc:h2:file:./data/sftp-manager # 数据库文件路径
driver-class-name: org.h2.Driver
username: sa
password:
# JPA配置
jpa:
hibernate:
ddl-auto: update # 自动更新表结构
show-sql: true # 显示SQL语句
properties:
hibernate:
format_sql: true # 格式化SQL输出
# 文件上传配置
servlet:
multipart:
enabled: true
max-file-size: 100MB # 单文件最大100MB
max-request-size: 500MB # 总请求最大500MB
# 自定义配置
app:
sftp:
session-timeout: 30000 # SFTP会话超时时间(ms)
connection-timeout: 10000 # 连接超时时间(ms)
max-retries: 3 # 连接失败重试次数
1.4 主类配置(SftpManagerApplication.java)
配置要点:
- 使用@SpringBootApplication注解,包含自动配置
- 启用JPA仓库(@EnableJpaRepositories)
- 配置静态资源访问路径
1.5 Web配置(WebConfig.java)
配置内容:
- CORS跨域配置(允许前端访问)
- 静态资源映射
- 文件上传配置
- 响应编码设置(UTF-8)
模块02:数据模型设计
2.1 连接实体(Connection.java)
字段说明:
@Entity
@Table(name = "connections")
public class Connection {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id; // 连接ID(主键)
private String name; // 连接名称(用户自定义)
private String host; // SFTP服务器地址
private Integer port; // SFTP端口(默认22)
private String username; // 用户名
@Column(columnDefinition = "TEXT")
private String password; // 密码(加密存储)
private String privateKeyPath; // 私钥路径(可选)
private String passPhrase; // 私钥密码(可选)
private Integer connectTimeout; // 连接超时时间
private String rootPath; // 默认登录后路径
private LocalDateTime createdAt; // 创建时间
private LocalDateTime updatedAt; // 更新时间
}
设计要点:
- 密码字段建议加密存储(使用AES或Base64)
- 支持密码认证和密钥认证两种方式
- 记录创建和更新时间便于追踪
2.2 文件信息实体(FileInfo.java)
字段说明:
public class FileInfo {
private String name; // 文件名
private String path; // 完整路径
private long size; // 文件大小(字节)
private boolean isDirectory; // 是否为目录
private LocalDateTime modifiedTime; // 修改时间
private String permissions; // 文件权限(如:-rw-r--r--)
}
设计要点:
- 使用DTO模式,不持久化到数据库
- 统一本地文件和SFTP文件的表示方式
- 包含文件元数据信息
2.3 通用响应对象(ApiResponse.java)
设计说明:
public class ApiResponse<T> {
private boolean success; // 操作是否成功
private String message; // 响应消息
private T data; // 响应数据
private String error; // 错误信息
}
使用场景:
- 统一所有API的响应格式
- 便于前端统一处理
- 支持泛型,灵活适配不同数据类型
2.4 数据传输对象(DTO)
2.4.1 连接请求DTO(ConnectionRequest.java)
public class ConnectionRequest {
private Long id; // 连接ID(用于保存配置)
private String name; // 连接名称
private String host; // 主机地址
private Integer port; // 端口
private String username; // 用户名
private String password; // 密码
private String privateKeyPath; // 私钥路径
private String passPhrase; // 私钥密码
}
2.4.2 文件操作请求DTO(FileOperationRequest.java)
public class FileOperationRequest {
private String sessionId; // 会话ID(标识是本地还是哪个SFTP连接)
private String path; // 操作的文件路径
private String newName; // 新文件名(重命名使用)
private String targetPath; // 目标路径(移动/复制使用)
private String targetSessionId; // 目标会话ID(跨服务器传输使用)
}
2.4.3 文件列表请求DTO(FileListRequest.java)
public class FileListRequest {
private String sessionId; // 会话ID("local"表示本地,否则为SFTP连接ID)
private String path; // 要浏览的目录路径
}
模块03:连接管理功能
3.1 功能概述
实现SFTP连接的建立、断开、保存、加载和删除功能,支持多连接同时管理。
3.2 后端设计
3.2.1 ConnectionRepository接口
public interface ConnectionRepository extends JpaRepository<Connection, Long> {
List<Connection> findByOrderByCreatedAtDesc(); // 按创建时间倒序查询
Optional<Connection> findByName(String name); // 按名称查询
}
3.2.2 ConnectionService服务类
核心方法设计:
-
connect(ConnectionRequest request) - 建立SFTP连接
- 输入:连接参数(主机、端口、用户名、密码/密钥)
- 输出:会话ID(用于后续操作)
- 实现逻辑:
- 创建JSch实例
- 配置连接参数(StrictHostKeyChecking=no)
- 建立Session和ChannelSftp
- 返回唯一会话ID(UUID)
- 异常处理:连接超时、认证失败
-
disconnect(String sessionId) - 断开连接
- 输入:会话ID
- 输出:操作结果
- 实现逻辑:
- 从缓存中获取ChannelSftp
- 关闭Channel和Session
- 从缓存中移除会话
-
saveConnection(Connection connection) - 保存连接配置
- 输入:连接实体
- 输出:保存后的连接实体
- 实现逻辑:
- 密码加密(可选)
- 设置创建/更新时间
- 保存到数据库
-
listConnections() - 获取所有保存的连接
- 输出:连接列表(按创建时间倒序)
-
deleteConnection(Long id) - 删除连接配置
- 输入:连接ID
- 输出:操作结果
- 实现逻辑:
- 先断开该连接(如果已连接)
- 从数据库删除记录
3.2.3 会话管理机制
使用ConcurrentHashMap存储活跃会话:
@Component
public class SessionManager {
private final Map<String, ChannelSftp> activeSessions = new ConcurrentHashMap<>();
public void addSession(String sessionId, ChannelSftp channel) {
activeSessions.put(sessionId, channel);
}
public ChannelSftp getSession(String sessionId) {
return activeSessions.get(sessionId);
}
public void removeSession(String sessionId) {
ChannelSftp channel = activeSessions.get(sessionId);
if (channel != null) {
channel.disconnect();
}
activeSessions.remove(sessionId);
}
public boolean isActive(String sessionId) {
return activeSessions.containsKey(sessionId);
}
}
会话ID规则:
- "local":表示本地文件系统
- "sftp-{uuid}":表示SFTP连接会话
3.3 API接口设计
3.3.1 ConnectionController
接口列表:
| 方法 | 路径 | 说明 | 请求参数 |
|---|---|---|---|
| POST | /api/connection/connect | 建立SFTP连接 | ConnectionRequest |
| POST | /api/connection/disconnect | 断开连接 | sessionId |
| POST | /api/connection/save | 保存连接配置 | Connection |
| GET | /api/connection/list | 获取所有保存的连接 | - |
| DELETE | /api/connection/{id} | 删除连接配置 | 路径参数id |
| GET | /api/connection/active | 获取所有活跃连接 | - |
请求/响应示例:
-
建立连接
POST /api/connection/connect Request: {"host":"192.168.1.100","port":22,"username":"root","password":"123456"} Response: {"success":true,"data":{"sessionId":"sftp-12345678-1234-1234-1234-123456789abc"}} -
获取连接列表
GET /api/connection/list Response: {"success":true,"data":[{"id":1,"name":"测试服务器","host":"192.168.1.100","port":22,...}]}
3.4 关键技术点
-
JSch连接配置
- 设置StrictHostKeyChecking=no(跳过主机密钥验证)
- 配置连接超时和会话超时
- 支持密码和私钥两种认证方式
-
密码加密
- 使用AES加密存储密码
- 使用Base64编码私钥内容
-
连接健康检查
- 定时检查活跃连接状态
- 自动断开超时未使用的连接
模块04:文件浏览功能
4.1 功能概述
实现本地文件系统和SFTP服务器文件系统的浏览功能,支持目录导航、文件列表展示。
4.2 后端设计
4.2.1 LocalFileService本地文件服务
核心方法:
-
listFiles(String path) - 列出本地目录文件
- 输入:目录路径
- 输出:FileInfo列表
- 实现逻辑:
- 使用Java NIO的Files类遍历目录
- 获取文件元数据(大小、修改时间)
- 过滤隐藏文件(可选)
-
fileExists(String path) - 检查文件是否存在
- 输入:文件路径
- 输出:boolean
-
getFileInfo(String path) - 获取文件信息
- 输入:文件路径
- 输出:FileInfo
4.2.2 SftpService SFTP文件服务
核心方法:
-
listFiles(String sessionId, String path) - 列出SFTP目录文件
- 输入:会话ID、目录路径
- 输出:FileInfo列表
- 实现逻辑:
- 从SessionManager获取ChannelSftp
- 调用ls()方法获取目录内容
- 将Vector转换为FileInfo列表
- 异常处理:连接断开、路径不存在
-
pwd(String sessionId) - 获取当前工作目录
- 输入:会话ID
- 输出:当前路径
-
cd(String sessionId, String path) - 切换目录
- 输入:会话ID、目标路径
- 输出:操作结果
4.2.3 FileController文件控制器
接口设计:
| 方法 | 路径 | 说明 | 请求参数 |
|---|---|---|---|
| POST | /api/files/list | 列出文件 | FileListRequest |
| POST | /api/files/info | 获取文件信息 | FileOperationRequest |
| GET | /api/files/path | 获取可用路径(本地根目录、SFTP当前目录) | sessionId |
请求/响应示例:
-
列出本地文件
POST /api/files/list Request: {"sessionId":"local","path":"C:/Users"} Response: { "success":true, "data":[ {"name":"Desktop","path":"C:/Users/Desktop","size":0,"isDirectory":true,"modifiedTime":"2024-01-01T10:00:00"}, {"name":"Documents","path":"C:/Users/Documents","size":0,"isDirectory":true,"modifiedTime":"2024-01-01T10:00:00"} ] } -
列出SFTP文件
POST /api/files/list Request: {"sessionId":"sftp-uuid","path":"/home/user"} Response: { "success":true, "data":[ {"name":"test.txt","path":"/home/user/test.txt","size":1024,"isDirectory":false,"modifiedTime":"2024-01-01T10:00:00"} ] }
4.3 前端设计
4.3.1 文件列表展示
布局结构:
<div class="panel-container">
<div class="panel" id="left-panel">
<div class="panel-header">
<select class="mode-select">
<option value="local">本地文件</option>
<option value="sftp">SFTP服务器</option>
</select>
<input type="text" class="path-input" readonly>
</div>
<div class="file-list">
<!-- 文件列表项 -->
</div>
</div>
<div class="panel" id="right-panel">
<!-- 同左面板结构 -->
</div>
</div>
文件列表项样式:
.file-item {
padding: 10px;
cursor: pointer;
display: flex;
align-items: center;
}
.file-item:hover {
background-color: #f0f0f0;
}
.file-item.selected {
background-color: #007bff;
color: white;
}
.file-icon {
margin-right: 10px;
}
4.3.2 目录导航逻辑
JavaScript实现:
- 点击目录项:进入子目录
- 面包屑导航:返回上级目录
- 路径输入框:直接输入路径跳转
关键函数:
function loadFiles(sessionId, path) {
$.ajax({
url: '/api/files/list',
method: 'POST',
data: {sessionId: sessionId, path: path},
success: function(response) {
if (response.success) {
renderFileList(response.data);
}
}
});
}
4.4 特殊处理
-
路径分隔符处理
- Windows系统:使用反斜杠(\)
- Linux/SFTP系统:使用正斜杠(/)
- 统一显示格式,底层自动转换
-
隐藏文件处理
- 本地文件:过滤以.开头的文件(Linux/Mac)
- SFTP文件:由服务器返回
-
文件图标
- 根据文件类型显示不同图标
- 支持常见文件类型识别(图片、视频、文档等)
模块05:文件上传下载功能
5.1 功能概述
实现本地与SFTP服务器之间、以及两个SFTP服务器之间的文件上传和下载功能。
5.2 后端设计
5.2.1 SftpService扩展方法
上传方法:
void uploadFile(String sessionId, String localPath, String remotePath);
- 输入:会话ID、本地文件路径、远程目标路径
- 实现逻辑:
- 获取ChannelSftp实例
- 使用put()方法上传文件
- 支持进度回调(可选)
- 异常处理:本地文件不存在、远程权限不足
下载方法:
void downloadFile(String sessionId, String remotePath, String localPath);
- 输入:会话ID、远程文件路径、本地目标路径
- 实现逻辑:
- 获取ChannelSftp实例
- 使用get()方法下载文件
- 异常处理:远程文件不存在、本地空间不足
SFTP间传输:
void transferBetweenSftp(String sourceSessionId, String sourcePath,
String targetSessionId, String targetPath);
- 输入:源会话ID、源路径、目标会话ID、目标路径
- 实现逻辑:
- 从源SFTP下载到临时文件
- 上传临时文件到目标SFTP
- 删除临时文件
- 性能优化:使用流式传输避免大文件占用内存
5.2.2 FileController扩展接口
| 方法 | 路径 | 说明 | 请求参数 |
|---|---|---|---|
| POST | /api/files/upload | 上传文件 | MultipartFile + targetInfo |
| GET | /api/files/download | 下载文件 | sessionId + path |
| POST | /api/files/transfer | 服务器间传输 | TransferRequest |
TransferRequest结构:
public class TransferRequest {
private String sourceSessionId; // 源会话ID
private String sourcePath; // 源文件路径
private String targetSessionId; // 目标会话ID
private String targetPath; // 目标路径
}
响应示例:
POST /api/files/upload
Request: FormData包含file和{"targetSessionId":"sftp-uuid","targetPath":"/home/user/"}
Response: {"success":true,"message":"上传成功"}
5.3 前端设计
5.3.1 上传界面
实现方式:
- 拖拽上传区域
- 点击选择文件按钮
- 显示上传进度
HTML结构:
<div class="upload-area">
<input type="file" id="file-input" multiple style="display:none">
<div class="drop-zone">
<p>拖拽文件到此处或点击选择文件</p>
</div>
<div class="upload-progress">
<!-- 进度条 -->
</div>
</div>
JavaScript实现:
function uploadFile(file, targetSessionId, targetPath) {
let formData = new FormData();
formData.append('file', file);
formData.append('targetSessionId', targetSessionId);
formData.append('targetPath', targetPath);
$.ajax({
url: '/api/files/upload',
method: 'POST',
data: formData,
processData: false,
contentType: false,
xhr: function() {
let xhr = new window.XMLHttpRequest();
xhr.upload.addEventListener('progress', function(e) {
if (e.lengthComputable) {
let percent = (e.loaded / e.total) * 100;
updateProgress(percent);
}
});
return xhr;
},
success: function(response) {
alert(response.message);
loadFiles(targetSessionId, targetPath);
}
});
}
5.3.2 下载界面
实现方式:
- 右键菜单选择下载
- 双击文件下载(文件)
- 显示下载进度
JavaScript实现:
function downloadFile(sessionId, path) {
window.location.href = '/api/files/download?sessionId=' +
encodeURIComponent(sessionId) +
'&path=' + encodeURIComponent(path);
}
5.3.3 跨服务器传输
UI交互:
- 左面板选择源文件
- 右面板选择目标位置
- 点击"传输到右侧"按钮
JavaScript实现:
function transferFiles() {
let sourceSessionId = leftPanel.sessionId;
let sourcePath = leftPanel.selectedFile.path;
let targetSessionId = rightPanel.sessionId;
let targetPath = rightPanel.currentPath;
$.ajax({
url: '/api/files/transfer',
method: 'POST',
data: {
sourceSessionId: sourceSessionId,
sourcePath: sourcePath,
targetSessionId: targetSessionId,
targetPath: targetPath
},
success: function(response) {
alert(response.message);
loadFiles(targetSessionId, targetPath);
}
});
}
5.4 性能优化
-
大文件处理
- 使用分块上传(可选)
- 设置合理的超时时间
- 显示实时进度
-
断点续传
- 记录已传输字节数
- 支持从断点继续传输
- 文件完整性校验
-
并发控制
- 限制同时上传/下载数量
- 队列管理机制
- 任务取消功能
-
临时文件清理
- SFTP间传输后删除临时文件
- 定期清理超时临时文件
- 使用系统临时目录
模块06:文件删除功能
6.1 功能概述
实现删除本地文件和SFTP服务器上文件的功能,支持单个文件删除和批量删除,包含删除确认机制。
6.2 后端设计
6.2.1 LocalFileService删除方法
单个文件删除:
boolean deleteFile(String path);
- 输入:文件/目录路径
- 输出:是否成功
- 实现逻辑:
- 检查文件是否存在
- 如果是目录,递归删除所有子文件
- 使用Files.delete()或Files.deleteIfExists()
- 异常处理:文件不存在、权限不足、文件被占用
批量删除:
int batchDelete(List<String> paths);
- 输入:文件路径列表
- 输出:成功删除数量
- 实现逻辑:
- 遍历路径列表
- 逐个调用deleteFile()
- 统计成功和失败数量
6.2.2 SftpService删除方法
单个文件删除:
boolean deleteFile(String sessionId, String path);
- 输入:会话ID、文件/目录路径
- 输出:是否成功
- 实现逻辑:
- 获取ChannelSftp实例
- 使用rm()删除文件,rmdir()删除空目录
- 递归删除目录(自定义实现)
- 异常处理:连接断开、权限不足
递归删除目录:
void deleteDirectoryRecursive(String sessionId, String path);
- 实现逻辑:
- 列出目录内容
- 递归删除子文件和子目录
- 最后删除空目录
6.2.3 FileController删除接口
| 方法 | 路径 | 说明 | 请求参数 |
|---|---|---|---|
| DELETE | /api/files/delete | 删除文件/目录 | sessionId + path |
| POST | /api/files/batch-delete | 批量删除 | sessionId + paths[] |
请求示例:
DELETE /api/files/delete?sessionId=sftp-uuid&path=/home/user/test.txt
Response: {"success":true,"message":"删除成功"}
POST /api/files/batch-delete
Request: {"sessionId":"local","paths":["C:/test/file1.txt","C:/test/file2.txt"]}
Response: {"success":true,"data":{"successCount":2,"failCount":0}}
6.3 前端设计
6.3.1 删除交互
实现方式:
- 选中文件后,点击删除按钮
- 右键菜单选择删除
- 支持键盘Delete键删除
确认对话框:
function confirmDelete(sessionId, paths) {
let message = paths.length === 1
? '确定要删除 ' + paths[0] + ' 吗?'
: '确定要删除选中的 ' + paths.length + ' 个文件吗?';
if (confirm(message)) {
deleteFiles(sessionId, paths);
}
}
6.3.2 删除实现
JavaScript代码:
function deleteFiles(sessionId, paths) {
if (paths.length === 1) {
$.ajax({
url: '/api/files/delete',
method: 'DELETE',
data: {sessionId: sessionId, path: paths[0]},
success: function(response) {
if (response.success) {
alert(response.message);
refreshFileList(sessionId);
}
}
});
} else {
$.ajax({
url: '/api/files/batch-delete',
method: 'POST',
contentType: 'application/json',
data: JSON.stringify({sessionId: sessionId, paths: paths}),
success: function(response) {
if (response.success) {
alert('成功删除 ' + response.data.successCount + ' 个文件');
refreshFileList(sessionId);
}
}
});
}
}
6.4 安全措施
-
删除确认
- 必须用户确认后才能执行删除
- 显示将被删除的文件数量和名称
- 防止误操作
-
权限检查
- 删除前检查文件是否存在
- 验证当前用户是否有删除权限
- 系统文件和受保护文件禁止删除
-
操作日志
- 记录所有删除操作
- 包含操作时间、用户、文件路径
- 便于审计和追踪
-
回收站机制(可选)
- 删除时移动到回收站而非直接删除
- 支持从回收站恢复文件
- 定期清理回收站
模块07:文件重命名功能
7.1 功能概述
实现重命名本地文件和SFTP服务器上文件的功能,支持单个文件重命名。
7.2 后端设计
7.2.1 LocalFileService重命名方法
boolean renameFile(String oldPath, String newPath);
- 输入:旧路径、新路径
- 输出:是否成功
- 实现逻辑:
- 检查旧文件是否存在
- 检查新文件名是否已存在
- 使用Files.move()重命名
- 异常处理:文件不存在、目标文件名冲突、权限不足
7.2.2 SftpService重命名方法
boolean renameFile(String sessionId, String oldPath, String newPath);
- 输入:会话ID、旧路径、新路径
- 输出:是否成功
- 实现逻辑:
- 获取ChannelSftp实例
- 使用rename()方法
- 异常处理:连接断开、文件不存在、权限不足
7.2.3 FileController重命名接口
| 方法 | 路径 | 说明 | 请求参数 |
|---|---|---|---|
| POST | /api/files/rename | 重命名文件 | sessionId + oldPath + newPath |
请求示例:
POST /api/files/rename
Request: {"sessionId":"local","oldPath":"C:/test/old.txt","newPath":"C:/test/new.txt"}
Response: {"success":true,"message":"重命名成功"}
7.3 前端设计
7.3.1 重命名交互
实现方式:
- 选中文件后,点击重命名按钮
- 右键菜单选择重命名
- 双击文件名(如果未实现双击进入目录)
重命名对话框:
function showRenameDialog(sessionId, oldPath, oldName) {
let newName = prompt('请输入新文件名:', oldName);
if (newName && newName !== oldName) {
let newPath = getParentPath(oldPath) + '/' + newName;
renameFile(sessionId, oldPath, newPath);
}
}
7.3.2 重命名实现
function renameFile(sessionId, oldPath, newPath) {
$.ajax({
url: '/api/files/rename',
method: 'POST',
contentType: 'application/json',
data: JSON.stringify({
sessionId: sessionId,
oldPath: oldPath,
newPath: newPath
}),
success: function(response) {
if (response.success) {
alert(response.message);
refreshFileList(sessionId);
} else {
alert('重命名失败: ' + response.message);
}
}
});
}
7.4 输入验证
-
文件名验证
- 不能包含特殊字符(如:\ / : * ? " < > |)
- 不能为空
- 长度限制(如:255字符)
-
同名检查
- 检查目标目录是否已存在同名文件
- 如存在则提示用户确认覆盖
-
扩展名保留
- 可选:保留原文件扩展名
- 仅允许修改文件名部分
模块08:新建文件夹功能
8.1 功能概述
实现在本地文件系统和SFTP服务器上创建新文件夹的功能。
8.2 后端设计
8.2.1 LocalFileService创建目录方法
boolean createDirectory(String path);
- 输入:目录路径
- 输出:是否成功
- 实现逻辑:
- 检查父目录是否存在
- 检查目录名是否已存在
- 使用Files.createDirectories()创建
- 异常处理:父目录不存在、目录名冲突、权限不足
8.2.2 SftpService创建目录方法
boolean createDirectory(String sessionId, String path);
- 输入:会话ID、目录路径
- 输出:是否成功
- 实现逻辑:
- 获取ChannelSftp实例
- 使用mkdir()方法
- 如需创建多级目录,递归创建
- 异常处理:连接断开、权限不足
8.2.3 FileController创建目录接口
| 方法 | 路径 | 说明 | 请求参数 |
|---|---|---|---|
| POST | /api/files/mkdir | 创建文件夹 | sessionId + path |
请求示例:
POST /api/files/mkdir
Request: {"sessionId":"sftp-uuid","path":"/home/user/newfolder"}
Response: {"success":true,"message":"创建成功"}
8.3 前端设计
8.3.1 新建文件夹交互
实现方式:
- 点击"新建文件夹"按钮
- 右键菜单选择"新建文件夹"
- 在当前路径创建
输入对话框:
function showMkdirDialog(sessionId, currentPath) {
let folderName = prompt('请输入文件夹名称:', '新建文件夹');
if (folderName) {
let newPath = currentPath + '/' + folderName;
createDirectory(sessionId, newPath);
}
}
8.3.2 创建实现
function createDirectory(sessionId, path) {
$.ajax({
url: '/api/files/mkdir',
method: 'POST',
contentType: 'application/json',
data: JSON.stringify({
sessionId: sessionId,
path: path
}),
success: function(response) {
if (response.success) {
alert(response.message);
refreshFileList(sessionId);
} else {
alert('创建失败: ' + response.message);
}
}
});
}
8.4 输入验证
-
目录名验证
- 不能包含特殊字符
- 不能为空
- 不能使用系统保留名称(如CON, PRN等)
-
同名检查
- 检查目标位置是否已存在同名目录
-
路径处理
- 自动拼接父路径
- 处理路径分隔符
模块09:双面板UI界面设计
9.1 界面布局
整体结构:
<body>
<div class="app-container">
<!-- 顶部导航栏 -->
<nav class="navbar">
<div class="navbar-brand">SFTP文件管理器</div>
<div class="navbar-menu">
<button onclick="showConnectionDialog()">连接管理</button>
</div>
</nav>
<!-- 工具栏 -->
<div class="toolbar">
<button onclick="uploadFiles()">上传</button>
<button onclick="downloadFiles()">下载</button>
<button onclick="transferFiles()">传输到右侧</button>
<button onclick="deleteFiles()">删除</button>
<button onclick="showRenameDialog()">重命名</button>
<button onclick="showMkdirDialog()">新建文件夹</button>
</div>
<!-- 双面板区域 -->
<div class="panels-container">
<!-- 左面板 -->
<div class="panel" id="left-panel">
<div class="panel-header">
<select class="panel-mode" onchange="onModeChange('left')">
<option value="local">本地文件</option>
<option value="sftp">SFTP服务器</option>
</select>
<select class="connection-select" onchange="onConnectionChange('left')">
<!-- SFTP连接列表 -->
</select>
</div>
<div class="path-bar">
<button onclick="goUp('left')">↑</button>
<input type="text" class="path-input" id="left-path" readonly>
</div>
<div class="file-list" id="left-file-list">
<!-- 文件列表 -->
</div>
</div>
<!-- 右面板 -->
<div class="panel" id="right-panel">
<!-- 同左面板结构 -->
</div>
</div>
<!-- 状态栏 -->
<div class="status-bar">
<span id="status-text">就绪</span>
</div>
</div>
</body>
9.2 样式设计
主要样式:
.app-container {
display: flex;
flex-direction: column;
height: 100vh;
background-color: #f5f5f5;
}
.navbar {
background-color: #343a40;
color: white;
padding: 10px 20px;
display: flex;
justify-content: space-between;
}
.toolbar {
background-color: #e9ecef;
padding: 10px;
display: flex;
gap: 10px;
}
.panels-container {
display: flex;
flex: 1;
overflow: hidden;
}
.panel {
flex: 1;
display: flex;
flex-direction: column;
border: 1px solid #dee2e6;
background-color: white;
}
.panel:first-child {
border-right: 2px solid #6c757d;
}
.file-list {
flex: 1;
overflow-y: auto;
}
.file-item {
padding: 8px 10px;
cursor: pointer;
display: flex;
align-items: center;
border-bottom: 1px solid #f0f0f0;
}
.file-item:hover {
background-color: #f8f9fa;
}
.file-item.selected {
background-color: #007bff;
color: white;
}
9.3 响应式设计
移动端适配:
@media (max-width: 768px) {
.panels-container {
flex-direction: column;
}
.panel {
height: 50%;
}
.toolbar {
flex-wrap: wrap;
}
}
9.4 交互设计
-
文件选择
- 单击选中文件
- Ctrl+单击多选
- Shift+单击范围选择
- 双击进入目录或打开文件
-
拖拽操作
- 文件拖拽到另一个面板进行传输
- 拖拽多个文件批量传输
-
快捷键支持
- Delete:删除文件
- F2:重命名
- F5:刷新
- Backspace:返回上级目录
- Ctrl+A:全选
模块10:模式切换功能
10.1 功能概述
实现左侧和右侧面板在"本地文件"和"SFTP服务器"模式之间切换,支持同时连接多个SFTP服务器。
10.2 模式状态管理
JavaScript状态管理:
const panelState = {
left: {
mode: 'local', // 'local' 或 'sftp'
sessionId: 'local', // 'local' 或 SFTP会话ID
currentPath: '', // 当前路径
selectedFiles: [] // 选中的文件
},
right: {
mode: 'local',
sessionId: 'local',
currentPath: '',
selectedFiles: []
}
};
10.3 切换逻辑
本地模式切换到SFTP模式:
function switchToSftpMode(panelId) {
// 显示SFTP连接选择器
$(`#${panelId} .connection-select`).show();
// 加载已保存的连接列表
loadConnections();
// 默认选择第一个连接(如果有)
const firstConnection = getFirstConnection();
if (firstConnection) {
connectToSftp(panelId, firstConnection);
}
}
SFTP模式切换到本地模式:
function switchToLocalMode(panelId) {
// 隐藏SFTP连接选择器
$(`#${panelId} .connection-select`).hide();
// 更新会话ID为local
panelState[panelId].mode = 'local';
panelState[panelId].sessionId = 'local';
panelState[panelId].currentPath = getDefaultLocalPath();
// 加载本地文件列表
loadFiles(panelId);
}
10.4 SFTP连接管理UI
连接管理对话框:
<div id="connection-dialog" class="modal">
<div class="modal-content">
<h2>连接管理</h2>
<div class="connection-list">
<!-- 已保存的连接列表 -->
</div>
<button onclick="showAddConnectionDialog()">添加连接</button>
<button onclick="closeConnectionDialog()">关闭</button>
</div>
</div>
添加连接表单:
<form id="connection-form">
<input type="text" name="name" placeholder="连接名称" required>
<input type="text" name="host" placeholder="主机地址" required>
<input type="number" name="port" placeholder="端口" value="22">
<input type="text" name="username" placeholder="用户名" required>
<input type="password" name="password" placeholder="密码">
<input type="text" name="privateKeyPath" placeholder="私钥路径">
<input type="password" name="passPhrase" placeholder="私钥密码">
<button type="submit">保存</button>
<button type="button" onclick="closeAddConnectionDialog()">取消</button>
</form>
10.5 连接状态显示
连接状态指示器:
<div class="connection-status" id="left-status">
<span class="status-dot" data-status="connected"></span>
<span class="status-text">已连接</span>
</div>
状态样式:
.status-dot {
width: 10px;
height: 10px;
border-radius: 50%;
display: inline-block;
margin-right: 5px;
}
.status-dot[data-status="connected"] {
background-color: #28a745;
}
.status-dot[data-status="disconnected"] {
background-color: #dc3545;
}
.status-dot[data-status="connecting"] {
background-color: #ffc107;
}
模块11:API接口设计规范
11.1 RESTful设计原则
URL设计规范:
- 使用名词复数形式(/api/files)
- 使用HTTP方法表示操作类型
- 使用查询参数传递可选参数
- 使用路径参数传递必需参数
HTTP方法映射:
| 方法 | 操作 | 示例 |
|---|---|---|
| GET | 查询 | GET /api/files/list |
| POST | 创建 | POST /api/files/mkdir |
| PUT | 更新 | PUT /api/files/rename |
| DELETE | 删除 | DELETE /api/files/delete |
11.2 完整API列表
11.2.1 连接管理API
# 建立SFTP连接
POST /api/connection/connect
Request Body:
{
"name": "测试服务器",
"host": "192.168.1.100",
"port": 22,
"username": "root",
"password": "123456"
}
Response:
{
"success": true,
"message": "连接成功",
"data": {
"sessionId": "sftp-12345678-1234-1234-1234-123456789abc"
}
}
# 断开连接
POST /api/connection/disconnect
Request Body:
{
"sessionId": "sftp-12345678-1234-1234-1234-123456789abc"
}
Response:
{
"success": true,
"message": "断开成功"
}
# 保存连接配置
POST /api/connection/save
Request Body:
{
"name": "测试服务器",
"host": "192.168.1.100",
"port": 22,
"username": "root",
"password": "encrypted_password"
}
Response:
{
"success": true,
"message": "保存成功",
"data": {
"id": 1,
"name": "测试服务器",
...
}
}
# 获取所有保存的连接
GET /api/connection/list
Response:
{
"success": true,
"data": [
{
"id": 1,
"name": "测试服务器",
"host": "192.168.1.100",
...
}
]
}
# 删除连接配置
DELETE /api/connection/{id}
Response:
{
"success": true,
"message": "删除成功"
}
# 获取活跃连接列表
GET /api/connection/active
Response:
{
"success": true,
"data": [
{
"sessionId": "sftp-12345678-1234-1234-1234-123456789abc",
"connection": {
"name": "测试服务器",
"host": "192.168.1.100"
}
}
]
}
11.2.2 文件操作API
# 列出文件
POST /api/files/list
Request Body:
{
"sessionId": "sftp-12345678-1234-1234-1234-123456789abc",
"path": "/home/user"
}
Response:
{
"success": true,
"data": [
{
"name": "test.txt",
"path": "/home/user/test.txt",
"size": 1024,
"isDirectory": false,
"modifiedTime": "2024-01-01T10:00:00",
"permissions": "-rw-r--r--"
}
]
}
# 上传文件
POST /api/files/upload
Request: FormData
- file: MultipartFile
- targetSessionId: String
- targetPath: String
Response:
{
"success": true,
"message": "上传成功"
}
# 下载文件
GET /api/files/download?sessionId={sessionId}&path={path}
Response: 文件流
# 服务器间传输
POST /api/files/transfer
Request Body:
{
"sourceSessionId": "sftp-12345678-1234-1234-1234-123456789abc",
"sourcePath": "/home/user/test.txt",
"targetSessionId": "sftp-87654321-4321-4321-4321-cba987654321",
"targetPath": "/home/target/"
}
Response:
{
"success": true,
"message": "传输成功"
}
# 删除文件
DELETE /api/files/delete?sessionId={sessionId}&path={path}
Response:
{
"success": true,
"message": "删除成功"
}
# 批量删除
POST /api/files/batch-delete
Request Body:
{
"sessionId": "local",
"paths": ["C:/test/file1.txt", "C:/test/file2.txt"]
}
Response:
{
"success": true,
"data": {
"successCount": 2,
"failCount": 0
}
}
# 重命名
POST /api/files/rename
Request Body:
{
"sessionId": "sftp-12345678-1234-1234-1234-123456789abc",
"oldPath": "/home/user/old.txt",
"newPath": "/home/user/new.txt"
}
Response:
{
"success": true,
"message": "重命名成功"
}
# 新建文件夹
POST /api/files/mkdir
Request Body:
{
"sessionId": "local",
"path": "C:/test/newfolder"
}
Response:
{
"success": true,
"message": "创建成功"
}
11.3 统一响应格式
成功响应:
{
"success": true,
"message": "操作成功",
"data": {}
}
失败响应:
{
"success": false,
"message": "操作失败",
"error": "错误详细信息"
}
11.4 错误码定义
| 错误码 | 说明 |
|---|---|
| 400 | 请求参数错误 |
| 401 | 未授权(连接失败) |
| 404 | 资源不存在 |
| 500 | 服务器内部错误 |
模块12:错误处理与日志
12.1 全局异常处理
自定义异常类:
public class SftpException extends RuntimeException {
private String errorCode;
public SftpException(String message) {
super(message);
}
public SftpException(String errorCode, String message) {
super(message);
this.errorCode = errorCode;
}
}
public class FileOperationException extends RuntimeException {
private String filePath;
public FileOperationException(String message, String filePath) {
super(message);
this.filePath = filePath;
}
}
全局异常处理器:
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(SftpException.class)
public ResponseEntity<ApiResponse> handleSftpException(SftpException e) {
ApiResponse response = new ApiResponse();
response.setSuccess(false);
response.setMessage("SFTP操作失败");
response.setError(e.getMessage());
return ResponseEntity.status(500).body(response);
}
@ExceptionHandler(FileOperationException.class)
public ResponseEntity<ApiResponse> handleFileOperationException(FileOperationException e) {
ApiResponse response = new ApiResponse();
response.setSuccess(false);
response.setMessage("文件操作失败");
response.setError(e.getMessage());
return ResponseEntity.status(500).body(response);
}
@ExceptionHandler(Exception.class)
public ResponseEntity<ApiResponse> handleException(Exception e) {
ApiResponse response = new ApiResponse();
response.setSuccess(false);
response.setMessage("系统错误");
response.setError(e.getMessage());
return ResponseEntity.status(500).body(response);
}
}
12.2 日志配置
Logback配置(logback-spring.xml):
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>logs/sftp-manager.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>logs/sftp-manager.%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="FILE" />
<appender-ref ref="CONSOLE" />
</root>
<logger name="com.sftp.manager" level="DEBUG" />
</configuration>
12.3 操作日志记录
操作日志实体:
@Entity
@Table(name = "operation_logs")
public class OperationLog {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String operationType; // 操作类型:upload, download, delete等
private String sessionId; // 会话ID
private String sourcePath; // 源路径
private String targetPath; // 目标路径
private boolean success; // 是否成功
private String errorMessage; // 错误信息
private LocalDateTime operationTime; // 操作时间
}
操作日志服务:
@Service
public class OperationLogService {
@Autowired
private OperationLogRepository logRepository;
public void logOperation(String operationType, String sessionId,
String sourcePath, String targetPath,
boolean success, String errorMessage) {
OperationLog log = new OperationLog();
log.setOperationType(operationType);
log.setSessionId(sessionId);
log.setSourcePath(sourcePath);
log.setTargetPath(targetPath);
log.setSuccess(success);
log.setErrorMessage(errorMessage);
log.setOperationTime(LocalDateTime.now());
logRepository.save(log);
}
}
12.4 错误信息展示
前端错误处理:
function handleError(xhr, status, error) {
let errorMessage = '操作失败';
try {
const response = JSON.parse(xhr.responseText);
if (response.error) {
errorMessage = response.error;
} else if (response.message) {
errorMessage = response.message;
}
} catch (e) {
errorMessage = error || '未知错误';
}
alert(errorMessage);
updateStatus(errorMessage);
}
模块13:部署与测试
13.1 部署说明
13.1.1 本地运行
步骤:
- 确保已安装JDK 8+
- 克隆或下载项目
- 在项目根目录执行:
mvn clean install mvn spring-boot:run - 访问:http://localhost:8080/sftp-manager
13.1.2 打包部署
打包命令:
mvn clean package
运行JAR包:
java -jar target/sftp-manager-1.0.0.jar
自定义端口:
java -jar target/sftp-manager-1.0.0.jar --server.port=8081
13.1.3 生产环境配置
外部配置文件(application-prod.yml):
server:
port: 80
spring:
datasource:
url: jdbc:h2:file:/var/data/sftp-manager
username: ${DB_USERNAME:sa}
password: ${DB_PASSWORD:}
logging:
file:
name: /var/log/sftp-manager/app.log
level:
root: INFO
启动命令:
java -jar target/sftp-manager-1.0.0.jar --spring.profiles.active=prod
13.2 测试指南
13.2.1 功能测试清单
连接管理测试:
- 建立SFTP连接(密码认证)
- 建立SFTP连接(密钥认证)
- 断开连接
- 保存连接配置
- 加载保存的连接
- 删除连接配置
- 同时连接多个SFTP服务器
文件浏览测试:
- 浏览本地文件系统
- 浏览SFTP服务器文件
- 进入子目录
- 返回上级目录
- 直接输入路径跳转
- 刷新文件列表
文件操作测试:
- 上传单个文件到SFTP
- 批量上传文件
- 从SFTP下载文件
- 删除本地文件
- 删除SFTP文件
- 删除目录(递归)
- 批量删除
- 重命名文件
- 重命名目录
- 新建文件夹
跨面板操作测试:
- 本地 → SFTP传输
- SFTP → 本地传输
- SFTP → SFTP传输
- 拖拽传输
模式切换测试:
- 左面板本地/SFTP切换
- 右面板本地/SFTP切换
- 双SFTP模式
- 双本地模式
- 混合模式
13.2.2 边界条件测试
大文件测试:
- 上传大于100MB的文件
- 下载大于100MB的文件
- 断点续传测试
特殊文件名测试:
- 中文文件名
- 空格文件名
- 特殊字符文件名
- 超长文件名
权限测试:
- 无权限文件操作
- 只读文件上传
- 受保护目录访问
异常情况测试:
- 网络中断
- 服务器断开
- 连接超时
- 磁盘空间不足
13.2.3 性能测试
测试指标:
- 文件上传/下载速度
- 目录列表加载时间
- 同时操作多个连接的响应时间
- 内存占用
测试工具:
- Apache JMeter
- Postman
13.3 常见问题排查
问题1:无法连接SFTP服务器
- 检查网络连接
- 验证服务器地址和端口
- 确认用户名和密码正确
- 检查服务器SSH服务是否运行
问题2:文件上传失败
- 检查目标目录权限
- 确认磁盘空间充足
- 查看服务器日志
问题3:文件列表加载慢
- 检查网络延迟
- 减少目录文件数量
- 考虑分页加载
问题4:连接频繁断开
- 检查防火墙设置
- 增加连接超时时间
- 检查服务器SSH配置
附录
A. 依赖版本清单
<properties>
<java.version>1.8</java.version>
<spring-boot.version>2.7.18</spring-boot.version>
<jsch.version>0.1.55</jsch.version>
<h2.version>2.1.214</h2.version>
<lombok.version>1.18.30</lombok.version>
</properties>
B. 数据库表结构
connections表:
CREATE TABLE connections (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL,
host VARCHAR(255) NOT NULL,
port INT NOT NULL,
username VARCHAR(255) NOT NULL,
password TEXT,
private_key_path VARCHAR(500),
pass_phrase VARCHAR(255),
connect_timeout INT,
root_path VARCHAR(500),
created_at TIMESTAMP,
updated_at TIMESTAMP
);
operation_logs表:
CREATE TABLE operation_logs (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
operation_type VARCHAR(50) NOT NULL,
session_id VARCHAR(100),
source_path VARCHAR(1000),
target_path VARCHAR(1000),
success BOOLEAN,
error_message TEXT,
operation_time TIMESTAMP
);
C. JSch常用API参考
连接配置:
JSch jsch = new JSch();
Session session = jsch.getSession(username, host, port);
session.setPassword(password);
session.setConfig("StrictHostKeyChecking", "no");
session.connect(timeout);
文件操作:
ChannelSftp channel = (ChannelSftp) session.openChannel("sftp");
channel.connect();
// 列出文件
Vector<LsEntry> files = channel.ls(path);
// 上传
channel.put(localPath, remotePath);
// 下载
channel.get(remotePath, localPath);
// 删除
channel.rm(path);
// 重命名
channel.rename(oldPath, newPath);
// 新建目录
channel.mkdir(path);
// 切换目录
channel.cd(path);
D. 前端API调用示例
使用jQuery的完整示例:
// 列出文件
function loadFiles(sessionId, path) {
$.ajax({
url: '/api/files/list',
method: 'POST',
contentType: 'application/json',
data: JSON.stringify({sessionId: sessionId, path: path}),
success: function(response) {
if (response.success) {
renderFileList(response.data);
}
},
error: handleError
});
}
// 上传文件
function uploadFile(file, sessionId, path) {
let formData = new FormData();
formData.append('file', file);
formData.append('targetSessionId', sessionId);
formData.append('targetPath', path);
$.ajax({
url: '/api/files/upload',
method: 'POST',
data: formData,
processData: false,
contentType: false,
success: function(response) {
if (response.success) {
loadFiles(sessionId, path);
}
},
error: handleError
});
}
E. 开发工具推荐
后端开发:
- IntelliJ IDEA
- Eclipse
- VS Code
前端开发:
- VS Code
- Chrome DevTools
测试工具:
- Postman
- Apache JMeter
- BrowserStack(跨浏览器测试)
F. 参考资源
更新日志
v1.0.0 (2024-02-02)
- ✅ 初始版本发布
- ✅ 实现基本功能模块
- ✅ 支持本地和SFTP文件管理
- ✅ 双面板UI界面
- ✅ 基础文件操作功能