写点什么

在线问题反馈模块实战 (九)​: 实现图片上传功能 (下)

作者:bug菌
  • 2022-10-21
    江苏
  • 本文字数:4981 字

    阅读完需:约 1 分钟

在线问题反馈模块实战(九)​:实现图片上传功能(下)

👨‍🎓作者:bug 菌

✏️博客:​​CSDN​​​、​​掘金​​等

💌公众号:​​猿圈奇妙屋​

🚫特别声明:原创不易,转载请附上原文出处链接和本文声明,谢谢配合。

🙏版权声明:文章里可能部分文字或者图片来源于互联网或者百度百科,如有侵权请联系 bug 菌处理。 

一、前言🔥

       接下来的这几期,bug 菌想跟大家分享一下自己昨天刚接到一个临时的需求,热乎着呢,想分享一下自己是如何面对临时需求并制定整个开发周期,其中包括从梳理业务到创建业务表再到实现业务逻辑形成闭环再到与前端对接,其中会穿插一些业务拓展及功能性拓展,这一条龙流程在线与大家一起见证,分享给刚入门的小伙伴,希望对你们有所帮助。

环境说明:idea2019.3 + springboot2.3.1.REALSE + mybati-plus3.2.0 + mysql5.6 + jdk1.8

       若小伙伴们在批阅文章的过程中觉得文章对您有一丝丝帮助,还请别吝啬您手里的赞呀,大胆的把文章点亮👍吧,您的点赞三连(收藏⭐️+关注👨‍🎓+留言📃)就是对 bug 菌我创作道路上最好的鼓励与支持😘。时光不弃🏃🏻‍♀️,创作不停💕,加油☘️ 

二、正文🔥

        上一期我们讲述了如何从一个业务梳理成具体的某些接口,再到接口如何定义,需要注意那些事项,不知道大家是否有记起来,然而这一期,我们就顺着已经确定的接口上实现业务逻辑,可能你们还会问,不就是对于该接口进行一个代码实现么,是的没错,但是我此处讲的肯定是经过了自己改了又改,删了又写最终得出来的,我就要拿最优的代码思路给大家做参考,但是也并不是说我这就是最优的,肯定都是有值得优化的地方,这里就需要发挥大家的思维与创造力了。

        好啦,咱们进入正题吧。手把手带着大家进行 coding。

三、接口逻辑实战🔥

        我们先是在 Controller 层定义了该问题反馈保存接口及访问接口路径等,具体定义如下:

