解决的问题:

  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. Java程序,JVM之间的关系

    java程序是跑在JVM上的,严格来讲,是跑在JVM实例上的.一个JVM实例其实就是JVM跑起来的进程,二者合起来称之为一个JAVA进程.各个JVM实例之间是相互隔离的. 每个java程序都运行于某个 ...

  2. 第三天·HTML常用标签

    一·<h1>-<h6> 单词缩写:headHTML的<h1>-<h6>代表了六个等级的标题,其中<h1>标签比较重要,因此要尽量少用.一般& ...

  3. Spark学习(二)——RDD的设计与运行原理

    Spark的核心是建立在统一的抽象RDD之上,使得Spark的各个组件可以无缝进行集成,在同一个应用程序中完成大数据计算任务.RDD的设计理念源自AMP实验室发表的论文<Resilient Di ...

  4. SAP MaxDB Backup and Restore

    Back up the data and redo log entries from the data and log areas of your database to data carriers ...

  5. IP冲突如何把冲突的IP挤下去

    把冲突IP挤下去的方法: ①进入网络和共享中心>本地连接>禁用. ②进入网络和共享中心>更改适配器设置>双击被禁用的连接,自动重新连接即可.

  6. 一键发布shell脚本

    1.配置集群间免密登录 (1)配置host:vim /etc/hosts (2)生成公钥 :ssh-keygen -t rsa -P '' 这时会提示生成的公钥的存放地址,直接回车,公钥生成成功 (3 ...

  7. c# VirtualKeys

    /// <summary> /// Enumeration for virtual keys taken from http://www.pinvoke.net/default.aspx/ ...

  8. java:JavaScript2:(setTimeout定时器,history.go()前进/后退,navigator.userAgent判断浏览器,location.href,五种方法获取标签属性,setAttribute,innerHTML,三种方法获取form表单信息,JS表单验证,DOM对象,form表单操作)

    1.open,setTimeout,setInterval,clearInterval,clearTimeout <!DOCTYPE> <html> <head> ...

  9. java里null强转为某个类会报错吗?

    1.定义一个User类如下: /** * @author lizhibiao * @date 2018/11/27 17:21 */public class User{ private String ...

  10. 根据输入的整数n使得输出精确到小数n位

    #include<iostream> #include<stdio.h> using namespace std; int main(){ int a,b,c; while(t ...