multipart change to package http

This commit is contained in:
Looly
2024-08-23 18:45:49 +08:00
parent ad07814775
commit df180b2e12
11 changed files with 14 additions and 14 deletions

View File

@@ -0,0 +1,290 @@
/*
* Copyright (c) 2013-2024 Hutool Team and hutool.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.hutool.http.multipart;
import org.dromara.hutool.core.collection.CollUtil;
import org.dromara.hutool.core.convert.ConvertUtil;
import org.dromara.hutool.core.map.multi.ListValueMap;
import org.dromara.hutool.core.map.multi.MultiValueMap;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
/**
* HttpRequest解析器<br>
* 来自Jodd
*
* @author jodd.org
*/
public class MultipartFormData {
/** 请求参数 */
private final MultiValueMap<String, String> requestParameters = new ListValueMap<>();
/** 请求文件 */
private final MultiValueMap<String, UploadFile> requestFiles = new ListValueMap<>();
/** 上传选项 */
private final UploadSetting setting;
/** 是否解析完毕 */
private boolean loaded;
// --------------------------------------------------------------------- Constructor start
/**
* 构造
*/
public MultipartFormData() {
this(null);
}
/**
* 构造
*
* @param uploadSetting 上传设定
*/
public MultipartFormData(final UploadSetting uploadSetting) {
this.setting = uploadSetting == null ? new UploadSetting() : uploadSetting;
}
// --------------------------------------------------------------------- Constructor end
/**
* 提取上传的文件和表单数据
*
* @param inputStream HttpRequest流
* @param charset 编码
* @throws IOException IO异常
*/
public void parseRequestStream(final InputStream inputStream, final Charset charset) throws IOException {
setLoaded();
final MultipartRequestInputStream input = new MultipartRequestInputStream(inputStream);
input.readBoundary();
while (true) {
final UploadFileHeader header = input.readDataHeader(charset);
if (header == null) {
break;
}
if (header.isFile == true) {
// 文件类型的表单项
final String fileName = header.fileName;
if (!fileName.isEmpty() && header.contentType.contains("application/x-macbinary")) {
input.skipBytes(128);
}
final UploadFile newFile = new UploadFile(header, setting);
if(newFile.processStream(input)){
putFile(header.formFieldName, newFile);
}
} else {
// 标准表单项
putParameter(header.formFieldName, input.readString(charset));
}
input.skipBytes(1);
input.mark(1);
// read byte, but may be end of stream
final int nextByte = input.read();
if (nextByte == -1 || nextByte == '-') {
input.reset();
break;
}
input.reset();
}
}
// ---------------------------------------------------------------- parameters
/**
* 返回单一参数值,如果有多个只返回第一个
*
* @param paramName 参数名
* @return null未找到否则返回值
*/
public String getParam(final String paramName) {
final Collection<String> values = getListParam(paramName);
if (CollUtil.isNotEmpty(values)) {
return CollUtil.get(values, 0);
}
return null;
}
/**
* @return 获得参数名集合
*/
public Set<String> getParamNames() {
return requestParameters.keySet();
}
/**
* 获得数组表单值
*
* @param paramName 参数名
* @return 数组表单值
*/
public String[] getArrayParam(final String paramName) {
final Collection<String> listParam = getListParam(paramName);
if(null != listParam){
return listParam.toArray(new String[0]);
}
return null;
}
/**
* 获得集合表单值
*
* @param paramName 参数名
* @return 数组表单值
* @since 5.3.0
*/
public Collection<String> getListParam(final String paramName) {
return requestParameters.get(paramName);
}
/**
* 获取所有属性的集合
*
* @return 所有属性的集合
*/
public Map<String, String[]> getParamMap() {
return ConvertUtil.toMap(String.class, String[].class, getParamListMap());
}
/**
* 获取所有属性的集合
*
* @return 所有属性的集合
*/
public MultiValueMap<String, String> getParamListMap() {
return this.requestParameters;
}
// --------------------------------------------------------------------------- Files parameters
/**
* 获取上传的文件
*
* @param paramName 文件参数名称
* @return 上传的文件, 如果无为null
*/
public UploadFile getFile(final String paramName) {
final UploadFile[] values = getFiles(paramName);
if ((values != null) && (values.length > 0)) {
return values[0];
}
return null;
}
/**
* 获得某个属性名的所有文件<br>
* 当表单中两个文件使用同一个name的时候
*
* @param paramName 属性名
* @return 上传的文件列表
*/
public UploadFile[] getFiles(final String paramName) {
final Collection<UploadFile> fileList = getFileList(paramName);
if(null != fileList){
return fileList.toArray(new UploadFile[0]);
}
return null;
}
/**
* 获得某个属性名的所有文件<br>
* 当表单中两个文件使用同一个name的时候
*
* @param paramName 属性名
* @return 上传的文件列表
* @since 5.3.0
*/
public Collection<UploadFile> getFileList(final String paramName) {
return requestFiles.get(paramName);
}
/**
* 获取上传的文件属性名集合
*
* @return 上传的文件属性名集合
*/
public Set<String> getFileParamNames() {
return requestFiles.keySet();
}
/**
* 获取文件映射
*
* @return 文件映射
*/
public Map<String, UploadFile[]> getFileMap() {
return ConvertUtil.toMap(String.class, UploadFile[].class, getFileListValueMap());
}
/**
* 获取文件映射
*
* @return 文件映射
*/
public MultiValueMap<String, UploadFile> getFileListValueMap() {
return this.requestFiles;
}
// --------------------------------------------------------------------------- Load
/**
* 是否已被解析
*
* @return 如果流已被解析返回true
*/
public boolean isLoaded() {
return loaded;
}
// ---------------------------------------------------------------- Private method start
/**
* 加入上传文件
*
* @param name 参数名
* @param uploadFile 文件
*/
private void putFile(final String name, final UploadFile uploadFile) {
this.requestFiles.putValue(name, uploadFile);
}
/**
* 加入普通参数
*
* @param name 参数名
* @param value 参数值
*/
private void putParameter(final String name, final String value) {
this.requestParameters.putValue(name, value);
}
/**
* 设置使输入流为解析状态,如果已解析,则抛出异常
*
* @throws IOException IO异常
*/
private void setLoaded() throws IOException {
if (loaded == true) {
throw new IOException("Multi-part request already parsed.");
}
loaded = true;
}
// ---------------------------------------------------------------- Private method end
}

