上周总结需要解决的问题:
sn加上结束地址文件上传和下载不采用服务器,改成本地操作项目经理申请订单时,要能同时上传多个类型的key- 项目经理只能看到自己的项目
- 订单页展示各类型key名称,支持下载
- 给订单生成MD5码
- 邮箱点击下拉,弹出历史选项
问题1
sn加上结束地址比较快,数据库加一条属性,mapper.xml文件也做对应修改,页面上也加上这条数据的渲染。
问题2
之前采用的方案是将文件保存到Minio上,不过对于安全问题,由于我对于这个系统不够了解,不敢保证,需要更改为保存到项目资源目录resources下。
关于如何上传到resources目录下,方案较多,网上也很容易找到:
此方法为选择文件保存路径
static List<File> getUploadDirectory() throws FileNotFoundException{
// 开发环境获取 target/classes 目录:清理重新编译后就没有了
File targetPath = new File(ResourceUtils.getURL("classpath:").getPath());
if(!targetPath.exists()){
// 获取当前运行目录
targetPath = new File("");
}
// 开发环境 resources 目录:可永久保存
String resourcesPath = System.getProperty("user.dir")+"/ruoyi-admin/src/main/resources";
System.out.printf("resources目录路径:" + resourcesPath);
File path = new File(resourcesPath);
File upload = new File(path.getAbsolutePath(),"upload");
File uploadTarget = new File(targetPath.getAbsolutePath(),"upload");
// 不存在则创建
if(!upload.exists()){
upload.mkdirs();
}
if(!uploadTarget.exists()){
uploadTarget.mkdirs();
}
List<File> files = new ArrayList<File>();
files.add(upload);
files.add(uploadTarget);
// System.out.printf("当前目录:" + files);
return files;
}
此方法为上传文件并返回url
public static String upload(MultipartFile myFile,String dir) throws IOException{
String filePath ="";
if(myFile != null){
try{
String filename = myFile.getOriginalFilename();
filename = UUID.randomUUID() + filename;
// 之所以保存到 resources 和 target 两个目录,兼顾开发测试和永久保存
// 只保存到resources目录下每次上传了要重新编译下,target则清理打包后就没有了
List<File> files = getUploadDirectory();
// 注意这里一个文件不能循环同时写入多个目录,保存了第一个,第二个要复制过去
File curFile = new File(files.get(0), filename);
myFile.transferTo(curFile);
FileCopyUtils.copy(curFile,new File(files.get(1), filename));
filePath ="http://localhost:8080/upload/"+ filename;
}catch(Exception e){
e.printStackTrace();
}
}
return filePath;
}
前端测试代码:
<el-form-item label="key原件" prop="keyBaseUrl">
<!-- <el-upload ref="keyBaseUrl" :file-list="keyBaseUrlfileList" :action="keyBaseUrlAction"-->
<!-- :auto-upload="false" :before-upload="keyBaseUrlBeforeUpload">-->
<!-- <el-button size="small" type="primary" icon="el-icon-upload">点击上传</el-button>-->
<!-- </el-upload>-->
<el-upload
class="upload-demo"
ref="keyBaseUrl3"
:on-success="handleSuccess3"
:disabled="isSecondDisabled"
:on-error="handleError"
:limit="1"
:on-exceed="handleExceed"
:action="keyBaseUrlAction"
:on-preview="handlePreview"
:on-remove="handleRemove"
:on-change="getFile"
:file-list="keyBaseUrlfileList"
:headers="headers"
:auto-upload="true">
<el-button slot="trigger" size="small" type="primary">mgkid类型</el-button>
</el-upload>
<p>请注意,上传某个类型key文件之前,必须先上传在此之前的key类型文件</p>
</el-form-item>
测试比较顺利,一次就通过了。
但是在实现下载文件到本地的时候,就出了很多问题:
关于这个功能的实现,能找到的方案大部分都是用HttpServletResponse响应输出流,但这样直接把文件输出到浏览器控制台上了。其实这个功能实现很简单,关键在于 ClassPathResource 这个类,这个类可以直接访问资源目录下的文件。
代码也很简单,但是由于没找到关键点,花费了很长时间在这上面。
@GetMapping("/downloadResource")
public AjaxResult downloadResource(@RequestParam("filename") String filename) throws IOException {
Resource resource = new ClassPathResource("upload/" + filename);
if (!resource.exists()) {
return AjaxResult.error("文件不存在");
}
// 指定本地文件的保存路径
String savePath = "D:/DownLoad/" + filename;
try (BufferedReader br = new BufferedReader(new InputStreamReader(resource.getInputStream()))) {
try (FileWriter fw = new FileWriter(savePath);
BufferedWriter bw = new BufferedWriter(fw)) {
String line;
while ((line = br.readLine()) != null) {
bw.write(line);
bw.newLine(); // 写入换行符以保持原有的行结构
}
}
}
return AjaxResult.success("File saved to " + savePath);
}
问题3
这个问题也想了很长时间,因为同时上传多个文件,但是一次提交要区分三种类型,而且key记录的添加和url的添加并不是同步的操作,当文件上传后,立即就可以得到url,但是这个时候表单还没有提交,key记录都还不存在。
不过好在key类型是确定的,于是可以在表单数据中添加三个url,在文件上传的回调函数中处理,传给后端,同时限制用户上传顺序,保证后端能准确知道哪个url对应的是哪个类型的key。
给每个上传按钮加上禁用规则。
handleSuccess1(response, file, fileList) {
console.log(response)
this.formData.keyBaseUrl1 = decodeURIComponent(response.url)
this.keyName.push(this.formData.keyBaseUrl1.split('/').pop())
this.isFirstDisabled = false; // 启用第二个上传按钮
},
handleSuccess2(response, file, fileList) {
console.log(response)
this.formData.keyBaseUrl2 = decodeURIComponent(response.url)
this.keyName.push(this.formData.keyBaseUrl2.split('/').pop())
this.isSecondDisabled = false; // 启用第三个上传按钮
},
handleSuccess3(response, file, fileList) {
console.log(response)
this.formData.keyBaseUrl3 = decodeURIComponent(response.url)
this.keyName.push(this.formData.keyBaseUrl3.split('/').pop())
},
只有上一个文件上传成功,下一个按钮才会有取消禁用。
后端处理:
@Override
public int insertSdmcKey(SdmcKey sdmcKey)
{
String keyBaseUrl1 = sdmcKey.getKeyBaseUrl1();
String keyBaseUrl2 = sdmcKey.getKeyBaseUrl2();
String keyBaseUrl3 = sdmcKey.getKeyBaseUrl3();
// 循环向表中插入3种type的key
sdmcKey.setUpdateTime(LocalDateTime.now());
sdmcKey.setKeyDate(DateUtils.getNowDate());
sdmcKey.setUpdateBy(SecurityUtils.getUsername());
sdmcKey.setKeyBaseUrl(keyBaseUrl1);
sdmcKey.setKeyTypeId(1L);
int count1 = sdmcKeyMapper.insertSdmcKey(sdmcKey);
sdmcKey.setKeyBaseUrl(keyBaseUrl2);
sdmcKey.setKeyTypeId(2L);
int count2 = sdmcKeyMapper.insertSdmcKey(sdmcKey);
sdmcKey.setKeyBaseUrl(keyBaseUrl3);
sdmcKey.setKeyTypeId(3L);
int count3 = sdmcKeyMapper.insertSdmcKey(sdmcKey);
return count1 + count2 + count3;
}
测试成功,一个项目,对应不同类型key。
知识分享PPT
之后花时间写了后台搭建知识分享