一、父pom.xml导入相关依赖
commons-lang3工具依赖和文件上传核心依赖
<dependency>
<groupId>commons-fileuploadgroupId>
<artifactId>commons-fileuploadartifactId>
<version>${fileupload.version}version>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.apache.commonsgroupId>
<artifactId>commons-lang3artifactId>
dependency>
二、编写yml配置文件,分dev和pro两个环境
application-dev.yml
# 自定义fileupload的属性
fileupload:
# 开发环境上传文件的根路径就为项目路径下的upload目录
root-path: "D:\\IdeaProjects\\study\\springboot-demo\\springboot-fileupload\\upload"
# 图片上传的相对路径
image-path: /imgs
# pdf文件上传的相对路径
pdf-path: /pdf
# 其他文件的相对路径
other-path: /other
# 文件名的前缀
prefix-img: IMG_
spring:
datasource:
#===========JDBC 配置===========
url: jdbc:mysql://47.100.57.52:3310/db_test?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false
# 初始化线程池数量 最大数 最小数
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: root
type: com.alibaba.druid.pool.DruidDataSource
# 驱动包 8.0以上的配置
# =========== druid 连接池配置===========
druid:
initial-size: 5
max-active: 20
min-idle: 3
# 配置获取连接等待超时的时间 单位毫秒
max-wait: 60000
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
time-between-eviction-runs-millis: 60000
# 配置一个连接在池中最小生存的时间,单位是毫秒
min-evictable-idle-time-millis: 300000
validation-query: select
test-while-idle: true
test-on-borrow: false
test-on-return: false
# 打开PSCache,并且指定每个连接上PSCache的大小
pool-prepared-statements: true
# 配置监控统计拦截器 日志配置 防火墙
# stat监控数据库性能
# wall 用于防火墙
# 日志 slf4j logback
# log4j
# log4j2
# 配置多个英文逗号分隔
filters: stat,wall,slf4j
max-pool-prepared-statement-per-connection-size: 20
# 合并多个DruidDataSource的监控数据
use-global-data-source-stat: true
# 通过connectProperties属性来打开mergeSql功能;慢SQL记录
connect-properties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500
# ===========监控配置===========
# WebStatFilter配置,说明请参考Druid Wiki,配置_配置WebStatFilter
web-stat-filter:
#是否启用StatFilter默认值false
enabled: true
# 拦截所有的
url-pattern: /*
# 排除一些不必要的url,比如*:js/*等等:
exclusions: "*.js,*.gif,*.jpg,*.png,*.css,*.ico, /druid/*"
# 关闭和开启session 统计功能 默认关闭
# session-stat-enable: true
# sessionStatMaxCount是1000个
# session-stat-max-count: 1000
# 配置principalSessionName,使得druid能够知道当前的session的用户是谁
# principal-session-name:
# StatViewServlet配置,说明请参考Druid Wiki,配置_StatViewServlet配置
stat-view-servlet:
# 是否启用StatViewServlet默认值true
enabled: true
url-pattern: /druid/*
# 界面上有一个重置功能 执行这个操作之后,会导致所有计数器清零,重新计数 建议false
reset-enable: false
# 登录的后台的用户名,密码
login-username: admin
login-password: admin
# 访问控制,可以配置allow和deny这两个参数
# 配置格式 ip或者ip/子网掩码(24) 例如 192.168.2.112 ,192.168.2.112/24
# 注意 由于匹配规则不支持IPV6,配置了allow或者deny之后,会导致IPV6无法访问。
# allow:
# deny:
application-pro.yml
# 部署 静态文件 /ninx静态文件
fileupload:
# 部署环境下文件上传的根路径
root-path: /opt/uploads
# 部署环境下图片上传的相对路径
image-path: /imgs
# 部署环境下pdf文件上传的相对路径
pdf-path: /pdf
# 部署环境下其他文件上传的相对路径
other-path: /other
# 上传的图片文件的文件名前缀
prefix-img: IMG_
server:
port: 8080
spring:
datasource:
#===========JDBC 配置===========
url: jdbc:mysql://119.23.190.71:3307/db_upload?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false
# 初始化线程池数量 最大数 最小数
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: root
type: com.alibaba.druid.pool.DruidDataSource
# 驱动包 8.0以上的配置
# =========== druid 连接池配置===========
druid:
initial-size: 5
max-active: 20
min-idle: 3
# 配置获取连接等待超时的时间 单位毫秒
max-wait: 60000
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
time-between-eviction-runs-millis: 60000
# 配置一个连接在池中最小生存的时间,单位是毫秒
min-evictable-idle-time-millis: 300000
validation-query: select
test-while-idle: true
test-on-borrow: false
test-on-return: false
# 打开PSCache,并且指定每个连接上PSCache的大小
pool-prepared-statements: true
# 配置监控统计拦截器 日志配置 防火墙
# stat监控数据库性能
# wall 用于防火墙
# 日志 slf4j logback
# log4j
# log4j2
# 配置多个英文逗号分隔
filters: stat,wall,slf4j
max-pool-prepared-statement-per-connection-size: 20
# 合并多个DruidDataSource的监控数据
use-global-data-source-stat: true
# 通过connectProperties属性来打开mergeSql功能;慢SQL记录
connect-properties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500
# ===========监控配置===========
# WebStatFilter配置,说明请参考Druid Wiki,配置_配置WebStatFilter
web-stat-filter:
#是否启用StatFilter默认值false
enabled: true
# 拦截所有的
url-pattern: /*
# 排除一些不必要的url,比如*:js/*等等:
exclusions: "*.js,*.gif,*.jpg,*.png,*.css,*.ico, /druid/*"
# 关闭和开启session 统计功能 默认关闭
# session-stat-enable: true
# sessionStatMaxCount是1000个
# session-stat-max-count: 1000
# 配置principalSessionName,使得druid能够知道当前的session的用户是谁
# principal-session-name:
# StatViewServlet配置,说明请参考Druid Wiki,配置_StatViewServlet配置
stat-view-servlet:
# 是否启用StatViewServlet默认值true
enabled: true
url-pattern: /druid/*
# 界面上有一个重置功能 执行这个操作之后,会导致所有计数器清零,重新计数 建议false
reset-enable: false
# 登录的后台的用户名,密码
login-username: admin
# 真实开发环境请把密码设置得复杂些
login-password: admin
# 访问控制,可以配置allow和deny这两个参数
# 配置格式 ip或者ip/子网掩码(24) 例如 192.168.2.112 ,192.168.2.112/24
# 注意 由于匹配规则不支持IPV6,配置了allow或者deny之后,会导致IPV6无法访问。
# allow:
# deny:
三、编写docker-compose.yml
# 指定docker-compose版本
version: '3'
# 服务
services:
# 服务名
file-upload:
container_name: file-upload
# 根据Dockerfile构建镜像
build: ./
# 映射数据卷
volumes:
- /opt/uploads/:/opt/uploads/
# 映射端口
ports:
- 8081:8080
# Nginx服务器,专门处理静态资源!
nginx-server:
# 镜像
image: nginx
# 指定一个容器名
container_name: nginx-container
# 映射数据卷
volumes:
- /opt/uploads/:/usr/share/nginx/html/
# 映射端口
ports:
- 80:80
四、编写Dockerfile
# 指定基础镜像
FROM ubuntu:18.04
# 移动jdk到/usr/local/java目录下
ADD jdk-8u221-linux-x64.tar.gz /usr/local/java/
# 配置jdk环境变量
ENV JAVA_HOME /usr/local/java/jdk1.8.0_221
ENV CLASSPATH $JAVA_HOME/lib;$JAVA_HOME/jre/lib
ENV PATH $PATH:$JAVA_HOME/bin
# 把项目jar包复制到指定目录
ADD ./target/*.jar /app.jar
# 容器启动时候执行的命令
CMD ["java","-jar","app.jar"]
五、编写主程序
FileUploadsUtils 实现文件上传的工具类
package com.qf.zsm.springbootfileupload.utils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
@Component
public class FileUploadUtils {
//注入FileUploadProperties
@Resource
FileUploadProperties fileUploadProperties;
/**
*
* @return imageRootPath 文件上传的相对路径
* imgs/20191101/
*/
public String getImagePath(){
String imageImagePath = fileUploadProperties.getImagePath()+
File.separator+ DateFormatUtils.format(new Date(),"yyyyMMdd");
return imageImagePath;
}
/**
*
* @param prefix 上传后将文件重命名的前缀
* @param oldFileName 上传后将文件重命名的主文件名,为防止名冲突,通常以当前时间为名以保证名字唯一
* @return 上传后的新文件名
*/
public String getFileName(String prefix,String oldFileName){
//截取上传的文件的后缀名 .jpg .png 等
String suffix = oldFileName.substring(oldFileName.indexOf("."));
return prefix+DateFormatUtils.format(new Date(),"yyyyMMddHHmmss")+suffix;
}
/**
* 上传文件的方法
* @param is 上传的文件的二进制输入流
* @param file 上传的文件的保存的位置
*/
public void saveFile(InputStream is,File file) throws IOException {
//路径不存在就创建
FileUtils.touch(file);
//把要上传的文件输入流copy进file路径
FileUtils.copyInputStreamToFile(is,file);
}
/**
* 调用上传文件方法saveFile()并返回存储在数据库中的相对路径
* @param multipartFile 上传的文件
* @return 存储在的数据库的图片相对路径
*/
public String saveImageFile(MultipartFile multipartFile) throws IOException {
String imagePath = getImagePath();
String fileName = getFileName(fileUploadProperties.getPrefixImg(),
multipartFile.getOriginalFilename());
//保存在数据库的图片的相对路径
String dbImagePath = imagePath+File.separator+fileName;
//本地跑项目上传文件的路径为rootPath+相对路径 远程服务器跑上传到相对路径
// imgs/201911xxx/xxx.jpg
File filePath = new File(fileUploadProperties.getRootPath()+dbImagePath);
saveFile(multipartFile.getInputStream(),filePath);
return dbImagePath;
}
}
FileUploadProperties 获取yml文件中自定义属性的类
package com.qf.zsm.springbootfileupload.utils;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
// 获取application-xxx.yml配置文件中的自定义属性
@Component
@ConfigurationProperties(prefix = "fileupload")
@Data
public class FileUploadProperties {
private String rootPath;
private String imagePath;
private String pdfPath;
private String otherPath;
private String prefixImg;
}
FileUploadServiceImpl 文件上传Service接口实现类(Service自己写一下)
package com.qf.zsm.springbootfileupload.service.impl;
import com.qf.zsm.springbootfileupload.service.FileUploadService;
import com.qf.zsm.springbootfileupload.utils.FileUploadUtils;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import java.io.IOException;
@Service
public class FileUploadServiceImpl implements FileUploadService {
// 注入FileUploadUtils
@Resource
FileUploadUtils fileUploadUtils;
@Override
public String fileUploadImage(MultipartFile multipartFile) throws IOException {
String imageFilePath = fileUploadUtils.saveImageFile(multipartFile);
return imageFilePath;
}
}
FileUploadController
package com.qf.zsm.springbootfileupload.controller;
import com.qf.zsm.springbootfileupload.service.FileUploadService;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
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 java.io.IOException;
@RestController
@RequestMapping("fileUpload")
public class FileUploadController {
@Resource
FileUploadService fileUploadService;
@RequestMapping(value = "/fileUploadImage",method = RequestMethod.POST)
public String fileUploadImage(@RequestParam("image")MultipartFile multipartFile) throws IOException {
String imagePath = fileUploadService.fileUploadImage(multipartFile);
return imagePath;
}
}
六、打包工程。拷贝一份jdk和docker-compose.yml和Dockerfile都放在项目根目录下
以上操作完成后只需要等docker-compose.yml文件构建完成!
七、测试
注意:一定要在application.yml配置文件中指定生效的yml文件
本地启动项目(指定yml生效文件为dev环境),利用PostMan工具去模拟Post请求(请求Controller的Mapping路径)传一张图片上去,
会发现本地项目的根路径已经按预想的一样成功上传了图片!
远程服务器上启动项目(指定yml生效文件为pro环境),利用PostMan工具去模拟Post请求(请求Controller的Mapping路径)传一张图片上去,一样的操作步骤,只需要把ip改成远程服务器的ip
可以看到图片已经成功上传到了远程服务器并且成功映射到了nginx服务器的静态资源路径下!
接下来,见证奇迹的一刻,去访问我们的nginx服务器这张图片静态资源,成功访问!