• 69:第六章:开发文章服务:2:富文本编辑器summernote简介;发文章,之开发【多文件上传,接口】;


    说明:

    (1)本篇博客的内容:富文本编辑器summernote简介;发文章,之开发【多文件上传,接口】;

    目录

    一:summernote富文本编辑器,简介; 

    1.本项目,使用的富文本编辑器是summernote;

    2.summernote简介;

    3.summernote,在前端代码中的应用; 

    二:summernote中是可以贴多张图片的,这就涉及到了多文件上传;

    1.summernote多文件上传,业务分析;

    2.开发【多文件上传,接口】;

    (1)在【api】接口工程的FileUploaderControllerApi接口中,定义多文件上传接口;

    (2)在【files】文件服务的FileUploaderController类中,去实现多文件上传接口;

    3.效果;

    三:【多文件上传,接口】需要用户登录、并且用户是已经激活的状态下,才能调用的;


    一:summernote富文本编辑器,简介; 

    1.本项目,使用的富文本编辑器是summernote;

    (1)以前在【SSM开发书评网28:后台一:富文本编辑器wangEditor使用入门;】中,自己就使用过百度的wangEditor;

    (2)其实,在GitHub中也有很多很多其他开源的富文本编辑器,都可以使用;

    (3)我们这儿使用的是summernote这款;

    2.summernote简介;

    3.summernote,在前端代码中的应用; 


    二:summernote中是可以贴多张图片的,这就涉及到了多文件上传;

    1.summernote多文件上传,业务分析;

    (1)summernote中,可以上传一张图片,也可以上传多张图片;

    (2)如果是上传一张图片,其实在【44:第四章:开发文件服务:5:在【files】文件服务中,整合FastDFS,实现【上传头像】的逻辑;】中上传用户头像时,就是上传一张图片,即单文件上传;

    (3.1)而这儿的多文件上传,就需要重新开发一个接口;

    (3.2)其实,当我们向summernote中放入多张图片时,前端会进行一个构建,构建成一个list数组;然后,发送给后端;后端,在进行相应的处理;

    (4)声明:"summernote中贴的图片"的上传会使用【多文件上传,接口】,"文章封面图片"的上传使用的也是【多文件上传,接口】;

    2.开发【多文件上传,接口】;

    文件上传这个功能,虽然在业务上属于【article】文章服务;但是,就功能上来说,我们把其放在了【files】文件服务中;

    (1)在【api】接口工程的FileUploaderControllerApi接口中,定义多文件上传接口;

    1. /**
    2. * 【多文件文件,接口】
    3. * @param userId:用户id;
    4. * @param files:前端传过来的文件;
    5. * @return
    6. * @throws Exception :因为这个接口是可能发生异常的,所以我们这儿先throws一下(打个提前亮);(然后,我们
    7. * 在【24:第三章:开发通行证服务:7:自定义异常(来表征程序中出现的错误);创建GraceExceptionHandler来全
    8. * 局统一处理异常(根据异常信息,构建对应的API统一返回对象的,JSON数据);】已经编写了应对这种情况情况的逻辑,
    9. * 如果忘记了,可以快速去参考)
    10. */
    11. @PostMapping("/uploadSomeFiles") //设置路由,这个是需要前后端约定好的;
    12. public GraceJSONResult uploadSomeFiles(@RequestParam("userId") String userId,
    13. MultipartFile[] files) throws Exception;

    说明:

    (1)这个接口的url、请求方式、参数不是瞎写的,需要前后端一致;

    (2)前端传送多文件的时候,后端这儿直接使用【MultipartFile[]】去承接即可,即这儿多了一个[];

              ● 自然,后端接口这儿的文件名,需要和前端保持一致;

    (2)在【files】文件服务的FileUploaderController类中,去实现多文件上传接口;

    1. /**
    2. * 【多文件文件,接口】
    3. * @param userId:用户id;
    4. * @param files:前端传过来的文件;
    5. * @return
    6. * @throws Exception :因为这个接口是可能发生异常的,所以我们这儿先throws一下(打个提前亮);(然后,我们
    7. * 在【24:第三章:开发通行证服务:7:自定义异常(来表征程序中出现的错误);创建GraceExceptionHandler来全
    8. * 局统一处理异常(根据异常信息,构建对应的API统一返回对象的,JSON数据);】已经编写了应对这种情况情况的逻辑,
    9. * 如果忘记了,可以快速去参考)
    10. */
    11. @Override
    12. public GraceJSONResult uploadSomeFiles(String userId, MultipartFile[] files) throws Exception {
    13. // 1. 声明一个List:(1)我们把图片上传到阿里云OSS或者FastDFS后,会返回一个该图片的url;(2)然后,后端会
    14. // 把这个地址返回给前端,以便在前端显示;(3)因为我们这儿可能是上传多张图片,所以声明了一个List;
    15. List imageUrlList = new ArrayList<>();
    16. // 2. 前端传过来的files不能为空,同时里面也必须得有内容;
    17. if (files != null && files.length > 0) {
    18. // 3. 循环遍历files;
    19. for (MultipartFile file : files) {
    20. //定义一个path变量,让其承接该次循环,上传的文件的url;
    21. String path = "";
    22. //4.判断前端传过来的file是否为空;
    23. // 4.1 如果文件不为空,我们就去处理;
    24. if (file != null) {
    25. //5. 获得文件的原始名称;
    26. String fileName = file.getOriginalFilename();
    27. //6. 使用【org.apache.commons.lang3】提供的工具,去判断一下文件名是否为空;
    28. // 7.1 如果文件名不为空,我们就去处理;
    29. if (StringUtils.isNotBlank(fileName)) {
    30. //通过截取最后一个“.”后面的内容,获取文件扩展名
    31. //String suffix = fileName.substring(fileName.lastIndexOf("."));
    32. //8. 这儿采用了另一个逻辑,来获取文件扩展名:先利用"."把文件名拆成了一个数组;然后,获取最后一个元素,就是扩展名;
    33. String[] fileNameArr = fileName.split("\\.");
    34. String suffix = fileNameArr[fileNameArr.length - 1];
    35. //8. 这儿出于安全考虑:这个接口有可能被黑客攻击;黑客可能上传一些.jsp、.php、.sh脚本文件等;如果黑客把这些文件上
    36. // 传了,并且运行;那么,其就可以直接攻击我们的服务器了;所以,我们要判断一下其上传的文件的后缀,是否符合我们的规
    37. // 范;比如,这儿我们就可以规定图片文件只能是.jpg、.png、.jpeg格式的
    38. //8.1 如果文件格式不符合要求;
    39. if (!suffix.equalsIgnoreCase("png") &&
    40. !suffix.equalsIgnoreCase("jpg") &&
    41. !suffix.equalsIgnoreCase("jpeg")) {
    42. //如果文件图片格式既不是"png"、也不是"jpg"、还不是"jpeg"的话;就返回返回提示"文件图片格式不支持!"的GraceJSONResult;
    43. // return GraceJSONResult.errorCustom(ResponseStatusEnum.FILE_FORMATTER_FAILD);
    44. //注:由于我们这儿是多文件上传,如果在上传中间某个文件出错了,就抛出的话;用户体验是不好的;所以,我们
    45. // 这儿的做法时,如果中间上传某个文件出错时,我们就continue跳过此次循环,直接上传下一个文件;
    46. continue;
    47. } else {//8.2 如果能执行到这儿,说明文件时OK的(自然,文件格式也是符合要求);调用service层的方法,去上传文件;
    48. // path = uploaderService.uploadFdfs(file, suffix);//调用Fdfs的逻辑
    49. path = uploaderService.uploadOSS(file, userId, suffix);//调用阿里OSS的逻辑
    50. }
    51. } else {
    52. //7.2 如果文件名为空,直接返回提示"文件不能为空,请选择一个文件再上传!"的GraceJSONResult;
    53. // return GraceJSONResult.errorCustom(ResponseStatusEnum.FILE_UPLOAD_NULL_ERROR);
    54. //注:由于我们这儿是多文件上传,如果在上传中间某个文件出错了,就抛出的话;用户体验是不好的;所以,我们
    55. // 这儿的做法时,如果中间上传某个文件出错时,我们就continue跳过此次循环,直接上传下一个文件;
    56. continue;
    57. }
    58. } else {
    59. //4.2 如果文件为空,直接返回提示"文件不能为空,请选择一个文件再上传!"的GraceJSONResult;
    60. // return GraceJSONResult.errorCustom(ResponseStatusEnum.FILE_UPLOAD_NULL_ERROR);
    61. //注:由于我们这儿是多文件上传,如果在上传中间某个文件出错了,就抛出的话;用户体验是不好的;所以,我们
    62. // 这儿的做法时,如果中间上传某个文件出错时,我们就continue跳过此次循环,直接上传下一个文件;
    63. continue;
    64. }
    65. //如果能执行到这儿,说明上面的一切顺利;
    66. logger.info("path= " + path);//把返回的文件路径信息,打印一下日志,
    67. //最后,还要判断一下,其返回的path是否为空
    68. String finalPath = "";
    69. if (StringUtils.isNotBlank(path)) {
    70. //如果文件名没问题,就拼接文件的最终全路径
    71. // finalPath = fileResource.getHost() + path;//调用Fdfs的storage服务的IP地址和端口号,拼接最终的全路径
    72. finalPath = fileResource.getOssHost() + path;//调用阿里OSS的【https】+【Bucket 名称】+【Endpoint】,拼接最终的全路径
    73. //将此次循环上传的文件,上传后的路径存到imageURLList中去;
    74. // FIXME:其实,在放入imageURLList之前,需要对图片进行一下审核;(只是,图片审核功能,自己并没有做)
    75. imageUrlList.add(finalPath);
    76. } else {
    77. //如果返回的path为空,就返回一个返回提示"文件上传失败!"的GraceJSONResult;
    78. // return GraceJSONResult.errorCustom(ResponseStatusEnum.FILE_UPLOAD_FAILD);
    79. //注:由于我们这儿是多文件上传,如果在上传中间某个文件出错了,就抛出的话;用户体验是不好的;所以,我们
    80. // 这儿的做法时,如果中间上传某个文件出错时,我们就continue跳过此次循环,直接上传下一个文件;
    81. continue;
    82. }
    83. }
    84. }
    85. return GraceJSONResult.ok(imageUrlList);
    86. }

    说明:

    (1)这儿其实就是在 【44:第四章:开发文件服务:5:在【files】文件服务中,整合FastDFS,实现【上传头像】的逻辑;】的基础上,做了一层循环处理;看注释;

    (2)在上传多个文件时,如果上传某个文件出错时,直接continue跳过此次循环即可;其实,在接口处理完返回给前端的时候,前端会做一次判断,如果多张图片中有几张图片上传失败的话,其会给出提示;

    3.效果;

    (1)先install一下整个项目;(2)记得使用SwitchHost开启虚拟域名映射;(3)使用Tomcat启动前端项目;(4)然后,启动后端项目;


    三:【多文件上传,接口】需要用户登录、并且用户是已经激活的状态下,才能调用的;

    利用我们在【36:第三章:开发通行证服务:19:拦截那些“想要访问【获得用户账户信息,接口】和【更改/完善用户信息,接口】的请求“,检查登录信息,校验通过后再放行;(使用【Spring MVC中的拦截器】来实现)】中创建的UserTokenInterceptor拦截器;在InterceptorConfig类中配置UserTokenInterceptor拦截器的地方,增加对【多文件上传,接口】的拦截;

    利用我们在【37:第三章:开发通行证服务:20:拦截那些“想要访问【需要用户是激活状态,才能访问的接口】的请求“,去检查用户状态;(使用【Spring MVC中的拦截器】来实现)】中创建的UserActiveInterceptor拦截器;在InterceptorConfig类中配置UserActiveInterceptor拦截器的地方,增加对【多文件上传,接口】的拦截;

  • 相关阅读:
    Loongson Laptop应用/系统崩溃进入initramfs界面
    四 Pytorch构建分类器
    Linux Centos 根目录扩展分区(保级教程)
    新华三辅导笔记 2023/10/9-2023/10/13
    洛谷 P1349 广义斐波那契数列(矩阵快速幂, 水题)
    市场整改篇之应用宝报告
    【面试必问】HTTP与HTTPS的区别以及HTTPS的工作流程
    三维重建---第四章 三维重建及极几何
    Java+SpringBoot+Vue:瑜伽馆管理的黄金组合
    java并发编程,lock(),trylock(),lockInterruptibly()的区别
  • 原文地址:https://blog.csdn.net/csucsgoat/article/details/126272532