解决的问题:

  1、使用view的<Upload>组件实现图片文件的上传。

  2、<Upload>组件action请求地址无法到自己写的后台。

  3、前台base64的图片展示。

  4、文件伪造。(修改文件的后缀为图片格式的后缀)。

需求很简单:

  将某一模块的编辑页面的"XX图片"字段由文本框输入改成上传图片。或者新增一个图片上传的属性。

  要求:

  1、 前端图片展示用BASE64格式的形式展示。

一、完成后的效果图:

1、上传前

2、点击相机,选择图片文件进行上传。

2.1 文件格式的校验

2.2 文件大小的限制

3、上传后

4、点击图片中的眼睛图标,可以对图片进行放大查看。

5、点击图片中的垃圾筒的图标,可以对图片进行删除。回到上传前。

二、前端vue组件代码。

官网地址:

https://www.iviewui.com/components/upload

<template>
<div class="demo-upload-list" v-if="formData.stationPic">
<template>
<img :src="formData.stationPic">
<div class="demo-upload-list-cover">
<Icon type="ios-eye-outline" @click.native="handleView()"></Icon>
<Icon type="ios-trash-outline" @click.native="handleRemove()"></Icon>
</div>
</template>
</div>
<Upload
ref="upload"
:show-upload-list="false"
:on-success="handleSuccess"
:format="['jpg','jpeg']"
:max-size="2048"
:on-format-error="handleFormatError"
:on-exceeded-size="handleMaxSize"
:before-upload="handleBeforeUpload"
:headers="headers"
type="drag"
action="/api/zclanes/upload"
style="display: inline-block;width:58px;">
<div style="width: 58px;height:58px;line-height: 58px;">
<Icon type="ios-camera" size="20"></Icon>
</div>
</Upload>
<Modal title="View Image" v-model="visible">
<img :src="formData.stationPic" v-if="visible" style="width: 100%">
</Modal>
</template>
    data() {
return {
headers: {'Sonep-Token': CacheUtil.getSession('access-token')},
visible: false,
},
    methods: {
handleView() {
this.visible = true;
},
handleRemove() {
this.formData.stationPic = null;
},
handleSuccess(res, file) {
if (res.status === 200) {//上传成功
this.$Message.success('上传成功');
this.formData.stationPic = res.data;
} else {
this.$Message.error('上传失败');
}
},
handleFormatError(file) {
this.$Notice.warning({
title: '文件格式不正确',
desc: file.name + '的文件格式不正确, 请选择jpg或者jpeg格式的图片'
});
},
handleMaxSize(file) {
this.$Notice.warning({
title: '超出文件大小限制',
desc: file.name + '文件太大,不能超过2M.'
});
},
handleBeforeUpload() {//上传文件之前的钩子,参数为上传的文件,若返回 false 或者 Promise 则停止上传 } },

三、后端代码

3.1 controller

    /**
* 图片上传
* @param file
* @return
*/
@RequestMapping("/upload")
public ResponsePayload upload(MultipartFile file){ return service.upload(file);
}

3.2 service

    @Override
public ResponsePayload upload(MultipartFile file) { try {
//判断文件是不是图片
BufferedImage image = ImageIO.read(file.getInputStream());
if (image == null || image.getWidth() <= 0 || image.getHeight() <= 0) {
return ResponseUtil.getFailResponse(HttpStatus.SC_BAD_REQUEST, "你上传的不是图片文件");
}
} catch (IOException e) {
e.printStackTrace();
return ResponseUtil.getFailResponse(HttpStatus.SC_INTERNAL_SERVER_ERROR, "上传异常, 请稍后再试...");
} //获取存放文件的临时路径
String filePath = IOHelper.checkPath(System.getProperty("java.io.tmpdir") + "img/");
// String filePath = FileUtils.getDataFilePath("d:/img");
//1. 获取文件的原始名称
String originalFilename = file.getOriginalFilename();//timg (1).jpg
//1.1 获取最后一个.的位置
int lastIndexOf = file.getOriginalFilename().lastIndexOf(".");
//1.2 获取文件的后缀名 .jpg
String suffix = originalFilename.substring(lastIndexOf);
//2. 重命名文件名称
String fileName = UUID.randomUUID().toString() + suffix;
File savedFile = new File(filePath, fileName);
try {
file.transferTo(savedFile);
//转BASE64
String path = savedFile.getPath();
//返回BASE64图片字符串
return ResponseUtil.success(ImageBase64Utils.toBase64(path));
} catch (IOException e) {
e.printStackTrace();
return ResponseUtil.getFailResponse(HttpStatus.SC_INTERNAL_SERVER_ERROR,"上传异常, 请稍后再试...");
} finally {
//删除本地保存的图片
savedFile.delete();
} }

四、问题回顾及解决

我们依次看下文章开头提到的4个问题

4.1 使用view的<Upload>组件实现图片文件的上传。

可以看下本文的第二部分:前端vue组件代码。

同时也给出官网地址:

https://www.iviewui.com/components/upload

4.2 <Upload>组件action请求地址无法到自己写的后台。

这个问题很恶心。

4.2.1 action地址的写法

官网用的是自己写的请求地址:action="//jsonplaceholder.typicode.com/posts/"。仔细一看是什么鬼,怎么有两个斜杠。

运行下官网的例子:

我们看到发送的请求是:https://jsonplaceholder.typicode.com/posts/。

仔细分析下:发现地址前面是带域名的:jsonplaceholder.typicode.com

这里有几种写法:

写法一:如果域名是不变的。

action="//localhost:8080/api/zclanes/upload"  ---> http://localhost:8080/api/zclanes/upload

写法二:不加域名的写法。(本文用的是这种)

action="/api/zclanes/upload"   ---> http://localhost:8080/api/zclanes/upload

4.2.2 请求的发送

填写完正确的地址后,后台代码也写好了。重启项目后,请求发送不出去。

我这里最后查出来是少加了个请求头。猜测:项目有auth功能,每个请求都必须加鉴权的请求头进行鉴权。如果有跟我一样的问题,找到要加的请求头,把请求头加上去就ok了。部分代码如下,详细代码上文有。其实想说明的是,<Upload>组件请求头如何添加。 其实还可以添加请求参数,具体参考官网API。

:headers="headers"
headers: {'Sonep-Token': CacheUtil.getSession('access-token')},

4.2.3 前台base64的图片展示。

参考地址:https://www.cnblogs.com/hjw-zq/p/8821898.html

其实就一句代码:

formData.stationPic: 就是后台返回的BASE64的字符串。
<img :src="formData.stationPic">

base图片展示原理: https://www.cnblogs.com/zdz8207/p/web-image-base64.html

个人理解:将图片文件转成BASE64格式的字符串。由页面自动会解析BASE64格式的图片文件。跟图片文件所在路径没有关系。也就是说,转完BASE64格式后,你把本地的图片删了都没事。

4.2.4 文件伪造。(修改文件的后缀为图片格式的后缀)。

其实解决完上面三个问题,这个功能完成的就八九不离十了。 当我在测文件大小限制的时候,我电脑里没找到2M的图片,于是我就找了个2M的excel文件,把它的后缀名改成了图片格式进行上传。测试通过。于是我就想到了,如果小于2M的文件改了会上传成功么。 答案肯定是不允许的,因为它本质就不是图片。测试也能上传成功,但就是显示不出图案来。这肯定是不对的。

于是我就想到了还少个判断文件是否是图片的逻辑。

Java判断文件是否是图片:
参考地址:https://blog.csdn.net/itjauser/article/details/97395034

五、小结:

图片上传看似简单的一个动作,其实过程很复杂。

流程大致如下:

1、选择上传的文件,发送请求。(这里请求的业务逻辑有很多种解决方案,可以把图片上传到服务器(七牛云、阿里云、本地的数据库等)。或者转成BASE64格式的字符串。不管哪种实现方式,目的都是为了把图片以某种形式存放起来,并将图片地址存放的地址返回,在前台进行显示)。

2、 将图片以BASE64的形式存储。

3、 返回BASE64字符串。

4、 拿到后台响应的图片地址,进行展示。

ImageBase64Utils 工具类
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sun.misc.BASE64Encoder; import java.io.File;
import java.io.FileInputStream;
import java.io.IOException; public class ImageBase64Utils {
private static Logger log = LoggerFactory.getLogger(ImageBase64Utils.class);
public static String toBase64(String filePath) {
FileInputStream fis = null;
String base64Prefix = "data:image/jpeg;base64,";
String imgStr = "";
try {
File file = new File(filePath);
if(file.exists()) {
fis = new FileInputStream(file);
byte[] buffer = new byte[(int) file.length()];
int offset = 0;
int numRead = 0;
while (offset < buffer.length && (numRead = fis.read(buffer, offset, buffer.length - offset)) >= 0) {
offset += numRead;
}
if (offset != buffer.length) {
log.error("图片文件未读取完毕!");
}
fis.close();
BASE64Encoder encoder = new BASE64Encoder();
imgStr = base64Prefix + encoder.encode(buffer);
}
} catch (Exception e) { } finally {
if(fis != null) {
try {
fis.close();
} catch (IOException e) {
}
}
}
return imgStr;
}
}

最后,不喜勿喷。 有想法可以在下面留言,一起交流。

ivew组件上传图片文件的功能:的更多相关文章

  1. angularJs中上传图片/文件功能:ng-file-upload

    原文技术交流:http://www.ncloud.hk/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/angularjs-ng-file-upload/ 在做网站的过程中难 ...

  2. .NET平台开源项目速览(13)机器学习组件Accord.NET框架功能介绍

    Accord.NET Framework是在AForge.NET项目的基础上封装和进一步开发而来.因为AForge.NET更注重与一些底层和广度,而Accord.NET Framework更注重与机器 ...

  3. .NET跨平台之旅:增加文件日志功能遇到的挫折

    在将我们的ASP.NET 5示例站点(about.cnblogs.com)升级至ASP.NET 5 RC1的时候,我们增加了控制台日志功能. 在ASP.NET 5添加日志功能很简单,只需在projec ...

  4. 利用其它带文件防护功能的软件防止*.asp;*.jpg写入文件。

    此木马是一个.NET程序制作,如果你的服务器支持.NET那就要注意了,,进入木马有个功能叫:IIS Spy,点击以后可以看到所有站点所在的物理路径.以前有很多人提出过,但一直没有人给解决的答案.. 防 ...

  5. 转: KindEditor 图片空间文件增加删除文件、文件夹功能(ASP语言环境)

    KindEditor 图片上传功能中集成的图片空间文件管理插件可以对已上传图片进行管理,十分便捷,只是没有图片删除功能,仔细研读xieliang分享的经验后,自己动手改造了一下,顺便分享给有同样需求的 ...

  6. 利用 FormData 对象和 Spring MVC 配合可以实现Ajax文件上载功能

    Ajax文件上载 利用 FormData 对象和 Spring MVC 配合可以实现Ajax文件上载功能: 步骤 导入组件并准备静态脚本 <dependency> <groupId& ...

  7. C#使用FileSystemWatcher控件实现的文件监控功能示例

    本文实例讲述了C#使用FileSystemWatcher控件实现的文件监控功能.分享给大家供大家参考,具体如下: FileSystemWatcher 可以使用FileSystemWatcher组件监视 ...

  8. JS 上传图片 + 预览功能(一)

    JS 上传图片 + 预览功能 <body> <input type="file" id="fileimg1" style="disp ...

  9. jquery组件WebUploader文件上传用法详解

    这篇文章主要为大家详细介绍了jquery组件WebUploader文件上传用法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下 WebUploader是由Baidu WebFE(FEX)团队开发的一 ...

随机推荐

  1. kaliXSSbeef的使用

    Kali中Beef的安装和使用: 先打开终端输入 apt-get install beef-xss 然后切换到beef的安装目录 cd /usr/share/beef-xss 然后启动beef ./b ...

  2. python学习之路(10)--难点

    递归函数 在函数内部,可以调用其他函数.如果一个函数在内部调用自身本身,这个函数就是递归函数. 举个例子,我们来计算阶乘n! = 1 x 2 x 3 x ... x n,用函数fact(n)表示,可以 ...

  3. snmpEngineBoots & snmpEngineID数据存储到非易失性存储设备

    #include <stdio.h> #include <stdlib.h> #include <string.h> int regenerateID() { ; ...

  4. 数字 kotlin (1)

    数字Kotlin 处理数字在某种程度上接近 Java,但是并不完全相同.例如,对于数字没有隐式拓宽转换(如 Java 中 int 可以隐式转换为 long ——译者注),另外有些情况的字面值略有不同. ...

  5. CondenseNet: An Efficient DenseNet using Learned Group Convolutions

    1. 摘要 作者提出了一个前所未有高效的新奇网络结构,称之为 CondenseNet,该结构结合了密集连接性和可学习的分组卷积模块. 密集连接性有利于网络中的特征复用,而可学习的分组卷积模块则可以移除 ...

  6. CSS二级菜单

    0.需求:当鼠标hover到按钮上时,出现下拉菜单导航条. 1.问题拆解: (1)HTML应该如何组织比较方便合理 因为题中要求下拉菜单位于按钮的正下方,可以使用列表<li>中嵌套无序列表 ...

  7. JForum论坛安装以及部署(转)

    链接地址:https://www.cnblogs.com/Amos-Turing/p/7151009.html 下载JForum2.1.9 包手动放到tomcat的webapps下面, 这次打开网址: ...

  8. 之前写的页面导出Excel表格

    废话不多说,直接上代码 <%@ page language="java" import="java.util.*" pageEncoding=" ...

  9. RTX和谐说明

    1.下载安装原版RTX20152.打开“服务”,停止RTX开头的服务.3.替换C:\Program Files\Tencent\RTXServer\License目录下的License.ini文件:替 ...

  10. opencv的曲线拟合polyfit

    推荐一个不错的网页,可以直接用solve函数求解方程组: http://m.blog.csdn.net/u014652390/article/details/52789591 4.1 曲线拟合的最小二 ...