对HttpServer进行再封装,实现一个自己的服务器

服务器基本功能实现,实现一套接口

1.注解(此注解作用类似于spring中的RequestMapper)

package com.zj;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.TYPE , ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface RequestMapper {
	String path() default "" ;
}

2.服务器需要的接口
1)HttpServlet

package com.inter;

public interface HttpServlet {
	void service(HttpServletRequest request , HttpServletResponse response) throws Exception ;
}

2)HttpServletRequest

package com.inter;

import java.util.Map;


public interface HttpServletRequest {
	/**
	 * 获取请求参数
	 * @param key 请求参数
	 * @return 请求参数的值
	 */
	String getParameter(String key) ;
	/**
	 * 设置请求编码
	 * @param charset 编码类型
	 */
	void setCharacter(String charset) ;
	/**
	 * 获取请求头参数
	 * @param key
	 * @return
	 */
	String getHeadField(String key) ;
	/**
	 * 获取请求ip
	 */
	String getRequestIP() ;
	
	/**
	 * 获取所有请求参数
	 * @return
	 */
	Map getParameters() ;
}

3)HttpServletResponse

package com.inter;

import java.io.OutputStream;
import java.io.PrintStream;
import java.io.UnsupportedEncodingException;

public interface HttpServletResponse {
	/**
	 * 设置返回前端编码
	 **/
	void setCharactor(String charset) ;
	/**
	 * 获取浏览器io对象
	 * @return
	 */
	OutputStream getOutputStream() ;
	/**
	 * 获取字符流对象
	 * @throws UnsupportedEncodingException 
	 */
	PrintStream getWriter() throws UnsupportedEncodingException ;
	/**
	 * 设置返回数据类型
	 * @throws Exception 
	 */
	void setContentTyoe(String type) throws Exception ;
	/**
	 * 设置重定向地址
	 * @param url
	 */
	void sendRedirect(String url) ;
}

这套接口是模仿javaweb的

3.接口实现
1)Request

package com.server;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpCookie;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.Map;

import org.jboss.com.sun.net.httpserver.Headers;
import org.jboss.com.sun.net.httpserver.HttpExchange;

import com.inter.HttpServletRequest;

/**
 * 采用适配器原理将exange对象拆分成Request和Response两个对象
 * @author wf
 *
 */
public class Request implements HttpServletRequest {
	//定义一个Exange对象
	private HttpExchange exchange ;
	
	/**
	 * 保存字符串编码
	 */
	private String charset = "utf-8" ;
	
	/**
	 * 请求参数保存
	 */
	private Map query = null ;
	
	/**
	 * 参数部分字符串
	 */
	private String paramesString = "" ;
	
	/**
	 * 保存当前访问对象的cookie
	 */
	private HttpCookie cookie ;
	
	/**
	 * 构造方法
	 * @param exchange 每次请求的exange对象
	 */
	public Request(HttpExchange exchange){
		this.exchange = exchange ;
	}

	public String getParameter(String key) {
		if(query == null){
			query = queryFormat() ;
		}
		return query.get(key);
	}
	
	public Map getParameters() {
		if(query == null){
			query = queryFormat() ;
		}
		return query;
	}

	public void setCharacter(String charset) {
		this.charset = charset ;
		query = null ;
		queryFormat() ;
	}

	public String getHeadField(String key) {
		Headers header = exchange.getRequestHeaders() ;
		return (header.get(key) != null ? header.get(key).toString() : null); 
	}
	

	public String getRequestIP() {
		return exchange.getRemoteAddress().getHostName();
	}
	
	/**
	 * 请求参数拆分
	 */
	private Map queryFormat(){
		if(paramesString == null || "".equals(paramesString)){
			paramesString = queryGet() ;
		}
        return getQuerys() ;
	}
	
