【新增】完善固件上传

This commit is contained in:
2025-11-21 18:39:28 +08:00
parent 884459e91a
commit 75ed266532
6 changed files with 83 additions and 5 deletions

View File

@@ -43,7 +43,7 @@ dependencies {
annotationProcessor 'org.projectlombok:lombok' // Lombok 注解处理 annotationProcessor 'org.projectlombok:lombok' // Lombok 注解处理
testImplementation 'org.springframework.boot:spring-boot-starter-test' // 测试框架 testImplementation 'org.springframework.boot:spring-boot-starter-test' // 测试框架
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' // thymeleaf模版引擎 implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' // thymeleaf模版引擎
implementation 'com.aliyun.oss:aliyun-sdk-oss:3.17.4' // OSS SDK implementation 'com.aliyun.oss:aliyun-sdk-oss:3.18.1' // OSS SDK
} }
tasks.named('test') { tasks.named('test') {

View File

@@ -71,8 +71,8 @@ public class BizFirmwareController {
*/ */
@DeleteMapping("/delete") @DeleteMapping("/delete")
@ResponseBody @ResponseBody
public Result<Firmware> delete(String id) { public Result<Firmware> delete(Long id) {
return Result.isBool(firmwareService.removeById(id)); return Result.isBool(firmwareService.removeData(id));
} }
/** /**
@@ -97,4 +97,6 @@ public class BizFirmwareController {
return Result.isBool(firmwareService.uploadFile(file, id)); return Result.isBool(firmwareService.uploadFile(file, id));
} }
} }

View File

@@ -33,4 +33,11 @@ public interface FirmwareService extends IService<Firmware> {
* @return * @return
*/ */
boolean uploadFile(MultipartFile file, Long id); boolean uploadFile(MultipartFile file, Long id);
/**
* 根据id删除固件
* @param id
* @return
*/
boolean removeData(Long id);
} }

View File

@@ -9,6 +9,7 @@ import com.corewing.app.mapper.FirmwareMapper;
import com.corewing.app.service.FirmwareService; import com.corewing.app.service.FirmwareService;
import com.corewing.app.util.OSSUploadUtil; import com.corewing.app.util.OSSUploadUtil;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
@@ -49,5 +50,62 @@ public class FirmwareServiceImpl extends ServiceImpl<FirmwareMapper, Firmware> i
} }
} }
@Transactional(rollbackFor = Exception.class)
@Override
public boolean removeData(Long id) {
Firmware firmware = getById(id);
if(firmware != null ){
if(firmware.getDownloadUrl() != null) {
OSSUploadUtil.deleteFile(getUrlLastSegment(firmware.getDownloadUrl()));
}
return removeById(id);
}
return false;
}
/**
* 获取 URL 路径的最后一节(忽略查询参数 ? 和锚点 #
* @param urlStr URL字符串
* @return 最后一节如文件名、资源ID异常/无路径时返回空字符串
*/
public static String getUrlLastSegment(String urlStr) {
// 1. 空值判断
if (urlStr == null || urlStr.trim().isEmpty()) {
return "";
}
// 2. 移除查询参数(? 及后面的内容)
int queryIndex = urlStr.indexOf('?');
if (queryIndex != -1) {
urlStr = urlStr.substring(0, queryIndex);
}
// 3. 移除锚点(# 及后面的内容)
int anchorIndex = urlStr.indexOf('#');
if (anchorIndex != -1) {
urlStr = urlStr.substring(0, anchorIndex);
}
// 4. 找到最后一个 "/" 的位置
int lastSlashIndex = urlStr.lastIndexOf('/');
// 5. 处理特殊情况:无 "/" 或 "/" 在末尾
if (lastSlashIndex == -1) {
// 无路径(如 "https://example.com" 或 "example.com"
return "";
}
if (lastSlashIndex == urlStr.length() - 1) {
// 路径以 "/" 结尾(如 "https://example.com/folder/"),需找倒数第二个 "/"
urlStr = urlStr.substring(0, lastSlashIndex);
lastSlashIndex = urlStr.lastIndexOf('/');
// 若倒数第二个 "/" 不存在(如 "https://example.com/"),返回空
if (lastSlashIndex == -1) {
return "";
}
}
// 6. 截取最后一个 "/" 后面的内容
return urlStr.substring(lastSlashIndex + 1);
}
} }

View File

@@ -47,7 +47,11 @@ public class OSSUploadUtil {
// 上传文件 // 上传文件
PutObjectRequest request = new PutObjectRequest(BUCKET_NAME, objectName, inputStream, metadata); PutObjectRequest request = new PutObjectRequest(BUCKET_NAME, objectName, inputStream, metadata);
PutObjectResult result = ossClient.putObject(request); PutObjectResult result = ossClient.putObject(request);
ossClient.setObjectAcl(
BUCKET_NAME, // Bucket 名称
objectName, // 刚上传的文件路径
CannedAccessControlList.PublicRead // 公共可读权限
);
// 生成文件访问 URL公网访问需 Bucket 设为公共读) // 生成文件访问 URL公网访问需 Bucket 设为公共读)
return String.format("https://%s.%s/%s", BUCKET_NAME, ENDPOINT, objectName); return String.format("https://%s.%s/%s", BUCKET_NAME, ENDPOINT, objectName);
} finally { } finally {
@@ -69,6 +73,11 @@ public class OSSUploadUtil {
try { try {
File file = new File(localFilePath); File file = new File(localFilePath);
ossClient.putObject(BUCKET_NAME, objectName, file); ossClient.putObject(BUCKET_NAME, objectName, file);
ossClient.setObjectAcl(
BUCKET_NAME, // Bucket 名称
objectName, // 刚上传的文件路径
CannedAccessControlList.PublicRead // 公共可读权限
);
return String.format("https://%s.%s/%s", BUCKET_NAME, ENDPOINT, objectName); return String.format("https://%s.%s/%s", BUCKET_NAME, ENDPOINT, objectName);
} finally { } finally {
if (ossClient != null) { if (ossClient != null) {

View File

@@ -269,7 +269,7 @@
</select> </select>
</div> </div>
</div> </div>
<div class="mb-3 row"> <div class="mb-3 row" v-if="addOrEditDto.id != null">
<label class="col-sm-3 col-form-label">固件地址</label> <label class="col-sm-3 col-form-label">固件地址</label>
<div class="col-sm-9"> <div class="col-sm-9">
<input type="text" class="form-control" v-model="addOrEditDto.downloadUrl" <input type="text" class="form-control" v-model="addOrEditDto.downloadUrl"
@@ -557,12 +557,14 @@
}, },
// 打开新增模态框 // 打开新增模态框
openAddModal() { openAddModal() {
this.clearForm();
this.addOrEditTitle = '新增'; this.addOrEditTitle = '新增';
this.modalInstances['addOrEditModel'].show(); this.modalInstances['addOrEditModel'].show();
}, },
// 打开编辑模态框 // 打开编辑模态框
openEditModal(item) { openEditModal(item) {
this.clearForm();
this.addOrEditTitle = '编辑'; this.addOrEditTitle = '编辑';
this.addOrEditDto = item; this.addOrEditDto = item;
this.modalInstances['addOrEditModel'].show(); this.modalInstances['addOrEditModel'].show();