​ MinIO​使用

article/2025/9/23 11:11:07

引言:为什么要使用minio

 MinIO是对象存储服务,它基于Apache License 开源协议,兼容Amazon S3云存储接口。适合存储非结构化数据,如图片,音频,视频,日志等。对象文件最大可以达到5TB。类似于腾讯的oss或者阿里的对象存储平台,适用于解决分布式云存储。

1. MinIO的基础概念

术语含义
Object存储到MinIO的基本对象。如文件,字节流等
Bucket存储Object的逻辑空间,每个Bucket之间的数据时相互隔离的。对于用户而言,相当于存放文件的顶层文件夹。
Drive存储Object的磁盘。在MinIO启动时,以参数的方式传入。
Set

一组Drive的集合。根据集群规模自动划分Set,每个Set中的Drive分布在不同位置。

-  一个对象存储在一个Set上。

-  一个集群划分成多个Set。

- 一个Set包含的Drive数量是固定的,默认由系统根据集群规模自动计算出。

- 一个Set中的Drive尽可能分布在不同的节点上。

EC

纠删码(Erasure Code),保证高可靠。

- n 份原始数据,m份编码数据。

- 任意小于等于m份的数据丢失,以通过剩下的数据还原出来。

2. MinIO的优点

序号优点
1部署简单,支持各种平台
2海量存储,支持单个对象最大5TB
3兼容 Amazon S3接口
4低冗余,磁盘损坏高容忍
5读写性能优异
6便宜不花钱适用于搭建自己的云存储服务器

3. MinIO实战开发

我这里是使用docker进行安装的你可以安装别的版本

编写docker命令:

docker run --name minio -p 9000:9000 -p 9001:9001 
-e "MINIO_ROOT_USER=admin" 
-e "MINIO_ROOT_PASSWORD=admin123" 
-v /root/minio/data:/data 
-d minio/minio server /data --console-address ":9001"

–name:容器名称
MINIO_ROOT_USER: 账号
MINIO_ROOT_PASSWORD: 密码
-d:在后台运行
-v: 挂在data文件在本地

成功启动就可以直接登录页面了
http://IP号:9001/

或者也可以编写docker-compose启动minio(这里推荐大家使用docker-compose的方式启动,现在的启动也是这么启动的)

version: '3.8'
services:minio:image: minio/miniohostname: "minio"ports:- "9090:9090" # api 端口- "9091:9091" # 控制台端口environment:MINIO_ACCESS_KEY: admin #管理后台用户名MINIO_SECRET_KEY: admin123 #管理后台密码,最小8个字符volumes:- ./data:/data               #映射当前目录下的data目录至容器内/data目录- ./config:/root/.minio/     #映射配置目录command: server --console-address ':9091' --address ':9090' /data  #指定容器中的目录 /dataprivileged: truerestart: always #设置开机自启动

我这里是启动的单机版的minio(这里我是访问的本地虚拟机的地址大家如果使用的话建议买服务器上部署一下) 

这里我是拿docker-compose启动的

账号:admin

密码   admin123

申请 accessKey secretKey 的秘钥后面会用到

 4.springboot集成minio

4.1编写pom文件

   
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.5.6</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.cwg</groupId><artifactId>pushNotification</artifactId><version>0.0.1-SNAPSHOT</version><name>pushNotification</name><description>pushNotification</description><properties><java.version>1.8</java.version><springfox.boot.starter.version>3.0.0</springfox.boot.starter.version><commons.io.version>2.11.0</commons.io.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-mail</artifactId></dependency><!-- io常用工具类 --><dependency><groupId>commons-io</groupId><artifactId>commons-io</artifactId><version>${commons.io.version}</version></dependency><dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId></dependency><!--swagger3--><dependency><groupId>io.springfox</groupId><artifactId>springfox-boot-starter</artifactId><version>${springfox.boot.starter.version}</version></dependency><dependency><groupId>io.minio</groupId><artifactId>minio</artifactId><version>8.2.2</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><scope>runtime</scope><optional>true</optional></dependency><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.8.1</version></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></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><version>3.0.2</version><configuration><excludes><exclude><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></exclude></excludes></configuration></plugin></plugins></build></project>

4.2编写application.yml文件

#minio文件服务器配置(这里的9090是我上传的端口不是我访问控制页面的端口不一样)
minio.address=http://192.168.80.135:9090
#这里的minio的accessKey跟secretKey 是登录进去自己创建的
minio.accessKey=ZHbAyn7zxejVOz0Vtpk7
minio.secretKey=QDDV8YNKThIqthI1xaqIbIvvzO5GL0gsOdpljEeE
minio.bucketName=myfile
server.port=8081
server.servlet.context-path=/api
# 配置文件上传大小限制
spring.servlet.multipart.max-file-size=200MB
spring.servlet.multipart.max-request-size=200MB

编写配置minio的配置文件对桶进行操作 

