最近在做一个完全义务性的用作展示的公司小网站(因为原来的那个真的丑的不能看了我都忍不住了) 。因为是义务性的,他们不是特别在意这个网站变成什么样子(毕竟不靠这个做生意啊不然这么能忍这么丑的公司网站)。 于是我思索了一番,决定用spring boot来写这个网站了,毕竟技术要多用才会熟练嘛(其实也就这个暑假的时候学的 )。
这时候就遇到了一个问题,展示嘛,一般大家都是看看图片,看看文章的吖,但是文章有那么多,我总不能一个一个地给每一个文章、产品介绍写一个网页吧(智障才这么做 ),于是我就把文章做成txt文件保存在了一个静态资源static/document/文件夹里,然后为了预防这些文章里有恶意的前端代码(没错我也很智障,为什么我要将文章做成html代码呢然后在前端插入这段代码呢 ),我需要在后端用正则表达式过滤一下它们的内容。于是就遇到了第一个问题——怎么读静态资源。
Spring Boot读取在static文件夹下的静态资源
首先第一步,配置静态资源的路径。这个其实到开发前端的时候也是需要的,因为Spring Boot的默认静态资源路径是这样的:
classpath:/static
classpath:/public
classpath:/resources
classpath:/META-INF/resources
就是说Spring Boot默认会在这几个文件夹里搜索的,问题是,不!包!括!子!文!件!夹! 这样下来会弄得我们这些把js、css、images分成一个一个文件夹的就很不爽,更何况我现在还要在static下加一个document的文件夹呢。所以在application.properties
中要加入一句
spring.mvc.static-path-pattern=/static/**
然后,第二步就来说说怎么读文件了。
Spring很贴心地为我们提供一个Resource接口,是Spring提供用于访问底层外部资源的一致性访问接口,它下面有几个实现类,这里用到的是ClassPathResource类,其它几个感兴趣的可以去找找学习学习。ClassPathResource提供四个构造方法,具体的用法可以上其它博客找,毕竟百度一下你就发现有很多Ctrl+C过来的用法解释,所以我就不说了。这里我用它的第一个构造方法——也就是传入一个路径,如果是相对路径的话会默认在classpath里面找,这里我写了一个工具类
/*
* ReadFile 用于读入文件内容
* readTxtFile(String) 用于以字符串的方式读入txt文件(文件编码方式为UTF-8)
*/
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
public class ReadFile {
public static String readTxtFile(String path) {
StringBuffer content=new StringBuffer("");
try {
Resource resource = new ClassPathResource(path);
BufferedReader br = new BufferedReader(new InputStreamReader(resource.getInputStream(),"UTF-8"));
String line = br.readLine();
while(line!=null) {
content.append(line);
content.append("\r\n");
line=br.readLine();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
}
return content.toString();
}
}
可以看到我这是字符流的方式把它读出来的,这里之所以不把它做成File对象是因为Spring Boot打包之后用File对象会导致读不了这个文件。
现在已经可以轻松地将静态资源里的文件读到后端处理然后送回前端进行展示(感觉有点怪怪的 ),于是我就在考虑到,我总不能每次出一篇新文章或者产品都要重新提交一次jar包到服务器吧(我才不会说其实是我闲得蛋疼于是想给他们扩充点功能的 )。于是就遇到了第二个问题——怎么将文件写到静态资源的文件夹里
Spring Boot将文件写入项目的静态资源里
一开始我想,Spring既然这么贴心地给我们提供了ClassPathResource类,是不是也会提供写入的类呢(美滋滋)。于是我就百度了一下发现,还真有一个FileSystemResource,但是这是在文件系统(就是绝对路径了)用的,不是很想用咋整。其实在之前一直想用用NIO来着然而之前在读文件的时候发现它对冒号的意见特别大,写成classpath:static/document/
会报java.nio.file.invalidpathexception:illegal char <:>
的错误,就是说它不认这种路径。问题是我也不知道项目内部的真实的相对路径啊
后来我灵机一动,我不知道相对路径我可以测试一下吖,把文件保存到项目同级文件夹不就知道了咯(我真是个小机灵鬼 )。最后我发现文件被保存在项目的根目录里,对,就是和src文件夹同级的目录里。这就好办了,下面就是上传文件的Controller的代码
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
@Controller
public class UpLoadController {
@PostMapping("/upload")
public String upload(@RequestParam("file") MultipartFile file, ModelMap map){
if (file.isEmpty()){
map.addAttribute("message", "The file is empty!");
return "message";
}
try{
byte[] bytes = file.getBytes();
Path path = Paths.get("src/main/resources/static/document/"+file.getOriginalFilename());
Files.write(path, bytes);
map.addAttribute("message", "succes");
}catch (Exception e){
e.printStackTrace();
}
return "message";
}
}
虽然现在我把这个方法写在了Controller里面,但按我的尿性我绝对会把它做成一个工具类。
其实现在既然已经知道了Spring Boot项目里面读写文件的相对路径以后,其实不止是NIO的方法,其他IO的方法和FileSystemResource也可以很容易地将文件写到项目的静态资源里。
题外话
虽然说现在已经可以读写静态资源,但是据我所知,Thymeleaf模板提供了一个缓存机制,这个机制使得我上传的资源无法被第一时间读到,其次在开发的时候,eclipse在运行的过程中会给项目缓存,新提交的资源同样是无法被第一时间读到的(这个甚至需要手动刷新)这就很烦了,我想我以后应该会把这部分的坑给填上,所以先留个flag在这(自古flag立下了除了基拉就没有人能活到那个时候 )。