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 IteratorkeyIter=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> parameterMapValues; 26 27 public HttpServletRequest(){ 28 parameterMapValues=new HashMap >(); 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 ()); 93 } 94 95 List 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 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 Mapservlet; 11 public ServletContext(){ 12 servlet=new HashMap (); 13 } 14 15 /** 16 * 获取servlet容器 17 * @return 18 */ 19 public Map 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 Mapservlet=context.getServlet(); 15 Iterator >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 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("lishenglin - Error report HTTP Status 404 -
type Status"); 16 conetxt.append("report
message
description The requested resource is not available.
); 17 conetxt.append("noshade=\"noshade\">lishenglin
"); 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> getClasses(String packName,boolean scanSubdirectory) 24 { 25 26 Set > classes = new LinkedHashSet >(); // 装载class集合 27 String packageName = packName; // 获取包的名字 并进行替换 28 String packageUrlName = packageName.replace('.', '/'); 29 Enumeration 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 > 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 > clas=PackageScanUtils.getClasses("cn.javax",true); 107 Iterator >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 }
测试