package com.cwg.config;import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.cwg.entity.AjaxResult;
import com.cwg.util.StringUtils;
import io.minio.*;
import io.minio.http.Method;
import io.minio.messages.*;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import sun.misc.BASE64Encoder;import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.sql.rowset.serial.SerialException;
import java.io.*;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;@Data
@Component
@Slf4j
public class MinIOService {@Value("${minio.address}")private String address;@Value("${minio.accessKey}")private String accessKey;@Value("${minio.secretKey}")private String secretKey;@Value("${minio.bucketName}")private String bucketName;public MinioClient getMinioClient() {try {return  MinioClient.builder().endpoint(address).credentials(accessKey,secretKey).build();} catch (Exception e) {e.printStackTrace();return null;}}/*** 检查存储桶是否存在** @param bucketName 存储桶名称* @return*/public boolean bucketExists(MinioClient minioClient, String bucketName) {boolean flag = false;try {flag = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());if (flag) {return true;}} catch (Exception e) {e.printStackTrace();return false;}return false;}// Upload '/home/user/Photos/asiaphotos.zip' as object name 'asiaphotos-2015.zip' to bucket// 'asiatrip'./*** 创建存储桶** @param bucketName 存储桶名称*/public boolean makeBucket(MinioClient minioClient, String bucketName) {try {boolean found = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());//存储桶不存在则创建存储桶if (!found) {// 如果不存在创建桶minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());}return true;} catch (Exception e) {e.printStackTrace();return false;}}/*** 上传文件** @param file 上传文件* @return 成功则返回文件名,失败返回空*/public AjaxResult uploadFile(MinioClient minioClient, MultipartFile file) throws SerialException {//创建存储桶boolean createFlag = makeBucket(minioClient, bucketName);//创建存储桶失败if (createFlag == false) {throw new SerialException("创建存储桶失败");}try {String originalFilename = file.getOriginalFilename();int pointIndex = originalFilename.lastIndexOf(".");//得到文件流InputStream inputStream = file.getInputStream();//保证文件不重名(并且没有特殊字符)String fileName = bucketName+ DateUtil.format(new Date(), "_yyyy-MM-dd-HH-mm-ss") + (pointIndex > -1 ? originalFilename.substring(pointIndex) : "");minioClient.putObject(PutObjectArgs.builder().bucket(bucketName).object(fileName).contentType(ViewContentType.getContentType(fileName)).stream(inputStream,inputStream.available(),-1).build());inputStream.close();return AjaxResult.success(fileName);} catch (Exception e) {e.printStackTrace();return AjaxResult.error();}}/*** 下载文件** @param originalName 文件路径*/public InputStream downloadFile(MinioClient minioClient, String originalName, HttpServletResponse response) {try {// 2. 获取对象的InputStream,并保存为文件InputStream file = minioClient.getObject(GetObjectArgs.builder().bucket(bucketName).object(originalName).build());String filename = new String(originalName.getBytes("ISO8859-1"), StandardCharsets.UTF_8);if (StrUtil.isNotBlank(originalName)) {filename = originalName;}response.setHeader("Content-Disposition", "attachment;filename=" + filename);ServletOutputStream servletOutputStream = response.getOutputStream();int len;byte[] buffer = new byte[1024];while ((len = file.read(buffer)) > 0) {servletOutputStream.write(buffer, 0, len);}servletOutputStream.flush();file.close();servletOutputStream.close();return file;} catch (Exception e) {e.printStackTrace();return null;}}/*** 删除文件** @param fileName 文件路径* @return*/public boolean deleteFile(MinioClient minioClient, String fileName) {try {minioClient.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(fileName).build());} catch (Exception e) {e.printStackTrace();return false;}return true;}/*** Description 生成预览链接,最大7天有效期;* 如果想永久有效,在 minio 控制台设置仓库访问规则总几率* Create by Mr.Fang** @param object      文件名称* @param contentType 预览类型 image/gif", "image/jpeg", "image/jpg", "image/png", "application/pdf* @Params**//*** @description:获取文件预览接口* @date: 2022/8/18 9:44* @param: fileName: 文件名* @Param: bucketName: 桶名* @Param: previewExpiry: 预览到期时间(小时)* @return: java.lang.String**/public String getPreviewUrl(MinioClient minioClient,String fileName,Integer previewExpiry) {if (StringUtils.isNotBlank(fileName)) {bucketName = StringUtils.isNotBlank(bucketName) ? bucketName : this.bucketName;try {minioClient.statObject(StatObjectArgs.builder().bucket(bucketName).object(fileName).build());if (null != previewExpiry){return minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder().method(Method.GET).bucket(bucketName).object(fileName).expiry(previewExpiry, TimeUnit.HOURS).build());}else {return minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder().method(Method.GET).bucket(bucketName).object(fileName).build());}} catch (Exception e) {e.printStackTrace();}}return null;}/*** 查询所有桶文件** @return*/public  List<Bucket> getListBuckets(MinioClient minioClient) {try {return minioClient.listBuckets();} catch (Exception e) {e.printStackTrace();}return Collections.emptyList();}/*** 批量删除文件* @param objects 对象名称* @return boolean*/public List<DeleteError> deleteObject(MinioClient minioClient,List<String> objects) {List<DeleteError> deleteErrors = new ArrayList<>();List<DeleteObject> deleteObjects = objects.stream().map(value -> new DeleteObject(value)).collect(Collectors.toList());Iterable<Result<DeleteError>> results =minioClient.removeObjects(RemoveObjectsArgs.builder().bucket(bucketName).objects(deleteObjects).build());try {for (Result<DeleteError> result : results) {DeleteError error = result.get();deleteErrors.add(error);}} catch (Exception e) {e.printStackTrace();}return deleteErrors;}/*** 获取单个桶中的所有文件对象名称** @param bucket 桶名称* @return {@link List}<{@link String}>*/public  List<String> getBucketObjectName(MinioClient minioClient,String bucket) {boolean exsit = makeBucket(minioClient,bucket);if (exsit) {List<String> listObjetcName = new ArrayList<>();try {Iterable<Result<Item>> myObjects = minioClient.listObjects(ListObjectsArgs.builder().bucket(bucket).build());for (Result<Item> result : myObjects) {Item item = result.get();listObjetcName.add(item.objectName());}return listObjetcName;} catch (Exception e) {e.printStackTrace();}}return null;}/*** 获取某个桶下某个对象的URL** @param objectName 对象名 (文件夹名 )* @return*/public  String getBucketObject(MinioClient minioClient, String objectName) throws Exception {// 删除之前先检查`my-bucket`是否存在。boolean found = makeBucket(minioClient,bucketName);if (found) {final GetObjectResponse object = minioClient.getObject(GetObjectArgs.builder().bucket(bucketName).object(objectName).build());return object.object();}return "";}/*** @description: 批量下载* @param: filenames: 多个文件名称* @Param: zip: 压缩包名称* @Param: res: 响应对象* @return: void**/public void batchDownload(MinioClient minioClient,List<String> filenames, String zip, HttpServletResponse res,HttpServletRequest req){try {BucketExistsArgs bucketArgs = BucketExistsArgs.builder().bucket(bucketName).build();boolean bucketExists = minioClient.bucketExists(bucketArgs);BufferedOutputStream bos = null;res.reset();bos = new BufferedOutputStream(res.getOutputStream());ZipOutputStream out = new ZipOutputStream(bos);res.setHeader("Access-Control-Allow-Origin", "*");for (int i=0;i<filenames.size();i++) {GetObjectArgs objectArgs = GetObjectArgs.builder().bucket(bucketName).object(filenames.get(i)).build();InputStream object = minioClient.getObject(objectArgs);byte buf[] = new byte[1024];int length = 0;res.setCharacterEncoding("utf-8");res.setContentType("application/force-download");// 设置强制下载不打开res.setHeader("Access-Control-Expose-Headers", "Content-Disposition");res.setHeader("Content-Disposition", "attachment;filename=" + filenameEncoding(zip,req) + ".zip");out.putNextEntry(new ZipEntry(filenames.get(i)));while ((length = object.read(buf)) > 0) {out.write(buf, 0, length);}}out.close();bos.close();} catch (Exception e) {e.printStackTrace();}}/***  设置不同浏览器编码* @param filename 文件名称* @param request 请求对象*/public static String filenameEncoding(String filename, HttpServletRequest request) throws UnsupportedEncodingException {// 获得请求头中的User-AgentString agent = request.getHeader("User-Agent");// 根据不同的客户端进行不同的编码if (agent.contains("MSIE")) {// IE浏览器filename = URLEncoder.encode(filename, "utf-8");} else if (agent.contains("Firefox")) {// 火狐浏览器BASE64Encoder base64Encoder = new BASE64Encoder();filename = "=?utf-8?B?" + base64Encoder.encode(filename.getBytes("utf-8")) + "?=";} else {// 其它浏览器filename = URLEncoder.encode(filename, "utf-8");}return filename;}
}
package com.cwg.config;import cn.hutool.core.util.StrUtil;public enum ViewContentType {DEFAULT("default","application/octet-stream"),JPG("jpg", "image/jpeg"),TIFF("tiff", "image/tiff"),GIF("gif", "image/gif"),JFIF("jfif", "image/jpeg"),PNG("png", "image/png"),TIF("tif", "image/tiff"),ICO("ico", "image/x-icon"),JPEG("jpeg", "image/jpeg"),WBMP("wbmp", "image/vnd.wap.wbmp"),FAX("fax", "image/fax"),NET("net", "image/pnetvue"),JPE("jpe", "image/jpeg"),RP("rp", "image/vnd.rn-realpix");private String prefix;private String type;public static String getContentType(String prefix){if(StrUtil.isEmpty(prefix)){return DEFAULT.getType();}prefix = prefix.substring(prefix.lastIndexOf(".") + 1);for (ViewContentType value : ViewContentType.values()) {if(prefix.equalsIgnoreCase(value.getPrefix())){return value.getType();}}return DEFAULT.getType();}ViewContentType(String prefix, String type) {this.prefix = prefix;this.type = type;}public String getPrefix() {return prefix;}public String getType() {return type;}
}

