记录一次浪费时间比较多的问题
背景
在写SpringBoot的校园商铺系统时,在自己的windows系统上测试没有问题,打包发布到linux服务器上就一直报创建缩略图失败错误,抛出如下异常
java.lang.RuntimeException: 创建缩略图失败:javax.imageio.IIOException: Can't read input file!
起初我以为是linux读取不到图片(我甚至给图片更改了777权限),后来写了测试小程序发现并没有问题
相关代码
这个是之前错误的
/**
* 处理缩略图,并返回新生成图片的相对值路径
*
* @param thumbnail
* @param targetAddr
* @return
*/
public static String generateThumbnail(ImageHolder thumbnail, String targetAddr) {
// 获取不重复的随机名
String realFileName = getRandomFileName();
// 获取文件的扩展名如png,jpg等
String extension = getFileExtension(thumbnail.getImageName());
// 如果目标路径不存在,则自动创建
makeDirPath(targetAddr);
// 获取文件存储的相对路径(带文件名)
String relativeAddr = targetAddr + realFileName + extension;
logger.debug("current relativeAddr is :" + relativeAddr);
// 获取文件要保存到的目标路径
File dest = new File(PathUtil.getImgBasePath() + relativeAddr);
logger.debug("current complete addr is :" + PathUtil.getImgBasePath() + relativeAddr);
logger.debug("basePath is :" + basePath);
// 调用Thumbnails生成带有水印的图片
try {
System.out.println("***************************"+basePath+"**********************************");
Thumbnails.of(thumbnail.getImage()).size(200, 200)
.watermark(
Positions.BOTTOM_RIGHT,
ImageIO.read(new File("E:\\test\\watermark.png")), 0.25f)
.outputQuality(0.8f).toFile(dest);
} catch (IOException e) {
logger.error(e.toString());
throw new RuntimeException("创建缩略图失败:" + e.toString());
}
// 返回图片相对路径地址
return relativeAddr;
}
/**
* 处理详情图,并返回新生成图片的相对值路径
*
* @param thumbnail
* @param targetAddr
* @return
*/
public static String generateNormalImg(ImageHolder thumbnail, String targetAddr) {
// 获取不重复的随机名
String realFileName = getRandomFileName();
// 获取文件的扩展名如png,jpg等
String extension = getFileExtension(thumbnail.getImageName());
// 如果目标路径不存在,则自动创建
makeDirPath(targetAddr);
// 获取文件存储的相对路径(带文件名)
String relativeAddr = targetAddr + realFileName + extension;
logger.debug("current relativeAddr is :" + relativeAddr);
// 获取文件要保存到的目标路径
File dest = new File(PathUtil.getImgBasePath() + relativeAddr);
logger.debug("current complete addr is :" + PathUtil.getImgBasePath() + relativeAddr);
// 调用Thumbnails生成带有水印的图片
/**
* 本地添加水印
try {
System.out.println("***************************"+basePath+"**********************************");
Thumbnails.of(thumbnail.getImage()).size(200, 200)
.watermark(Positions.BOTTOM_RIGHT, ImageIO.read(new File("E:\\test\\watermark.png")), 0.25f)
.outputQuality(0.8f).toFile(dest);
}*/
try {
System.out.println("***************************"+basePath+"**********************************");
System.out.println("@@@@@@@@relativeAddr="+relativeAddr);
System.out.println("@@@@@@@@targetAddr="+targetAddr);
System.out.println("@@@@@@@@dest="+dest);
Thumbnails.of(thumbnail.getImage()).size(337, 640)
.watermark(Positions.BOTTOM_RIGHT, ImageIO.read(new File(basePath + "/watermark.png")), 0.25f)
.outputQuality(0.9f).toFile(dest);
System.out.println();
} catch (IOException e) {
logger.error(e.toString());
throw new RuntimeException("创建缩图片失败:" + e.toString());
}
// 返回图片相对路径地址
return relativeAddr;
}
这个是修改后的
/**
* 处理缩略图,并返回新生成图片的相对值路径
* 注意:下面有类似的处理详情图片方法 generateNormalImg()
* @param thumbnail
* @param targetAddr
* @return
*/
public static String generateThumbnail(ImageHolder thumbnail, String targetAddr) {
// 获取不重复的随机名
String realFileName = getRandomFileName();
// 获取文件的扩展名如png,jpg等
String extension = getFileExtension(thumbnail.getImageName());
// 如果目标路径不存在,则自动创建
makeDirPath(targetAddr);
// 获取文件存储的相对路径(带文件名)
String relativeAddr = targetAddr + realFileName + extension;
logger.debug("current relativeAddr is :" + relativeAddr);
// 获取文件要保存到的目标路径
File dest = new File(PathUtil.getImgBasePath() + relativeAddr);
logger.debug("current complete addr is :" + PathUtil.getImgBasePath() + relativeAddr);
logger.debug("basePath is :" + basePath);
// 调用Thumbnails生成带有水印的图片
try {
System.out.println("***************************"+basePath+"**********************************");
Thumbnails.of(thumbnail.getImage()).size(200, 200)
.watermark(
Positions.BOTTOM_RIGHT,
ImageIO.read(new File(basePath + "/watermark.png")), 0.25f)
.outputQuality(0.8f).toFile(dest);
} catch (IOException e) {
logger.error(e.toString());
throw new RuntimeException("创建缩略图失败:" + e.toString());
}
// 返回图片相对路径地址
return relativeAddr;
}
/**
* 处理详情图,并返回新生成图片的相对值路径
* 注意:上面有类似的处理详情图片方法 generateThumbnail()
* @param thumbnail
* @param targetAddr
* @return
*/
public static String generateNormalImg(ImageHolder thumbnail, String targetAddr) {
// 获取不重复的随机名
String realFileName = getRandomFileName();
// 获取文件的扩展名如png,jpg等
String extension = getFileExtension(thumbnail.getImageName());
// 如果目标路径不存在,则自动创建
makeDirPath(targetAddr);
// 获取文件存储的相对路径(带文件名)
String relativeAddr = targetAddr + realFileName + extension;
logger.debug("current relativeAddr is :" + relativeAddr);
// 获取文件要保存到的目标路径
File dest = new File(PathUtil.getImgBasePath() + relativeAddr);
logger.debug("current complete addr is :" + PathUtil.getImgBasePath() + relativeAddr);
// 调用Thumbnails生成带有水印的图片
try {
Thumbnails.of(thumbnail.getImage()).size(337, 640)
.watermark(Positions.BOTTOM_RIGHT, ImageIO.read(new File(basePath + "/watermark.png")), 0.25f)
.outputQuality(0.9f).toFile(dest);
System.out.println();
} catch (IOException e) {
logger.error(e.toString());
throw new RuntimeException("创建详情图片失败:" + e.toString());
}
// 返回图片相对路径地址
return relativeAddr;
}
错误的真正原因
看完代码应该很容易就能看出来,是生成缩略图时使用了windows的绝对路径引入水印图片,导致了Can't read input file!
陷入错误的原因以及感悟
根据提示,一直在生成缩略图的方法里面找bug,其实我感觉被这个错误困这么久的最大原因就是那个报错信息。由于两个方法作用很相似,写第二个方法的时候就直接copy了第一个方法然后修改的,这就导致了报错信息忘记修改的巨大错误。
由此也吸取了教训,以后写方法,方法名一定要有区分性,方法名相似的方法(特别是方法体也很相似的方法)甚至可以用注释标注上注意和另外一个方法做好区分,还有就是尽量不要图省事直接copy一段代码然后在上面修改。如果真的特别相似,也可以考虑是否能够抽象成一个参数不同的方法。