Failed to bind properties under

2020-08-12  本文已影响0人  爱的旋转体

1 springboot升级版本后,上传文件配置报错:

Description:

Failed to bind properties under 'spring.servlet.multipart.max-request-size' to org.springframework.util.unit.DataSize:

    Property: spring.servlet.multipart.max-request-size
    Value: 100Mb
    Origin: class path resource [config/application.yml]:78:31
    Reason: failed to convert java.lang.String to org.springframework.util.unit.DataSize

Action:

Update your application's configuration

之前的配置是:

    servlet:
        multipart:
            max-file-size: 100Mb
            max-request-size: 100Mb

2 分析原因

2.1 MultipartProperties

可以看出,需要DataSize类型

/*
 * Copyright 2012-2019 the original author or authors.
 *
 * 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
 *
 *      https://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.springframework.boot.autoconfigure.web.servlet;

import javax.servlet.MultipartConfigElement;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.PropertyMapper;
import org.springframework.boot.web.servlet.MultipartConfigFactory;
import org.springframework.util.unit.DataSize;

/**
 * Properties to be used in configuring a {@link MultipartConfigElement}.
 * <ul>
 * <li>{@link #getLocation() location} specifies the directory where uploaded files will
 * be stored. When not specified, a temporary directory will be used.</li>
 * <li>{@link #getMaxFileSize() max-file-size} specifies the maximum size permitted for
 * uploaded files. The default is 1MB</li>
 * <li>{@link #getMaxRequestSize() max-request-size} specifies the maximum size allowed
 * for {@literal multipart/form-data} requests. The default is 10MB.</li>
 * <li>{@link #getFileSizeThreshold() file-size-threshold} specifies the size threshold
 * after which files will be written to disk. The default is 0.</li>
 * </ul>
 * <p>
 * These properties are ultimately passed to {@link MultipartConfigFactory} which means
 * you may specify numeric values using {@literal long} values or using more readable
 * {@link DataSize} variants.
 *
 * @author Josh Long
 * @author Toshiaki Maki
 * @author Stephane Nicoll
 * @since 2.0.0
 */
@ConfigurationProperties(prefix = "spring.servlet.multipart", ignoreUnknownFields = false)
public class MultipartProperties {

    /**
     * Whether to enable support of multipart uploads.
     */
    private boolean enabled = true;

    /**
     * Intermediate location of uploaded files.
     */
    private String location;

    /**
     * Max file size.
     */
    private DataSize maxFileSize = DataSize.ofMegabytes(1);

    /**
     * Max request size.
     */
    private DataSize maxRequestSize = DataSize.ofMegabytes(10);

    /**
     * Threshold after which files are written to disk.
     */
    private DataSize fileSizeThreshold = DataSize.ofBytes(0);

    /**
     * Whether to resolve the multipart request lazily at the time of file or parameter
     * access.
     */
    private boolean resolveLazily = false;

    public boolean getEnabled() {
        return this.enabled;
    }

    public void setEnabled(boolean enabled) {
        this.enabled = enabled;
    }

    public String getLocation() {
        return this.location;
    }

    public void setLocation(String location) {
        this.location = location;
    }

    public DataSize getMaxFileSize() {
        return this.maxFileSize;
    }

    public void setMaxFileSize(DataSize maxFileSize) {
        this.maxFileSize = maxFileSize;
    }

    public DataSize getMaxRequestSize() {
        return this.maxRequestSize;
    }

    public void setMaxRequestSize(DataSize maxRequestSize) {
        this.maxRequestSize = maxRequestSize;
    }

    public DataSize getFileSizeThreshold() {
        return this.fileSizeThreshold;
    }

    public void setFileSizeThreshold(DataSize fileSizeThreshold) {
        this.fileSizeThreshold = fileSizeThreshold;
    }

    public boolean isResolveLazily() {
        return this.resolveLazily;
    }

    public void setResolveLazily(boolean resolveLazily) {
        this.resolveLazily = resolveLazily;
    }