编写控制层controller

package com.cwg.controller;import com.cwg.config.MinIOService;
import com.cwg.entity.AjaxResult;
import io.minio.MinioClient;
import io.minio.messages.DeleteError;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.sql.rowset.serial.SerialException;
import java.util.ArrayList;
import java.util.List;@RequestMapping("/file")
@RestController
public class FileController {@Autowiredprivate MinIOService minIOService;/*** 上传文件** @param file 文件* @return*/@PostMapping("/uploadFile")public AjaxResult uploadFile(@RequestBody MultipartFile file) throws SerialException {MinioClient minioClient = minIOService.getMinioClient();if (minioClient == null) {throw new SerialException("连接MinIO服务器失败");}return minIOService.uploadFile(minioClient, file);}/*** 下载文件** @param response 返回请求* @param fileName 文件路径* @return
*/@GetMapping("/downloadFile")public String downloadFile(HttpServletResponse response,@RequestParam String fileName) throws SerialException {MinioClient minioClient = minIOService.getMinioClient();if (minioClient == null) {throw new SerialException("连接MinIO服务器失败");}return minIOService.downloadFile(minioClient, fileName, response) != null ? "下载成功" : "下载失败";}/*** 删除文件** @param fileName 文件路径* @return*/@DeleteMapping("/deleteFile/{fileName}")public AjaxResult deleteFile(@PathVariable("fileName") String fileName) throws SerialException {MinioClient minioClient = minIOService.getMinioClient();if (minioClient == null) {throw new SerialException("连接MinIO服务器失败");}boolean flag = minIOService.deleteFile(minioClient, fileName);return flag == Boolean.TRUE ? AjaxResult.success("删除成功") : AjaxResult.success("删除失败");}/*** 文件预览*/@GetMapping("/prevpreviewFile/{fileName}")public AjaxResult previewFile(@PathVariable(value = "fileName",required = true) String fileName) throws SerialException {MinioClient minioClient = minIOService.getMinioClient();if (minioClient == null) {throw new SerialException("连接MinIO服务器失败");}Integer previewExpiry=1;String previewUrl = minIOService.getPreviewUrl(minioClient, fileName, previewExpiry);return AjaxResult.success(previewUrl);}/*** 获取某个桶下某个对象的URL* */@GetMapping("/getBucketObject/{fileName}")public AjaxResult getBucketObject(@PathVariable(value = "fileName",required = true) String fileName) throws Exception {MinioClient minioClient = minIOService.getMinioClient();if (minioClient == null) {throw new SerialException("连接MinIO服务器失败");}return AjaxResult.success( minIOService.getBucketObject(minioClient, fileName));}/*** 批量删除某个文件* */@PostMapping("/getRemoveObjects")public AjaxResult getRemoveObjects(@RequestBody ArrayList<String> objectNames) throws SerialException {MinioClient minioClient = minIOService.getMinioClient();if (minioClient == null) {throw new SerialException("连接MinIO服务器失败");}List<DeleteError> deleteErrors = minIOService.deleteObject(minioClient, objectNames);return AjaxResult.success(deleteErrors);}/*多文件上传**/@ApiOperation("多文件上传minio")@PostMapping("/uploadAllFile")public AjaxResult upload(@RequestBody MultipartFile[] files) throws Exception {MinioClient minioClient = minIOService.getMinioClient();if (minioClient == null) {throw new SerialException("连接MinIO服务器失败");}for (MultipartFile file : files) {minIOService.uploadFile(minioClient, file);}return AjaxResult.success();}@PostMapping("/batchDownload")public void batchDownload(@RequestBody() List<String> fileNames,HttpServletResponse res, HttpServletRequest req) throws SerialException {MinioClient minioClient = minIOService.getMinioClient();if (minioClient == null) {throw new SerialException("连接MinIO服务器失败");}minIOService.batchDownload(minioClient,fileNames,"1.zip",res,req);}
}

