一、前言

在使用spring boot做后台系统,vue做前端系统,给客户开发一套系统时候,其中用到了图片上传和显示的功能。

二、环境

前端:vue
前端组件:tinymce
后台:spring boot:2.2.3

三、正文

    在客户开发一套门户管理系统时,集成了tinymce组件,用于编辑内容,springboot不同于其他项目。
是集成tomcat的,文件和图片是不能直接访问的。所以我在做集成富文本编辑器时,需要处理图片的问题。
这个问题跟上传头像等显示图片的功能是类似的。下面记录详情步骤代码。

第一步:集成tinymce组件

<!--引入tinymce组件-->
import Tinymce from '@/components/Tinymce'
<!--启用tinymce组件-->
<el-form-item>
<el-button type="primary" :loading="btnLoading" @click="onSubmit" >保 存</el-button>
</el-form-item>
<!--核心代码-->
<template>
<div class="page-container">
<div class="page-title-section"> </div>
<div class="page-content-section">
<div class="page-content-form">
<el-form ref="dataForm" :model="formData" :rules="formRules" label-width="180px"> <el-form-item>
<div>
<tinymce v-model="formData.content" :height="300" />
</div>
</el-form-item>
<el-form-item>
<el-button type="primary" :loading="btnLoading" @click="onSubmit" >保 存</el-button>
</el-form-item>
</el-form>
</div>
</div> </div>
</template>
<script> import Tinymce from '@/components/Tinymce' export default {
name:"contentEdit",
components: {Tinymce},
data(){
return{ formData:{
content:'',
}, }
},
created() { },
mounted() {},
activated() {},
deactivated() {},
methods:{
//表单提交
onSubmit(){
this.$refs['dataForm'].validate((valid) => {
if (valid) {
this.btnLoading = true
this.$axios({
url: this.formData.id == '' ? '/products/save' : '/products/edit',
method: 'POST',
params: this.formData
}).then(res => {
//处理成功回调
const{ state,result , errmsg} = res.data
if( state && state == 1 ){
this.$message.success('操作成功');
this.$router.push( {path:'/products/list'} )
}else{
return this.$message.error(errmsg || '操作失败');
} }).finally(() => {
this.btnLoading = false
})
}
})
}, </script>
<!--Tinymce初始化代码-->
initTinymce() {
const _this = this
window.tinymce.init({
selector: `#${this.tinymceId}`,
language: this.languageTypeList['en'],
height: this.height,
body_class: 'panel-body ',
object_resizing: false,
toolbar: this.toolbar.length > 0 ? this.toolbar : toolbar,
menubar: this.menubar,
plugins: plugins,
end_container_on_empty_block: true,
powerpaste_word_import: 'clean',
code_dialog_height: 450,
code_dialog_width: 1000,
advlist_bullet_styles: 'square',
advlist_number_styles: 'default',
imagetools_cors_hosts: ['www.tinymce.com', 'codepen.io'],
default_link_target: '_blank',
link_title: false,
nonbreaking_force_tab: true, // inserting nonbreaking space &nbsp; need Nonbreaking Space Plugin
//上传图片回调
images_upload_handler:(blobInfo, success, failure) => {
var xhr, formData; xhr = new XMLHttpRequest();
xhr.withCredentials = false;
xhr.open('POST', '/api/file/imageUpload'); xhr.onload = function () {
var json; if (xhr.status !== 200) {
failure('HTTP Error: ' + xhr.status);
return;
} json = JSON.parse(xhr.responseText);
// console.log(json);
json.location = util.baseURL + json.data.filename; //在该位置,如果您的后端人员返回的字段已经包含json.location信息,则该处可以省略
if (!json || typeof json.location !== 'string') {
failure('Invalid JSON: ' + xhr.responseText);
return;
} success(json.location);
}; formData = new FormData();
formData.append('file', blobInfo.blob(), blobInfo.filename()); xhr.send(formData); },
init_instance_callback: editor => {
if (_this.value) {
editor.setContent(_this.value)
}
_this.hasInit = true
editor.on('NodeChange Change KeyUp SetContent', () => {
this.hasChange = true
this.$emit('input', editor.getContent())
})
},
setup(editor) {
editor.on('FullscreenStateChanged', (e) => {
_this.fullscreen = e.state
})
}
// 整合七牛上传
// images_dataimg_filter(img) {
// setTimeout(() => {
// const $image = $(img);
// $image.removeAttr('width');
// $image.removeAttr('height');
// if ($image[0].height && $image[0].width) {
// $image.attr('data-wscntype', 'image');
// $image.attr('data-wscnh', $image[0].height);
// $image.attr('data-wscnw', $image[0].width);
// $image.addClass('wscnph');
// }
// }, 0);
// return img
// },
// images_upload_handler(blobInfo, success, failure, progress) {
// progress(0);
// const token = _this.$store.getters.token;
// getToken(token).then(response => {
// const url = response.data.qiniu_url;
// const formData = new FormData();
// formData.append('token', response.data.qiniu_token);
// formData.append('key', response.data.qiniu_key);
// formData.append('file', blobInfo.blob(), url);
// upload(formData).then(() => {
// success(url);
// progress(100);
// })
// }).catch(err => {
// failure('出现未知问题,刷新页面,或者联系程序员')
// console.log(err);
// });
// },
})
},
destroyTinymce() {
const tinymce = window.tinymce.get(this.tinymceId)
if (this.fullscreen) {
tinymce.execCommand('mceFullScreen')
} if (tinymce) {
tinymce.destroy()
}
},
setContent(value) {
window.tinymce.get(this.tinymceId).setContent(value)
},
getContent() {
window.tinymce.get(this.tinymceId).getContent()
},
imageSuccessCBK(arr) {
const _this = this
arr.forEach(v => {
window.tinymce.get(_this.tinymceId).insertContent(`<img class="wscnph" src="${v.url}" >`)
})
}
}

第二步:后台代码

@RequestMapping(value = "/imageUpload", method = RequestMethod.POST)
public void imageUpload(@RequestParam("file") MultipartFile file, HttpServletRequest request, HttpServletResponse response) {
try {
logger.info("上传图片名 :" + file.getOriginalFilename()); if (!file.isEmpty()) {
// Properties p = new Properties();// 属性集合对象
// String path = RedisUtil.class.getClassLoader().getResource("").getPath()+"global.properties";
// FileInputStream fis = new FileInputStream(path);// 属性文件输入流
// p.load(fis);// 将属性文件流装载到Properties对象中
// fis.close();// 关闭流
// String uploadPath = p.getProperty("imgUpload.url");
// //路径名称上加上-年/月日:yyyy/MMdd
// uploadPath += "Uploads/"+new SimpleDateFormat("yyyy").format(new Date())+ "/" +new SimpleDateFormat("MMdd").format(new Date())+"/"; String path= request.getServletContext().getRealPath("/"); path="/Users/qinshengfei/fsdownload";
logger.error("path:"+path);
//路径名称上加上-年/月日:yyyy/MMdd
String uploadPath = File.separatorChar+"Uploads"+File.separatorChar+new SimpleDateFormat("yyyy").format(new Date())+
File.separatorChar +new SimpleDateFormat("MMdd").format(new Date())+File.separatorChar; // 文件上传大小
long fileSize = 10 * 1024 * 1024;
//判断文件大小是否超过
if (file.getSize() > fileSize) {
backInfo(response, false, 2, "");
return;
}
//获取上传文件名称
String OriginalFilename = file.getOriginalFilename();
//获取文件后缀名:如jpg
String fileSuffix = OriginalFilename.substring(OriginalFilename.lastIndexOf(".") + 1).toLowerCase();
if (!Arrays.asList(TypeMap.get("image").split(",")).contains(fileSuffix)) {
backInfo(response, false, 3, "");
return;
}
//判断是否有文件上传
// if (!ServletFileUpload.isMultipartContent(request)) {
// backInfo(response, false, -1, "");
// return;
// } // 检查上传文件的目录
File uploadDir = new File(path+uploadPath);
System.out.println(path+uploadPath);
if (!uploadDir.isDirectory()) {
if (!uploadDir.mkdirs()) {
backInfo(response, false, 4, "");
return;
}
} // 是否有上传的权限
if (!uploadDir.canWrite()) {
backInfo(response, false, 5, "");
return;
} // 新文件名-加13为随机字符串
String newname = getRandomString(13) +"." + fileSuffix; File saveFile = new File(path+uploadPath, newname); try {
file.transferTo(saveFile); backInfo(response, true, 0, uploadPath+newname);
} catch (Exception e) {
logger.error(e.getMessage(), e);
backInfo(response, false, 1, "");
return;
}
} else {
backInfo(response, false, -1, "");
return;
}
} catch (Exception e) {
logger.error(e.getMessage());
} } // 返回信息
private void backInfo(HttpServletResponse response, boolean flag, int message, String fileName) {
fileName=fileName.replace("\\","/");
String json = "";
if (flag) {
json = "{ \"status\": \"success";
} else {
json = "{ \"status\": \"error";
}
json += "\",\"fileName\": \"http://127.0.0.1:8090/file/show?fileName=" + fileName + "\",\"message\": \"" + message + "\"}";
try {
response.setContentType("text/html;charset=utf-8");
response.getWriter().write(json);
} catch (IOException e) {
logger.error(e.getMessage(), e);
}
}

第三步:后台处理显示图片

 /**
* 显示单张图片
* @return
*/
@RequestMapping("/show")
public ResponseEntity showPhotos(String fileName){ try {
String path = "/Users/qinshengfei/fsdownload";
// 由于是读取本机的文件,file是一定要加上的, path是在application配置文件中的路径
logger.error("showPhotos:"+path+fileName);
return ResponseEntity.ok(resourceLoader.getResource("file:" + path + fileName));
} catch (Exception e) {
return ResponseEntity.notFound().build();
}
}

第四步:显示效果

总结

这个例子是工作中遇到的一个问题,这里只讲述tinymce组件图片功能。同时,工作中使用使用到了vue-cropper组件,原理类似。

ps:上述代码使用中,如有问题,请联系公众号:

vue+springboot图片上传和显示的更多相关文章

  1. ruby on rails爬坑(三):图片上传及显示

    一,问题及思路 最近在用rails + react + mysql基本框架写一个cms + client的项目,里面涉及到了图片的上传及显示,下面简单说说思路,至于这个项目的配置部署,应该会在寒假结束 ...

  2. 图片上传即时显示javascript代码

    这是基于javascript的一种图片上传即时显示方法,测试结果IE6和火狐浏览器可以正常使用.google浏览器不兼容. 这种方法兼容性比较差,仅供参考,建议使用ajax方法来即时显示图片. 1.首 ...

  3. 图片上传并显示(兼容ie),图片大小判断

    图片上传并显示(兼容ie),图片大小判断 HTML <div id="swf" style="margin: 0 auto;text-align: center;& ...

  4. SpringBoot图片上传(五) 上一篇的新版本,样式修改后的

    简单描述:一次上传N张图片(N可自定义):上传完后图片回显,鼠标放到已经上传的图片上后,显示删除,点击后可以删除图片,鼠标离开后,图片恢复. 效果:一次上传多个图片后的效果 上传成功: 鼠标悬浮到图片 ...

  5. SpringBoot图片上传(四) 一个input上传N张图,支持各种类型

    简单介绍:需求上让实现,图片上传,并且可以一次上传9张图,图片格式还有要求,网上找了一个测试了下,好用,不过也得改,仅仅是实现了功能,其他不尽合理的地方,还需自己打磨. 代码: //html<d ...

  6. struts中用kindeditor实现的图片上传并且显示在页面上

    做公司网站的时候由于需要在内容属性中加入图片,所以就有了这个问题,本来一开始找几篇文章看都是讲修改kindeditor/jsp/file_manager_json.jsp和upload_json.js ...

  7. ueditor图片上传和显示问题

    图片上传: 这段是contorller代码 @RequestMapping(value = "/uploadImg", method = RequestMethod.POST) @ ...

  8. MVC图片上传并显示缩略图

    前面已经说了怎么通过MVC来上传文件,那么这次就说说如何上传图片然后显示缩略图,这个的实用性还是比较大.用UpLoad文件夹来保存上传的图片,而Temp文件夹来保存缩略图,前面文件上传部分就不再重复了 ...

  9. django 图片上传与显示

    由于图片上传的需要,学习了一波上传 1. 上传 前端代码 <form action="写上相应的定向位置" method="post" enctype=& ...

  10. H5 利用vue实现图片上传功能。

    H5的上传图片如何实现呢? 以下是我用vue实现的图片上传功能,仅供参考. <!DOCTYPE html> <html> <head> <meta chars ...

随机推荐

  1. 全世界 LoRA 训练脚本,联合起来!

    来自社区的 SD-XL Dreambooth LoRA 微调最佳实践指南 太长不看版 我们把 Replicate 在 SDXL Cog 训练器中使用的枢轴微调 (Pivotal Tuning) 技术与 ...

  2. .NET Core开发实战(第28课:工作单元模式(UnitOfWork):管理好你的事务)--学习笔记

    28 | 工作单元模式(UnitOfWork):管理好你的事务 工作单元模式有如下几个特性: 1.使用同一上下文 2.跟踪实体的状态 3.保障事务一致性 我们对实体的操作,最终的状态都是应该如实保存到 ...

  3. 实现阿里云模型服务灵积 DashScope 的 Semantic Kernel Connector

    Semantic Kernel 内置的 IChatCompletionService 实现只支持 OpenAI 与 Azure OpenAI,而我却打算结合 DashScope(阿里云模型服务灵积) ...

  4. 吉特日化MES & WMS 与周边系统集成架构

    作者:情缘   出处:http://www.cnblogs.com/qingyuan/ 关于作者:从事仓库,生产软件方面的开发,在项目管理以及企业经营方面寻求发展之路 版权声明:本文版权归作者和博客园 ...

  5. MQTT-QoS与协议流程

    QoS的报文收发流程 QoS 0 最多交付一次,消息有可能丢失,最低的QoS等级,没有任何的机制,不需要等待确认和重传,只要保证消息发送,也可能到达不了接收端 QoS0消息发送流程: 发送端调用API ...

  6. 从 KeyStore 中获取 PublicKey 和 PrivateKey

    KeyStore(译:密钥存储库) 代表用于加密密钥和证书的存储设施. KeyStore 管理不同类型的 entry(译:条目).每种类型的 entry 都实现了 KeyStore.Entry 接口. ...

  7. CSS隐藏元素的方法

    CSS隐藏元素的方法 使用CSS隐藏元素的主要方式有diaplay: none;.opacity: 0;.visibility: hidden;.position: absolute; overflo ...

  8. C++ 快速加载 Dll 里的 API

    最近项目里要重新编写程序加载器,也就是编译出一个可执行文件,在 Windows 上是 .exe 为什么要程序加载器? 个人理解是,可执行文件大小最好是越小越好,功能都可以由 dll 文件执行 而程序加 ...

  9. android 逆向笔记

    壳检测工具 GDA 2. 逆向分析APP 一般流程 1. 使用自动化检测工具检测APP是否加壳,或者借助一些反编译工具依靠经验判断是否加壳 2. 如果apk加壳,则需要先对apk进行脱壳 3. 使用` ...

  10. 【Android逆向】滚动的天空中插入smali日志

    1. 编写一个MyLog.java 放到一个android工程下,编译打包,然后反编译拿到MyLog的smali代码 package com.example.logapplication; impor ...