    /**
     * Create a new {@link MultipartConfigElement} using the properties.
     * @return a new {@link MultipartConfigElement} configured using there properties
     */
    public MultipartConfigElement createMultipartConfig() {
        MultipartConfigFactory factory = new MultipartConfigFactory();
        PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull();
        map.from(this.fileSizeThreshold).to(factory::setFileSizeThreshold);
        map.from(this.location).whenHasText().to(factory::setLocation);
        map.from(this.maxRequestSize).to(factory::setMaxRequestSize);
        map.from(this.maxFileSize).to(factory::setMaxFileSize);
        return factory.createMultipartConfig();
    }

}

2.2 DataSize

根据注释可以看出,需要大写的MB

/*
 * Copyright 2002-2019 the original author or authors.
 *
 * 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
 *
 *      https://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.springframework.util.unit;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

/**
 * A data size, such as '12MB'.
 *
 * <p>This class models data size in terms of bytes and is immutable and thread-safe.
 *
 * <p>The terms and units used in this class are based on
 * <a href="https://en.wikipedia.org/wiki/Binary_prefix">binary prefixes</a>
 * indicating multiplication by powers of 2. Consult the following table and
 * the Javadoc for {@link DataUnit} for details.
 *
 * <p>
 * <table border="1">
 * <tr><th>Term</th><th>Data Size</th><th>Size in Bytes</th></tr>
 * <tr><td>byte</td><td>1B</td><td>1</td></tr>
 * <tr><td>kilobyte</td><td>1KB</td><td>1,024</td></tr>
 * <tr><td>megabyte</td><td>1MB</td><td>1,048,576</td></tr>
 * <tr><td>gigabyte</td><td>1GB</td><td>1,073,741,824</td></tr>
 * <tr><td>terabyte</td><td>1TB</td><td>1,099,511,627,776</td></tr>
 * </table>
 *
 * @author Stephane Nicoll
 * @author Sam Brannen
 * @since 5.1
 * @see DataUnit
 */
public final class DataSize implements Comparable<DataSize> {

    /**
     * The pattern for parsing.
     */
    private static final Pattern PATTERN = Pattern.compile("^([+\\-]?\\d+)([a-zA-Z]{0,2})$");

    /**
     * Bytes per Kilobyte.
     */
    private static final long BYTES_PER_KB = 1024;

    /**
     * Bytes per Megabyte.
     */
    private static final long BYTES_PER_MB = BYTES_PER_KB * 1024;

    /**
     * Bytes per Gigabyte.
     */
    private static final long BYTES_PER_GB = BYTES_PER_MB * 1024;

    /**
     * Bytes per Terabyte.
     */
    private static final long BYTES_PER_TB = BYTES_PER_GB * 1024;


    private final long bytes;


    private DataSize(long bytes) {
        this.bytes = bytes;
    }


    /**
     * Obtain a {@link DataSize} representing the specified number of bytes.
     * @param bytes the number of bytes, positive or negative
     * @return a {@link DataSize}
     */
    public static DataSize ofBytes(long bytes) {
        return new DataSize(bytes);
    }

    /**
     * Obtain a {@link DataSize} representing the specified number of kilobytes.
     * @param kilobytes the number of kilobytes, positive or negative
     * @return a {@link DataSize}
     */
    public static DataSize ofKilobytes(long kilobytes) {
        return new DataSize(Math.multiplyExact(kilobytes, BYTES_PER_KB));
    }

    /**
     * Obtain a {@link DataSize} representing the specified number of megabytes.
     * @param megabytes the number of megabytes, positive or negative
     * @return a {@link DataSize}
     */
    public static DataSize ofMegabytes(long megabytes) {
        return new DataSize(Math.multiplyExact(megabytes, BYTES_PER_MB));
    }

    /**
     * Obtain a {@link DataSize} representing the specified number of gigabytes.
     * @param gigabytes the number of gigabytes, positive or negative
     * @return a {@link DataSize}
     */
    public static DataSize ofGigabytes(long gigabytes) {
        return new DataSize(Math.multiplyExact(gigabytes, BYTES_PER_GB));
    }

    /**
     * Obtain a {@link DataSize} representing the specified number of terabytes.
     * @param terabytes the number of terabytes, positive or negative
     * @return a {@link DataSize}
     */
    public static DataSize ofTerabytes(long terabytes) {
        return new DataSize(Math.multiplyExact(terabytes, BYTES_PER_TB));
    }