编写返回的请求

package com.cwg.entity;import com.cwg.constant.HttpStatus;
import com.cwg.util.StringUtils;import java.util.HashMap;/*** 操作消息提醒* * @author cwg*/
public class AjaxResult extends HashMap<String, Object>
{private static final long serialVersionUID = 1L;/** 状态码 */public static final String CODE_TAG = "code";/** 返回内容 */public static final String MSG_TAG = "msg";/** 数据对象 */public static final String DATA_TAG = "data";/*** 初始化一个新创建的 AjaxResult 对象,使其表示一个空消息。*/public AjaxResult(){}/*** 初始化一个新创建的 AjaxResult 对象* * @param code 状态码* @param msg 返回内容*/public AjaxResult(int code, String msg){super.put(CODE_TAG, code);super.put(MSG_TAG, msg);}/*** 初始化一个新创建的 AjaxResult 对象* * @param code 状态码* @param msg 返回内容* @param data 数据对象*/public AjaxResult(int code, String msg, Object data){super.put(CODE_TAG, code);super.put(MSG_TAG, msg);if (StringUtils.isNotNull(data)){super.put(DATA_TAG, data);}}/*** 返回成功消息* * @return 成功消息*/public static AjaxResult success(){return AjaxResult.success("操作成功");}/*** 返回成功数据* * @return 成功消息*/public static AjaxResult success(Object data){return AjaxResult.success("操作成功", data);}/*** 返回成功消息* * @param msg 返回内容* @return 成功消息*/public static AjaxResult success(String msg){return AjaxResult.success(msg, null);}/*** 返回成功消息* * @param msg 返回内容* @param data 数据对象* @return 成功消息*/public static AjaxResult success(String msg, Object data){return new AjaxResult(HttpStatus.SUCCESS, msg, data);}/*** 返回警告消息** @param msg 返回内容* @return 警告消息*/public static AjaxResult warn(String msg){return AjaxResult.warn(msg, null);}/*** 返回警告消息** @param msg 返回内容* @param data 数据对象* @return 警告消息*/public static AjaxResult warn(String msg, Object data){return new AjaxResult(HttpStatus.WARN, msg, data);}/*** 返回错误消息* * @return 错误消息*/public static AjaxResult error(){return AjaxResult.error("操作失败");}/*** 返回错误消息* * @param msg 返回内容* @return 错误消息*/public static AjaxResult error(String msg){return AjaxResult.error(msg, null);}/*** 返回错误消息* * @param msg 返回内容* @param data 数据对象* @return 错误消息*/public static AjaxResult error(String msg, Object data){return new AjaxResult(HttpStatus.ERROR, msg, data);}/*** 返回错误消息* * @param code 状态码* @param msg 返回内容* @return 错误消息*/public static AjaxResult error(int code, String msg){return new AjaxResult(code, msg, null);}/*** 方便链式调用** @param key 键* @param value 值* @return 数据对象*/@Overridepublic AjaxResult put(String key, Object value){super.put(key, value);return this;}
}

