本文主要介绍如何简化MultipartFile压缩流程,使得调用者只需要简单的注解配置达到目的,传统的处理方式需要增加方法体中的代码,无法做到代码简洁。
经过一番思考,我决定利用spring的aop机制,完成配置自动化压缩的目的,我们知道aop主要有Before,Around,AfterReturning
我们在Around环绕方法中将post上来的MultipartFile进行分离压缩,并返还参数中。下面介绍一下具体代码实现如下:
@Around("webLog()") public Object around(ProceedingJoinPoint pjp) throws Throwable { ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); assert attributes != null; HttpServletRequest request = attributes.getRequest(); //首先获取方法名称列表 MethodSignature msg = (MethodSignature) pjp.getSignature(); //获取传入的参数 Object[] args = pjp.getArgs(); if (request.getMethod().equals("POST")) { compress(args, msg); } //返回 return pjp.proceed(args); }
自定义注解
@Target({ElementType.FIELD, ElementType.PARAMETER}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Compress { /** * 压缩目标大小,单位kb */ long destSize(); /** * 图片质量,0-1f */ float quality(); /** * 图片宽度 */ int width(); /** * 图片高度 */ int height(); }
@SuppressWarnings("ResultOfMethodCallIgnored") private void compress(Object[] objects, MethodSignature signature) throws IOException { //获取所有参数上的注解 Annotation[][] parameterAnnotations = signature.getMethod().getParameterAnnotations(); for (Annotation[] parameterAnnotation : parameterAnnotations) { int paramIndex = ArrayUtils.indexOf(parameterAnnotations, parameterAnnotation); for (Annotation annotation : parameterAnnotation) { if (annotation instanceof Compress) { Compress compress = (Compress) annotation; Object paramValue = objects[paramIndex]; if (!(paramValue instanceof MultipartFile)) { throw new RuntimeException("Compress can only modified MultipartFile"); } int width = compress.width(); int height = compress.height(); float quality = compress.quality(); long destSize = compress.destSize(); String destPath = IMAGE_PATH + "cache" + File.separator; File destFileDir = new File(destPath); if (!destFileDir.exists()) { destFileDir.mkdir(); } //进行压缩 MultipartFile multipartFile = (MultipartFile) paramValue; File file = MultipartFileUtil.convertToFile(destPath + multipartFile.getOriginalFilename(), MultipartFileUtil.compressToSpecifySize(multipartFile.getBytes(), destSize, width, height, quality)); objects[paramIndex] = MultipartFileUtil.parseMulFile(file.getAbsolutePath(), multipartFile.getName(), multipartFile.getOriginalFilename()); } } } }
文件处理工具类
import net.coobird.thumbnailator.Thumbnails; import org.apache.commons.fileupload.FileItemFactory; import org.apache.commons.fileupload.disk.DiskFileItemFactory; import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.commons.CommonsMultipartFile; import org.apache.commons.fileupload.FileItem; import java.io.*; public class MultipartFileUtil { /** * @param fileName :文件名称 * @param textFieldName 文件参数名称 * @param picPath :文件路径 */ public static MultipartFile parseMulFile(String picPath, String textFieldName, String fileName) { FileItem fileItem = createFileItem(picPath, textFieldName, fileName); return new CommonsMultipartFile(fileItem); } private static FileItem createFileItem(String filePath, String textFieldName, String fileName) { FileItemFactory factory = new DiskFileItemFactory(16, null); int num = filePath.lastIndexOf("."); String extFile = filePath.substring(num); FileItem item = factory.createItem(textFieldName, "text/plain", true, fileName + extFile); File newfile = new File(filePath); int bytesRead = 0; byte[] buffer = new byte[8192]; try { FileInputStream fis = new FileInputStream(newfile); OutputStream os = item.getOutputStream(); while ((bytesRead = fis.read(buffer, 0, 8192)) != -1) { os.write(buffer, 0, bytesRead); } os.close(); fis.close(); } catch (IOException e) { e.printStackTrace(); } return item; } public static File convertToFile(String filePath, byte[] fileByte) throws IOException { try (FileOutputStream stream = new FileOutputStream(filePath)) { stream.write(fileByte, 0, fileByte.length); } return new File(filePath); } public static byte[] compressToSpecifySize(byte[] fileByte, long desSize,int w,int h,float quality) throws IOException { desSize*=1024; try (ByteArrayInputStream inputStream = new ByteArrayInputStream(fileByte); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(fileByte.length)) { while (fileByte.length > desSize) { Thumbnails.of(inputStream).size(w, h).outputQuality(quality).toOutputStream(outputStream); fileByte = outputStream.toByteArray(); } return fileByte; } } }
调用controller
@PostMapping("/compressImage") public Result compressImage(@Compress(destSize = 100,width = 700,height =600,quality = 0.9f) MultipartFile rootImage) { return Result.success(); }
这样配置完成就ok了,您只需配置该注解,就能自动进行压缩