接上文:實現tomcat對於靜態資源的功能;
本文增加動態功能以及對比servletapi,項目目錄大概就是這樣html主要是靜態的上篇文章說的
package cn.wcy.mytomcat2;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import cn.wcy.mytomcat2.Servlet;
public class Server2 {
//定義一個變量,存放服務端WebContent目錄的絕對路徑
public static String WEB_ROOT=System.getProperty("user.dir")+"/"+"WebContent";
//定義靜態變量,用於存放本次請求的靜態頁面名稱
private static String url = "";
//定義一個靜態類型map,存儲服務端conf.properties中的配置信息
private static Map<String,String> map = new HashMap<String,String>();
static {
Properties prop = new Properties();
try {
prop.load(new FileInputStream(WEB_ROOT+"\\conf.properties"));
Set set = prop.keySet();
Iterator iterator = set.iterator();
while(iterator.hasNext()) {
String key = (String)iterator.next();
String value = prop.getProperty(key);
map.put(key,value);
}
}catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws IOException {
//創建ServerSocket,監聽本機的80端口,等待來自客戶端的請求
ServerSocket ss = null;
Socket socket = null;
OutputStream os = null;
InputStream is = null;
try {
ss = new ServerSocket(8080);
while(true) {
//獲取到客戶端對應的socket
socket = ss.accept();
//獲取到輸入流對象
is = socket.getInputStream();
//獲取到輸出流對象
os = socket.getOutputStream();
//獲取HTTP協議的請求部分 ,截取客戶端訪問的資源名稱,將這個資源名稱賦值給url
parse(is);
//判斷一下獲取到的url是靜態資源還是動態資源
if(null!=url) {
//如果有.就是有後綴就是說知道了靜態資源名
if(url.indexOf(".")!=-1) {
//發送靜態資源
sendStaticResource(os);
}else {
sendDynamicResource(is,os);
}
}
}
}catch(Exception e) {
e.printStackTrace();
}finally {
if(null!=is) {
is.close();
is = null;
}
if(null!=os) {
os.close();
os = null;
}
if(null!=socket) {
socket.close();
socket = null;
}
}
}
//獲取HTTP協議的請求部分 ,截取客戶端訪問的資源名稱,將這個資源名稱賦值給url
private static void parse(InputStream is) throws IOException {
//定義一個變量,存放http協議請求部分數據
StringBuffer content = new StringBuffer(2048);
//定義一個數組,存放http協議請求部分數據
byte[] buffer = new byte[2048];
int i=-1;
i = is.read(buffer);
for(int j=0;j<i;j++) {
content.append((char)buffer[j]);
}
System.out.println(content);
parseUrl(content.toString());
}
private static void parseUrl(String content) {
//定義兩個變量存放請求行的兩個控制的位置
int index1,index2;
//獲取http請求部分第1個空格的位置
index1 = content.indexOf(" ");
if(index1!=-1) {
index2=content.indexOf(" ",index1+1);
//獲取http請求部分第二個空格的位置
if(index2>index1) {
//獲取字符串穿獲取到本次請求資源的名稱
url = content.substring(index1+2,index2);
}
}
}
private static void sendDynamicResource(InputStream is,OutputStream os) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException {
// TODO Auto-generated method stub
//將http協議的響應行和響應頭髮送到客戶端
os.write("HTTP/1.1 200 OK\n".getBytes());
os.write("Server:apache-Coyote/1.1\n".getBytes());
// os.write("Server:Apache\n".getBytes());
os.write("Content-type:text/html;charset=utf-8\n".getBytes());
os.write("\n".getBytes());
//判斷map中的是否存在key是和本次請求的資源路徑一直
if(map.containsKey(url)) {
//如果包含指定的key
String value = map.get(url);
//通過反射將對應的java程序加載
Class clazz = Class.forName(value);
Servlet servlet = (Servlet)clazz.newInstance();
//執行init方法
servlet.init();
//執行service方法
servlet.Service(is,os);
}
}
//發送靜態資源
private static void sendStaticResource(OutputStream os) throws IOException {
//定義一個字節數組,用於存放本次請求的靜態資源demo01.html的內容
byte[] bytes = new byte[2048];
//定義一個文件輸入流,用戶獲取靜態資源demo01.html的內容
FileInputStream is = null;
try {
//創建文件對象File,代表本次要請求的資源demo01.html
File file = new File(WEB_ROOT,url);
if(file.exists()) {
//向客戶端輸出http協議的響應頭和響應行
os.write("HTTP/1.1 200 OK\n".getBytes());
os.write("Server:apache-Coyote/1.1\n".getBytes());
os.write("Content-Type:text/html;charset=utf-8\n".getBytes());
os.write("\n".getBytes());
is = new FileInputStream(file);
int ch = is.read(bytes);
while(ch!=-1) {
os.write(bytes,0,ch);
ch = is.read(bytes);
}
}else {
os.write("HTTP/1.1 404 not found\n".getBytes());
os.write("Server:apache-Coyote/1.1\n".getBytes());
os.write("Content-Type:text/html;charset=utf-8\n".getBytes());
os.write("\n".getBytes());
String errorMessage = "404 not found";
os.write(errorMessage.getBytes());
}
}catch(Exception e) {
e.printStackTrace();
}finally {
if(null!=is) {
is.close();
is = null;
}
}
}
}
這裏的server類相比上篇文章的沒有增加多少功能,可以對比一下也就是發送動態的功能吧;接下來是一個servlet接口:
package cn.wcy.mytomcat2;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
//所有服務端的java小程序要實現的內容
public interface Servlet {
//初始化
public void init();
//裏邊可以動態寫入內容
public void Service(InputStream is,OutputStream os) throws IOException;
//銷燬方法
public void destroy();
}
然後有兩個實現類:實現類的方法就是重寫了接口的方法而已主要是在server()方法中做的動作;
package cn.wcy.mytomcat2;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import cn.wcy.mytomcat2.Servlet;
public class FirstServlet implements Servlet{
@Override
public void init() {
// TODO Auto-generated method stub
System.out.println("FirstServlet....init");
}
@Override
public void Service(InputStream is, OutputStream os) throws IOException {
// TODO Auto-generated method stub
os.write("I am form FirstServlet".getBytes());
os.flush();
}
@Override
public void destroy() {
// jdk的servlet接口也是有這個方法的,並且實現類註釋已經寫明瞭說什麼也不做
}
}
secondServlet所做的事情跟first類似不再贅述;然後是conf.properties
aa=cn.wcy.mytomcat2.FirstServlet
bb=cn.wcy.mytomcat2.SecondServlet
就是用來提供全限定類名的;
整個邏輯也就是通過ServerSocket拿到訪問的客戶端的Socket,然後在拿到OutputStream流之後手動寫入響應頭和響應體,剩下的就交給瀏覽器自己解析就可以了當然我們也可以用web.xml來配置映射關係,但是需要用到xml解析技術我們這裏重點不在這不贅述了;
接下來我們來給apache-tomcat做一下對比用我們這次所定義的類:
- servlet是java中定義的一個接口,我們寫jsp的controller實現的是HttpServlet類,這個類裏邊有doget和dopost方法,裏邊也包含了對inputstream的解析,不過是以request的形式,重寫的那兩個方法是protect類型的;
- HttpServlet類是繼承了靜態類GenericServlet,這個類實現了Servlet和ServletConfig兩個接口當然還有這個java.io.Serializable,不過這個接口裏邊方法也是空方法,也就是起了一個標誌性的作用(標誌可序列化)
Java API中java.io.Serializable接口源碼: public interface Serializable {
}
- 類通過實現java.io.Serializable接口可以啓用其序列化功能。未實現次接口的類無法使其任何狀態序列化或反序列化。可序列化類的所有子類型本身都是可序列化的。序列化接口沒有方法或字段,僅用於標識可序列化的語義。
- ServletConfig中的方法:
- getInitParameter(): 獲取指定名稱的初始化參數值。
- getInitParameterNames():獲取當前 Servlet 所有的初始化參數名稱。其返回值爲枚舉類型 Enumeration。
- getServletName():獲取當前 Servlet 的中指定的 Servlet名稱。
- getServletContext():獲取到當前 Servlet 的上下文對象 ServletContext。
– ServletConfig接口的特點
每一個servlet都對應一個ServletConfig用於封裝各自的配置信息,即有幾個servlet就會產生幾個ServletConfig對象。
上一篇文章:實現tomcat的靜態資源功能;