HttpServer服務類
1 package javax.servlet.http.server2; 2 3 import java.io.IOException; 4 import java.net.InetSocketAddress; 5 import java.nio.channels.SelectionKey; 6 import java.nio.channels.Selector; 7 import java.nio.channels.ServerSocketChannel; 8 import java.util.Iterator; 9 10 public class HttpServer { 11 private int DEFULT_PORT=8080; //默認端口 12 private boolean isShudown=true; //服務狀態 13 private ServerSocketChannel ssc; 14 public HttpServer(){ 15 try{ 16 start(DEFULT_PORT); 17 } catch (IOException e){ 18 e.printStackTrace(); 19 } 20 } 21 22 public HttpServer(int port){ 23 try{ 24 start(port); 25 } catch (IOException e){ 26 e.printStackTrace(); 27 } 28 } 29 public void start(int port) throws IOException{ 30 ssc=ServerSocketChannel.open(); // 打開服務器套接字通道 31 ssc.socket().bind(new InetSocketAddress(port)); //綁定到特定端口 32 ssc.configureBlocking(false); //設置為非阻塞模式 33 Selector selector=Selector.open(); //打開一個選擇器 34 ssc.register(selector, SelectionKey.OP_ACCEPT); //向給定的選擇器注冊此通道,返回一個選擇鍵 35 while(isShudown){ 36 /*if(selector.select(3000)==0){ //沒有請求阻塞3秒,繼續執行 37 continue; 38 }*/ 39 if(selector.select()>0){ //等待請求,請求過來繼續執行,沒有請求一直等待 40 Iterator<SelectionKey> keyIter=selector.selectedKeys().iterator(); //獲取等待處理的請求 41 while (keyIter.hasNext()){ 42 SelectionKey key=keyIter.next(); 43 new Thread(new HttpHandler(key)).run(); // 啟動新線程處理SelectionKey 44 keyIter.remove(); // 處理完后,從待處理的SelectionKey迭代器中移除當前所使用的key 45 } 46 } 47 48 } 49 } 50 51 /** 52 * 關閉端口 53 * @throws IOException 54 */ 55 public void stop() throws IOException{ 56 isShudown=false; 57 //ssc.socket().close(); 58 } 59 60 /** 61 * 打開服務的主入口 62 * @param args 63 * @throws Exception 64 */ 65 public static void main(String[] args) throws Exception{ 66 67 new HttpServer(2222); 68 } 69 70 71 }
HttpHandler請求處理類
1 package javax.servlet.http.server2; 2 3 import java.io.IOException; 4 import java.io.PrintWriter; 5 import java.io.StringWriter; 6 import java.nio.ByteBuffer; 7 import java.nio.channels.SelectionKey; 8 import java.nio.channels.ServerSocketChannel; 9 import java.nio.channels.SocketChannel; 10 11 public class HttpHandler implements Runnable{ 12 private int bufferSize = 1024; 13 private SelectionKey key; 14 private int CODE=200; 15 public HttpHandler(SelectionKey key){ 16 this.key = key; 17 } 18 19 /** 20 * 接收連接處理 21 * @throws IOException 22 */ 23 public void handleAccept() throws IOException { 24 SocketChannel clientChannel=((ServerSocketChannel)key.channel()).accept(); 25 clientChannel.configureBlocking(false); //線程不阻塞 26 clientChannel.register(key.selector(), SelectionKey.OP_READ|SelectionKey.OP_WRITE, ByteBuffer.allocate(bufferSize)); //注冊讀寫 27 28 } 29 @Override 30 public void run() 31 { 32 // 接收到連接請求時 33 if (key.isAcceptable()) 34 { 35 try 36 { 37 handleAccept(); 38 } catch (IOException e) 39 { 40 e.printStackTrace(); 41 } 42 43 } 44 45 if (key.isReadable()&&key.isWritable()) //可讀可寫 46 { 47 try 48 { 49 HttpServletRequest ser=new HttpServletRequest(key); //封裝Request 50 HttpServletResponse serr=new HttpServletResponse(key); //封裝Response 51 HttpServlet servlet=WebApp.getServlet(ser.getUrl()); //通過映射地址獲取具體的servlet 52 if(servlet==null){ 53 this.CODE=404; 54 }else{ 55 try 56 { 57 servlet.service(ser, serr); 58 } catch (Exception e) 59 { 60 e.printStackTrace(); 61 this.CODE=500; 62 StringWriter sw = new StringWriter(); 63 PrintWriter pw = new PrintWriter(sw, true); 64 pw.flush(); 65 sw.flush(); 66 serr.println(sw.toString()); 67 } 68 } 69 serr.pushToClient(CODE); 70 ser.close(); 71 serr.close(); 72 } catch (IOException e) 73 { 74 e.printStackTrace(); 75 } 76 77 } 78 79 80 } 81 }
HttpServlet基類
1 package javax.servlet.http.server2; 2 3 public abstract class HttpServlet { 4 public void service(HttpServletRequest req,HttpServletResponse rep) throws Exception{ 5 this.doGet(req,rep); 6 } 7 8 protected abstract void doGet(HttpServletRequest req,HttpServletResponse rep) throws Exception; 9 protected abstract void doPost(HttpServletRequest req,HttpServletResponse rep) throws Exception; 10 }
HttpServletRequest請求封裝類
1 package javax.servlet.http.server2; 2 3 import java.io.IOException; 4 import java.nio.ByteBuffer; 5 import java.nio.channels.SelectionKey; 6 import java.nio.channels.SocketChannel; 7 import java.nio.charset.Charset; 8 import java.util.ArrayList; 9 import java.util.Arrays; 10 import java.util.HashMap; 11 import java.util.List; 12 import java.util.Map; 13 import java.util.StringTokenizer; 14 15 public class HttpServletRequest 16 { 17 private final String DEFULT_CODE="UTF-8"; 18 private final String CRLF="\r\n"; //回車換行 19 private final String SPACE=" "; 20 private SocketChannel sc; 21 private ByteBuffer buffer; 22 private String requestInfo; 23 private String method; 24 private String url; 25 private Map<String,List<String>> parameterMapValues; 26 27 public HttpServletRequest(){ 28 parameterMapValues=new HashMap<String,List<String>>(); 29 } 30 public HttpServletRequest(SelectionKey key) throws IOException{ 31 this(); 32 sc=(SocketChannel)key.channel(); 33 buffer=(ByteBuffer)key.attachment(); 34 buffer.clear(); 35 if(sc.read(buffer)==-1){ 36 sc.close(); 37 }else{ 38 buffer.flip(); 39 requestInfo=Charset.forName(DEFULT_CODE).newDecoder().decode(buffer).toString(); 40 } 41 parseRequestInfo(); 42 } 43 44 /** 45 * 分析請求,主要是獲取資源地址、封裝專遞的參數 46 */ 47 private void parseRequestInfo(){ 48 String paramInfo = null; 49 if(requestInfo==null||"".equals(requestInfo)){ 50 return ; 51 } 52 String[] requestMessage = requestInfo.split(CRLF); //得到請求的消息 53 String[] firstLine = requestMessage[0].split(SPACE); //獲取首行頭文件 54 this.method=firstLine[0]; //獲取提交方式 55 String tempUrl=firstLine[1]; //獲取資源地址 56 if(method.equals(RequestType.POST.toString())){ 57 this.url=tempUrl; 58 paramInfo=requestMessage[requestMessage.length-1]; 59 }else if(method.equals(RequestType.GET.toString())){ 60 if(tempUrl.contains("?")){ //如果有參數 61 String params[]=tempUrl.split("\\?"); 62 this.url=params[0]; 63 paramInfo=params[1];//接收請求參數 64 }else 65 this.url=tempUrl; 66 } 67 68 if(paramInfo==null||"".equals(paramInfo)){ 69 return ; 70 }else 71 parseParams(paramInfo); 72 } 73 74 /** 75 * 保存傳遞的參數 76 * @param paramInfo 77 */ 78 private void parseParams(String paramInfo){ 79 StringTokenizer token=new StringTokenizer(paramInfo,"&"); 80 while(token.hasMoreTokens()){ 81 String keyValue =token.nextToken(); 82 String[] keyValues=keyValue.split("="); 83 if(keyValues.length==1){ 84 keyValues =Arrays.copyOf(keyValues, 2); 85 keyValues[1] =null; 86 } 87 88 String key = keyValues[0].trim(); 89 String value = null==keyValues[1]?null:keyValues[1].trim(); 90 //轉換成Map 分揀 91 if(!parameterMapValues.containsKey(key)){ 92 parameterMapValues.put(key,new ArrayList<String>()); 93 } 94 95 List<String> values =parameterMapValues.get(key); 96 values.add(value); 97 } 98 } 99 100 /** 101 * 根據頁面的name 獲取對應的多個值 102 * @param name 名 103 */ 104 public String[] getParameterValues(String name){ 105 List<String> values=null; 106 if((values=parameterMapValues.get(name))==null){ 107 return null; 108 }else{ 109 return values.toArray(new String[]{}); 110 } 111 } 112 113 /** 114 * 返回單個值 115 * @param name 名 116 * @return 117 */ 118 public String getParameter(String name){ 119 String[] values =getParameterValues(name); 120 if(null==values){ 121 return null; 122 } 123 return values[0]; 124 } 125 126 /** 127 * 獲取請求方法 128 * @return 129 */ 130 public String getMethod() 131 { 132 return method; 133 } 134 135 /** 136 * 獲取url資源訪問地址 137 * @return 138 */ 139 public String getUrl() 140 { 141 return url; 142 } 143 /** 144 * 關閉連接 145 */ 146 void close() 147 { 148 try 149 { 150 if (sc.isOpen()) 151 { 152 sc.close(); 153 } 154 } catch (IOException e) 155 { 156 e.printStackTrace(); 157 } 158 } 159 }
HttpServletResponse響應封裝類
1 package javax.servlet.http.server2; 2 3 import java.io.IOException; 4 import java.nio.ByteBuffer; 5 import java.nio.channels.SelectionKey; 6 import java.nio.channels.SocketChannel; 7 import java.util.Date; 8 public class HttpServletResponse 9 { 10 11 //兩個常量 12 public static final String CRLF="\r\n"; 13 public static final String BLANK=" "; 14 private static final String localCharset="UTF-8"; 15 //正文 16 private StringBuilder content; 17 //存儲頭信息 18 private StringBuilder headInfo; 19 //存儲正文長度 20 private int len =0; 21 private StringBuilder bu; 22 private ByteBuffer buffer; 23 private SocketChannel sc; 24 public HttpServletResponse(){ 25 bu=new StringBuilder(); 26 headInfo =new StringBuilder(); 27 content =new StringBuilder(); 28 len =0; 29 } 30 public HttpServletResponse(SelectionKey key){ 31 this(); 32 sc=(SocketChannel)key.channel(); 33 buffer=(ByteBuffer)key.attachment(); 34 buffer.clear(); 35 buffer.flip(); 36 } 37 38 /** 39 * 構建正文 40 */ 41 public HttpServletResponse print(String info){ 42 content.append(info); 43 len+=info.getBytes().length; 44 return this; 45 } 46 47 /** 48 * 構建正文+回車 49 */ 50 public HttpServletResponse println(String info){ 51 content.append(info).append(CRLF); 52 len+=(info+CRLF).getBytes().length; 53 return this; 54 } 55 56 /** 57 * 構建響應頭 58 */ 59 private void createHeadInfo(int code){ 60 //1) HTTP協議版本、狀態代碼、描述 61 headInfo.append("HTTP/1.1").append(BLANK).append(code).append(BLANK); 62 switch(code){ 63 case 200: 64 headInfo.append("OK"); 65 break; 66 case 404: 67 headInfo.append("NOT FOUND"); 68 break; 69 case 505: 70 headInfo.append("SEVER ERROR"); 71 break; 72 } 73 headInfo.append(CRLF); 74 //2) 響應頭(Response Head) 75 headInfo.append("Server:bjsxt Server/0.0.1").append(CRLF); 76 headInfo.append("Date:").append(new Date()).append(CRLF); 77 headInfo.append("Content-type:text/html;charset="+localCharset).append(CRLF); 78 //正文長度 :字節長度 79 headInfo.append("Content-Length:").append(len).append(CRLF); 80 headInfo.append(CRLF); //分隔符 81 } 82 83 //推送到客戶端 84 void pushToClient(int code) throws IOException{ 85 if(null==headInfo){ 86 code =500; 87 } 88 createHeadInfo(code); 89 //頭信息+分割符 90 bu.append(headInfo.toString()); 91 92 //正文 93 bu.append(content.toString()); 94 buffer = ByteBuffer.wrap(bu.toString().getBytes(localCharset)); 95 if(sc.isOpen()) 96 sc.write(buffer); 97 98 } 99 100 /** 101 * 關閉 102 */ 103 void close(){ 104 try 105 { 106 if(sc.isOpen()){ 107 sc.close(); 108 } 109 110 } catch (IOException e) 111 { 112 e.printStackTrace(); 113 } 114 } 115 }
RequestType請求類型
1 package javax.servlet.http.server2; 2 3 public enum RequestType 4 { 5 POST //post請求 6 ,GET //get請求 7 8 }
ServletContext 容器
1 package javax.servlet.http.server2; 2 3 import java.util.HashMap; 4 import java.util.Map; 5 6 7 public class ServletContext 8 { 9 10 private Map<String,String>servlet; 11 public ServletContext(){ 12 servlet=new HashMap<String,String>(); 13 } 14 15 /** 16 * 獲取servlet容器 17 * @return 18 */ 19 public Map<String, String> getServlet() 20 { 21 return servlet; 22 } 23 24 }
WebApp功能映射處理
1 package javax.servlet.http.server2; 2 3 import java.util.Iterator; 4 import java.util.Map; 5 import javax.servlet.annotation.WebServlet; 6 import javax.servlet.util.PackageScanUtils; 7 8 public class WebApp 9 { 10 11 private static ServletContext context; 12 static{ 13 context=new ServletContext(); 14 Map<String,String>servlet=context.getServlet(); 15 Iterator<Class<?>>clas=PackageScanUtils.getClasses("javax.servlet.http.server2",true).iterator(); 16 while(clas.hasNext()){ 17 Class<?>cla=clas.next(); 18 WebServlet ws=cla.getAnnotation(WebServlet.class); 19 if(ws!=null){ 20 servlet.put(ws.value(), cla.getName()); 21 } 22 } 23 } 24 25 /** 26 * 獲取url地址 27 * @param url 28 * @return 29 */ 30 public static HttpServlet getServlet(String url) 31 { 32 Map<String,String>temp=context.getServlet(); 33 if(temp.containsKey(url)){ 34 try 35 { 36 return (HttpServlet)Class.forName(temp.get(url)).newInstance(); 37 } catch (InstantiationException e) 38 { 39 e.printStackTrace(); 40 } catch (IllegalAccessException e) 41 { 42 e.printStackTrace(); 43 } catch (ClassNotFoundException e) 44 { 45 e.printStackTrace(); 46 } 47 } 48 return null; 49 } 50 }
Message 狀態
1 package javax.servlet.cod; 2 3 public class Message 4 { 5 6 public static String message404(){ 7 StringBuilder conetxt=new StringBuilder(); 8 conetxt.append("<html><head><title>lishenglin - Error report</title><style><!--H1"); 9 conetxt.append("{font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:22px;} H2"); 10 conetxt.append("{font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:16px;} H3"); 11 conetxt.append("{font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:14px;} BODY"); 12 conetxt.append("{font-family:Tahoma,Arial,sans-serif;color:black;background-color:white;} B"); 13 conetxt.append("{font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;} P"); 14 conetxt.append("{font-family:Tahoma,Arial,sans-serif;background:white;color:black;font-size:12px;}A {color : black;}A.name {color : black;}HR"); 15 conetxt.append("{color : #525D76;}--></style> </head><body><h1>HTTP Status 404 - </h1><HR size=\"1\" noshade=\"noshade\"><p><b>type</b> Status"); 16 conetxt.append("report</p><p><b>message</b> <u></u></p><p><b>description</b> <u>The requested resource is not available.</u></p><HR size=\"1\""); 17 conetxt.append("noshade=\"noshade\"><h3>lishenglin</h3></body></html>"); 18 return conetxt.toString(); 19 20 } 21 22 }
PackageScanUtils 掃描class
1 package javax.servlet.util; 2 3 import java.io.File; 4 import java.io.FileFilter; 5 import java.io.FileNotFoundException; 6 import java.io.IOException; 7 import java.net.URL; 8 import java.net.URLDecoder; 9 import java.util.Enumeration; 10 import java.util.Iterator; 11 import java.util.LinkedHashSet; 12 import java.util.Set; 13 14 public class PackageScanUtils 15 { 16 17 /** 18 * 獲取class集合 19 * @param packName 包名 20 * @param scanSubdirectory 掃描子目錄 21 * @return 22 */ 23 public static Set<Class<?>> getClasses(String packName,boolean scanSubdirectory) 24 { 25 26 Set<Class<?>> classes = new LinkedHashSet<Class<?>>(); // 裝載class集合 27 String packageName = packName; // 獲取包的名字 並進行替換 28 String packageUrlName = packageName.replace('.', '/'); 29 Enumeration<URL> urls; // 定義一個枚舉的集合 並進行循環來處理這個目錄下的class 30 try 31 { 32 urls = Thread.currentThread().getContextClassLoader().getResources(packageUrlName); 33 34 // 循環迭代下去 35 while (urls.hasMoreElements()) 36 { 37 38 URL url = urls.nextElement(); // 獲取下一個元素 39 40 String protocol = url.getProtocol(); // 得到協議的名稱,比如http、file 41 42 if ("file".equals(protocol)) 43 { // 如果是以文件的形式保存在服務器上 44 45 String filePath = URLDecoder.decode(url.getFile(), "UTF-8"); // 獲取包的物理路徑 46 // 以文件的方式掃描整個包下的文件 並添加到集合中 47 findClassesInPackageByFile(packageName, filePath, scanSubdirectory, classes); 48 } 49 } 50 } catch (IOException e) 51 { 52 e.printStackTrace(); 53 } 54 55 return classes; 56 } 57 58 /** 59 * 以文件的方式掃描整個包下的文件 並添加到集合中 60 * @param packageName 包名 61 * @param packagePath 包路徑 62 * @param scanSubdirectory 是否掃描子目錄 63 * @param classes class集合 64 * @throws FileNotFoundException 65 */ 66 public static void findClassesInPackageByFile(String packageName, String packagePath, final boolean scanSubdirectory, Set<Class<?>> classes) throws FileNotFoundException 67 { 68 69 File dir = new File(packagePath); // 獲取此包的目錄 建立一個File 70 File[] dirfiles = dir.listFiles(new FileFilter() 71 { // 如果存在 就獲取包下的所有文件 包括目錄 72 73 public boolean accept(File file) 74 { // 自定義過濾規則 如果可以循環(包含子目錄) 或則是以.class結尾的文件(編譯好的java類文件) 75 return (scanSubdirectory && file.isDirectory()) || (file.getName().endsWith(".class")); 76 } 77 }); 78 79 for (File file : dirfiles) 80 { // 循環所有文件 81 82 if (file.isDirectory()) 83 { // 如果是目錄 則繼續掃描 84 findClassesInPackageByFile(packageName==""? file.getName():packageName + "." + file.getName(), file.getAbsolutePath(), scanSubdirectory, classes); 85 } else 86 { // 如果是java類文件 去掉后面的.class 只留下類名 87 88 String className = file.getName().substring(0, file.getName().length() - 6); 89 try 90 { 91 if("".equals(packageName)){ 92 classes.add(Thread.currentThread().getContextClassLoader().loadClass(className)); 93 }else{ 94 classes.add(Thread.currentThread().getContextClassLoader().loadClass(packageName + '.' + className)); 95 } 96 } catch (ClassNotFoundException e) 97 { 98 e.printStackTrace(); 99 } 100 } 101 } 102 } 103 104 public static void main(String[] args) 105 { 106 Set<Class<?>> clas=PackageScanUtils.getClasses("cn.javax",true); 107 Iterator<Class<?>>cla=clas.iterator(); 108 while(cla.hasNext()){ 109 /*Annotation[]ann=cla.next().getAnnotations(); 110 for(Annotation a:ann){ 111 if(a instanceof WebServlet){ 112 System.out.println(((WebServlet) a).value()); 113 } 114 }*/ 115 System.out.println(cla.next().getName()); 116 } 117 } 118 }
MyServlet 測試servlet
1 package javax.servlet.http.server2; 2 3 import javax.servlet.annotation.WebServlet; 4 5 @WebServlet("/myservlet") 6 public class Myservlet extends HttpServlet 7 { 8 9 10 @Override 11 protected void doGet(HttpServletRequest req, HttpServletResponse rep) throws Exception 12 { 13 this.doPost(req, rep); 14 15 } 16 17 @Override 18 protected void doPost(HttpServletRequest req, HttpServletResponse rep) throws Exception 19 { 20 String name=req.getParameter("name"); 21 rep.println("獲取的參數name="+name); 22 rep.println("請求的url是:"+req.getUrl()); 23 24 } 25 }
WebServlet簡單注解
1 package javax.servlet.annotation; 2 3 import java.lang.annotation.ElementType; 4 import java.lang.annotation.Retention; 5 import java.lang.annotation.RetentionPolicy; 6 import java.lang.annotation.Target; 7 8 @Target(ElementType.TYPE) 9 @Retention(RetentionPolicy.RUNTIME) 10 /** 11 * webServlet注解 12 * @author 李聖霖 13 * @date 2017年3月28日 14 */ 15 public abstract @interface WebServlet 16 { 17 public abstract java.lang.String value() default ""; //映射地址 18 }
測試