我正在一个用户可以上传图片的网站上工作。
我为此创建了一个Spring控制器。当用户上传我想将其转换为PNG的图像时,请将其上传到AWS S3文件夹。在Windows上一切正常,但是在Linux上PNG转换失败并且java.lang.IllegalArgumentException: image == null!
。
Windows和Linux都安装了相同的Oracle JDK,java版本为1.8.0_161。
这些是服务器上可用的图像阅读器:
Oracle Corporation | 0.5 | Standard JPEG Image Reader
Oracle Corporation | 1.0 | Standard BMP Image Reader
Oracle Corporation | 1.0 | Standard WBMP Image Reader
Oracle Corporation | 1.0 | Standard GIF image reader
Oracle Corporation | 1.0 | Standard PNG image reader
我用JPG,PNG和GIF文件测试过它。所有这些都失败了。
确切的例外是:
018-04-05 06:23:57.414 ERROR 31434 --- [p-nio-80-exec-5] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.IllegalArgumentException: image == null!] with root cause
java.lang.IllegalArgumentException: image == null!
at javax.imageio.ImageTypeSpecifier.createFromRenderedImage(ImageTypeSpecifier.java:925)
at javax.imageio.ImageIO.getWriter(ImageIO.java:1592)
at javax.imageio.ImageIO.write(ImageIO.java:1578)
at com.morethanheroic.restaurantapp.restaurant.service.logo.RestaurantLogoUploader.convertImageToPng(RestaurantLogoUploader.java:69)
当我禁用PNG转换并仅将原始图像上传到S3时,从Linux上传的图像大小略大(约+ 30%)。正确的图像显然是从Windows上传的图像。
我发布了所有相关代码,因为我并不完全确定女巫步骤会导致问题。
这是我的控制者:
package com.morethanheroic.restaurantapp.restaurant.view.controller;
import com.morethanheroic.restaurantapp.restaurant.domain.RestaurantEntry;
import com.morethanheroic.restaurantapp.restaurant.service.RestaurantEntryFactory;
import com.morethanheroic.restaurantapp.restaurant.service.logo.RestaurantLogoUploader;
import com.morethanheroic.restaurantapp.restaurant.view.controller.exception.UnauthorizedAccessException;
import com.morethanheroic.restaurantapp.restaurant.view.service.file.FileConverter;
import com.morethanheroic.user.domain.UserEntity;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
@RestController
@RequestMapping("/restaurant/{restaurantId}/logo")
@RequiredArgsConstructor
public class RestaurantLogoUploadController {
private final RestaurantEntryFactory restaurantEntryFactory;
private final RestaurantLogoUploader restaurantLogoUploader;
private final FileConverter fileConverter;
@PostMapping("/upload")
public void uploadFile(final UserEntity userEntity, @PathVariable final int restaurantId,
@RequestPart("logo") final MultipartFile logo) {
final RestaurantEntry restaurantEntry = restaurantEntryFactory.getRestaurant(restaurantId);
if (!restaurantEntry.isOwner(userEntity)) {
throw new UnauthorizedAccessException();
}
restaurantLogoUploader.uploadLogo(restaurantEntry, fileConverter.convertMultiPartToFile(logo));
}
}
文件转换器:
package com.morethanheroic.restaurantapp.restaurant.view.service.file;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
@Slf4j
@Service
public class FileConverter {
public File convertMultiPartToFile(final MultipartFile multipartFile) {
final File result = new File(multipartFile.getOriginalFilename());
try (final FileOutputStream fos = new FileOutputStream(result)) {
fos.write(multipartFile.getBytes());
} catch (IOException e) {
log.error("Unable to convert MultiPart to File!", e);
}
return result;
}
}
这是转换发生的实际图片上传器。
package com.morethanheroic.restaurantapp.restaurant.service.logo;
import com.amazonaws.services.s3.AmazonS3;
import com.morethanheroic.restaurantapp.restaurant.domain.RestaurantEntry;
import com.morethanheroic.restaurantapp.restaurant.service.logo.configuration.RestaurantLogoProperties;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
@Slf4j
@Service
public class RestaurantLogoUploader {
private final AmazonS3 amazonS3;
private final RestaurantLogoProperties restaurantLogoProperties;
private final RestaurantLogoNameFactory restaurantLogoNameFactory;
public RestaurantLogoUploader(@Qualifier("amazonLogoUploaderS3Client") final AmazonS3 amazonS3,
final RestaurantLogoProperties restaurantLogoProperties,
final RestaurantLogoNameFactory restaurantLogoNameFactory) {
this.amazonS3 = amazonS3;
this.restaurantLogoProperties = restaurantLogoProperties;
this.restaurantLogoNameFactory = restaurantLogoNameFactory;
}
public void uploadLogo(final RestaurantEntry restaurant, final File restaurantLogo) {
final String logoName = restaurantLogoNameFactory.buildName(restaurant);
amazonS3.putObject(restaurantLogoProperties.getBucketName(), logoName, convertImageToPng(restaurantLogo));
}
private File convertImageToPng(final File inputFile) {
log.info("Converting file " + inputFile.getAbsolutePath() + " to png.");
try {
final BufferedImage bufferedImage = ImageIO.read(inputFile);
final ByteArrayOutputStream byteArrayOut = new ByteArrayOutputStream();
ImageIO.write(bufferedImage, "png", byteArrayOut);
final byte[] resultingBytes = byteArrayOut.toByteArray();
final File result = new File(inputFile.getName());
FileOutputStream fos = new FileOutputStream(result);
fos.write(resultingBytes);
fos.close();
return result;
} catch (IOException e) {
throw new RuntimeException("Unable to convert image.");
}
}
}
答案 0 :(得分:1)
网络应用不应以root
(管理员权限)运行,因此不允许访问 / root 目录。在其他地方配置上传目录。
答案 1 :(得分:0)
该错误是由AWS API Gateway引起的。将“multipart / form-data”列为二进制媒体类型后,一切都按预期工作。