目录
问题1:传输给前端的时间格式不对
因为我们传递给前端的是Json对象,所以可以通过Jackson的ObjectMapper设置相应的序列化器与反序列化器,实现正确的格式转换
private ObjectMapper objectMapper() {
final String DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
ObjectMapper mapper = new ObjectMapper();
JavaTimeModule javaTimeModule = new JavaTimeModule();
javaTimeModule.addSerializer(LocalDateTime.class,
new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DATE_TIME_FORMAT)));
javaTimeModule.addDeserializer(LocalDateTime.class,
new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DATE_TIME_FORMAT)));
javaTimeModule.addSerializer(Long.class, ToStringSerializer.instance);
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
mapper.registerModule(javaTimeModule);
return mapper;
}
addSerializer()方法的第一个参数是要序列化的对象类型,第二个参数是序列化器
addDeserializer()方法的第一个参数是要反序列化的对象类型(即json要转为Java对象的类型),第二个参数是反序列化器
public <T> SimpleModule addSerializer(Class<? extends T> type, JsonSerializer<T> ser);
public <T> SimpleModule addDeserializer(Class<T> type, JsonDeserializer<? extends T> deser);
或者在要序列化的时间属性上添加@JsonFormat注解
@Data
public class Category implements Serializable {
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8", shape = JsonFormat.Shape.STRING)
private LocalDateTime createTime;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8", shape = JsonFormat.Shape.STRING)
private LocalDateTime updateTime;
}
@JsonFormat属性
shape 表示序列化后的一种类型,枚举类 pattern 表示日期的格式 timezone 默认是GMT,中国需要GMT+8 locale 根据位置序列化的一种格式,默认为本地的语言简称
问题2:文件上传与下载
1、文件上传
文件上传时,对页面的form表单有如下要求:
表单属性 | 取值 | 说明 |
---|---|---|
method | post | 必须选择post方式提交 |
enctype | multipart/form-data | 采用multipart格式上传文件 |
type | file | 使用input的file控件上传 |
<form method="post" action="/common/upload" enctype="multipart/form-data">
<input name="myFile" type="file" />
<input type="submit" value="提交" />
</form>
后端可以使用MultipartFile来接收文件
//public Result<String> uploadImg(@RequestParam("file") MultipartFile multipartFile) {
@PostMapping("/upload")
public Result<String> uploadImg(MultipartFile file) {
String type = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."));
String fileName = UUID.randomUUID().toString() + type;
File parent = new File(basePath);
if (!parent.exists()) {
parent.mkdir();
}
File img = new File(basePath + fileName);
try {
file.transferTo(img);
} catch (IOException e) {
e.printStackTrace();
}
return Result.success(fileName);
}
补充:
1、MultipartFile这个对象实际上是一个临时文件,由服务器存储到某个临时文件夹下,因此上传文件实际上就是把临时文件转存到项目的某个文件夹下。
2、MultipartFile的getName与getOriginalFileName方法的差别
getOriginalFileName:上传文件名,不同浏览器可能提交给服务端的文件名不同
getName:返回参数的名称,如(MultipartFile oriFile)则返回为oriFile
相关文章:MultipartFile详解
2、文件下载
文件下载分为两种;
- 客户端以附件形式下载
- 客户端以内联形式下载(在浏览器直接打开)
文件下载的本质是向浏览器传输字节,并且告诉浏览器该如何处理文件 。比如使用Content-Disposition,可以实现附件下载,或者设置content-type告诉浏览器文件类型,让它决定如何处理文件。
文件下载不一定要以流的形式返回给浏览器,可以先把文件全部读取到内存中,再把文件放在响应体中。
下面我们采用以流的形式返回,即从磁盘中读数据到内存的同时,将数据从内存中返回给前端
Content-Disposition的作用:告知浏览器以何种方式处理响应返回的文件,用浏览器打开还是以附件的形式下载到本地保存
1、请求内联形式下载的后端响应方法
@RestController
@RequestMapping("/common")
public class CommonController {
//不支持静态
@Value("${reggie.basePath}")
private String basePath;
@GetMapping("/download")
public void download(HttpServletResponse response, String name) {
File file = new File(basePath + name);
FileInputStream inputStream = null;
try {
inputStream = new FileInputStream(file);
ServletOutputStream outputStream = response.getOutputStream();
byte[] bytes = new byte[1024 * 1024];
int len = 0;
while ((len = inputStream.read(bytes)) != -1) {
outputStream.write(bytes, 0, len);
}
outputStream.close();
inputStream.close();
} catch (IOException e) {
log.info("找不到文件: " + file.getAbsolutePath());
}
}
}
在上述方法中,没有设置Content-Disposition,浏览器接收到二进制流后,默认是内联形式,直接打开。
2、附件形式
@GetMapping(value = "/test01")
public void test01(HttpServletResponse response) throws IOException {
File file = new File("D:\\springbootDemo\\src\\main\\resources\\picture\\729d14e6-9f91-4cbb-8f31-b423be35450f.jpg");
byte[] bytes = new byte[1024 * 1024];
int len = 0;
FileInputStream fileInputStream = new FileInputStream(file);
response.setHeader("Content-Disposition", "attachment; filename=" + file.getName());
ServletOutputStream outputStream = response.getOutputStream();
while ((len = fileInputStream.read(bytes)) != -1) {
outputStream.write(bytes, 0, len);
}
outputStream.close();
fileInputStream.close();
}
补充:content-type:application/octet-stream
告知浏览器这是一个字节流,浏览器处理字节流的默认方式就是下载。
Application/octet-stream是应用程序文件的默认值。意思是未知的应用程序文件,浏览器一般不会自动执行或询问执行。浏览器会像对待,设置了HTTP头Content-Disposition值为attachment的文件一样来对待这类文件,即浏览器会触发下载行为。说人话就是,浏览器并不认得这是什么类型,也不知道应该如何展示,只知道这是一种二进制文件,因此遇到content-type为application/octet-stream的文件时,浏览器会直接把它下载下来。这个类型一般会配合另一个响应头Content-Disposition,该响应头指示回复的内容该以何种形式展示,是以内联的形式(即网页或者网页的一部分),还是以附件的形式下载并保存到本地。
————————————————
版权声明:本文为CSDN博主「心潮的滴滴」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_42582773/article/details/121807555
对于application/octet-stream,浏览器只会将其下载到本地,已经过测试。
@GetMapping(value = "/test01")
public void test01(HttpServletResponse response) throws IOException {
File file = new File("D:\\springbootDemo\\src\\main\\resources\\picture\\729d14e6-9f91-4cbb-8f31-b423be35450f.jpg");
byte[] bytes = new byte[1024 * 1024];
int len = 0;
FileInputStream fileInputStream = new FileInputStream(file);
response.setContentType("application/octet-stream");
response.setHeader("Content-Disposition", "inline; filename=" + file.getName());
ServletOutputStream outputStream = response.getOutputStream();
while ((len = fileInputStream.read(bytes)) != -1) {
outputStream.write(bytes, 0, len);
}
outputStream.close();
fileInputStream.close();
}