View File

@@ -0,0 +1,271 @@
/*
* Copyright (c) 2013-2024 Hutool Team and hutool.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.hutool.http.multipart;
import org.dromara.hutool.core.io.stream.FastByteArrayOutputStream;
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.Charset;
/**
* Http请求解析流提供了专门针对带文件的form表单的解析<br>
* 来自Jodd
*
* @author jodd.org
*/
public class MultipartRequestInputStream extends BufferedInputStream {
/**
* 构造
*
* @param in {@link InputStream}
*/
public MultipartRequestInputStream(final InputStream in) {
super(in);
}
/**
* 读取byte字节流在末尾抛出异常
*
* @return byte
* @throws IOException 读取异常
*/
public byte readByte() throws IOException {
final int i = super.read();
if (i == -1) {
throw new IOException("End of HTTP request stream reached");
}
return (byte) i;
}
/**
* 跳过指定位数的 bytes.
*
* @param i 跳过的byte数
* @throws IOException IO异常
*/
public void skipBytes(final long i) throws IOException {
final long len = super.skip(i);
if (len != i) {
throw new IOException("Unable to skip data in HTTP request");
}
}
// ---------------------------------------------------------------- boundary
/**
* part部分边界
*/
protected byte[] boundary;
/**
* 输入流中读取边界
*
* @return 边界
* @throws IOException 读取异常
*/
public byte[] readBoundary() throws IOException {
final ByteArrayOutputStream boundaryOutput = new ByteArrayOutputStream(1024);
byte b;
// skip optional whitespaces
//noinspection StatementWithEmptyBody
while ((b = readByte()) <= ' ') {
}
boundaryOutput.write(b);
// now read boundary chars
while ((b = readByte()) != '\r') {
boundaryOutput.write(b);
}
if (boundaryOutput.size() == 0) {
throw new IOException("Problems with parsing request: invalid boundary");
}
skipBytes(1);
boundary = new byte[boundaryOutput.size() + 2];
System.arraycopy(boundaryOutput.toByteArray(), 0, boundary, 2, boundary.length - 2);
boundary[0] = '\r';
boundary[1] = '\n';
return boundary;
}
// ---------------------------------------------------------------- data header
/**
* 最后的头部信息
*/
protected UploadFileHeader lastHeader;
/**
* 获取最后的头信息
*
* @return 头信息
*/
public UploadFileHeader getLastHeader() {
return lastHeader;
}
/**
* 从流中读取文件头部信息, 如果达到末尾则返回null
*
* @param encoding 字符集
* @return 头部信息, 如果达到末尾则返回null
* @throws IOException 读取异常
*/
public UploadFileHeader readDataHeader(final Charset encoding) throws IOException {
final String dataHeader = readDataHeaderString(encoding);
if (dataHeader != null) {
lastHeader = new UploadFileHeader(dataHeader);
} else {
lastHeader = null;
}
return lastHeader;
}
/**
* 读取数据头信息字符串
*
* @param charset 编码
* @return 数据头信息字符串
* @throws IOException IO异常
*/
protected String readDataHeaderString(final Charset charset) throws IOException {
final ByteArrayOutputStream data = new ByteArrayOutputStream();
byte b;
while (true) {
// end marker byte on offset +0 and +2 must be 13
if ((b = readByte()) != '\r') {
data.write(b);
continue;
}
mark(4);
skipBytes(1);
final int i = read();
if (i == -1) {
// reached end of stream
return null;
}
if (i == '\r') {
reset();
break;
}
reset();
data.write(b);
}
skipBytes(3);
return charset == null ? data.toString() : data.toString(charset.name());
}
// ---------------------------------------------------------------- copy
/**
* 读取字节流直到下一个boundary
*
* @param charset 编码null表示系统默认编码
* @return 读取的字符串
* @throws IOException 读取异常
*/
public String readString(final Charset charset) throws IOException {
final FastByteArrayOutputStream out = new FastByteArrayOutputStream();
copy(out);
return out.toString(charset);
}
/**
* 字节流复制到out直到下一个boundary
*
* @param out 输出流
* @return 复制的字节数
* @throws IOException 读取异常
*/
public long copy(final OutputStream out) throws IOException {
long count = 0;
while (true) {
final byte b = readByte();
if (isBoundary(b)) {
break;
}
out.write(b);
count++;
}
return count;
}
/**
* 复制字节流到out 大于maxBytes或者文件末尾停止
*
* @param out 输出流
* @param limit 最大字节数
* @return 复制的字节数
* @throws IOException 读取异常
*/
public long copy(final OutputStream out, final long limit) throws IOException {
long count = 0;
while (true) {
final byte b = readByte();
if (isBoundary(b)) {
break;
}
out.write(b);
count++;
if (count > limit) {
break;
}
}
return count;
}
/**
* 跳过边界表示
*
* @return 跳过的字节数
* @throws IOException 读取异常
*/
public long skipToBoundary() throws IOException {
long count = 0;
while (true) {
final byte b = readByte();
count++;
if (isBoundary(b)) {
break;
}
}
return count;
}
/**
* @param b byte
* @return 是否为边界的标志
* @throws IOException 读取异常
*/
public boolean isBoundary(byte b) throws IOException {
final int boundaryLen = boundary.length;
mark(boundaryLen + 1);
int bpos = 0;
while (b == boundary[bpos]) {
b = readByte();
bpos++;
if (bpos == boundaryLen) {
return true; // boundary found!
}
}
reset();
return false;
}
}