全局异常处理

package com.cwg.constant;/*** 缓存的key 常量* * @author cwg*/
public class CacheConstants
{/*** 登录用户 redis key*/public static final String LOGIN_TOKEN_KEY = "login_tokens:";/*** 验证码 redis key*/public static final String CAPTCHA_CODE_KEY = "captcha_codes:";/*** 参数管理 cache key*/public static final String SYS_CONFIG_KEY = "sys_config:";/*** 字典管理 cache key*/public static final String SYS_DICT_KEY = "sys_dict:";/*** 防重提交 redis key*/public static final String REPEAT_SUBMIT_KEY = "repeat_submit:";/*** 限流 redis key*/public static final String RATE_LIMIT_KEY = "rate_limit:";/*** 登录账户密码错误次数 redis key*/public static final String PWD_ERR_CNT_KEY = "pwd_err_cnt:";
}
package com.cwg.constant;import cn.hutool.jwt.Claims;/*** 通用常量信息* * @author cwg*/
public class Constants
{/*** UTF-8 字符集*/public static final String UTF8 = "UTF-8";/*** GBK 字符集*/public static final String GBK = "GBK";/*** www主域*/public static final String WWW = "www.";/*** http请求*/public static final String HTTP = "http://";/*** https请求*/public static final String HTTPS = "https://";/*** 通用成功标识*/public static final String SUCCESS = "0";/*** 通用失败标识*/public static final String FAIL = "1";/*** 登录成功*/public static final String LOGIN_SUCCESS = "Success";/*** 注销*/public static final String LOGOUT = "Logout";/*** 注册*/public static final String REGISTER = "Register";/*** 登录失败*/public static final String LOGIN_FAIL = "Error";/*** 验证码有效期(分钟)*/public static final Integer CAPTCHA_EXPIRATION = 2;/*** 令牌*/public static final String TOKEN = "token";/*** 令牌前缀*/public static final String TOKEN_PREFIX = "Bearer ";/*** 令牌前缀*/public static final String LOGIN_USER_KEY = "login_user_key";/*** 用户ID*/public static final String JWT_USERID = "userid";/*** 用户头像*/public static final String JWT_AVATAR = "avatar";/*** 创建时间*/public static final String JWT_CREATED = "created";/*** 用户权限*/public static final String JWT_AUTHORITIES = "authorities";/*** 资源映射路径 前缀*/public static final String RESOURCE_PREFIX = "/profile";/*** RMI 远程方法调用*/public static final String LOOKUP_RMI = "rmi:";/*** LDAP 远程方法调用*/public static final String LOOKUP_LDAP = "ldap:";/*** LDAPS 远程方法调用*/public static final String LOOKUP_LDAPS = "ldaps:";/*** 定时任务白名单配置(仅允许访问的包名,如其他需要可以自行添加)*/public static final String[] JOB_WHITELIST_STR = { "com.ruoyi" };/*** 定时任务违规的字符*/public static final String[] JOB_ERROR_STR = { "java.net.URL", "javax.naming.InitialContext", "org.yaml.snakeyaml","org.springframework", "org.apache", "com.ruoyi.common.utils.file", "com.ruoyi.common.config" };
}
package com.cwg.constant;/*** 代码生成通用常量* * @author cwg*/
public class GenConstants
{/** 单表(增删改查) */public static final String TPL_CRUD = "crud";/** 树表(增删改查) */public static final String TPL_TREE = "tree";/** 主子表(增删改查) */public static final String TPL_SUB = "sub";/** 树编码字段 */public static final String TREE_CODE = "treeCode";/** 树父编码字段 */public static final String TREE_PARENT_CODE = "treeParentCode";/** 树名称字段 */public static final String TREE_NAME = "treeName";/** 上级菜单ID字段 */public static final String PARENT_MENU_ID = "parentMenuId";/** 上级菜单名称字段 */public static final String PARENT_MENU_NAME = "parentMenuName";/** 数据库字符串类型 */public static final String[] COLUMNTYPE_STR = { "char", "varchar", "nvarchar", "varchar2" };/** 数据库文本类型 */public static final String[] COLUMNTYPE_TEXT = { "tinytext", "text", "mediumtext", "longtext" };/** 数据库时间类型 */public static final String[] COLUMNTYPE_TIME = { "datetime", "time", "date", "timestamp" };/** 数据库数字类型 */public static final String[] COLUMNTYPE_NUMBER = { "tinyint", "smallint", "mediumint", "int", "number", "integer","bit", "bigint", "float", "double", "decimal" };/** 页面不需要编辑字段 */public static final String[] COLUMNNAME_NOT_EDIT = { "id", "create_by", "create_time", "del_flag" };/** 页面不需要显示的列表字段 */public static final String[] COLUMNNAME_NOT_LIST = { "id", "create_by", "create_time", "del_flag", "update_by","update_time" };/** 页面不需要查询字段 */public static final String[] COLUMNNAME_NOT_QUERY = { "id", "create_by", "create_time", "del_flag", "update_by","update_time", "remark" };/** Entity基类字段 */public static final String[] BASE_ENTITY = { "createBy", "createTime", "updateBy", "updateTime", "remark" };/** Tree基类字段 */public static final String[] TREE_ENTITY = { "parentName", "parentId", "orderNum", "ancestors", "children" };/** 文本框 */public static final String HTML_INPUT = "input";/** 文本域 */public static final String HTML_TEXTAREA = "textarea";/** 下拉框 */public static final String HTML_SELECT = "select";/** 单选框 */public static final String HTML_RADIO = "radio";/** 复选框 */public static final String HTML_CHECKBOX = "checkbox";/** 日期控件 */public static final String HTML_DATETIME = "datetime";/** 图片上传控件 */public static final String HTML_IMAGE_UPLOAD = "imageUpload";/** 文件上传控件 */public static final String HTML_FILE_UPLOAD = "fileUpload";/** 富文本控件 */public static final String HTML_EDITOR = "editor";/** 字符串类型 */public static final String TYPE_STRING = "String";/** 整型 */public static final String TYPE_INTEGER = "Integer";/** 长整型 */public static final String TYPE_LONG = "Long";/** 浮点型 */public static final String TYPE_DOUBLE = "Double";/** 高精度计算类型 */public static final String TYPE_BIGDECIMAL = "BigDecimal";/** 时间类型 */public static final String TYPE_DATE = "Date";/** 模糊查询 */public static final String QUERY_LIKE = "LIKE";/** 相等查询 */public static final String QUERY_EQ = "EQ";/** 需要 */public static final String REQUIRE = "1";
}
package com.cwg.constant;/*** 返回状态码* * @author cwg*/
public class HttpStatus
{/*** 操作成功*/public static final int SUCCESS = 200;/*** 对象创建成功*/public static final int CREATED = 201;/*** 请求已经被接受*/public static final int ACCEPTED = 202;/*** 操作已经执行成功,但是没有返回数据*/public static final int NO_CONTENT = 204;/*** 资源已被移除*/public static final int MOVED_PERM = 301;/*** 重定向*/public static final int SEE_OTHER = 303;/*** 资源没有被修改*/public static final int NOT_MODIFIED = 304;/*** 参数列表错误(缺少,格式不匹配)*/public static final int BAD_REQUEST = 400;/*** 未授权*/public static final int UNAUTHORIZED = 401;/*** 访问受限,授权过期*/public static final int FORBIDDEN = 403;/*** 资源,服务未找到*/public static final int NOT_FOUND = 404;/*** 不允许的http方法*/public static final int BAD_METHOD = 405;/*** 资源冲突,或者资源被锁*/public static final int CONFLICT = 409;/*** 不支持的数据,媒体类型*/public static final int UNSUPPORTED_TYPE = 415;/*** 系统内部错误*/public static final int ERROR = 500;/*** 接口未实现*/public static final int NOT_IMPLEMENTED = 501;/*** 系统警告消息*/public static final int WARN = 601;
}
package com.cwg.constant;/*** 任务调度通用常量* * @author cwg*/
public class ScheduleConstants
{public static final String TASK_CLASS_NAME = "TASK_CLASS_NAME";/** 执行目标key */public static final String TASK_PROPERTIES = "TASK_PROPERTIES";/** 默认 */public static final String MISFIRE_DEFAULT = "0";/** 立即触发执行 */public static final String MISFIRE_IGNORE_MISFIRES = "1";/** 触发一次执行 */public static final String MISFIRE_FIRE_AND_PROCEED = "2";/** 不触发立即执行 */public static final String MISFIRE_DO_NOTHING = "3";public enum Status{/*** 正常*/NORMAL("0"),/*** 暂停*/PAUSE("1");private String value;private Status(String value){this.value = value;}public String getValue(){return value;}}
}
package com.cwg.constant;/*** 用户常量信息* * @author cwg*/
public class UserConstants
{/*** 平台内系统用户的唯一标志*/public static final String SYS_USER = "SYS_USER";/** 正常状态 */public static final String NORMAL = "0";/** 异常状态 */public static final String EXCEPTION = "1";/** 用户封禁状态 */public static final String USER_DISABLE = "1";/** 角色封禁状态 */public static final String ROLE_DISABLE = "1";/** 部门正常状态 */public static final String DEPT_NORMAL = "0";/** 部门停用状态 */public static final String DEPT_DISABLE = "1";/** 字典正常状态 */public static final String DICT_NORMAL = "0";/** 是否为系统默认(是) */public static final String YES = "Y";/** 是否菜单外链(是) */public static final String YES_FRAME = "0";/** 是否菜单外链(否) */public static final String NO_FRAME = "1";/** 菜单类型(目录) */public static final String TYPE_DIR = "M";/** 菜单类型(菜单) */public static final String TYPE_MENU = "C";/** 菜单类型(按钮) */public static final String TYPE_BUTTON = "F";/** Layout组件标识 */public final static String LAYOUT = "Layout";/** ParentView组件标识 */public final static String PARENT_VIEW = "ParentView";/** InnerLink组件标识 */public final static String INNER_LINK = "InnerLink";/** 校验是否唯一的返回标识 */public final static boolean UNIQUE = true;public final static boolean NOT_UNIQUE = false;/*** 用户名长度限制*/public static final int USERNAME_MIN_LENGTH = 2;public static final int USERNAME_MAX_LENGTH = 20;/*** 密码长度限制*/public static final int PASSWORD_MIN_LENGTH = 5;public static final int PASSWORD_MAX_LENGTH = 20;
}
package com.cwg.config.exception;import com.cwg.entity.AjaxResult;
import com.cwg.util.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;import javax.servlet.http.HttpServletRequest;
import java.nio.file.AccessDeniedException;/*** 全局异常处理器* * @author cwg*/
@RestControllerAdvice
public class GlobalExceptionHandler
{private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);/*** 请求方式不支持*/@ExceptionHandler(HttpRequestMethodNotSupportedException.class)public AjaxResult handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException e,HttpServletRequest request){String requestURI = request.getRequestURI();log.error("请求地址'{}',不支持'{}'请求", requestURI, e.getMethod());return AjaxResult.error(e.getMessage());}/*** 业务异常*/@ExceptionHandler(ServiceException.class)public AjaxResult handleServiceException(ServiceException e, HttpServletRequest request){log.error(e.getMessage(), e);Integer code = e.getCode();return StringUtils.isNotNull(code) ? AjaxResult.error(code, e.getMessage()) : AjaxResult.error(e.getMessage());}/*** 系统异常*/@ExceptionHandler(Exception.class)public AjaxResult handleException(Exception e, HttpServletRequest request){String requestURI = request.getRequestURI();log.error("请求地址'{}',发生系统异常.", requestURI, e);return AjaxResult.error(e.getMessage());}
}

 