    /**
     * Obtain a {@link DataSize} representing an amount in the specified {@link DataUnit}.
     * @param amount the amount of the size, measured in terms of the unit,
     * positive or negative
     * @return a corresponding {@link DataSize}
     */
    public static DataSize of(long amount, DataUnit unit) {
        Assert.notNull(unit, "Unit must not be null");
        return new DataSize(Math.multiplyExact(amount, unit.size().toBytes()));
    }

    /**
     * Obtain a {@link DataSize} from a text string such as {@code 12MB} using
     * {@link DataUnit#BYTES} if no unit is specified.
     * <p>
     * Examples:
     * <pre>
     * "12KB" -- parses as "12 kilobytes"
     * "5MB"  -- parses as "5 megabytes"
     * "20"   -- parses as "20 bytes"
     * </pre>
     * @param text the text to parse
     * @return the parsed {@link DataSize}
     * @see #parse(CharSequence, DataUnit)
     */
    public static DataSize parse(CharSequence text) {
        return parse(text, null);
    }

    /**
     * Obtain a {@link DataSize} from a text string such as {@code 12MB} using
     * the specified default {@link DataUnit} if no unit is specified.
     * <p>
     * The string starts with a number followed optionally by a unit matching one of the
     * supported {@linkplain DataUnit suffixes}.
     * <p>
     * Examples:
     * <pre>
     * "12KB" -- parses as "12 kilobytes"
     * "5MB"  -- parses as "5 megabytes"
     * "20"   -- parses as "20 kilobytes" (where the {@code defaultUnit} is {@link DataUnit#KILOBYTES})
     * </pre>
     * @param text the text to parse
     * @return the parsed {@link DataSize}
     */
    public static DataSize parse(CharSequence text, @Nullable DataUnit defaultUnit) {
        Assert.notNull(text, "Text must not be null");
        try {
            Matcher matcher = PATTERN.matcher(text);
            Assert.state(matcher.matches(), "Does not match data size pattern");
            DataUnit unit = determineDataUnit(matcher.group(2), defaultUnit);
            long amount = Long.parseLong(matcher.group(1));
            return DataSize.of(amount, unit);
        }
        catch (Exception ex) {
            throw new IllegalArgumentException("'" + text + "' is not a valid data size", ex);
        }
    }

    private static DataUnit determineDataUnit(String suffix, @Nullable DataUnit defaultUnit) {
        DataUnit defaultUnitToUse = (defaultUnit != null ? defaultUnit : DataUnit.BYTES);
        return (StringUtils.hasLength(suffix) ? DataUnit.fromSuffix(suffix) : defaultUnitToUse);
    }

    /**
     * Checks if this size is negative, excluding zero.
     * @return true if this size has a size less than zero bytes
     */
    public boolean isNegative() {
        return this.bytes < 0;
    }

    /**
     * Return the number of bytes in this instance.
     * @return the number of bytes
     */
    public long toBytes() {
        return this.bytes;
    }

    /**
     * Return the number of kilobytes in this instance.
     * @return the number of kilobytes
     */
    public long toKilobytes() {
        return this.bytes / BYTES_PER_KB;
    }

    /**
     * Return the number of megabytes in this instance.
     * @return the number of megabytes
     */
    public long toMegabytes() {
        return this.bytes / BYTES_PER_MB;
    }

    /**
     * Return the number of gigabytes in this instance.
     * @return the number of gigabytes
     */
    public long toGigabytes() {
        return this.bytes / BYTES_PER_GB;
    }

    /**
     * Return the number of terabytes in this instance.
     * @return the number of terabytes
     */
    public long toTerabytes() {
        return this.bytes / BYTES_PER_TB;
    }

    @Override
    public int compareTo(DataSize other) {
        return Long.compare(this.bytes, other.bytes);
    }

    @Override
    public String toString() {
        return String.format("%dB", this.bytes);
    }


    @Override
    public boolean equals(@Nullable Object other) {
        if (this == other) {
            return true;
        }
        if (other == null || getClass() != other.getClass()) {
            return false;
        }
        DataSize otherSize = (DataSize) other;
        return (this.bytes == otherSize.bytes);
    }

    @Override
    public int hashCode() {
        return Long.hashCode(this.bytes);
    }

}

3 最后的修改结果

  servlet:
        multipart:
            max-file-size: 100MB
            max-request-size: 100MB
上一篇下一篇

猜你喜欢

热点阅读