View File

@@ -0,0 +1,289 @@
/*
* Copyright (c) 2013-2024 Hutool Team and hutool.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.hutool.http.multipart;
import org.dromara.hutool.core.io.file.FileUtil;
import org.dromara.hutool.core.io.IoUtil;
import org.dromara.hutool.core.io.file.FileNameUtil;
import org.dromara.hutool.core.text.StrUtil;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.NoSuchFileException;
/**
* 上传的文件对象
*
* @author Looly
*/
public class UploadFile {
private static final String TMP_FILE_PREFIX = "hutool-";
private static final String TMP_FILE_SUFFIX = ".upload.tmp";
private final UploadFileHeader header;
private final UploadSetting setting;
private long size = -1;
// 文件流(小文件位于内存中)
private byte[] data;
// 临时文件(大文件位于临时文件夹中)
private File tempFile;
/**
* 构造
*
* @param header 头部信息
* @param setting 上传设置
*/
public UploadFile(final UploadFileHeader header, final UploadSetting setting) {
this.header = header;
this.setting = setting;
}
// ---------------------------------------------------------------- operations
/**
* 从磁盘或者内存中删除这个文件
*/
public void delete() {
if (tempFile != null) {
//noinspection ResultOfMethodCallIgnored
tempFile.delete();
}
if (data != null) {
data = null;
}
}
/**
* 将上传的文件写入指定的目标文件路径,自动创建文件<br>
* 写入后原临时文件会被删除
*
* @param destPath 目标文件路径
* @return 目标文件
* @throws IOException IO异常
*/
public File write(final String destPath) throws IOException {
if (data != null || tempFile != null) {
return write(FileUtil.file(destPath));
}
return null;
}
/**
* 将上传的文件写入目标文件<br>
* 写入后原临时文件会被删除
*
* @param destination 目标文件
* @return 目标文件
* @throws IOException IO异常
*/
public File write(File destination) throws IOException {
assertValid();
if (destination.isDirectory()) {
destination = new File(destination, this.header.getFileName());
}
if (data != null) {
// 内存中
FileUtil.writeBytes(data, destination);
data = null;
} else {
// 临时文件
if(null == this.tempFile){
throw new NullPointerException("Temp file is null !");
}
if(!this.tempFile.exists()){
throw new NoSuchFileException("Temp file: [" + this.tempFile.getAbsolutePath() + "] not exist!");
}
FileUtil.move(tempFile, destination, true);
}
return destination;
}
/**
* @return 获得文件字节流
* @throws IOException IO异常
*/
public byte[] getFileContent() throws IOException {
assertValid();
if (data != null) {
return data;
}
if (tempFile != null) {
return FileUtil.readBytes(tempFile);
}
return null;
}
/**
* @return 获得文件流
* @throws IOException IO异常
*/
public InputStream getFileInputStream() throws IOException {
assertValid();
if (data != null) {
return IoUtil.toBuffered(IoUtil.toStream(this.data));
}
if (tempFile != null) {
return IoUtil.toBuffered(IoUtil.toStream(this.tempFile));
}
return null;
}
// ---------------------------------------------------------------- header
/**
* @return 上传文件头部信息
*/
public UploadFileHeader getHeader() {
return header;
}
/**
* @return 文件名
*/
public String getFileName() {
return header == null ? null : header.getFileName();
}
// ---------------------------------------------------------------- properties
/**
* @return 上传文件的大小,&gt; 0 表示未上传
*/
public long size() {
return size;
}
/**
* @return 是否上传成功
*/
public boolean isUploaded() {
return size > 0;
}
/**
* @return 文件是否在内存中
*/
public boolean isInMemory() {
return data != null;
}
// ---------------------------------------------------------------- process
/**
* 处理上传表单流,提取出文件
*
* @param input 上传表单的流
* @return 是否成功
* @throws IOException IO异常
*/
protected boolean processStream(final MultipartRequestInputStream input) throws IOException {
if (!isAllowedExtension()) {
// 非允许的扩展名
size = input.skipToBoundary();
return false;
}
size = 0;
// 处理内存文件
final int memoryThreshold = setting.memoryThreshold;
if (memoryThreshold > 0) {
final ByteArrayOutputStream baos = new ByteArrayOutputStream(memoryThreshold);
final long written = input.copy(baos, memoryThreshold);
data = baos.toByteArray();
if (written <= memoryThreshold) {
// 文件存放于内存
size = data.length;
return true;
}
}
// 处理硬盘文件
tempFile = FileUtil.createTempFile(TMP_FILE_PREFIX, TMP_FILE_SUFFIX, FileUtil.touch(setting.tmpUploadPath), false);
final BufferedOutputStream out = FileUtil.getOutputStream(this.tempFile);
if (data != null) {
size = data.length;
out.write(data);
data = null; // not needed anymore
}
final long maxFileSize = setting.maxFileSize;
try {
if (maxFileSize == -1) {
size += input.copy(out);
return true;
}
size += input.copy(out, maxFileSize - size + 1); // one more byte to detect larger files
if (size > maxFileSize) {
// 超出上传大小限制
//noinspection ResultOfMethodCallIgnored
tempFile.delete();
tempFile = null;
input.skipToBoundary();
return false;
}
} finally {
IoUtil.closeQuietly(out);
}
return true;
}
// ---------------------------------------------------------------------------- Private method start
/**
* @return 是否为允许的扩展名
*/
private boolean isAllowedExtension() {
final String[] exts = setting.fileExts;
final boolean isAllow = setting.isAllowFileExts;
if (exts == null || exts.length == 0) {
// 如果给定扩展名列表为空,当允许扩展名时全部允许,否则全部禁止
return isAllow;
}
final String fileNameExt = FileNameUtil.extName(this.getFileName());
for (final String fileExtension : setting.fileExts) {
if (fileNameExt.equalsIgnoreCase(fileExtension)) {
return isAllow;
}
}
// 未匹配到扩展名如果为允许列表返回false 否则true
return !isAllow;
}
/**
* 断言是否文件流可用
*
* @throws IOException IO异常
*/
private void assertValid() throws IOException {
if (!isUploaded()) {
throw new IOException(StrUtil.format("File [{}] upload fail", getFileName()));
}
}
// ---------------------------------------------------------------------------- Private method end
}

