文件上传下载
- -需要直接的路径文件下载(静态资源访问等) - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 public class MvcConfig {
 
 public WebMvcConfigurer webMvcConfigurer() {
 return new WebMvcConfigurer() {
 /**
 * 首页设置
 * @param registry
 */
 
 public void addViewControllers(ViewControllerRegistry registry) {
 registry.addViewController("/").setViewName("html/index");
 registry.addViewController("/index.html").setViewName("html/index");
 }
 
 /**
 * 静态资源虚拟地址映射
 * 文件上传读取相关
 * @param registry
 */
 
 public void addResourceHandlers(ResourceHandlerRegistry registry) {
 //获取jar包物理路径
 ApplicationHome ah = new ApplicationHome(getClass());
 File jarFile = ah.getSource();
 String filePath = jarFile.getParentFile().getPath() + "/upload";
 System.out.println("初始化文件上传路径:" + filePath);
 //添加静态文件资源与实际文件路径之间的映射(app_file换成自定义路径)
 registry.addResourceHandler("/app_file/**")
 .addResourceLocations("file:" + filePath + "/") ;
 }
 };
 }
 }- 之后我们就可以通过 - ip:端口/app_file/文件路径来访问对应的文件资源了
- 服务器直接读取文件 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49- public class FileService implements InitializingBean{ 
 private static String FILE_PATH;
 
 //这里不能直接在static代码中编写方法,因为getClass()方法会报空指针
 //实现InitializingBean的afterPropertiesSet方法,注入FILE_PATH
 
 public void afterPropertiesSet() throws Exception {
 //获取jar包物理路径
 File jarFile = null;
 String filePath = null;
 try {
 ApplicationHome ah = new ApplicationHome(getClass());
 jarFile = ah.getSource();
 filePath = jarFile.getParentFile().getPath() + "/upload/";
 FILE_PATH = filePath;
 System.out.println("初始化文件上传路径:" + filePath);
 } catch (NullPointerException e) {
 // 运行单元测试时ApplicationHome(getClass())会报空指针异常
 }
 }
 
 public String getContent(String location) {
 StringBuilder builder = new StringBuilder();
 location = FILE_PATH + location;
 try {
 contentFile = ResourceUtils.getFile(location);
 } catch (FileNotFoundException e) {
 System.out.println("文件不存在,location:" + location);;
 }
 //流操作使用try-with-resource方式,更安全
 try (BufferedReader bufferedReader = new BufferedReader(new FileReader(contentFile))) {
 String tmpLine;
 int i = 2;
 while ((tmpLine = bufferedReader.readLine()) != null) {
 if (i > 0) {
 if (tmpLine.equals("---"))
 i--;
 } else if (!tmpLine.equals("<!--more-->")) {
 builder.append(tmpLine);
 builder.append("\n");
 }
 }
 } catch (IOException e) {
 e.printStackTrace();
 }
 content = builder.toString();
 return content;
 }
 }
- 服务器接收上传文件 - 直接使用 - CommonsMultipartFile.transferTo()会有打jar包保存文件不兼容问题,- 这里通过 - FileUtils.copyInputStreamToFile()来进行实现- 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 public class FIleController {
 //最大限制1M
 private static final Long FILE_SIZE_LIMIT = 1L * 1024L * 1024L;
 
 private FIleService fIleService;
 
 /**
 * 数据和文件必须异步上传
 * 上传文件早于保存数据
 * @param file
 * @param params
 * @return
 * @throws IOException
 */
 
 
 
 public JsonObject upload( MultipartFile file, Map<String, Object> params) throws IOException {
 JsonObject res = new JsonObject();
 if (!verifyFile(file, res)) {
 //验证不通过
 return res;
 }
 String uploadPath = fIleService.upload(file, blogId);
 res.put("uploadPath", uploadPath);
 return res;
 }
 
 /**
 * 验证是否通过
 * @param res 这里如果检验不通过会在res中设置status和message
 * @return 检验结果
 */
 private Boolean verifyFile(MultipartFile file, JsonObject res) {
 if (file.getSize() > FILE_SIZE_LIMIT) {
 res.setStatus(false);
 res.setMessage("文件不能超过最大值1M!");
 return false;
 }
 String originName = file.getOriginalFilename();
 //这里需要注意转义问题
 String[] names = originName.split("\\.");
 String lastName = names[names.length - 1];
 if (!"md".equals(lastName) && !"markdown".equals(lastName)) {
 res.setStatus(false);
 res.setMessage("文件类型不正确!请上传markdown文件");
 return false;
 }
 return true;
 }
 }- 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17- //FileService中的方法 
 public String upload(MultipartFile file, String blogId) throws IOException {
 Date date = new Date();
 int year = date.getYear();
 int month = date.getMonth();
 //年月子文件夹路径前缀
 String datePath = "/" + (1900 + year) + "-" + (1 + month);
 File realPath = new File(FILE_PATH + datePath);
 if (!realPath.exists()) {
 realPath.mkdir();
 }
 String blogPath = realPath + "/" + blogId;
 //保存文件
 FileUtils.copyInputStreamToFile(file.getInputStream(), new File(blogPath));
 System.out.println("上传文件路径:" + blogPath);
 return "public/posts" + datePath + "/" + blogId;
 }
Jackson序列化相关
时间转换
虽然jdk8提供了新的日期api,但是一般使用基础的java.util.Date或者java.util.TimeStamp就足够了
这里注意不要将java.util.Date和java.sql.Date搞混,后者是前者的子类,toString时只展示日期,同理还有java.util.Timestamp和java.sql.TimeStamp
我在项目中所使用的是java.util.Date,在格式化日期显示方面,可以选择使用下面方式手动进行转换:
| 1 | SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); | 
但这种方式需要在每个调用的位置都手动赋值,并且需要构建新的传输对象VO
这里推荐使用Jackson包含的注解@JsonFormat来实现
jackson依赖已经由springboot自动引入
- 在后端服务器响应日期数据时,只需要在实体类的属性上加上 - @JsonFormat,Jackson在序列化时就会自动帮我们完成日期格式转换- 1 
 2
 3
 4
 5- class Entity { 
 private Long id;
 
 private Date createTime;
 }
- 在接收前端日期数据时使用 - @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")来接收参数,可以自动转换成Date实体类- 由于时间一般由服务器自行生成,我在项目中并没有实际用到这个注解 
Long和String的转换
众所周知,服务器向前端直接传输Long类型数据时,如果Long数据的长度较长,可能会造成精度丢失
因此一般服务端需要将Long类型转换成String类型进行传输,以防止精度丢失
这里同样推荐使用Jackson的统一配置进行实现
| 1 | 
 | 
Thymeleaf小坑
在编写Html中的js代码时,如果需要通过[[$value]]来获取ModelAndView中的数据,需要在对应的script标签上添加th标签,如下所示:
| 1 | <script type="text/javascript" th:inline="javascript"> | 
否则js会直接转义替换string造成页面代码错误
统一Ajax返回对象
这里自定义了用于返回服务器数据的对象传输类,方便统一进行管理
| 1 | package com.lan5th.blog.utils; |