目录
前言
我们之前实现了自定义的Servlet功能,并且可以根据路径分发对应的Servlet来处理请求。接下来实现对于静态资源文件访问。
实现
首先我们需要添加一个配置文件,配置文件中存储不同格式的文件对应的ContentType。
创建MIME.properties
html=text/html;charset=utf-8
jpg=application/x-jpg
接下来需要在我们的tomcat启动时,需要读取这个文件。同时在MyServletHandler中添加Map集合用来存储MIME.properties的信息。也需要我们存储对应的静态资源访问路径与服务器中的绝对路径,以及访问路径与ContentType的关系。
//这个map用于存放静态资源访问路径和绝对路径的对应关系
public static final ConcurrentHashMap<String, String> STATIC_NAME_PATH = new ConcurrentHashMap<>();
//这个map用于存放静态资源访问路径和ContendType的对应关系
public static final ConcurrentHashMap<String, String> STATIC_NAME_HEADER = new ConcurrentHashMap<>();
//这个map用于存放扩展名和ContentType的对应关系,在一个静态代码块中加载
public static final ConcurrentHashMap<String, String> STATIC_SUFFIX_HEADER = new ConcurrentHashMap<>();
一个静态代码块。在启动时初始化加载MIME.properties文件
static {
Properties properties = new Properties();
try {
String path = URLDecoder.decode(Objects.requireNonNull(MyServletHandler.class.getResource("/").getPath()), "utf-8");
properties.load(new FileInputStream(path + "/com/zmt/config/MIME.properties"));
//获取MIME文件的key值,也就是文件的后缀名
Set<Object> suffixes = properties.keySet();
for (Object suffix : suffixes) {
Object value = properties.get(suffix);
STATIC_SUFFIX_HEADER.put((String) suffix, (String) value);
}
} catch (IOException e) {
e.printStackTrace();
}
}
接下来实现扫描web目录下静态资源文件
private static void forDir(File rootFile) {
//对webapp目录下的文件进行遍历
File[] files = rootFile.listFiles();
for (File file : files) {
//不读取该目录
if (file.getName().equals("WEB-INF")) {
continue;
}
//如果是文件夹
if (file.isDirectory()) {
forDir(file);
} else {
//如果是文件的话
//获取绝对路径
String absolutePath = file.getAbsolutePath();
String[] webapps = absolutePath.split("webapp");
String filePath = webapps[1];
String suffix = filePath.substring(filePath.lastIndexOf(".") + 1);
//如果读取的文件后缀名在配置文件中存在
if (STATIC_SUFFIX_HEADER.get(suffix) != null) {
filePath = filePath.replace("\\", "/");
STATIC_NAME_HEADER.put(filePath, STATIC_SUFFIX_HEADER.get(suffix));
STATIC_NAME_PATH.put(filePath, absolutePath);
}
}
}
}
修改线程池类,添加处理访问静态资源的Servlet
else if (MyServletHandler.STATIC_NAME_PATH.containsKey(uri)) {
//获取访问路径
String path = MyServletHandler.STATIC_NAME_PATH.get(uri);
//获取静态资源的contentType
String contentType = MyServletHandler.STATIC_NAME_HEADER.get(uri);
//设置contentType
myHttpResponse.setContentType(contentType);
FileInputStream inputStream = new FileInputStream(path);
myHttpResponse.write(inputStream);
我们之前没有实现参数为inputStream的write方法。我们添加一个对应的write方法
@Override
public void write(FileInputStream inputStream) {
String header = responseRow + status + "\r\n" + responseHead + contentType;
System.out.println(header);
try {
outputStream.write(header.getBytes());
byte[] bytes = new byte[1024];
int len;
while ((len = inputStream.read(bytes)) != -1) {
System.out.println(len);
outputStream.write(bytes, 0, len);
if (len != bytes.length) break;
}
outputStream.flush();
inputStream.close();
System.out.println("处理结束");
} catch (IOException e) {
e.printStackTrace();
}
}
测试
我们的webapp目录下存在一些文件
接下来访问login.html与pic.jpg文件
浏览器依次输入localhost:8080/login.html与localhost:8080/pic/pic.jpg路径
访问成功。
问题
在访问静态资源路径时,需要先返回一个响应头。响应头的ContentType的值后面要跟两个"/r/n"。当只有一个或是不加"/r/n",浏览器则不会响应正常页面。或是空白页面或是响应信息错误。
完整代码
完整代码下载地址:tomcat: tomcat简单实现