View File

@@ -0,0 +1,220 @@
/*
* Copyright (c) 2013-2024 Hutool Team and hutool.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.hutool.http.multipart;
import org.dromara.hutool.core.io.file.FileUtil;
import org.dromara.hutool.core.text.StrUtil;
/**
* 上传的文件的头部信息<br>
* 来自Jodd
*
* @author jodd.org
*/
public class UploadFileHeader {
// String dataHeader;
String formFieldName;
String formFileName;
String path;
String fileName;
boolean isFile;
String contentType;
String mimeType;
String mimeSubtype;
String contentDisposition;
UploadFileHeader(final String dataHeader) {
processHeaderString(dataHeader);
}
// ---------------------------------------------------------------- public interface
/**
* Returns {@code true} if uploaded data are correctly marked as a file.<br>
* This is true if header contains string 'filename'.
*
* @return 是否为文件
*/
public boolean isFile() {
return isFile;
}
/**
* 返回表单字段名
*
* @return 表单字段名
*/
public String getFormFieldName() {
return formFieldName;
}
/**
* 返回表单中的文件名,来自客户端传入
*
* @return 表单文件名
*/
public String getFormFileName() {
return formFileName;
}
/**
* 获取文件名,不包括路径
*
* @return 文件名
*/
public String getFileName() {
return fileName;
}
/**
* Returns uploaded content type. It is usually in the following form:<br>
* mime_type/mime_subtype.
*
* @return content type
* @see #getMimeType()
* @see #getMimeSubtype()
*/
public String getContentType() {
return contentType;
}
/**
* Returns file types MIME.
*
* @return types MIME
*/
public String getMimeType() {
return mimeType;
}
/**
* Returns file sub type MIME.
*
* @return sub type MIME
*/
public String getMimeSubtype() {
return mimeSubtype;
}
/**
* Returns content disposition. Usually it is 'form-data'.
*
* @return content disposition
*/
public String getContentDisposition() {
return contentDisposition;
}
// ---------------------------------------------------------------- Private Method
/**
* 获得头信息字符串字符串中指定的值
*
* @param dataHeader 头信息
* @param fieldName 字段名
* @return 字段值
*/
private String getDataFieldValue(final String dataHeader, final String fieldName) {
String value = null;
final String token = StrUtil.format("{}=\"", fieldName);
final int pos = dataHeader.indexOf(token);
if (pos > 0) {
final int start = pos + token.length();
final int end = dataHeader.indexOf('"', start);
if ((start > 0) && (end > 0)) {
value = dataHeader.substring(start, end);
}
}
return value;
}
/**
* 头信息中获得content type
*
* @param dataHeader data header string
* @return content type or an empty string if no content type defined
*/
private String getContentType(final String dataHeader) {
final String token = "Content-Type:";
int start = dataHeader.indexOf(token);
if (start == -1) {
return StrUtil.EMPTY;
}
start += token.length();
return dataHeader.substring(start);
}
private String getContentDisposition(final String dataHeader) {
final int start = dataHeader.indexOf(':') + 1;
final int end = dataHeader.indexOf(';');
return dataHeader.substring(start, end);
}
private String getMimeType(final String ContentType) {
final int pos = ContentType.indexOf('/');
if (pos == -1) {
return ContentType;
}
return ContentType.substring(1, pos);
}
private String getMimeSubtype(final String ContentType) {
int start = ContentType.indexOf('/');
if (start == -1) {
return ContentType;
}
start++;
return ContentType.substring(start);
}
/**
* 处理头字符串,使之转化为字段
*
* @param dataHeader 头字符串
*/
private void processHeaderString(final String dataHeader) {
isFile = dataHeader.indexOf("filename") > 0;
formFieldName = getDataFieldValue(dataHeader, "name");
if (isFile) {
formFileName = getDataFieldValue(dataHeader, "filename");
if (formFileName == null) {
return;
}
if (formFileName.isEmpty()) {
path = StrUtil.EMPTY;
fileName = StrUtil.EMPTY;
}
final int ls = FileUtil.lastIndexOfSeparator(formFileName);
if (ls == -1) {
path = StrUtil.EMPTY;
fileName = formFileName;
} else {
path = formFileName.substring(0, ls);
fileName = formFileName.substring(ls);
}
if (!fileName.isEmpty()) {
this.contentType = getContentType(dataHeader);
mimeType = getMimeType(contentType);
mimeSubtype = getMimeSubtype(contentType);
contentDisposition = getContentDisposition(dataHeader);
}
}
}
}

