标签:之间 cti getpath 单元 好的 specific assert ase ann
/
,等等,在bootstrap中建立一个映射用于保存path和context。当服务启动时,就扫描webapp目录下的所有应用并将其保存。package jerrymice.catalina;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.TimeInterval;
import cn.hutool.log.LogFactory;
/**
* @author :xiaosong
* @description:
* 代表一个应用,它有两个属性,一个是path,表示访问的路径,docBase表示在文件系统中得分位置
* @date :2020/8/4 16:09
*/
public class Context {
private String path;
private String docBase;
public Context(String path, String docBase){
TimeInterval timeInterval = DateUtil.timer();
this.path = path;
this.docBase = docBase;
LogFactory.get().info("Deploying web application directory {}", this.docBase);
LogFactory.get().info("Deployment of web application directory {} has finished in {} ms",
this.docBase, timeInterval.intervalMs());
}
public String getPath() {
return path;
}
public String getDocBase() {
return docBase;
}
public void setPath(String path) {
this.path = path;
}
public void setDocBase(String docBase) {
this.docBase = docBase;
}
}
package jerrymice.http;
import jerrymice.Bootstrap;
import jerrymice.catalina.Context;
import cn.hutool.core.util.StrUtil;
import jerrymice.util.MiniBrowser;
import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
/**
* @author :xiaosong
* @description:TODO
* @date :2020/8/3 20:44
*/
public class Request {
private String requestString;
private String uri;
private Socket socket;
private Context context;
public Context getContext() {
return context;
}
/**
* 根据request的uri来解析成Context
*/
public void parseContext(){
String path = StrUtil.subBetween(uri, "/", "/");
if (null == path) {
// 如果uri = /timeConsume.html,那么path = null, 经过此处之后path=/
path = "/";
}
else {
// uri = /dir1/1.html, 那么path= dir1, 经过此处之后path=/dir1
path = "/" + path;
}
// 根据获取到的path去扫描得到的映射中去寻找这个文件夹
context = Bootstrap.contextMap.get(path);
if (context == null) {
// 如果没有获取到这个context对象,那么说明目录中根本就没有这个应用,或者本身就在根目录下
context = Bootstrap.contextMap.get("/");
}
}
/**
* 构造方法
*/
public Request(Socket socket) throws IOException {
this.socket = socket;
parseHttpRequest();
if (StrUtil.isEmpty(requestString)){
return;
}
parseUri();
parseContext();
// 比如 uri 是 /a/index.html, 获取出来的 Context路径不是 "/”, 那么要修正 uri 为 /index.html
if (!"/".equals(context.getPath())){
uri = StrUtil.removePrefix(uri, context.getPath());
}
}
private void parseHttpRequest() throws IOException {
// 解析Request,服务器端获取浏览器端传过来的请求
InputStream inputStream = this.socket.getInputStream();
byte[] bytes = MiniBrowser.readBytes(inputStream);
this.requestString = new String(bytes, StandardCharsets.UTF_8);
}
private void parseUri() {
// 解析uri,定位服务器上的文件
String temp;
/*
StrUtil.subBetween方法返回before和after之间的子串,不包含before和after
此处就是获取两个空格之间的内容,如果地址是 http://127.0.0.1:18080/index.html?name=gareen
那么http请求就会是
GET /index.html?name=gareen HTTP/1.1
Host: 127.0.0.1:18080
Connection: keep-alive
。。。。
只需要获取两个空格之间的部分就可以获得请求的uri
*/
temp = StrUtil.subBetween(requestString, " ", " ");
if (!StrUtil.contains(temp, ‘?‘)){
uri = temp;
return;
}
this.uri = StrUtil.subBefore(temp, "?", false);
}
public String getUri(){
return uri;
}
public String getRequestString() {
return requestString;
}
}
package jerrymice;
import jerrymice.catalina.Context;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.log.LogFactory;
import cn.hutool.system.SystemUtil;
import jerrymice.http.Request;
import jerrymice.http.Response;
import jerrymice.util.Constant;
import sun.awt.windows.WPrinterJob;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
/**
* @author :xiaosong
* @description:项目的启动类
* @date :2020/7/28 20:41
*/
public class Bootstrap {
/**
* 定义服务器的端口号
*/
final static int PORT = 10086;
public static Map<String, Context> contextMap = new HashMap<>();
public static void main(String[] args) {
System.out.println(SystemUtil.get("user.dir"));;
try {
// 打印jvm信息
logJvm();
LogFactory.get().info("Scanning webapps ...");
// 扫描文件夹内的所有应用
scanContextOnWebAppsFolder();
// 在port端口上新建serverSocket
ServerSocket serverSocket = new ServerSocket(PORT);
// 外部使用一个while循环,当处理完一个Socket的链接请求之后,再处理下一个链接请求
while (true) {
Socket socket = serverSocket.accept();
// 使用lambda表达式代替Runnable
Runnable runnable = () -> {
try {
// 获取输入流,这个输入流表示的是收到一个浏览器客户端的请求
Request request = new Request(socket);
System.out.println("浏览器的输入信息: \r\n" + request.getRequestString());
Response response = new Response();
// 先将html信息写入到response的Writer的StringWriter中
String uri;
uri = request.getUri();
if (uri == null) {
return;
}
Context context = request.getContext();
if ("/".equals(uri)) {
String html = "Hello JerryMice";
response.getWriter().println(html);
} else {
// removePrefix()方法可以去掉字符串指定的前缀
String fileName = StrUtil.removePrefix(uri, "/");
File file = FileUtil.file(context.getDocBase(), fileName);
if (file.exists()) {
//如果文件存在,那就去试图访问
String fileContent = FileUtil.readUtf8String(file);
// 写入到response中
response.getWriter().println(fileContent);
// 判断是否是模拟的耗时任务
if ("timeConsume.html".equals(fileName)) {
ThreadUtil.sleep(1000);
}
} else {
System.out.println("File not found!");
}
}
System.out.println(uri);
// 打开输出流,准备给客户端输出信息
handle200(socket, response);
} catch (IOException e) {
LogFactory.get().error(e);
}
};
jerrymice.util.ThreadUtil.run(runnable);
}
} catch (IOException e) {
LogFactory.get().error(e);
}
}
private static void logJvm() {
// 创建一个Map用于保存各种信息
Map<String, String> infoMap = new LinkedHashMap<>();
infoMap.put("Server version", "JerryMice 1.0.0");
infoMap.put("Server build", "2020-08-03");
infoMap.put("OS:\t", SystemUtil.get("os.name"));
infoMap.put("OS version", SystemUtil.get("os.version"));
infoMap.put("Architecture", SystemUtil.get("os.arch"));
infoMap.put("Java Home", SystemUtil.get("java.home"));
infoMap.put("JSM Version", SystemUtil.get("java.runtime.version"));
infoMap.put("JVM Vendor", SystemUtil.get("java.vm.specification.vendor"));
Set<String> keys = infoMap.keySet();
for (String key : keys) {
// 调用hutool的LogFactory工厂函数获取logger,logger会自动根据log4j.properties来对Log4j的Logger进行配置
LogFactory.get().info(key + ":\t\t" + infoMap.get(key));
}
}
/**
* @param socket:
* @param response:Response对象,服务器对浏览器请求的响应,可以通过response的getBody()获取存储在其中的html文本
* @throws IOException
*/
private static void handle200(Socket socket, Response response) throws IOException {
// 获取类型
String contentType = response.getContentType();
String headText = Constant.responseHead200;
headText = StrUtil.format(headText, contentType);
byte[] head = headText.getBytes();
// 获取response中的html文本,这个html文本是通过writer写到stringWriter字符流上的
byte[] body = response.getBody();
byte[] responseBytes = new byte[head.length + body.length];
ArrayUtil.copy(head, 0, responseBytes, 0, head.length);
ArrayUtil.copy(body, 0, responseBytes, head.length, body.length);
OutputStream outputStream = socket.getOutputStream();
outputStream.write(responseBytes);
socket.close();
}
/**
*
* 扫描webapp的根目录,将所有的文件夹(应用)做成Context对象保存在Map中
*/
private static void scanContextOnWebAppsFolder(){
File[] files = Constant.webappsFolder.listFiles();
if (files == null){
// 如果应用目录下根本没有应用,那就直接再见报告错误日志
LogFactory.get().error(new NoSuchFieldError());
return;
}
for (File file : files){
if (!file.isDirectory()) {
continue;
}
loadContext(file);
}
}
private static void loadContext(File folder) {
// 对文件夹中的文件进行解析, 获取文件夹名
String path = folder.getName();
if ("ROOT".equals(path)) {
// 如果是根目录的话
path = "/";
}
else {
path = "/" + path;
}
String docBase = folder.getAbsolutePath();
// 建立Context对象用于保存path和docBase
Context context = new Context(path, docBase);
// 将创建好的context放在Map中留待使用
contextMap.put(context.getPath(), context);
}
}
@Test
public void testContext(){
String html = getContentString("/dir1/1.html");
Assert.assertEquals(html, "this file in webapps/dir1/");
}
标签:之间 cti getpath 单元 好的 specific assert ase ann
原文地址:https://www.cnblogs.com/xsliu/p/13435732.html