	/**
	 * 请求参数拆分
	 */
	private String queryGet(){
		//获取请求的地址
		String urlString = exchange.getRequestURI().toString() ;
		
		//拿到输出流对象
		OutputStream out = null ;
		
		BufferedReader read = new BufferedReader(new InputStreamReader(exchange.getRequestBody())) ;
        String line = "" ;
        urlString = urlString.contains("?") ? urlString+"&" : urlString + "?" ;
        
        //读取POst请求参数
        try{
        	while((line = read.readLine()) != null){
            	urlString += line ;
            }
        }catch(Exception e){
        	System.out.println(e);
			int len = e.toString().getBytes().length ;
			exchange.getResponseHeaders().add("Content-Type", "text/html;charset=utf-8");
			try {
				exchange.sendResponseHeaders(500, len);
				out = exchange.getResponseBody() ;
				out.write(e.toString().getBytes());
			} catch (Exception e2) {
				System.out.println(e);
			} finally{
				if(out != null){
					try {
						out.close();
					} catch (IOException e1) {
						// TODO Auto-generated catch block
						e1.printStackTrace();
					}
				}
			}
        }finally{
        	if(read != null){
        		try {
					read.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
        	}
        }
        
        //拆分参数部分字符串
        String parames = "";
        if (urlString.contains("?")) {
        	String[] strs = urlString.split("\\?");
            if(strs.length > 1){
            	parames = strs[1];
            }
        }
        return parames ;
	}
	
	/**
	 * 请求参数拆分
	 * @param parames
	 * @return
	 */
	private Map getQuerys() {
		Map map = new HashMap() ;
        if (!paramesString.equals("")) {
            String[] strs = null ;
            if(!paramesString.contains("&")){
                strs = new String[]{paramesString};
            }else{
                strs = paramesString.split("&");
            }
            for (String string : strs) {
                if (string.contains("=")) {
                	String[] strs1 = string.split("=") ;
                    if(strs1.length > 1){
                    	String k = strs1[0];
                        String v = strs1[1];
                        try {
                        	v = URLDecoder.decode(v, charset) ;
							map.put(k, v);
						} catch (UnsupportedEncodingException e) {
							map.put(k, v);
						}
                    }
                }
            }
        }
        return map;
	}
}

2)Response

package com.server;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpCookie;
import java.util.Map;
import java.util.Set;

import org.jboss.com.sun.net.httpserver.Headers;
import org.jboss.com.sun.net.httpserver.HttpExchange;

import com.inter.HttpServletResponse;

public class Response implements HttpServletResponse {
	//保存浏览器访问对象
	private HttpExchange exchange ;
	
	/**
	 * 保存返回前端编码
	 */
	
	private String charset = "utf-8" ; 
	
	/**
	 * 定义缓冲区大小
	 */
	
	private final int SIZE = 1024*1024 ;
	
	/**
	 * 定义一个缓冲区(采用静态代理)
	 */
	private MyByteArrayOutputStream byteBuf = new MyByteArrayOutputStream(SIZE) ;
	
	/**
	 * 请求头是否已经返回
	 */
	
	private boolean isSendHead = false ;
	
	/**
	 * 返回头
	 */
	
	private Headers header ;
	
	/**
	 * 重定向地址
	 */
	
	private String reUrl = null ;
	
	/**
	 * @param exchange
	 */
	public Response(HttpExchange exchange) {
		this.exchange = exchange ;
		//初始化headers对象
		header = exchange.getResponseHeaders() ;
		//默认以text/html返回
		header.add("Content-Type", "text/html");
	}
	
	public void setCharactor(String charset) {
		this.charset = charset ;
	}

	public OutputStream getOutputStream() {
		return byteBuf ;
	}

	public PrintStream getWriter() throws UnsupportedEncodingException {
		return new PrintStream(byteBuf , true , charset);
	}

	public void setContentTyoe(String type) throws Exception {
		if(isSendHead){
			throw new Exception("header already send !!!") ;
		}
		if(header.containsKey("Content-Type")){
			header.set("Content-Type", type);
			return ;
		}
		header.add("Content-Type", type);
	}