View File

@@ -0,0 +1,123 @@
/*
* Copyright (c) 2013-2024 Hutool Team and hutool.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.hutool.http.multipart;
/**
* 上传文件设定文件
*
* @author Looly
*
*/
public class UploadSetting {
/** 最大文件大小,默认无限制 */
protected long maxFileSize = -1;
/** 文件保存到内存的边界 */
protected int memoryThreshold = 8192;
/** 临时文件目录 */
protected String tmpUploadPath;
/** 文件扩展名限定 */
protected String[] fileExts;
/** 扩展名是允许列表还是禁止列表 */
protected boolean isAllowFileExts = true;
// ---------------------------------------------------------------------- Setters and Getters start
/**
* @return 获得最大文件大小,-1表示无限制
*/
public long getMaxFileSize() {
return maxFileSize;
}
/**
* 设定最大文件大小,-1表示无限制
*
* @param maxFileSize 最大文件大小
*/
public void setMaxFileSize(final long maxFileSize) {
this.maxFileSize = maxFileSize;
}
/**
* @return 文件保存到内存的边界
*/
public int getMemoryThreshold() {
return memoryThreshold;
}
/**
* 设定文件保存到内存的边界<br>
* 如果文件大小小于这个边界,将保存于内存中,否则保存至临时目录中
*
* @param memoryThreshold 文件保存到内存的边界
*/
public void setMemoryThreshold(final int memoryThreshold) {
this.memoryThreshold = memoryThreshold;
}
/**
* @return 上传文件的临时目录,若为空,使用系统目录
*/
public String getTmpUploadPath() {
return tmpUploadPath;
}
/**
* 设定上传文件的临时目录null表示使用系统临时目录
*
* @param tmpUploadPath 临时目录,绝对路径
*/
public void setTmpUploadPath(final String tmpUploadPath) {
this.tmpUploadPath = tmpUploadPath;
}
/**
* @return 文件扩展名限定列表
*/
public String[] getFileExts() {
return fileExts;
}
/**
* 设定文件扩展名限定里列表<br>
* 禁止列表还是允许列表取决于isAllowFileExts
*
* @param fileExts 文件扩展名列表
*/
public void setFileExts(final String[] fileExts) {
this.fileExts = fileExts;
}
/**
* 是否允许文件扩展名<br>
*
* @return 若true表示只允许列表里的扩展名否则是禁止列表里的扩展名
*/
public boolean isAllowFileExts() {
return isAllowFileExts;
}
/**
* 设定是否允许扩展名
*
* @param isAllowFileExts 若true表示只允许列表里的扩展名否则是禁止列表里的扩展名
*/
public void setAllowFileExts(final boolean isAllowFileExts) {
this.isAllowFileExts = isAllowFileExts;
}
// ---------------------------------------------------------------------- Setters and Getters end
}

