英文网站建设教程,青岛的互联网公司排名,赶集网天津网站建设,网站建设项目概要设计方案文章目录 1 前言2 Maven 依赖3 上传接口4 如何解析 MultipartFormDataInput5 结语 1 前言 使用 Spring MVC 来处理文件上传#xff0c;想必是大家耳熟能详的了#xff0c;如下代码#xff1a;
ResponseBody
PostMapping(/upload)
public String upload(Request… 文章目录 1 前言2 Maven 依赖3 上传接口4 如何解析 MultipartFormDataInput5 结语 1 前言 使用 Spring MVC 来处理文件上传想必是大家耳熟能详的了如下代码
ResponseBody
PostMapping(/upload)
public String upload(RequestPart(file) MultipartFile file) throws IOException {appService.upload(file);return Success;
}但是现在如果我们不使用 Spring MVC , 而是使用 javax.ws.rs 下的注解该如何实现文件上传呢
2 Maven 依赖
propertiesjboss.resteasy.version3.6.3.Final/jboss.resteasy.version
/propertiesdependenciesdependencygroupIdorg.jboss.resteasy/groupIdartifactIdresteasy-client/artifactIdversion${jboss.resteasy.version}/version/dependencydependencygroupIdorg.jboss.resteasy/groupIdartifactIdresteasy-jackson2-provider/artifactIdversion${jboss.resteasy.version}/version/dependencydependencygroupIdorg.jboss.resteasy/groupIdartifactIdresteasy-jaxb-provider/artifactIdversion${jboss.resteasy.version}/version/dependencydependencygroupIdorg.jboss.resteasy/groupIdartifactIdresteasy-jaxrs/artifactIdversion${jboss.resteasy.version}/version/dependencydependencygroupIdorg.jboss.resteasy/groupIdartifactIdresteasy-netty/artifactIdversion${jboss.resteasy.version}/version/dependency!-- resteasy 文件上传的依赖开始 --dependencygroupIdorg.jboss.resteasy/groupIdartifactIdresteasy-multipart-provider/artifactIdversion${jboss.resteasy.version}/version/dependency!-- resteasy 文件上传的依赖结束 --
/dependencies3 上传接口
import org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataInput;
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;Path(/test)
public interface TestController {POSTPath(upload)Produces(MediaType.APPLICATION_JSON)Consumes(MediaType.MULTIPART_FORM_DATA)JsonResultString upload(MultipartFormDataInput input);
}4 如何解析 MultipartFormDataInput 从 MultipartFormDataInput 中应当可以解析出文件 或者其他 form-data 的字段。通过下面的 getDtoFromMultipartFormDataInput() 方法我们就可以把多部件转换为指定类型的 dto 了。然后就可以进行 DAO 层操作了。
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.jboss.resteasy.plugins.providers.multipart.InputPart;
import org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataInput;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;import javax.ws.rs.core.MultivaluedMap;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;Slf4j
public class TestService {/*** multipart-form/data 的文件的 key 统一为 file*/private static final String FORM_FILE_KEY file;/*** 把 {link MultipartFormDataInput} 转换为指定类型的 dto** param input 多部件上传的参数, 里面可能有文件, 也可能只是普通的 key-value* param clazz dto 的类型* return dto*/public T T getDtoFromMultipartFormDataInput(MultipartFormDataInput input, Class? extends T clazz) {T dto;try {dto clazz.newInstance();} catch (InstantiationException | IllegalAccessException e) {log.error([把多部件转换为 dto] 无法实例化 dto, 类名: {}, clazz.getName());throw new RuntimeException([把多部件转换为 dto] 无法实例化 dto, 类名: clazz.getName(), e);}MapString, ListInputPart formDataMap input.getFormDataMap();// 处理多部件中的文件, 可能需要解析文件, 也可能不需要, 全看 dto 里面有没有 file 字段this.handleFileFieldIfNeed(clazz, formDataMap, dto);// 解析 multipart/form-data 的其他字段this.handleNonFileFields(clazz, formDataMap, dto);return dto;}/*** 处理 dto 中 非文件类型的字段** param clazz dto 的类型* param formDataMap 多部件的内容* param dto dto 实例, new 出来的* param T 泛型, dto 的类型*/private T void handleNonFileFields(Class? extends T clazz, MapString, ListInputPart formDataMap, T dto) {Field[] dtoFields clazz.getDeclaredFields();for (Field dtoField : dtoFields) {String fieldName dtoField.getName();if (!file.equals(fieldName)) {// 处理非文件的字段ListInputPart inputParts formDataMap.get(fieldName);if (CollectionUtils.isEmpty(inputParts)) {log.warn([把多部件转换为 dto] dto 里面不存在 multipart/form-data 中的字段: {}, fieldName);} else {// 只取第一个InputPart inputPart inputParts.get(0);try {Object dtoFieldValue inputPart.getBody(dtoField.getType(), null);boolean accessible dtoField.isAccessible();if (!accessible) {dtoField.setAccessible(true);}dtoField.set(dto, dtoFieldValue);if (!accessible) {dtoField.setAccessible(false);}} catch (IOException | IllegalAccessException e) {log.error([把多部件转换为 dto] dto 字段: fieldName 无法从 form-data 中获取值, e);throw new RuntimeException([把多部件转换为 dto] dto 字段: fieldName 无法从 form-data 中获取值, e);}}}}}/*** 处理多部件中的文件, 可能需要解析文件, 也可能不需要, 全看 dto 里面有没有 file 字段** param clazz dto 的类型* param formDataMap 多部件的内容* param dto dto 实例, new 出来的* param T 泛型, dto 的类型*/private T void handleFileFieldIfNeed(Class? extends T clazz, MapString, ListInputPart formDataMap, T dto) {try {Field fileField clazz.getDeclaredField(file);if (File.class.equals(fileField.getType())) {// 如果 dto 里面有 file 这个字段, 而且 file 字段的类型是 java.io.File, 那么就开始解析// multipart/form-data 的内容, 解析出一个文件出来ListInputPart inputParts formDataMap.get(FORM_FILE_KEY);if (CollectionUtils.isEmpty(inputParts)) {throw new RuntimeException([把多部件转换为 dto] 上传文件的 form-data 的 key 应该为 file);}// 一个 key file, 只对应一个 文件InputPart inputPart inputParts.get(0);// 解析文件名MultivaluedMapString, String headers inputPart.getHeaders();String filename this.getFilename(headers).orElseThrow(() - new RuntimeException([把多部件转换为 dto] 解析文件名称失败));// 解析文件流try (InputStream is inputPart.getBody(InputStream.class, null)) {// 先生成本地的临时文件File file this.stream2file(is, filename);// 然后把这个文件设置到 dto 的 file 字段里面boolean fileFieldAccessible fileField.isAccessible();if (!fileFieldAccessible) {fileField.setAccessible(true);}fileField.set(dto, file);if (!fileFieldAccessible) {fileField.setAccessible(false);}} catch (IOException e) {log.error([把多部件转换为 dto] 获取文件输入流 或者把此输入流转换为字节数组失败, e);throw new RuntimeException([把多部件转换为 dto] 获取文件输入流 或者把此输入流转换为字节数组失败);} catch (IllegalAccessException e) {log.error([把多部件转换为 dto] 把 File 设置到 dto 的 file 字段时, 失败, e);throw new RuntimeException([把多部件转换为 dto] 把 File 设置到 dto 的 file 字段时, 失败);}}} catch (NoSuchFieldException e) {// 没有名称为 file 的字段log.warn([把多部件转换为 dto] dto 里面没有 file 字段. class:{}, clazz.getName());}}/*** 从 http 请求头中, 获取文件的名称** param headers http 请求头* return 文件的名称, 可能为空*/private OptionalString getFilename(MultivaluedMapString, String headers) {String[] contentDispositionArr headers.getFirst(Content-Disposition).split(;);for (String contentDisposition : contentDispositionArr) {if (contentDisposition.trim().startsWith(filename)) {String[] filenameArr contentDisposition.split();String filename filenameArr[1].trim().replaceAll(\, );if (!StringUtils.hasText(filename)) {// 文件名为空的话, 也是不可以的return Optional.empty();}String finalFilename this.urlDecodeFilename(filename);return Optional.ofNullable(finalFilename);}}return Optional.empty();}/*** 把字节输入流 转换为 临时文件.* 这些临时文件要记得及时清除** param is 字节输入流* param filename 文件名* return 临时文件*/private File stream2file(InputStream is, String filename) {File file this.createTempFile(filename);try (FileOutputStream fos new FileOutputStream(file)) {IOUtils.copy(is, fos);} catch (IOException e) {log.error(把输入流的内容拷贝到文件输出流 失败, e);}return file;}/*** 创建临时文件** param filename 临时文件名, 不包含路径* return 临时文件*/public File createTempFile(String filename) {// 统一的临时文件上传目录. 目录加了日期和uuid的区分String tmpParentDirPath this.getTmpFileParentDirPath() File.separator;File file new File(tmpParentDirPath filename);File parentDir file.getParentFile();if (!parentDir.exists()) {// 生成父目录//noinspection ResultOfMethodCallIgnoredparentDir.mkdirs();}if (!file.exists()) {try {//noinspection ResultOfMethodCallIgnoredfile.createNewFile();} catch (IOException e) {log.error(创建临时文件失败, 文件名: {}, file.getAbsolutePath());throw new RuntimeException(创建临时文件失败, 文件名: file.getAbsolutePath(), e);}}return file;}/*** 获取临时文件所在的父目录*/private String getTmpFileParentDirPath() {// 父目录的格式是 D:/年月日/uuidreturn D: File.separator DateTimeUtil.formatString(new Date(), yyyy-MM-dd) File.separator UUID.randomUUID().toString().replaceAll(-, );}
}这个 dto 可以是
import java.io.File;Data
public class MyTestDto {private File file;private String queryParamOne;private String queryParamTwo;
}5 结语 感谢阅读~ 文章转载自: http://www.morning.fhsgw.cn.gov.cn.fhsgw.cn http://www.morning.wxlzr.cn.gov.cn.wxlzr.cn http://www.morning.gjcdr.cn.gov.cn.gjcdr.cn http://www.morning.glnxd.cn.gov.cn.glnxd.cn http://www.morning.ghkgl.cn.gov.cn.ghkgl.cn http://www.morning.wnnfh.cn.gov.cn.wnnfh.cn http://www.morning.rybr.cn.gov.cn.rybr.cn http://www.morning.ryyjw.cn.gov.cn.ryyjw.cn http://www.morning.bpmtr.cn.gov.cn.bpmtr.cn http://www.morning.qzzmc.cn.gov.cn.qzzmc.cn http://www.morning.qcmhs.cn.gov.cn.qcmhs.cn http://www.morning.xnlj.cn.gov.cn.xnlj.cn http://www.morning.wrtbx.cn.gov.cn.wrtbx.cn http://www.morning.tkkjl.cn.gov.cn.tkkjl.cn http://www.morning.xbmwm.cn.gov.cn.xbmwm.cn http://www.morning.xgbq.cn.gov.cn.xgbq.cn http://www.morning.nzmhk.cn.gov.cn.nzmhk.cn http://www.morning.dmwjl.cn.gov.cn.dmwjl.cn http://www.morning.mjqms.cn.gov.cn.mjqms.cn http://www.morning.rsjng.cn.gov.cn.rsjng.cn http://www.morning.dfygx.cn.gov.cn.dfygx.cn http://www.morning.srbsr.cn.gov.cn.srbsr.cn http://www.morning.rhpgk.cn.gov.cn.rhpgk.cn http://www.morning.ylyzk.cn.gov.cn.ylyzk.cn http://www.morning.qnywy.cn.gov.cn.qnywy.cn http://www.morning.xqcst.cn.gov.cn.xqcst.cn http://www.morning.lpmjr.cn.gov.cn.lpmjr.cn http://www.morning.wgbsm.cn.gov.cn.wgbsm.cn http://www.morning.rxhs.cn.gov.cn.rxhs.cn http://www.morning.pjtnk.cn.gov.cn.pjtnk.cn http://www.morning.wbfly.cn.gov.cn.wbfly.cn http://www.morning.fhbhr.cn.gov.cn.fhbhr.cn http://www.morning.rcmwl.cn.gov.cn.rcmwl.cn http://www.morning.mqbdb.cn.gov.cn.mqbdb.cn http://www.morning.bfsqz.cn.gov.cn.bfsqz.cn http://www.morning.sdecsd.cn.gov.cn.sdecsd.cn http://www.morning.yzsdp.cn.gov.cn.yzsdp.cn http://www.morning.hysqx.cn.gov.cn.hysqx.cn http://www.morning.xdmsq.cn.gov.cn.xdmsq.cn http://www.morning.drnfc.cn.gov.cn.drnfc.cn http://www.morning.mttck.cn.gov.cn.mttck.cn http://www.morning.wzwpz.cn.gov.cn.wzwpz.cn http://www.morning.zylrk.cn.gov.cn.zylrk.cn http://www.morning.mzhhr.cn.gov.cn.mzhhr.cn http://www.morning.fmtfj.cn.gov.cn.fmtfj.cn http://www.morning.hrzhg.cn.gov.cn.hrzhg.cn http://www.morning.czrcf.cn.gov.cn.czrcf.cn http://www.morning.yjtnc.cn.gov.cn.yjtnc.cn http://www.morning.smdiaosu.com.gov.cn.smdiaosu.com http://www.morning.rjrlx.cn.gov.cn.rjrlx.cn http://www.morning.pwsnr.cn.gov.cn.pwsnr.cn http://www.morning.playmi.cn.gov.cn.playmi.cn http://www.morning.lwyqd.cn.gov.cn.lwyqd.cn http://www.morning.rqsnl.cn.gov.cn.rqsnl.cn http://www.morning.tjndb.cn.gov.cn.tjndb.cn http://www.morning.hmgqy.cn.gov.cn.hmgqy.cn http://www.morning.lxfdh.cn.gov.cn.lxfdh.cn http://www.morning.jftl.cn.gov.cn.jftl.cn http://www.morning.gcthj.cn.gov.cn.gcthj.cn http://www.morning.zhoer.com.gov.cn.zhoer.com http://www.morning.aa1585.com.gov.cn.aa1585.com http://www.morning.gmmyn.cn.gov.cn.gmmyn.cn http://www.morning.nlnmy.cn.gov.cn.nlnmy.cn http://www.morning.jllnh.cn.gov.cn.jllnh.cn http://www.morning.kncrc.cn.gov.cn.kncrc.cn http://www.morning.lwyqd.cn.gov.cn.lwyqd.cn http://www.morning.mprky.cn.gov.cn.mprky.cn http://www.morning.yltyz.cn.gov.cn.yltyz.cn http://www.morning.wnjsp.cn.gov.cn.wnjsp.cn http://www.morning.lwgsk.cn.gov.cn.lwgsk.cn http://www.morning.yltnl.cn.gov.cn.yltnl.cn http://www.morning.cjcry.cn.gov.cn.cjcry.cn http://www.morning.jfbgn.cn.gov.cn.jfbgn.cn http://www.morning.xinxianzhi005.com.gov.cn.xinxianzhi005.com http://www.morning.xnwjt.cn.gov.cn.xnwjt.cn http://www.morning.wncb.cn.gov.cn.wncb.cn http://www.morning.rqgbd.cn.gov.cn.rqgbd.cn http://www.morning.yfmlj.cn.gov.cn.yfmlj.cn http://www.morning.tqsmc.cn.gov.cn.tqsmc.cn http://www.morning.pgmyn.cn.gov.cn.pgmyn.cn