	public void sendRedirect(String url) {
		reUrl = url ;
	}
	
	public String getReUrl(){
		return reUrl ;
	}
	
	/**
	 * 以下方法全部设置为私有方法供反射调用
	 */
	private synchronized void flush(){
		try {
			if(!isSendHead){
				exchange.sendResponseHeaders(200 , 0);
				isSendHead = true ;
			}
			exchange.getResponseBody().write(byteBuf.toByteArray());
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	private String cookieFormat(Map map){
		Set set = map.keySet() ;
		StringBuffer buf = new StringBuffer() ;
		for (String s : set) {
			buf.append(s+"="+map.get(s)+";") ;
		}
		return buf.replace(buf.length()-1, buf.length(), "").toString() ;
	}
	
	/**
	 * 直接返回
	 */
	protected synchronized void response(int code , String data){
		try {
			if(!isSendHead){
				Headers head = exchange.getResponseHeaders();
				head.add("Content-Type", "text/html;charset="+charset);
				exchange.sendResponseHeaders(code, data.getBytes(charset).length);
				isSendHead = true ;
			}
			exchange.getResponseBody().write(data.getBytes(charset));
		} catch (IOException e) {
			e.printStackTrace();
		} 
	}
	
	/**
	 * 定义一个自己的字节流对象
	 * @author Administrator
	 *
	 */
	class MyByteArrayOutputStream extends ByteArrayOutputStream {
		public MyByteArrayOutputStream(int size){
			super(size) ;
		}
		
		@Override
		public void write(byte[] b) throws IOException {
			if(this.size() + 1 >= SIZE){
				if(!isSendHead){
					exchange.sendResponseHeaders(202, 0);
					isSendHead = true ;
				}
				exchange.getResponseBody().write(byteBuf.toByteArray());
				this.reset();
			}
			super.write(b);
		}
		
		@Override
		public synchronized void write(byte[] b, int off, int len) {
			if(this.size() + len >= SIZE){
				try {
					if(!isSendHead){
						exchange.sendResponseHeaders(202, 0);
						isSendHead = true ;
					}
					exchange.getResponseBody().write(byteBuf.toByteArray());
					this.reset();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			super.write(b, off, len);
		}
		
		@Override
		public synchronized void write(int b) {
			if(this.size() + 1 >= SIZE){
				try {
					if(!isSendHead){
						exchange.sendResponseHeaders(202, 0);
						isSendHead = true ;
					}
					exchange.getResponseBody().write(byteBuf.toByteArray());
					this.reset();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			super.write(b);
		}
	}
}

4.Server类的初始化

package com.server;

/******************************************************************************
 *                           对jdk的HttpServer再封装                                               *
 *                           实现一套注解(后端路由表&监听器注册)                         *
 *                           模仿javaweb的回话跟踪(Session)                                *
 *                           此项目的是练习java的设计模式                                        *
 *                           使用到了(单例,适配器,观察者,代理)                       *
 ******************************************************************************/

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.net.InetSocketAddress;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import org.jboss.com.sun.net.httpserver.HttpExchange;
import org.jboss.com.sun.net.httpserver.HttpHandler;
import org.jboss.com.sun.net.httpserver.HttpServer;

import com.inter.HttpServletRequest;
import com.inter.HttpServletResponse;
import com.zj.RequestMapper;

/**
 * 对jdk自带的HttpServer类进行二次封装
 * @author wf
 */
public class Server {
	/**
	 * 绑定端口
	 */
	private int port = 9999 ;
	/**
	 * servlet所在包名
	 */
	private String servlet = "com.servlet" ;
	/**
	 * 保存访问地址的映射
	 */
	private Map urls = new HashMap() ;
	/**
	 * 保存方法的映射
	 */
	private Map> murls = new HashMap>() ;
	/**
	 * 404页面内容
	 */
	private final String S_404 = "

404找不到页面

" ; /** * 构造方法 * @param port 绑定端口 * @param servlet servlet所在包名 */ public Server(int port , String servlet){ this.port = port ; this.servlet = servlet ; } /** * 服务器初始化 * @throws Exception */ public HttpServer init() throws Exception{ //创建HttpServer服务器 HttpServer server = HttpServer.create(new InetSocketAddress(port), 0) ; //给注解类加上 regist(server) ; //启动服务器 server.start(); return server ; } /** * 注册实现 * @param server 服务器对象 * @throws Exception */ public void regist(HttpServer server) throws Exception{ //遍历servlet包将注解中的类加入Map集合 String packageName = servlet.replaceAll("\\.", "/") ; packageName = Thread.currentThread().getContextClassLoader().getResource(packageName) != null ? Thread.currentThread().getContextClassLoader().getResource(packageName).getFile() : null ; //扫描包中的类 if(packageName != null){ File[] files = new File(packageName).listFiles() ; for (File f : files) { String className = f.getName().replace(".class", "") ; Class c = Class.forName(servlet+"."+className) ; doRegist(c); } } //创建一个核心处理器 server.createContext("/", new HttpHandler() { //读文件的io对象 public FileInputStream in = null ; //写的io对象 public OutputStream out = null ; //处理器代码 @SuppressWarnings("unused") //此注解可以忽略编译器警告 public void handle(HttpExchange exchange) throws IOException { //对访问地址进行拆分 String urlString = exchange.getRequestURI().toString(); String url = urlString.contains("?") ? urlString.split("\\?" , 2)[0] : urlString ; //实例化请求对象 Request request = new Request(exchange) ; Response response = new Response(exchange) ; //向Servlet发起请求 if(urls.get(url) != null){ try { String method = request.getParameter("method") ; if(method != null && murls.get(urls.get(url)) != null && murls.get(urls.get(url)).get(method) != null){ // System.err.println("time:"+new Date().toLocaleString()+" IP:"+request.getRequestIP()+" path:"+url+" params:"+paramepFormat(request)); murls.get(urls.get(url)).get(method).invoke(urls.get(url), request , response) ; return ; }else{ Method m = urls.get(url).getClass().getDeclaredMethod("service", HttpServletRequest.class , HttpServletResponse.class) ; m.setAccessible(true); if(m != null){ // System.err.println("time:"+new Date().toLocaleString()+" IP:"+request.getRequestIP()+" path:"+url+" params:"+paramepFormat(request)); m.invoke(urls.get(url), request , response) ; return ; }else{ // System.err.println("ERROR === time:"+new Date().toLocaleString()+" IP:"+request.getRequestIP()+" path:"+url+" params:"+paramepFormat(request)); response.response(404 , S_404) ; return ; } } } catch (Exception e) { response.response(500 , e.toString()) ; } finally{ if(exchange.getResponseBody() == null){ return ; } try { Method m = response.getClass().getDeclaredMethod("flush") ; m.setAccessible(true); m.invoke(response) ; } catch (Exception e) {} if(exchange.getResponseBody() != null){ exchange.getResponseBody().close(); } } return ; } //请求的是文件 try { writeHtml(exchange , url) ; // System.err.println("time:"+new Date().toLocaleString()+" IP:"+request.getRequestIP()+" file:"+url); } catch (Exception e) { // System.err.println("ERROR === time:"+new Date().toLocaleString()+" IP:"+request.getRequestIP()+" file:"+url); //System.out.println(e); response.response(404 , S_404) ; } finally{ if(this.in != null){ this.in.close(); } if(exchange.getResponseBody() != null){ exchange.getResponseBody().close(); } } } /** * 文件的地址 * @param path * @throws Exception * @throws Exception */ public void writeHtml(HttpExchange exchange , String path) throws Exception{ String filePath = "./WebRoot"+path ; this.in = new FileInputStream(filePath); this.out = exchange.getResponseBody() ; exchange.sendResponseHeaders(200, new File(filePath).length()); byte[] data = new byte[1024] ; int len = -1 ; while((len = in.read(data)) != -1){ out.write(data, 0, len); } } public String paramepFormat(HttpServletRequest request){ //返回字符串 StringBuffer buf = new StringBuffer("[") ; //获取请求全部参数 Map params = request.getParameters() ; //获取参数的建 Set keys = params.keySet() ; //遍历参数 for (String k : keys) { buf.append(k+" => "+ params.get(k)+" ,") ; } if(buf.length() == 1){ buf.append("]") ; }else{ buf = buf.replace(buf.length()-1, buf.length(), "]") ; } return buf.toString() ; } }) ; } //注解处理器 public void doRegist(Class c) throws Exception{ //利用反射生成一个对象 Object o ; try{ o = c.getConstructor().newInstance() ; }catch(Exception e){ return ; } //判断该对象是否写了注解 RequestMapper reMapper = o.getClass().getAnnotation(RequestMapper.class) ; if(reMapper != null){ System.err.println("time:"+new Date().toLocaleString()+" path:"+reMapper.path()+" file:"+c +" successful"); urls.put(reMapper.path() , o) ; findMethod(o) ; } } /** * 遍历方法的找到含有RequestMapper的方法反射 */ private void findMethod(Object o){ Method[] methods = o.getClass().getDeclaredMethods() ; Map map = new HashMap() ; for (Method m : methods) { //允许私有方法被访问 m.setAccessible(true); RequestMapper reMapper = m.getAnnotation(RequestMapper.class) ; if(reMapper != null){ //将实现注解的方法加入murls集合中 Parameter[] fields = m.getParameters() ; if(fields.length != 2){ throw new RuntimeException("实现注解的方法请传入HttpServletRequest和HttpServletResponse的对象") ; }else{ if(fields[0].getType() != HttpServletRequest.class || fields[1].getType() != HttpServletResponse.class){ throw new RuntimeException("实现注解的方法请传入HttpServletRequest和HttpServletResponse的对象") ; } } System.err.println("time:"+new Date().toLocaleString()+" path:"+reMapper.path()+" file:"+m +" successful"); map.put(reMapper.path(), m) ; } } murls.put(o, map) ; } }

服务器的基本代码已经封装完成
接下来再com.servlet中写一个Servlet做测试

1.UserServlet

package com.servlet;

import java.io.UnsupportedEncodingException;

import com.inter.HttpServlet;
import com.inter.HttpServletRequest;
import com.inter.HttpServletResponse;
import com.zj.RequestMapper;

@RequestMapper(path = "/user.do")
public class UserServlet implements HttpServlet {

	public void service(HttpServletRequest request, HttpServletResponse response)
			throws Exception {
		String name = request.getParameter("name") ;
		response.getWriter().print(name);
	}
	
	@RequestMapper(path="regist")
	public void regist(HttpServletRequest request, HttpServletResponse response) throws UnsupportedEncodingException{
		System.out.println("正在注册");
		response.getWriter().print("Success");
	}
}

建一个类启动服务器
Test
import com.server.Server;

public class Test {
	public static void main(String[] args) throws Exception {
		Server server = new Server(9999, "com.servlet") ; //9999表示监听端口,com.servlet表示等下要扫描这个包中的注解
		server.init() ;
	}
}

跑起来以后再浏览器中输入 http://127.0.0.1:9999/user.do?name=wf
浏览器会输出wf
输入 http://127.0.0.1:9999/user.do?method=regist
服务器端会在控制台输出“正在注册” , 浏览器会输出success

完整代码已经上传到github:https://github.com/wangffei/HttpServer
目前已经支持cookie的解析,支持session,还有一套类似于javaweb的基本语法(代码非常简单,只是平时练习的作品,需要使用的话可以自己扩充修改)

你可能感兴趣的:(HttpServer)