springboot 实现图片上传功能
这几天在做重构学校的图书馆项目,用sprinboot重新搭建项目,原项目是使用PHP搭建的,刚开始看着挺懵的,慢慢的就看懂。这个项目中遇到的难题是照片上传功能,弄了挺久才实现出来。
此功能没有导入如何jar包。
这里介绍呢,我就按照项目本身的结构来实现这个功能。
首先是数据库的数据结构,项目先是通过照片名(xxx.jpg)保存到数据库(picurl).
故我的想法是通过新书的名字,获取到这个新书对应的照片名,进行对上传上的照片进行名字的修改。
1.Mapper层
<!--上传图片-->
<select id="changeAvatar" resultType="NewBooks">
select * from newbooks where title=#{title}
</select>
2.Service层
@Override
public NewBooks changePicUrl(String title) {
//根据参数调用方法
NewBooks newBooks = newBooksMapper.changeAvatar(title);
if (newBooks == null){
throw new NewsBookNotException("书库没有该书数据,请先添加!");
}
return newBooks;
}
3.自定义异常
3.1service层自定义异常
为了便于统一管理自定义异常,在service包中创一个ex包用来放自定义异常的基类异常,继承自RuntimeException类,并从父类生成子类的五个构造方法。
创建NewsBookNotException类,当用户输入到的书名,在数据库中没有找到数据,则会出对应的信息。
3.2 上传文件自定义异常
处理异常
1.在处理上传文件的过程中,用户可能会选择错误的文件上传,此时就应该抛出对应的异常并进行处理。所以需要创建文件上传相关异常的基类,即在com.cy.store.controller.ex包下创建FileUploadException类,并继承自RuntimeException类。
package com.pzlib.service.ex;
/** 文件上传相关异常的基类 */
public class FileUploadException extends RuntimeException {
public FileUploadException() {
super();
}
public FileUploadException(String message) {
super(message);
}
public FileUploadException(String message, Throwable cause) {
super(message, cause);
}
public FileUploadException(Throwable cause) {
super(cause);
}
protected FileUploadException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}
2.在处理上传的文件过程中,经分析可能会产生以下异常。这些异常类都需要继承自FileUploadException类。
// 上传的文件为空
controller.ex.FileEmptyException
// 上传的文件大小超出了限制值
controller.ex.FileSizeException
// 上传的文件类型超出了限制
controller.ex.FileTypeException
// 上传的文件状态异常
controller.ex.FileStateException
// 上传文件时读写异常
controller.ex.FileUploadIOException
3.创建FileEmptyException异常类,并继承FileUploadException类。
package com.pzlib.service.ex;
/** 上传的文件为空的异常,例如没有选择上传的文件就提交了表单,或选择的文件是0字节的空文件 */
public class FileEmptyException extends FileUploadException {
// Override Methods...
}
4.创建FileSizeException异常类,并继承FileUploadException类。
package com.pzlib.service.ex;
/** 上传的文件的大小超出了限制值 */
public class FileSizeException extends FileUploadException {
// Override Methods...
}
5.创建FileTypeException异常类,并继承FileUploadException类。
package com.pzlib.service.ex;
/** 上传的文件类型超出了限制 */
public class FileTypeException extends FileUploadException {
// Override Methods...
}
6.创建FileStateException异常类,并继承FileUploadException类。
package com.pzlib.service.ex;
/** 上传的文件状态异常 */
public class FileStateException extends FileUploadException {
// Override Methods...
}
7.创建FileUploadIOException异常类,并继承FileUploadException类。
package com.pzlib.service.ex;
/** 上传文件时读写异常 */
public class FileUploadIOException extends FileUploadException {
// Override Methods...
}
8.然后在BaseController的handleException()的@ExceptionHandler注解中添加FileUploadException.class异常的处理;最后在方法中处理这些异常。
@ExceptionHandler({ServiceException.class, FileUploadException.class})
public JsonResult<Void> handleException(Throwable e) {
JsonResult<Void> result = new JsonResult<Void>(e);
if (e instanceof UsernameDuplicateException) {
result.setState(4000);
} else if (e instanceof UserNotFoundException) {
result.setState(4001);
} else if (e instanceof PasswordNotMatchException) {
result.setState(4002);
} else if (e instanceof InsertException) {
result.setState(5000);
} else if (e instanceof UpdateException) {
result.setState(5001);
} else if (e instanceof FileEmptyException) {
result.setState(6000);
} else if (e instanceof FileSizeException) {
result.setState(6001);
} else if (e instanceof FileTypeException) {
result.setState(6002);
} else if (e instanceof FileStateException) {
result.setState(6003);
} else if (e instanceof FileUploadIOException) {
result.setState(6004);
}
return result;
}
4.BaseController层
package com.pzlib.controller;
import com.pzlib.controller.ex.*;
import com.pzlib.service.ex.*;
import com.pzlib.util.JsonResult;
import org.springframework.web.bind.annotation.ExceptionHandler;
/** 控制器类的基类 */
public class BaseController {
/** 操作成功的状态码 */
public static final int OK = 200;
/** @ExceptionHandler用于统一处理方法抛出的异常 */
@ExceptionHandler({ServiceException.class,FileUploadException.class})
public JsonResult<Void> handleException(Throwable e) {
JsonResult<Void> result = new JsonResult<Void>(e);
if (e instanceof UsernameDuplicateException) {
result.setState(4000);
} else if (e instanceof UserNotFoundException) {
result.setState(4001);
} else if (e instanceof PasswordNotMatchException) {
result.setState(4002);
} else if (e instanceof NewsBookNotException) {
result.setState(4003);
}else if (e instanceof UpdateException) {
result.setState(5001);
}else if (e instanceof InsertException) {
result.setState(5002);
}else if (e instanceof SelectException) {
result.setState(5003);
}else if (e instanceof DeleteException) {
result.setState(5004);
}else if (e instanceof FileEmptyException) {
result.setState(6000);
} else if (e instanceof FileSizeException) {
result.setState(6001);
} else if (e instanceof FileTypeException) {
result.setState(6002);
} else if (e instanceof FileStateException) {
result.setState(6003);
} else if (e instanceof FileUploadIOException) {
result.setState(6004);
}
return result;
}
}
5.FileUrlController
自定义了异常,需要FileUrlController类继承BaseController类,捕获到异常信息。
package com.pzlib.controller;
import com.pzlib.controller.ex.*;
import com.pzlib.entity.NewBooks;
import com.pzlib.service.INewsBootService;
import com.pzlib.util.JsonResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.system.ApplicationHome;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@RestController
public class FileUrlController extends BaseController {
@Autowired
private INewsBootService newsBootService;
/** 头像文件大小的上限值(1MB) */
public static final int AVATAR_MAX_SIZE = 1 * 1024 * 1024;
/** 允许上传的头像的文件类型 */
public static final List<String> AVATAR_TYPES = new ArrayList<String>();
/** 初始化允许上传的头像的文件类型 */
static {
AVATAR_TYPES.add("image/jpeg");
AVATAR_TYPES.add("image/jpg");
AVATAR_TYPES.add("image/png");
AVATAR_TYPES.add("image/bmp");
AVATAR_TYPES.add("image/gif");
AVATAR_TYPES.add("image/pjpeg");
AVATAR_TYPES.add("image/x-png");
}
@PostMapping("/newsImage")
public JsonResult<String> newsImage(@RequestParam("file") MultipartFile file,String title) {
// 判断上传的文件是否为空
if (file.isEmpty()) {
// 是:抛出异常
throw new FileEmptyException("上传的头像文件不允许为空");
}
// 判断上传的文件大小是否超出限制值
if (file.getSize() > AVATAR_MAX_SIZE) { // getSize():返回文件的大小,以字节为单位
// 是:抛出异常
throw new FileSizeException("不允许上传超过" + (AVATAR_MAX_SIZE / 1024) + "KB的头像文件");
}
// 判断上传的文件类型是否超出限制
String contentType = file.getContentType();
// boolean contains(Object o):当前列表若包含某元素,返回结果为true;若不包含该元素,返回结果为false
if (!AVATAR_TYPES.contains(contentType)) {
// 是:抛出异常
throw new FileTypeException("不支持使用该类型的文件作为头像,允许的文件类型:" + AVATAR_TYPES);
}
//获取jar包所在目录
ApplicationHome h = new ApplicationHome(getClass());
File jarF = h.getSource();
//在jar包所在目录下生成一个upload文件夹用来存储上传的图片
String parent = jarF.getParentFile().toString()+"/classes/static/images/book/";
System.out.println(parent);
// 保存头像文件的文件夹
File dir = new File(parent);
if (!dir.exists()) {
dir.mkdirs();
}
// 保存的头像文件的文件名
String suffix = "";
String originalFilename = file.getOriginalFilename();
int beginIndex = originalFilename.lastIndexOf(".");
if (beginIndex > 0) {
suffix = originalFilename.substring(beginIndex);
}
NewBooks newBooks = newsBootService.changePicUrl(title);
String string = newBooks.getPicurl();
String[] split = string.split("\\.");
String filename =split[0]+ suffix;
// 创建文件对象,表示保存的头像文件
File dest = new File(dir, filename);
// 执行保存头像文件
try {
file.transferTo(dest);
} catch (IllegalStateException e) {
// 抛出异常
throw new FileStateException("文件状态异常,可能文件已被移动或删除");
} catch (IOException e) {
// 抛出异常
throw new FileUploadIOException("上传文件时读写错误,请稍后重新尝试");
}
/*// 头像路径
String avatar = "/images/book/" + filename;
// 返回成功头像路径*/
return new JsonResult<String>(OK);
}
运行结果
运行失败:
&图片保存路径是在target/classes/static/images/book/xxx.jpg,
&如果是打包成jar包,则路径和jar路径一样。
如有错误请指正,谢谢!