当前位置: 首页 > news >正文

哈尔滨制作手机网站东莞网络优化哪家公司好

哈尔滨制作手机网站,东莞网络优化哪家公司好,天津seo推广优化,自学做视频网站文章目录 1 前言2 Maven 依赖3 上传接口4 如何解析 MultipartFormDataInput5 结语 1 前言 使用 Spring MVC 来处理文件上传,想必是大家耳熟能详的了,如下代码: ResponseBody PostMapping("/upload") public String upload(Request…

文章目录

  • 1 前言
  • 2 Maven 依赖
  • 3 上传接口
  • 4 如何解析 MultipartFormDataInput
  • 5 结语

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 依赖

<properties><jboss.resteasy.version>3.6.3.Final</jboss.resteasy.version>
</properties><dependencies><dependency><groupId>org.jboss.resteasy</groupId><artifactId>resteasy-client</artifactId><version>${jboss.resteasy.version}</version></dependency><dependency><groupId>org.jboss.resteasy</groupId><artifactId>resteasy-jackson2-provider</artifactId><version>${jboss.resteasy.version}</version></dependency><dependency><groupId>org.jboss.resteasy</groupId><artifactId>resteasy-jaxb-provider</artifactId><version>${jboss.resteasy.version}</version></dependency><dependency><groupId>org.jboss.resteasy</groupId><artifactId>resteasy-jaxrs</artifactId><version>${jboss.resteasy.version}</version></dependency><dependency><groupId>org.jboss.resteasy</groupId><artifactId>resteasy-netty</artifactId><version>${jboss.resteasy.version}</version></dependency><!-- resteasy 文件上传的依赖开始 --><dependency><groupId>org.jboss.resteasy</groupId><artifactId>resteasy-multipart-provider</artifactId><version>${jboss.resteasy.version}</version></dependency><!-- resteasy 文件上传的依赖结束 -->
</dependencies>

3 上传接口

import org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataInput;
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;@Path("/test")
public interface TestController {@POST@Path("upload")@Produces(MediaType.APPLICATION_JSON)@Consumes(MediaType.MULTIPART_FORM_DATA)JsonResult<String> 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);}Map<String, List<InputPart>> 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, Map<String, List<InputPart>> formDataMap, T dto) {Field[] dtoFields = clazz.getDeclaredFields();for (Field dtoField : dtoFields) {String fieldName = dtoField.getName();if (!"file".equals(fieldName)) {// 处理非文件的字段List<InputPart> 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, Map<String, List<InputPart>> formDataMap, T dto) {try {Field fileField = clazz.getDeclaredField("file");if (File.class.equals(fileField.getType())) {// 如果 dto 里面有 file 这个字段, 而且 file 字段的类型是 java.io.File, 那么就开始解析// multipart/form-data 的内容, 解析出一个文件出来List<InputPart> 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);// 解析文件名MultivaluedMap<String, 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 Optional<String> getFilename(MultivaluedMap<String, 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.ritt.cn/news/11703.html

相关文章:

  • 中国建设厅或是建委的网站天天外链
  • 大连里程科技做网站外贸海外推广
  • 自己做交友网站宁波seo基础入门
  • 同城分类信息系统上海网站seo优化
  • 杭州网站排名关键词挖掘站长工具
  • 怎么介绍自己做的电影网站seo优化培训课程
  • 昆明网站建设猫咪科技什么平台引流最快
  • 创建一个网站 优帮云seo优化效果怎么样
  • 徐州网站建设 网站制作扬州百度seo
  • html论坛网站模板百度推广管家登录
  • 建设厅报名网站深圳网络营销策划有限公司
  • 深圳做棋牌网站建设哪家便宜青岛网络优化厂家
  • 做网站公司需要提供的资料域名批量查询系统
  • 中交建设招标有限公司网站宁德市旅游景点大全
  • 泰兴网站建设价格深圳网页设计公司
  • 网站集约化建设管理江门seo外包公司
  • cms开源建站系统太原seo哪家好
  • 海曙区做网站网络服务运营商
  • 大型电子商务网站需要配服务器网络广告策划
  • 合肥品牌网站建设宁波seo服务快速推广
  • 用wordpress做微站友情链接检查
  • 网站建设 日志seo独立站
  • 做玩网站怎么上传一天赚2000加微信
  • 方舟网站建设百度指数关键词未收录怎么办
  • 要绑定税务网站办税员怎样做如何制作微信小程序店铺
  • 网站还没完成 能备案吗电商营销策略
  • 网站前台模板下载100种宣传方式
  • 基于web的毕业设计好做吗seo商学院
  • 生鲜电商网站建设策划书seo网络培训学校
  • html做的网站图片横着摆放湖南今日新闻最新头条