/**     * 反馈问题保存     *     * @param images          img图片数组     * @param inPage          问题反馈/建议所在页面     * @param questionContent 反问题反馈/建议描述     * @param    @PostMapping("/save")    @SysLog(logType = LogTypeEnum.LOG_TYPE_IMG_UPLOAD)    @ApiOperation(value = "反馈问题保存", notes = "反馈问题保存")    public ResultResponse<Boolean> saveQuestion(@ApiParam("图片数组") MultipartFile[] images,                                                @ApiParam("问题反馈类型") String questionType,                                                @ApiParam("问题反馈/建议描述") String questionContent,                                                @ApiParam("问题反馈/建议所在页面") throws IOException {        return
复制代码

接着就是实现 saveQuestion()方法了。这里对于肯定是直接先定义到 userQuestionsService 接口层,然后通过实现该接口层进行方法的具体实现。

定义接口方法如下:

ResultResponse<Boolean> saveQuestion(MultipartFile[] images, String questionType, String questionContent, String inPage) throws
复制代码

这里我是直接反回了一个自定义类型,且自定义类型是个布尔值。

        然后就是该接口的的重点了,怎么说呢?这也是该接口的核心业务了,如何保存反馈内容,如何保存问题反馈图片数组。切记这里是支持多图片上传。

        接着就是通过 UserQuestionsServiceImpl 通过 implements 关键字来实现 IUserQuestionsService 接口层的所有方法,其中也就包括实现 saveQuestion()方法。


@Overridepublic ResultResponse<Boolean> saveQuestion(MultipartFile[] images, String questionType, String questionContent, String inPage) throws
复制代码


        对于这个业务实现,也是有点坑的。对于业务实现,我们一般要做的步骤就是,第一步干嘛,第二步干嘛...一定要先列举清楚,要不然写一点敲一点,最后肯定是有问题的。

第一步:遍历 MultipartFile[] images 图片数组,分别调用图片上传方法。

第二步:实现图片上传方法。

第三部:实现基础字段内容保存并方法返回。

        然后具体对于三步骤,我们也是要具体的业务思维,对于遍历图片保存,这里就需要有一点要注意,你应该要留意,我们一次问题反馈调用,就生成一条记录,但对于一次请求,对于多图片,我们怎么做到一对多呢?其实啊,这就在你定义表字段时,就应该考虑清楚,所以我这里就根据一个字段来处理,也就是在你进行保存图片之后,专属定义一个外循环变量来存放所有的图片保存地址,然后两图片地址之间,你可以用逗号隔开,也可以用别的字段间隔都可。

imgPaths = imgPaths + ","
复制代码

就像如上所示,直接用逗号隔开,但是有一点是需要大家注意的,在你进行逗号隔开时,你要考虑如果 MultipartFile[] images 图片数组为 1,你就不应该有逗号间隔了啊。

        讲到这里,我也诺列的差不多了,想必小伙伴们心里都清楚如何实现了吧?

第一步:遍历调用图片上传方法

if (images.length > 0) {
//分批处理图片保存 for (int i = 1; i <= images.length; i++) {
//当前图片 MultipartFile img = images[i - 1];
//获取文件后缀。 String imageSuffix = FilenameUtils.getExtension(img.getOriginalFilename()).toLowerCase(); //非以上文件后缀直接跳过。 if (!CONTENT_TYPES.contains(imageSuffix)) { continue; }
//获取当前时间进行命名。 String template = TimeUtils.getPrivateTime(ConstantUtils.TIME_STAMP_BEFORE2) + "_" + i;
//重写img文件名 eg:20220527100245.jpg String saveImgPath = template + "." + imageSuffix;
//图片保存绝对地址 String savePath = this.buildImgPath(saveImgPath, accountId);
//图片上传 uploader.uploadImg(img, savePath);
//路径用逗号拼接。 if (StringUtils.isNotEmpty(imgPaths)) { imgPaths = imgPaths + "," + saveImgPath; } else
复制代码

注意:这里会涉及到两个比较坑的点。第一个就是对于同一个遍历方法,获取到的时间戳会是一致的,所以如果你想自定义别名图片,你就不能只通过时间戳来进行别名,你应该还得加盐,由于我是想区分用户那天上传的那些图片,才特定通过获取时间戳来进行别名,我这里提供的做法就是在时间戳后再拼接一个遍历下边,这样就保证了同一用户在一次接口调用反馈时,图片是按 template_index 来命名的。第二点就是需要留意对于图片数组=1 的,你就不应该也逗号间隔,加一个判断即可。

第二步:实现图片上传方法

对于这一步,实现方式还是相对较多的,我这里为了给大家教学,就使用一种超级简单的实现方式,比如 MultipartFile 类自带的 transferTo()方法。

    public void uploadImg(MultipartFile image, String savePath) throws IOException {    File file = new File(savePath);    //检测是否存在该目录    if (!file.getParentFile().exists()) {        file.getParentFile().mkdirs();    }    //写入文件
复制代码

这里需要注意的就是一点,要判断该路径存在与否,不存在还是得要进行路径的创建再进行文件写入。

第三步:实现实体类数据库写入方法

        这一步就相对比较简单了,我们由于将已上传成功返回的图片保存地址进行了路径拼接,我们即可直接定义一个实体,进行数据赋值即可。

UserQuestionsEntity entity = new UserQuestionsEntity(user, questionType, questionContent, inPage, imgPaths);
复制代码

然后在对应的实体类将字段内容进行手动赋值即可。

public UserQuestionsEntity(SysUserEntity user, String questionType, String questionContent, String inPage, String imgPath) {        this.status = UsualStatusEnum.NORMAL.getKey();        this.creatorAccountId = user.getAccountId();        this.creatorName = user.getAccountName();        this.creatorDeptName = user.getDeptName();        this.questionType = questionType;        this.questionContent = questionContent;        this.inPage = inPage;        this.filePaths = imgPath;    }
复制代码

这里就不需要再手动赋值那些创建时间、创建人等操作字段了,因为我们前边是已经添加了字段自动填充。

最后就是直接调用 mp 提供的 save 方法即可。

return new ResultResponse<>(this.save(entity));
复制代码

第四步:接口调用测试

最后,我们重启项目,通过 postman 进行接口调用测试。


很完美也是成功将图片保存到了指定位置下。

 ... ...

        好啦,以上就是这期的所有内容啦,你们学废了么?如果对你有所帮助,还请不要忘记给 bug 菌[三连支持]哟。如果想获得更多的学习资源或者想和更多的技术爱好者一起交流,可以关注我的公众号『​​猿圈奇妙屋​​』,后台回复关键词领取学习资料、大厂面经、面试模板等海量资源,就等你来拿。

四、往期热文推荐🔥

        对于问题反馈模块实战开发,我完整的梳理了每一期的教学及链接地址,仅供参考:希望能对你们有所帮助。

        如上是整整二十期内容,每一期都是干货,对于一个模块的开发,如何一点一滴打造并测试部署上线,我再说一遍,这不是演习,是实战!是实战!是实战!

        若你们觉得只是需要了解其中某个知识点或者业务的话,也不反对,你就选择其中的几期进行学习就好,反正都已经完结啦;我只希望你们能有所收获,有所成长,也就不枉我苦心每天下班后给大家总结更新。

五、文末🔥

​《springboot零基础入门教学》​​,都是我一手打下的江山,持续更新中,希望能帮助到更多小伙伴们。

       我是 bug 菌,一名想走👣出大山改变命运的程序猿。接下来的路还很长,都等待着我们去突破、去挑战。来吧,小伙伴们,我们一起加油!未来皆可期,fighting!

        最后送大家两句我很喜欢的话,与诸君共勉!


☘️做你想做的人,没有时间限制,只要愿意,什么时候都可以 start。

🍀你能从现在开始改变,也可以一成不变,这件事,没有规矩可言,你可以活出最精彩的自己。




💌如果文章对您有所帮助,就请留下您的吧!(#^.^#);

💝如果喜欢 bug 菌分享的文章,就请给 bug 菌点个关注吧!(๑′ᴗ‵๑)づ╭❤~;

💗如果对文章有任何疑问,还请文末留言或者加群吧【QQ 交流群:708072830】;

💞鉴于个人经验有限,所有观点及技术研点,如有异议,请直接回复参与讨论(请勿发表攻击言论,谢谢);

💕版权声明:原创不易,转载请附上原文出处链接和本文声明,版权所有,盗版必究!!!谢谢。


发布于: 刚刚阅读数: 4
用户头像

bug菌

关注

公众号 | 猿圈奇妙屋 2020-07-30 加入

在CSDN、掘金等社区优质创作者,全网合计6w粉+,对一切技术都感兴趣,重心偏java方向,目前运营公众号[猿圈奇妙屋],欢迎小伙伴们的加入,一起秃头。

评论

发布
暂无评论
在线问题反馈模块实战(九)​:实现图片上传功能(下)_springboot_bug菌_InfoQ写作社区