摘要
完成笔记页面前置的文件选择
过程
需求: 用户可以创建笔记的主题并命名,比如“Java”。新建的主题只有默认图作为封皮。用户可以点进去某个主题,展示该主题下他拥有的所有笔记。这个页面中,还支持上传这个主题的封皮,新建笔记和删除主题。其中,新建笔记将导航到新的笔记编辑页面上,删除主题将递归地删除该主题下所有的笔记,并自动返回上一级目录。如果点击某个已存在的笔记,将进入这个笔记的编辑页面。
接口设计:
效果:
这部分前端就是搞流式布局难一些,但没太多好说的。后端是借助文件系统实现的,而不是数据库,因为资料显示用数据库存储超大数据会很慢:
是否应将二进制文件存储在数据库中?
SQL Server存储图像数据的策略与方法
SpringBoot+Vue实现文件的上传下载(含多文件、文件夹)_AtlantisChina-程序员宅基地
SpringBoot实现文件上传与下载(数据库版)
值得收藏:一份非常完整的 MySQL 规范
关于InnoDB存储引擎 text blob 大字段的存储和优化
后端实现:
@RequestMapping(value = "/common/note/save_note", method = RequestMethod.POST) //接口请求的地址
public int save_note(@RequestBody JSONObject req) throws IOException { //@RequestBody将返回的数据结构转换为 JSON 格式。
String id = req.getString("id");
String content = req.getString("content");
String album_name=req.getString("album_name");
String ori_note_name=req.getString("ori_note_name");
String note_name=req.getString("note_name");
if(ori_note_name.equals(note_name)){
//已存在相应文件且不需要重命名
System.out.println("ori equals new");
String notepath=staticFileSpace + "NOTE"+File.separator+"u_"+id+File.separator+album_name+ File.separator+"notes"+File.separator+note_name;
try {
BufferedWriter out = new BufferedWriter(new FileWriter(notepath));
out.write(content);
out.close();
System.out.println("文件创建成功!");
} catch (IOException e) {
e.printStackTrace();
}
return 0;
}
else if(ori_note_name.equals("")){
//需要检查笔记名是否与原来的重复
File newName = new File(staticFileSpace + "NOTE"+File.separator+"u_"+id+File.separator+album_name+ File.separator+"notes"+File.separator+note_name);
if (newName.exists()) { // 确保新的文件名不存在
return -1;//新文件名已存在
}
newName.getParentFile().mkdir();
try {
BufferedWriter out = new BufferedWriter(new FileWriter(newName));
out.write(content);
out.close();
System.out.println("文件创建成功!");
} catch (IOException e) {
e.printStackTrace();
}
return 0;
}
else{
//需要重命名
File oldName=new File(staticFileSpace + "NOTE"+File.separator+"u_"+id+File.separator+album_name+ File.separator+"notes"+File.separator+ori_note_name);
File newName = new File(staticFileSpace + "NOTE"+File.separator+"u_"+id+File.separator+album_name+ File.separator+"notes"+File.separator+note_name);
if (newName.exists()) { // 确保新的文件名不存在
return -1;//新文件名已存在
}
else if(oldName.renameTo(newName)) {
System.out.println("已重命名");
return 0;
} else {
System.out.println("Error");
return -2;
}
}
}
@RequestMapping(value = "/common/note/get_note", method = RequestMethod.GET) //接口请求的地址
public String getNote(@RequestParam("id") String id, @RequestParam("album_name") String album_name, @RequestParam("note_name") String note_name, @RequestParam("version") int version) { //@RequestBody将返回的数据结构转换为 JSON 格式。
StringBuilder res = new StringBuilder("");
try {
FileInputStream in = new FileInputStream(staticFileSpace + "NOTE"+File.separator+"u_"+id+File.separator+album_name+ File.separator+"notes"+File.separator+note_name);
Scanner sc;
sc = new Scanner(in, StandardCharsets.UTF_8);
while (sc.hasNextLine()) {
String line = sc.nextLine();
res.append(line);
}
sc.close();
} catch (FileNotFoundException e) {
return "";
}catch (Exception e){
e.printStackTrace();
return null;
}
System.out.println(res.toString());
return res.toString();
}
@RequestMapping(value = "/folder/create_album", method = RequestMethod.POST) //接口请求的地址
@CrossOrigin(origins = "*", maxAge = 3600)
public int createAlbum(@RequestBody JSONObject data) {
String id=data.getString("id");
String album_name=data.getString("album_name");
String album_path = staticFileSpace + "NOTE"+File.separator+"u_"+id+File.separator+album_name ;
File file = new File(album_path);
if (!file.isDirectory()) {
System.out.println("非目录");
System.out.println(file.mkdirs());
return 0;
}
else{
return -1;
}
}
@RequestMapping(value = "/folder/post_cover", method = RequestMethod.POST) //接口请求的地址
@CrossOrigin(origins = "*", maxAge = 3600)
public void uploadPicture(@RequestParam MultipartFile file,@RequestParam("id") String id,@RequestParam("album_name") String album_name) throws IOException {
// 1. 用数组MultipartFile[]来表示多文件,所以遍历数组,对其中的文件进行逐一操作
System.out.println("uploadPoster");
System.out.println(id);
// for(MultipartFile file:files) {
System.out.println(file.getOriginalFilename());
//
String path = staticFileSpace + "NOTE"+File.separator+"u_"+id+File.separator+album_name+File.separator+"cover.png";
String filePath = fileUtil.savaFileByNio((FileInputStream) file.getInputStream(), path);
System.out.println(filePath);
}
@RequestMapping(value = "/folder/get_folders", method = RequestMethod.GET) //接口请求的地址
@CrossOrigin(origins = "*", maxAge = 3600)
public Album[] getCovers(@RequestParam("id") String id) throws IOException {//ok
System.out.println("ok");
String path = staticFileSpace +"NOTE" + File.separator + "u_"+id;
System.out.println(path);
File file = new File(path);//这个文件夹下应该有n个子文件夹,每个子文件夹是一个主题
File[] tempList = file.listFiles();
if(tempList==null){
return null;
}
// byte[][] bytes=new byte[tempList.length][];
Album[] albums=new Album[tempList.length];
for(int i=0;i<tempList.length;i++) {
//对于每一个主题
//获取文件夹名字
String themename=tempList[i].getName();
//获取文件夹中cover文件内容
File theme = new File(path+File.separator+themename);//打开主题文件夹
File[] theme_content = theme.listFiles();
if(theme_content==null){//这个路径不是一个文件夹
return null;
}
int cover_index=-1;
for(int j=0;j<theme_content.length;j++){
// System.out.println(theme_content[j].getName());
if(theme_content[j].getName().equals("cover.png")){
cover_index=j;
break;
}
}
FileInputStream inputStream;
if(cover_index>-1){
//inputStream=cover.png内容
inputStream = new FileInputStream(theme_content[cover_index]);
}else{
inputStream = new FileInputStream(new File(staticFileSpace+"add.jpg"));
}
byte[] file_bytes = new byte[inputStream.available()];
inputStream.read(file_bytes, 0, inputStream.available());
albums[i] = new Album(file_bytes, themename);
}
return albums;
}
@RequestMapping(value = "/folder/get_note_names", method = RequestMethod.GET) //接口请求的地址
@CrossOrigin(origins = "*", maxAge = 3600)
public String[] getNoteNames(@RequestParam("id") String id,@RequestParam("album_name") String album_name) throws IOException {
//return 文件名(字符串)的数组
String album_path = staticFileSpace +"NOTE" + File.separator + "u_"+id+ File.separator+album_name+File.separator+"notes" ;
System.out.println(album_path);
File file = new File(album_path);
File[] notes = file.listFiles();
if(notes==null){
return null;
}
String[] names=new String[notes.length];
for(int i=0;i<notes.length;i++){
names[i]=notes[i].getName();
}
return names;
}
@RequestMapping(value = "/folder/delete_theme", method = RequestMethod.DELETE) //接口请求的地址
@CrossOrigin(origins = "*", maxAge = 3600)
public int deleteTheme(@RequestParam("id") String id,@RequestParam("album_name") String album_name) {
//return 文件名(字符串)的数组
String album_path = staticFileSpace +"NOTE" + File.separator + "u_"+id+ File.separator+album_name;
System.out.println(album_path);
try{
File file = new File(album_path);
if(file.delete()){
System.out.println(file.getName() + " 文件已被删除!");
}else{
File[] listFiles = file.listFiles();
for(File f : listFiles){
System.out.println("Deleting "+f.getName());
if(!f.delete()){
File[] notes=f.listFiles();
for(File n:notes){
if(!n.delete()){
System.out.println("删除失败!");
return -1;
}
}
f.delete();
}
}
file.delete();
return 0;
}
}catch(Exception e){
e.printStackTrace();
return -2;
}
return 0;
}
值得注意的是,当用户重命名笔记的情况比较复杂,不应该直接创建新的文件。这里的解决方案是,前端用ori_name和new_name区分是否重命名,后端判断这两个是否相同决定用户是真的创建了一个新的笔记还是对原有笔记进行重命名。如果是前者,则新开一个空白文件;如果是后者,则对原有文件进行覆写。