技术栈:springboot,maven
部分源码借鉴黑马程序员
搭建图床
部署minio
首先拉取镜像
docker pull minio/minio
部署到docker
docker run -d \
-p 9000:9000 \
-p 9001:9001 \
--name minio \
-v /home/minio/data:/data \
-e "MINIO_ROOT_USER=minio" \
-e "MINIO_ROOT_PASSWORD=minio" \
minio/minio server /data --console-address ":9001"
MINIO_ROOT_USER,MINIO_ROOT_PASSWORD分别为账号密码
然后在浏览器打开"服务器ip:9001",开放读写权限
创建后台服务
基于springboot创建上传图床的服务
导入依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>7.1.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
创建配置类
@Data
@Configuration
@EnableConfigurationProperties({MinIOConfigProperties.class})
//当引入FileStorageService接口时
@ConditionalOnClass(FileStorageService.class)
public class MinIOConfig {
@Autowired
private MinIOConfigProperties minIOConfigProperties;
@Bean
public MinioClient buildMinioClient() {
return MinioClient
.builder()
.credentials(minIOConfigProperties.getAccessKey(), minIOConfigProperties.getSecretKey())
.endpoint(minIOConfigProperties.getEndpoint())
.build();
}
}
@Data
@ConfigurationProperties(prefix = "minio") // 文件上传 配置前缀file.oss
public class MinIOConfigProperties implements Serializable {
private String accessKey;
private String secretKey;
private String bucket;
private String endpoint;
private String readPath;
}
创建service
public interface FileStorageService {
/**
* 上传图片文件
* @param prefix 文件前缀
* @param filename 文件名
* @param inputStream 文件流
* @return 文件全路径
*/
public String uploadImgFile(String prefix, String filename,InputStream inputStream);
/**
* 上传html文件
* @param prefix 文件前缀
* @param filename 文件名
* @param inputStream 文件流
* @return 文件全路径
*/
public String uploadHtmlFile(String prefix, String filename,InputStream inputStream);
/**
* 删除文件
* @param pathUrl 文件全路径
*/
public void delete(String pathUrl);
/**
* 下载文件
* @param pathUrl 文件全路径
* @return
*
*/
public byte[] downLoadFile(String pathUrl);
}
public interface UploadService {
String uploadPicture(MultipartFile multipartFile);
}
创建实现类
@Slf4j
@EnableConfigurationProperties(MinIOConfigProperties.class)
@Import(MinIOConfig.class)
@Service
public class MinIOFileStorageService implements FileStorageService {
@Autowired
private MinioClient minioClient;
@Autowired
private MinIOConfigProperties minIOConfigProperties;
private final static String separator = "/";
/**
* @param dirPath
* @param filename yyyy/mm/dd/file.jpg
* @return
*/
public String builderFilePath(String dirPath,String filename) {
StringBuilder stringBuilder = new StringBuilder(50);
if(!StringUtils.isEmpty(dirPath)){
stringBuilder.append(dirPath).append(separator);
}
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
String todayStr = sdf.format(new Date());
stringBuilder.append(todayStr).append(separator);
stringBuilder.append(filename);
return stringBuilder.toString();
}
/**
* 上传图片文件
* @param prefix 文件前缀
* @param filename 文件名
* @param inputStream 文件流
* @return 文件全路径
*/
@Override
public String uploadImgFile(String prefix, String filename, InputStream inputStream) {
String filePath = builderFilePath(prefix, filename);
try {
PutObjectArgs putObjectArgs = PutObjectArgs.builder()
.object(filePath)
.contentType("image/jpg")
.bucket(minIOConfigProperties.getBucket()).stream(inputStream,inputStream.available(),-1)
.build();
minioClient.putObject(putObjectArgs);
StringBuilder urlPath = new StringBuilder(minIOConfigProperties.getReadPath());
urlPath.append(separator+minIOConfigProperties.getBucket());
urlPath.append(separator);
urlPath.append(filePath);
return urlPath.toString();
}catch (Exception ex){
log.error("minio put file error.",ex);
throw new RuntimeException("上传文件失败");
}
}
/**
* 上传html文件
* @param prefix 文件前缀
* @param filename 文件名
* @param inputStream 文件流
* @return 文件全路径
*/
@Override
public String uploadHtmlFile(String prefix, String filename,InputStream inputStream) {
String filePath = builderFilePath(prefix, filename);
try {
PutObjectArgs putObjectArgs = PutObjectArgs.builder()
.object(filePath)
.contentType("text/html")
.bucket(minIOConfigProperties.getBucket()).stream(inputStream,inputStream.available(),-1)
.build();
minioClient.putObject(putObjectArgs);
StringBuilder urlPath = new StringBuilder(minIOConfigProperties.getReadPath());
urlPath.append(separator+minIOConfigProperties.getBucket());
urlPath.append(separator);
urlPath.append(filePath);
return urlPath.toString();
}catch (Exception ex){
log.error("minio put file error.",ex);
ex.printStackTrace();
throw new RuntimeException("上传文件失败");
}
}
/**
* 删除文件
* @param pathUrl 文件全路径
*/
@Override
public void delete(String pathUrl) {
String key = pathUrl.replace(minIOConfigProperties.getEndpoint()+"/","");
int index = key.indexOf(separator);
String bucket = key.substring(0,index);
String filePath = key.substring(index+1);
// 删除Objects
RemoveObjectArgs removeObjectArgs = RemoveObjectArgs.builder().bucket(bucket).object(filePath).build();
try {
minioClient.removeObject(removeObjectArgs);
} catch (Exception e) {
log.error("minio remove file error. pathUrl:{}",pathUrl);
e.printStackTrace();
}
}
/**
* 下载文件
* @param pathUrl 文件全路径
* @return 文件流
*
*/
@Override
public byte[] downLoadFile(String pathUrl) {
String key = pathUrl.replace(minIOConfigProperties.getEndpoint()+"/","");
int index = key.indexOf(separator);
String bucket = key.substring(0,index);
String filePath = key.substring(index+1);
InputStream inputStream = null;
try {
inputStream = minioClient.getObject(GetObjectArgs.builder().bucket(minIOConfigProperties.getBucket()).object(filePath).build());
} catch (Exception e) {
log.error("minio down file error. pathUrl:{}",pathUrl);
e.printStackTrace();
}
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
byte[] buff = new byte[100];
int rc = 0;
while (true) {
try {
if (!((rc = inputStream.read(buff, 0, 100)) > 0)) break;
} catch (IOException e) {
e.printStackTrace();
}
byteArrayOutputStream.write(buff, 0, rc);
}
return byteArrayOutputStream.toByteArray();
}
}
@Service
@Slf4j
public class UploadServiceImpl implements UploadService {
@Autowired
private FileStorageService fileStorageService;
@Override
public String uploadPicture(MultipartFile multipartFile) {
if (multipartFile == null || multipartFile.getSize() == 0) {
return "没有图片";
}
String fileName = UUID.randomUUID().toString().replace("-", "");
String originalFileName = multipartFile.getOriginalFilename();
String postfix = originalFileName.substring(originalFileName.lastIndexOf("."));
String fileId = null;
try {
fileId = fileStorageService.uploadImgFile("", fileName + postfix, multipartFile.getInputStream());
log.info("上传图片到minIO中,fileId:{}", fileId);
} catch (IOException e) {
e.printStackTrace();
log.error("WmMaterialServiceImpl-上传文件失败");
}
return fileId;
}
}
创建controller类
@RestController
@CrossOrigin
public class UploadPictureController {
@Autowired
private UploadService uploadPicture;
@PostMapping("/upload_picture")
public String uploadPicture(MultipartFile multipartFile, HttpServletRequest request) {
String ssr = request.getHeader("填入你想要的值");
if (ssr.equals("填入你想要的值")){
return uploadPicture.uploadPicture(multipartFile);
}
return "拜拜";
}
}
为了防止他人调用,简单的验证一下header,如果进一步加密可用用md5,jwt登
创建配置类application.yml
spring:
servlet:
multipart:
max-file-size: 10MB #单文件最大大小
max-request-size: 100MB #多文件最大大小
minio:
access-key: minio #账户
secret-key: minio #密码
bucket: name #minio桶名字
endpoint: http://服务器ip:9000
read-path: http://服务器ip:9000
server:
port: 9999
前端
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>上传图片</title>
</head>
<body>
<form id="uploadForm" action="http://服务器ip:9999/upload_picture" method="post" enctype="multipart/form-data">
<input type="file" name="multipartFile" multiple>
<input type="text" id="ssrValue" placeholder="输入ssr的值">
<input type="submit" value="上传" onclick="uploadFiles(event)">
</form>
<div id="response"></div>
<button onclick="copyToClipboard()">复制到剪切板</button>
<script>
function uploadFiles(event) {
event.preventDefault();
var form = document.getElementById('uploadForm');
var formData = new FormData(form);
var ssrValue = document.getElementById('ssrValue').value;
var headers = new Headers();
headers.append('ssr', ssrValue);
fetch('http://服务器ip:9999/upload_picture', {
method: 'POST',
headers: headers,
body: formData
})
.then(response => response.text())
.then(data => {
document.getElementById('response').innerText = data;
})
.catch(error => console.error('Error:', error));
}
function copyToClipboard() {
var responseText = document.getElementById('response').innerText;
var tempInput = document.createElement('input');
tempInput.value = responseText;
document.body.appendChild(tempInput);
tempInput.select();
document.execCommand('copy');
document.body.removeChild(tempInput);
document.querySelector('input[type=file]').value = '';
}
</script>
</body>
</html>
简陋の页面