文章目录
一、 本地文件上传的步骤
1.1 实现文件上传的service
package com.listudy.service.upload;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
@Service
public class UploadService {
@Value("${file.uploadFolder}")
private String uploadFolder;
@Value("${file.staticPath}")
private String staticPath;
/**
* MultipartFile 这个对象是springMvc提供的文件上传的接受的类,
* 它的底层自动会去和HttpServletRequest request中的request.getInputStream()融合
* 从而达到文件上传的效果。也就是告诉你一个道理:
* 文件上传底层原理是:request.getInputStream()
*
* @param multipartFile
* @param dir
* @return
*/
public String uploadImg(MultipartFile multipartFile, String dir) {
try {
String realfilename = multipartFile.getOriginalFilename(); // 上传的文件:aaa.jpg
// 2:截图文件名的后缀
String imgSuffix = realfilename.substring(realfilename.lastIndexOf("."));// 拿到:.jpg
// 3:生成的唯一的文件名:能不能用中文名:不能因为统一用英文命名。
String newFileName = UUID.randomUUID().toString()+imgSuffix;// 将aaa.jpg改写成:SD23423k324-23423ms.jpg
// 4:日期目录
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd");
String datePath = dateFormat.format(new Date());// 日期目录:2021/10/27
// 5: 指定文件上传以后的目录
String servrepath = uploadFolder;// 这不是tomcat服务目录,别人不认识
File targetPath = new File(servrepath+dir,datePath);// 生成一个最终目录:F://tmp/avatar/2021/10/27
if(!targetPath.exists()){
targetPath.mkdirs(); // 如果目录不存在:F://tmp/avatar/2021/10/27 递归创建
}
// 6: 指定文件上传以后的服务器的完整的文件名
File targetFileName = new File(targetPath,newFileName);// 文件上传以后在服务器上最终文件名和目录是:F://tmp/avatar/2021/10/27/SD23423k324-23423ms.jpg
// 7: 文件上传到指定的目录
multipartFile.transferTo(targetFileName);//将用户选择的aaa.jpg上传到F://tmp/avatar/2021/10/27/SD23423k324-23423ms.jpg
// 可访问的路径要返回页面
String filename = dir+"/"+datePath+"/"+newFileName;
return staticPath+"/upimages/"+filename;
} catch (IOException e) {
e.printStackTrace();
return "fail";
}
}
/**
* MultipartFile 这个对象是springMvc提供的文件上传的接受的类,
* 它的底层自动会去和HttpServletRequest request中的request.getInputStream()融合
* 从而达到文件上传的效果。也就是告诉你一个道理:
* 文件上传底层原理是:request.getInputStream()
*
* @param multipartFile
* @param dir
* @return
*/
public Map<String,Object> uploadImgMap(MultipartFile multipartFile, String dir) {
try {
String realfilename = multipartFile.getOriginalFilename(); // 上传的文件:aaa.jpg
// 2:截图文件名的后缀
String imgSuffix = realfilename.substring(realfilename.lastIndexOf("."));// 拿到:.jpg
// 3:生成的唯一的文件名:能不能用中文名:不能因为统一用英文命名。
String newFileName = UUID.randomUUID().toString()+imgSuffix;// 将aaa.jpg改写成:SD23423k324-23423ms.jpg
// 4:日期目录
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd");
String datePath = dateFormat.format(new Date());// 日期目录:2021/10/27
// 5: 指定文件上传以后的目录
String servrepath = uploadFolder;// 这不是tomcat服务目录,别人不认识
File targetPath = new File(servrepath+dir,datePath);// 生成一个最终目录:F://tmp/avatar/2021/10/27
if(!targetPath.exists()){
targetPath.mkdirs(); // 如果目录不存在:F://tmp/avatar/2021/10/27 递归创建
}
// 6: 指定文件上传以后的服务器的完整的文件名
File targetFileName = new File(targetPath,newFileName);// 文件上传以后在服务器上最终文件名和目录是:F://tmp/avatar/2021/10/27/SD23423k324-23423ms.jpg
// 7: 文件上传到指定的目录
multipartFile.transferTo(targetFileName);//将用户选择的aaa.jpg上传到F://tmp/avatar/2021/10/27/SD23423k324-23423ms.jpg
// 可访问的路径要返回页面
// http://localhpst:8777/bbs/2021/10/27/5f61dea2-4b77-4068-8d0b-fdf415eac6df.png
String filename = dir+"/"+datePath+"/"+newFileName;
Map<String,Object> map = new HashMap<>();
map.put("url",staticPath+"/upimages/"+filename);
map.put("size",multipartFile.getSize());
map.put("ext",imgSuffix);
map.put("filename",realfilename);
map.put("rpath",dir+"/"+datePath+"/"+newFileName);
// ftp 远程服务器文件io
return map;
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
}
1.2 实现文件上传controller
package com.listudy.controller.upload;
import com.alibaba.fastjson.JSONObject;
import com.kuangstudy.service.upload.UploadService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
/**
* @Description
* @Author lya
* @Date 2021-12-15 14:04
*/
@Controller
public class UploadController {
private static final Logger LOGGER = LoggerFactory.getLogger(UploadController.class);
@Autowired
private UploadService uploadService;
/**
* 本地文件直接返回图片地址
* @param file
* @param request
* @return
* @throws IOException
* @throws ServletException
*/
@PostMapping("/api/local/upload")
@ResponseBody
public String upload(@RequestParam("file") MultipartFile file, HttpServletRequest request) throws IOException, ServletException {
if (file.isEmpty()) {
return "上传失败,请选择文件";
}
String dir = request.getParameter("dir");
if(StringUtils.isEmpty(dir)){
dir = "course";
}
// handler调用文件上传的service 得到文件的虚拟路径
String filepath = uploadService.uploadImg(file,dir);
return filepath;
}
/**
* 本地文件上传返回json
* @param file
* @param request
* @return
* @throws IOException
* @throws ServletException
*/
@PostMapping("/api/local/mdupload")
@ResponseBody
public Map<String,Object> uploadmdupload(@RequestParam("editormd-image-file") MultipartFile file, HttpServletRequest request) throws IOException, ServletException {
if (file.isEmpty()) {
return null;
}
String dir = request.getParameter("dir");
if (StringUtils.isEmpty(dir)) {
dir = "course";
}
// handler调用文件上传的service 得到文件的虚拟路径
String filepath = uploadService.uploadImg(file, dir);
Map<String, Object> map = new HashMap<>();
map.put("path", filepath);
map.put("url", filepath);
map.put("success", "1");
map.put("message", "upload success!");
return map;
}
/**
* 本地文件上传返回json
* @param file
* @param request
* @return
* @throws IOException
* @throws ServletException
*/
@PostMapping("/api/local/uploadjson")
@ResponseBody
public Map<String,Object> uploadJson(@RequestParam("file") MultipartFile file, HttpServletRequest request) throws IOException, ServletException {
if (file.isEmpty()) {
return null;
}
String dir = request.getParameter("dir");
if(StringUtils.isEmpty(dir)){
dir = "course";
}
// handler调用文件上传的service 得到文件的虚拟路径
String filepath = uploadService.uploadImg(file,dir);
Map<String,Object> map = new HashMap<>();
map.put("path",filepath);
map.put("url",filepath);
return map;
}
}
1.3 在application.yml配置即可
因为默认情况下,文件上传的限制大小是:1M 。可能是不够的。所以需要打开。
spring:
servlet:
multipart:
enabled: true
# 是单个文件大小 默认1M
max-file-size: 5MB
# 是设置总上传的数据大小
max-request-size: 10MB
#当文件达到多少时进行磁盘写入
file-size-threshold: 20MB
application-dev.yml配置如下:
# 服务器配置
file:
# 资源的服务
staticPath: http://localhost:9888
# 文件上传的映射路径
staticPatternPath: /upimages/**
# 文件上传的存储目录
uploadFolder: F://tmp/
application-prod.yml配置如下:
# 服务器配置
file:
# 资源的服务
staticPath: http://localhost:9888
# 文件上传的映射路径
staticPatternPath: /upimages/**
# 文件上传的存储目录
uploadFolder: /www/upload/
1.4 配置静态资源服务目录映射
新建springmvc的配置类
/**
* Description:
* Author: lya
* Version: 1.0
* Create Date Time: 2021/11/15 21:49.
* Update Date Time:
*
* @see
*/
@Configuration
public class WebMvcConfiguration implements WebMvcConfigurer {
@Value("${file.staticPatternPath}")
private String staticPatternPath;
@Value("${file.uploadFolder}")
private String uploadFolder;
/*
* @Author lya
* @Description 静态资源路径映射
* 其实就自定义静态资源服务器
* @Date 20:11 2021/12/18
* @Param [registry]
* @return void
**/
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler(staticPatternPath).addResourceLocations("file:" + uploadFolder);
}
}
1.5 对接webuploader文件上传
官网地址:http://fex.baidu.com/webuploader/getting-started.html
- 先下载webuploader。把下载的文件放入到static/js目录下:
- 打开add.html 引入依赖
<script src="/js/jquery.min.js"></script>
<link rel="stylesheet" type="text/css" href="/js/webuploader/webuploader.css">
<script type="text/javascript" src="/js/webuploader/webuploader.js"></script>
- 定义目标位置
<span style="position: relative">
<input type="text" id="article-img" v-model="blog.img" ref="blogimg" class="article-title"
placeholder="上传封面图" style="width: 18%; font-weight:400;font-size: 12px;position: relative;top:-2px;">
<span id="filePicker" style="position: absolute;top:-10px;right:20px;">选择图片</span>
<img style="position: absolute;top:-10px;right:-40px;" width="48" height="40" id="imgshow" alt="">
</span>
- 初始化文件上传
<script>
// 初始化Web Uploader
var uploader = WebUploader.create({
// 选完文件后,是否自动上传。
auto: true,
// 内部根据当前运行是创建,可能是input元素,也可能是flash.
pick:{
id:'#filePicker',
multiple:false // 默认是:true代表选择多张上传,false只能选择一张上传
},
// swf文件路径
swf: '/js/webuploader/Uploader.swf',
// 文件接收服务端。
server: '/api/local/uploadjson?dir=blogs',
// 选择文件的按钮。可选。
// 只允许选择图片文件。
accept: {
title: 'Images',
extensions: 'gif,jpg,jpeg,bmp,png',
mimeTypes: 'image/*'
}
});
// 文件上传成功的回调
uploader.on( 'uploadSuccess', function( file,response ) {
// 把上传的图片放入到input框中
document.getElementById("article-img").value = response.url;
// 把图片放入到img标签进行展示
document.getElementById("imgshow").src = response.url;
});
</script>
二、 阿里云上传
2.1 申请oss阿里云服务
阿里云oss注册:https://oss.console.aliyun.com/overview
阿里云oss文件存储,默认情况下是免费上传,但是不能显示(不必须要购买流量才可以访问).
2.2 对接oss的sdk
参考地址:https://help.aliyun.com/document_detail/32009.html
2.3 添加oss的依赖
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>3.10.2</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.72</version>
</dependency>
2.4 实现文件上传的功能
// yourEndpoint填写Bucket所在地域对应的Endpoint。以华东1(杭州)为例,Endpoint填写为https://oss-cn-hangzhou.aliyuncs.com。
String endpoint = "oss-cn-guangzhou.aliyuncs.com";
// 阿里云账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维,请登录RAM控制台创建RAM用户。
String accessKeyId = "LTAI5tKhZtakAU4JHciGtUvg";
String accessKeySecret = "yourAccessKeySecret";
// 填写Bucket名称,例如examplebucket。
String bucketName = "examplebucket";
OSS ossClient = null;
try {
// 创建OSSClient实例。
ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
// 创建存储空间。
ossClient.createBucket(bucketName);
} catch (OSSException e){
e.printStackTrace();
} finally {
// 关闭OSSClient。
ossClient.shutdown();
}
2.5 具体实现文件上传
常量类:
package com.listudy.service.upload;
public class AliyunOssConstans {
public static String endPoint = "xxxxxx";
public static String accessKeyId = "xxx";
public static String accessKeySecret = "xxxx";
public static String bucketName = "xxxxxx";
}
具体的文件上传类:OssUploadService.java
package com.listudy.service.upload;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.model.CannedAccessControlList;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.UUID;
@Service
public class OssUploadService {
public static void main(String[] args) {
String uploadfile = new OssUploadService().uploadfile(new File("f://a.txt"));
System.out.println(uploadfile);
}
/**
* 本地文件上传
* @param multipartFile
* @return
*/
public String uploadfile(File multipartFile) {
// yourEndpoint填写Bucket所在地域对应的Endpoint。以华东1(杭州)为例,Endpoint填写为https://oss-cn-hangzhou.aliyuncs.com。
String endpoint = AliyunOssConstans.endPoint;
// 阿里云账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维,请登录RAM控制台创建RAM用户。
String accessKeyId = AliyunOssConstans.accessKeyId;
String accessKeySecret = AliyunOssConstans.accessKeySecret;
// 填写Bucket名称,例如examplebucket。
String bucketName = AliyunOssConstans.bucketName;
OSS ossClient = null;
try {
// 创建OSSClient实例。
ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
if (!ossClient.doesBucketExist(bucketName)) {
//创建bucket
ossClient.createBucket(bucketName);
//设置oss实例的访问权限:公共读
ossClient.setBucketAcl(bucketName, CannedAccessControlList.PublicRead);
}
// 2: 获取文件上传的流
InputStream inputStream = new FileInputStream(multipartFile);
// 3:构建日期目录
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd");
String datePath = dateFormat.format(new Date());// 日期目录:2021/10/27
// 4: 获取文件名
String originname = multipartFile.getName();
String filename = UUID.randomUUID().toString();
String suffix = originname.substring(originname.lastIndexOf("."));
String newName = filename + suffix;
String fileUrl = datePath + "/" + newName;
//5:文件上传到阿里云服务器
ossClient.putObject(bucketName, fileUrl, inputStream);
return "https://" + bucketName + "." + endpoint + "/" + fileUrl;
} catch (Exception e) {
e.printStackTrace();
return "fail";
} finally {
ossClient.shutdown();
}
}
/**
* 基础程序上传
* @param multipartFile
* @param dir
* @return
*/
public String uploadfile(MultipartFile multipartFile,String dir) {
// yourEndpoint填写Bucket所在地域对应的Endpoint。以华东1(杭州)为例,Endpoint填写为https://oss-cn-hangzhou.aliyuncs.com。
String endpoint = AliyunOssConstans.endPoint;
// 阿里云账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维,请登录RAM控制台创建RAM用户。
String accessKeyId = AliyunOssConstans.accessKeyId;
String accessKeySecret = AliyunOssConstans.accessKeySecret;
// 填写Bucket名称,例如examplebucket。
String bucketName = AliyunOssConstans.bucketName;
OSS ossClient = null;
try {
// 创建OSSClient实例。
ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
// 2: 获取文件上传的流
InputStream inputStream = multipartFile.getInputStream();
// 3:构建日期目录
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd");
String datePath = dateFormat.format(new Date());// 日期目录:2021/10/27
// 4: 获取文件名
String originname = multipartFile.getOriginalFilename();
String filename = UUID.randomUUID().toString();
String suffix = originname.substring(originname.lastIndexOf("."));
String newName = filename + suffix;
String fileUrl = dir+"/"+datePath + "/" + newName;
//5:文件上传到阿里云服务器
ossClient.putObject(bucketName, fileUrl, inputStream);
return "https://" + bucketName + "." + endpoint + "/" + fileUrl;
} catch (Exception e) {
e.printStackTrace();
return "fail";
} finally {
ossClient.shutdown();
}
}
}
controller
package com.listudy.controller.upload;
import com.alibaba.fastjson.JSONObject;
import com.kuangstudy.service.upload.OssUploadService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.Optional;
@RestController
public class OssController {
@Autowired
private OssUploadService ossUploadService;
@PostMapping("/api/oss/upload")
public JSONObject fileUpload(@RequestParam(value = "editormd-image-file", required = true) MultipartFile file, HttpServletRequest request) throws IOException {
String dir = Optional.ofNullable(request.getParameter("dir")).orElse("bbs");
// 上传图片文件到oss
String url = ossUploadService.uploadfile(file, dir);
//给editormd进行回调
JSONObject res = new JSONObject();
res.put("url", url);
res.put("success", "1");
res.put("message", "upload success!");
return res;
}
@PostMapping("/api/oss/uploadfile")
public JSONObject fileUpload2(@RequestParam(value = "file", required = true) MultipartFile file, HttpServletRequest request) throws IOException {
String dir = Optional.ofNullable(request.getParameter("dir")).orElse("bbs");
// 上传图片文件到oss
String url = ossUploadService.uploadfile(file, dir);
//给editormd进行回调
JSONObject res = new JSONObject();
res.put("url", url);
res.put("success", "1");
res.put("message", "upload success!");
return res;
}
}
2.6 editormd对接文件上传
springboot默认情况下,文件上传的大小是:1M。如果异常,在application.yml配置即可:
spring:
servlet:
multipart:
enabled: true
# 是单个文件大小 默认1M
max-file-size: 5MB
# 是设置总上传的数据大小
max-request-size: 10MB
#当文件达到多少时进行磁盘写入
file-size-threshold: 20MB
在editormd对接文件上传
testEditor = editormd("article-content", {
width: "100%",
height: "82vh",
path: '/js/editormd/lib/',
theme: "white",
previewTheme: "white",
editorTheme: "pastel-on-white",
markdown: "",
codeFold: true,
saveHTMLToTextarea: true, // 保存 HTML 到 Textarea
searchReplace: true,
//watch : false, // 关闭实时预览
htmlDecode: "style,script,iframe|on*", // 开启 HTML 标签解析,为了安全性,默认不开启
//toolbar : false, //关闭工具栏
//previewCodeHighlight : false, // 关闭预览 HTML 的代码块高亮,默认开启
emoji: true,
taskList: true,
tocm: true, // Using [TOCM]
tex: true, // 开启科学公式TeX语言支持,默认关闭
flowChart: true, // 开启流程图支持,默认关闭
sequenceDiagram: true, // 开启时序/序列图支持,默认关闭,
dialogLockScreen: false, // 设置弹出层对话框不锁屏,全局通用,默认为true
dialogShowMask: false, // 设置弹出层对话框显示透明遮罩层,全局通用,默认为true
dialogDraggable: false, // 设置弹出层对话框不可拖动,全局通用,默认为true
dialogMaskOpacity: 0.4, // 设置透明遮罩层的透明度,全局通用,默认值为0.1
dialogMaskBgColor: "#000", // 设置透明遮罩层的背景颜色,全局通用,默认为#fff
imageUpload: true,
imageFormats: ["jpg", "jpeg", "gif", "png", "bmp", "webp"],
imageUploadURL: "/api/oss/upload?dir=blogs", // ***********************************在这个里指定文件上传即可
onload: function () {
var cacheContent = window.localStorage.getItem("kss_blog_content");
if(cacheContent){
testEditor.setMarkdown(cacheContent);
}
},
onchange:function(){
cacheBlog();
}
});