View File

@@ -0,0 +1,23 @@
/*
* Copyright (c) 2013-2024 Hutool Team and hutool.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* 文件上传封装
*
* @author looly
*
*/
package org.dromara.hutool.http.multipart;

View File

@@ -26,8 +26,8 @@ import org.dromara.hutool.core.map.CaseInsensitiveMap;
import org.dromara.hutool.core.map.MapUtil;
import org.dromara.hutool.core.map.multi.ListValueMap;
import org.dromara.hutool.core.net.NetUtil;
import org.dromara.hutool.core.net.multipart.MultipartFormData;
import org.dromara.hutool.core.net.multipart.UploadSetting;
import org.dromara.hutool.http.multipart.MultipartFormData;
import org.dromara.hutool.http.multipart.UploadSetting;
import org.dromara.hutool.core.net.url.UrlQueryUtil;
import org.dromara.hutool.core.text.StrUtil;
import org.dromara.hutool.core.util.CharsetUtil;

View File

@@ -35,8 +35,8 @@ import org.dromara.hutool.core.io.file.FileUtil;
import org.dromara.hutool.core.map.CaseInsensitiveMap;
import org.dromara.hutool.core.map.MapUtil;
import org.dromara.hutool.core.net.NetUtil;
import org.dromara.hutool.core.net.multipart.MultipartFormData;
import org.dromara.hutool.core.net.multipart.UploadSetting;
import org.dromara.hutool.http.multipart.MultipartFormData;
import org.dromara.hutool.http.multipart.UploadSetting;
import org.dromara.hutool.core.net.url.UrlEncoder;
import org.dromara.hutool.core.reflect.ConstructorUtil;
import org.dromara.hutool.core.text.StrUtil;

View File

@@ -29,8 +29,8 @@ import org.dromara.hutool.core.map.CaseInsensitiveMap;
import org.dromara.hutool.core.map.MapUtil;
import org.dromara.hutool.core.net.NetUtil;
import org.dromara.hutool.core.net.url.UrlEncoder;
import org.dromara.hutool.core.net.multipart.MultipartFormData;
import org.dromara.hutool.core.net.multipart.UploadSetting;
import org.dromara.hutool.http.multipart.MultipartFormData;
import org.dromara.hutool.http.multipart.UploadSetting;
import org.dromara.hutool.core.reflect.ConstructorUtil;
import org.dromara.hutool.core.text.StrUtil;
import org.dromara.hutool.core.array.ArrayUtil;