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 }
测试