http://chatgpt.dhexx.cn/article/IPb7XUuj.shtml

相关文章

MiniApp Dev

小程序开发 MiniApp Dev 2_WinkeyTseng_YongTai的博客-CSDN博客 MiniApp Dev 3_WinkeyTseng_YongTai的博客-CSDN博客 MiniApp Dev 4_spencer_tseng的博客-CSDN博客

MinIO的简单实用(一)

一、什么是MinIO MinIO是在GNU Affero 通用公共许可证v3.0下发布的高性能对象存储。它与AmazonS3云存储服务API兼容。使用MinIO为机器学习、分析和应用程序工作负载构建高性能基础架构。 MinIO是高性能对象存储&#xff0c;什么是对象存储&#xff08;Object Storage Service&…

取代奶瓶Minidwep-gtk破解WPA 全攻略

原文地址为&#xff1a; 取代奶瓶Minidwep-gtk破解WPA 全攻略 取代奶瓶Minidwep-gtk 破 WPA 全攻略 目录 1、 CDlinux 下使用 minidwepgtk 获取握手包并使用自带的字典破解 2、 自带的字典破解不出密码时使用 U 盘外挂字典继续暴力破解密码 3、 将握手包拷贝到 Windows 系统下…

Minidwep-gtk字典 破 WPA

取代奶瓶Minidwep-gtk 破 WPA 全攻略 目录 1、 CDlinux 下使用 minidwepgtk 获取握手包并使用自带的字典破解 2、 自带的字典破解不出密码时使用 U 盘外挂字典继续暴力破解密码 3、 将握手包拷贝到 Windows 系统下使用 ewsa 工具高速破解密码 4、破解 WPA 加密“握手包”字典的…

无线密码破解----minidwep-gtk的PIN破解方法

原文地址为&#xff1a; 无线密码破解----minidwep-gtk的PIN破解方法 使用虚拟机对minidwep-gtk进行PIN破解 用CDLINUX支持8187和3070_30211版.iso系统PJpin码 1.用虚拟机的好处是方便&#xff0c;可以一边破解&#xff0c;一边上网做其他事情。 虚拟机的安装非常简单&#xf…

完整安装minidwep-gtk教程

完整安装minidwep-gtk教程 一&#xff1a;安装Aircrack-ng 安装依赖软件包 sudo apt-get install build-essential libssl-dev iw 下载软件包并解压缩 wget http://download.aircrack-ng.org/aircrack-ng-1.1.tar.gz tar-zxvf aircrack-ng-1.1.tar.gz cd aircrack-ng-1.1 …

移动网优大神VoLTE学习笔记(五):被叫信令流程

文/张阳&#xff0c;本文来源于微信公众号&#xff1a;网优小谈&#xff08;wireless_talk&#xff09; VoLTE的被叫信令流程相比主叫信令流程要复杂一点&#xff0c;一般通信系统的被叫信令流程相比主叫信令流程都要复杂一点&#xff0c;因为往往不知道用户的位置需要进行相应…

对SDP的理解

一、SDP 是什么 SDP&#xff08;Session Description Protocal&#xff09;会话描述协议 主要用于两个会话开始之前的媒体协商&#xff0c;用于建立会话的。 这里要分清会话&#xff1a;SIP协议也是只是用来建立会话的&#xff0c;真正的会话说白了是媒体传输&#xff0c;而在…

RTSP服务器:RTP传输AAC流

工作流程&#xff1a; 1&#xff09;读取ADTS头&#xff08;7字节&#xff09;&#xff0c;解析得到aac帧的信息&#xff08;频率&#xff0c;声道&#xff0c;帧长度&#xff09; 2&#xff09;读取aac原始数据块&#xff0c;使用RTP打包aac原始数据 RTP打包h264码流时&…

webrtc会话建立

WebRTC SDP 解析 还我漂漂拳哒哒哒关注 0.5032019.03.06 13:01:21字数 1,954阅读 3,150 sdp&#xff08;Session Description Protocol&#xff09;是一种会话描述协议&#xff0c;属于文本协议&#xff0c;即WebRTC中常说的信令&#xff08;Signalling&#xff09;&#xff…

H.264视频的RTP有效负载格式 (RFC-3984)

RFC文档链接 本备忘录的状态 略 摘要 本备忘录描述了ITU-T建议的H.264视频编解码器和技术上相同的ISO/IEC国际标准14496-10视频编解码器的RTP有效载荷格式。RTP有效载荷格式允许在每个RTP有效载荷中对H.264视频编码器产生的一个或多个网络抽象层单元&#xff08;NALU&#…

音视频协议-RTP协议打包

目录 H264打包RTP的方法 RTP打包AAC 1. H264打包RTP的方法 RTP的特点不仅仅支持承载在UDP上&#xff0c;这样利于低延迟音视频数据的传输&#xff0c;另外一个特点是它允许通过其它协议接收端和发送端协商音视频数据的封装和编解码格式&#xff0c;这样固定头的playload typ…

webRTC原理及信令简介

WebRtc基本概念及协议介绍 术语 Signaling channel(信令通道) a) 一种资源&#xff0c;使应用程序可以通过交换信令消息来发现&#xff0c;建立&#xff0c;控制和终止对等连接 b) 信令消息是两个应用程序相互交换以建立对等连接的元数据。该元数据包括本地媒体信息&#xff0…

国网B接口调阅实时视频(INVITE)接口描述和消息示例

前面三篇blog分别介绍国网B接口注册、资源上报和资源信息获取&#xff0c;今天过一下国网B接口调阅实时视频相关的接口描述和消息示例&#xff0c;做过GB28181设备接入的都知道&#xff0c;国网B接口调阅实时视频流程和GB28181的基本一致的&#xff0c;区别在于SDP的一些参数描…

SIP协议之PRACK机制

SIP PRACK&#xff08;Provisional Response ACKnowledgement&#xff09;是由SIP的扩展协议RFC3262定义的&#xff0c;旨在为SIP的临时应答提供传输的可靠性。扩展机制使用选项100rel和临时应答方法PRACK实现。该机制同SIP协议中的2xx对INVITE应答的可靠机制类似。 流程图&am…

HackTheBox: Arctic靶场

废话不多说直接开始&#xff1a; 第一步是在计算机上运行NMAP&#xff1a; # Nmap 7.80 scan initiated Sat Sep 19 14:54:46 2020 as: nmap -sV -O -sC -p- -oN scan 10.10.10.11 Nmap scan report for 10.10.10.11 Host is up (0.021s latency). Not shown: 65532 filtered…

webrtc sdp详解

SDP&#xff08;Session Description Protocol&#xff09;是一种通用的会话描述协议&#xff0c;主要用来描述多媒体会话&#xff0c;用途包括会话声明、会话邀请、会话初始化等。 WebRTC主要在连接建立阶段用到SDP&#xff0c;连接双方通过信令服务交换会话信息&#xff0c;…

SIP协议之呼叫流程

SIP呼呼叫是SIP协议最基本的功能。一个用户呼叫另外一个用户最终完成多媒体通话。此处以常见的B2BUA的服务器模式进行介绍。 环境说明&#xff1a; 主叫&#xff1a;1006 192.168.1.131 被叫&#xff1a;1012 192.168.0.24 SIP服务器&#xff08;以下简称服务器&#xff09;…

GB/T 28181-2011、2016、2022变更对比

一、GB/T 28181-2016与GB/T 28181-2011变更对比 GB/T 28181-2016与GB/T 28181-2011相比&#xff0c; 除编辑性修改外主要技术变化如下&#xff1a; ----(1) 修改了标准名称&#xff1b; ----(2) 增加了媒体流TCP传输要求(见4.3.1&#xff0c; 5.2&#xff0c;附录F&#xff…

会话描述协议-SDP

目录 一. 前言 二. 标准SDP规范说明 会话级描述 媒体级描述 三. WebRTC的SDP 会话描述 媒体信息描述 网络描述 安全描述 服务质量描述 四. 其他 一. 前言 SDP&#xff08;Session Description Protocol&#xff09; 是一种通用的会话描述协议&#xff0c;例如在音视…