实现简单HttpServer案例
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<html> <head> <title>第一个表单</title> </head> <body> <pre> method:请求方式 get/post get: 默认方式,数据量小,安全性不高 post:量大,安全性相对高 action:请求的服务器路径 id:编号,前端区分唯一性 ,js中使用 name:名称,后端(服务器)区分唯一性 ,获取值 只要提交数据给后台,必须存在name </pre> <form method="post" action="http://localhost:8888/g"> 用户名:<input type="text" name="uname" id="uname"/> 密码:<input type="password" name="pwd" id="pwd"/> <input type="submit" value="登录"/> </form> </body> </html>
配置文件:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<?xml version="1.0" encoding="UTF-8"?> <web-app> <servlet> <servlet-name>login</servlet-name> <servlet-class>com.bjsxt.servlet.LoginWeb</servlet-class> </servlet> <servlet-mapping> <servlet-name>login</servlet-name> <url-pattern>/g</url-pattern> <url-pattern>/y</url-pattern> </servlet-mapping> </web-app>
工具类:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
package com.bjsxt.util; import java.io.Closeable; import java.net.DatagramSocket; import java.net.ServerSocket; import java.net.Socket; public class CloseUtil { /** * 关闭IO流 */ /* public static void closeIO(Closeable... io){ for(Closeable temp:io){ try { if (null != temp) { temp.close(); } } catch (Exception e) { } } }*/ /** * 使用泛型方法实现关闭IO流 * @param io */ public static <T extends Closeable> void closeIO(T... io){ for(Closeable temp:io){ try { if (null != temp) { temp.close(); } } catch (Exception e) { } } } public static void closeSocket(ServerSocket socket){ try { if (null != socket) { socket.close(); } } catch (Exception e) { } } public static void closeSocket(Socket socket){ try { if (null != socket) { socket.close(); } } catch (Exception e) { } } public static void closeSocket(DatagramSocket socket){ try { if (null != socket) { socket.close(); } } catch (Exception e) { } } }
Servlet:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
package com.bjsxt.servlet;
import com.bjsxt.server.Request;
import com.bjsxt.server.Response;
public class LoginWeb extends Servlet {
@Override
public void doGet(Request req, Response rep) throws Exception {
rep.println("success.....");
}
@Override
public void doPost(Request req, Response rep) throws Exception {
// TODO Auto-generated method stub
}
}
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
package com.bjsxt.servlet;
import com.bjsxt.server.Request;
import com.bjsxt.server.Response;
/**
* 抽象为一个父类
* @author Administrator
*
*/
public abstract class Servlet {
public void service(Request req,Response rep) throws Exception{
this.doGet(req,rep);
this.doPost(req,rep);
}
protected abstract void doGet(Request req,Response rep) throws Exception;
protected abstract void doPost(Request req,Response rep) throws Exception;
}
Server:
转发类:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
package com.bjsxt.server; import java.io.IOException; import java.net.Socket; import com.bjsxt.servlet.Servlet; import com.bjsxt.util.CloseUtil; /** * 一个请求与响应 就一个此对象 * @author Administrator * */ public class Dispatcher implements Runnable{ private Socket client; private Request req; private Response rep; private int code=200; Dispatcher(Socket client){ this.client=client; try { req =new Request(client.getInputStream()); rep =new Response(client.getOutputStream()); } catch (IOException e) { //e.printStackTrace(); code =500; return ; } } @Override public void run() { try { Servlet serv =WebApp.getServlet(req.getUrl()); if(null==serv){ this.code=404; //找不到处理 }else{ serv.service(req, rep); } rep.pushToClient(code); //推送到客户端 }catch (Exception e) { e.printStackTrace(); this.code=500; } try { rep.pushToClient(500); } catch (IOException e) { e.printStackTrace(); } req.close(); rep.close(); CloseUtil.closeSocket(client); } }
获取配置文件实体类:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
package com.bjsxt.server; /* <servlet> <servlet-name>login</servlet-name> <servlet-class>com.bjsxt.server.demo4.LoginServlet</servlet-class> </servlet> */ public class Entity { private String name; private String clz; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getClz() { return clz; } public void setClz(String clz) { this.clz = clz; } }
映射类:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
package com.bjsxt.server; import java.util.ArrayList; import java.util.List; /* <servlet-mapping> <servlet-name>login</servlet-name> <url-pattern>/login</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>login</servlet-name> <url-pattern>/log</url-pattern> </servlet-mapping> */ public class Mapping { private String name; private List<String> urlPattern; public Mapping(){ urlPattern =new ArrayList<String>(); } public String getName() { return name; } public void setName(String name) { this.name = name; } public List<String> getUrlPattern() { return urlPattern; } public void setUrlPattern(List<String> urlPattern) { this.urlPattern = urlPattern; } }
请求类:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
package com.bjsxt.server; import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.StringTokenizer; import com.bjsxt.util.CloseUtil; /** * 封装request * @author Administrator * */ public class Request { //请求方式 private String method; //请求资源 private String url; //请求参数 private Map<String,List<String>> parameterMapValues; //内部 public static final String CRLF="\r\n"; private InputStream is; private String requestInfo; public Request(){ method =""; url =""; parameterMapValues=new HashMap<String,List<String>>(); requestInfo=""; } public Request(InputStream is){ this(); this.is=is; try { byte[] data = new byte[20480]; int len = is.read(data); requestInfo = new String(data, 0, len); } catch (Exception e) { return ; } //分析请求信息 parseRequestInfo(); } /** * 分析请求信息 */ private void parseRequestInfo(){ if(null==requestInfo ||(requestInfo=requestInfo.trim()).equals("")){ return ; } /** * ===================================== * 从信息的首行分解出 :请求方式 请求路径 请求参数(get可能存在) * 如:GET /index.html?name=123&pwd=5456 HTTP/1.1 * * 如果为post方式,请求参数可能在 最后正文中 * * 思路: * 1)请求方式 :找出第一个/ 截取即可 * 2)请求资源:找出第一个/ HTTP/ * ===================================== */ String paramString =""; //接收请求参数 //1、获取请求方式 String firstLine =requestInfo.substring(0,requestInfo.indexOf(CRLF)); int idx =requestInfo.indexOf("/"); // /的位置 this.method=firstLine.substring(0, idx).trim(); String urlStr =firstLine.substring(idx,firstLine.indexOf("HTTP/")).trim(); if(this.method.equalsIgnoreCase("post")){ this.url=urlStr; paramString=requestInfo.substring(requestInfo.lastIndexOf(CRLF)).trim(); }else if(this.method.equalsIgnoreCase("get")){ if(urlStr.contains("?")){ //是否存在参数 String[] urlArray=urlStr.split("\\?"); this.url=urlArray[0]; paramString=urlArray[1];//接收请求参数 }else{ this.url=urlStr; } } //不存在请求参数 if(paramString.equals("")){ return ; } //2、将请求参数封装到Map中 parseParams(paramString); } private void parseParams(String paramString){ //分割 将字符串转成数组 StringTokenizer token=new StringTokenizer(paramString,"&"); while(token.hasMoreTokens()){ String keyValue =token.nextToken(); String[] keyValues=keyValue.split("="); if(keyValues.length==1){ keyValues =Arrays.copyOf(keyValues, 2); keyValues[1] =null; } String key = keyValues[0].trim(); String value = null==keyValues[1]?null:decode(keyValues[1].trim(),"gbk"); //转换成Map 分拣 if(!parameterMapValues.containsKey(key)){ parameterMapValues.put(key,new ArrayList<String>()); } List<String> values =parameterMapValues.get(key); values.add(value); } } /** * 解决中文 * @param value * @param code * @return */ private String decode(String value,String code){ try { return java.net.URLDecoder.decode(value, code); } catch (UnsupportedEncodingException e) { //e.printStackTrace(); } return null; } /** * 根据页面的name 获取对应的多个值 * @param args */ public String[] getParameterValues(String name){ List<String> values=null; if((values=parameterMapValues.get(name))==null){ return null; }else{ return values.toArray(new String[0]); } } /** * 根据页面的name 获取对应的单个值 * @param args */ public String getParameter(String name){ String[] values =getParameterValues(name); if(null==values){ return null; } return values[0]; } public String getUrl() { return url; } public void close(){ CloseUtil.closeIO(is); } }
响应类:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
package com.bjsxt.server; import java.io.BufferedWriter; import java.io.IOException; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.net.Socket; import java.util.Date; import com.bjsxt.util.CloseUtil; /** * 封装响应信息 * @author Administrator * */ public class Response { //两个常量 public static final String CRLF="\r\n"; public static final String BLANK=" "; //流 private BufferedWriter bw ; //正文 private StringBuilder content; //存储头信息 private StringBuilder headInfo; //存储正文长度 private int len =0; public Response(){ headInfo =new StringBuilder(); content =new StringBuilder(); len =0; } public Response(Socket client){ this(); try { bw= new BufferedWriter(new OutputStreamWriter(client.getOutputStream())); } catch (IOException e) { headInfo=null; } } public Response(OutputStream os){ this(); bw= new BufferedWriter(new OutputStreamWriter(os)); } /** * 构建正文 */ public Response print(String info){ content.append(info); len+=info.getBytes().length; return this; } /** * 构建正文+回车 */ public Response println(String info){ content.append(info).append(CRLF); len+=(info+CRLF).getBytes().length; return this; } /** * 构建响应头 */ private void createHeadInfo(int code){ //1) HTTP协议版本、状态代码、描述 headInfo.append("HTTP/1.1").append(BLANK).append(code).append(BLANK); switch(code){ case 200: headInfo.append("OK"); break; case 404: headInfo.append("NOT FOUND"); break; case 505: headInfo.append("SEVER ERROR"); break; } headInfo.append(CRLF); //2) 响应头(Response Head) headInfo.append("Server:bjsxt Server/0.0.1").append(CRLF); headInfo.append("Date:").append(new Date()).append(CRLF); headInfo.append("Content-type:text/html;charset=GBK").append(CRLF); //正文长度 :字节长度 headInfo.append("Content-Length:").append(len).append(CRLF); headInfo.append(CRLF); //分隔符 } //推送到客户端 void pushToClient(int code) throws IOException{ if(null==headInfo){ code =500; } createHeadInfo(code); //头信息+分割符 bw.append(headInfo.toString()); //正文 bw.append(content.toString()); bw.flush(); } public void close(){ CloseUtil.closeIO(bw); } }
服务器:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
package com.bjsxt.server; import java.io.IOException; import java.net.ServerSocket; import com.bjsxt.util.CloseUtil; /** * 创建服务器,并启动 * * 1、请求 * 2、响应 * @author Administrator * */ public class Server { private ServerSocket server; public static final String CRLF="\r\n"; public static final String BLANK=" "; private boolean isShutDown= false; /** * @param args */ public static void main(String[] args) { Server server = new Server(); server.start(); } /** * 启动方法 */ public void start(){ start(8888); } /** * 指定端口的启动方法 */ public void start(int port){ try { server = new ServerSocket(port); this.receive(); } catch (IOException e) { //e.printStackTrace(); stop(); } } /** * 接收客户端 */ private void receive(){ try { while(!isShutDown){ new Thread(new Dispatcher(server.accept())).start(); } } catch (IOException e) { //e.printStackTrace(); stop(); } } /** * 停止服务器 */ public void stop(){ isShutDown=true; CloseUtil.closeSocket(server); } }
Servlet上下文:(container)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
package com.bjsxt.server; import java.util.HashMap; import java.util.Map; /** * 上下文 * @author Administrator * */ public class ServletContext { //为每一个servlet取个别名 // login -->com.bjsxt.server.demo03.LoginServlet private Map<String,String> servlet ; //url -->login // /log -->login // /login -->login private Map<String,String> mapping; ServletContext(){ servlet =new HashMap<String,String>(); mapping =new HashMap<String,String>(); } public Map<String, String> getServlet() { return servlet; } public void setServlet(Map<String, String> servlet) { this.servlet = servlet; } public Map<String, String> getMapping() { return mapping; } public void setMapping(Map<String, String> mapping) { this.mapping = mapping; } }
Webapp:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
package com.bjsxt.server; import java.util.List; import java.util.Map; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import com.bjsxt.servlet.Servlet; public class WebApp { private static ServletContext contxt; static{ try { //获取解析工厂 SAXParserFactory factory = SAXParserFactory.newInstance(); //获取解析器 SAXParser sax = factory.newSAXParser(); //指定xml+处理器 WebHandler web = new WebHandler(); sax.parse(Thread.currentThread().getContextClassLoader() .getResourceAsStream("WEB_INFO/web.xml"), web); //将list 转成Map contxt =new ServletContext(); Map<String,String> servlet =contxt.getServlet(); //servlet-name servlet-class for(Entity entity:web.getEntityList()){ servlet.put(entity.getName(), entity.getClz()); } //url-pattern servlet-name Map<String,String> mapping =contxt.getMapping(); for(Mapping mapp:web.getMappingList()){ List<String> urls =mapp.getUrlPattern(); for(String url:urls ){ mapping.put(url, mapp.getName()); } } } catch (Exception e) { } } public static Servlet getServlet(String url) throws InstantiationException, IllegalAccessException, ClassNotFoundException{ if((null==url)||(url=url.trim()).equals("")){ return null; } //根据字符串(完整路径)创建对象 //return contxt.getServlet().get(contxt.getMapping().get(url)); String name=contxt.getServlet().get(contxt.getMapping().get(url)); return (Servlet)Class.forName(name).newInstance();//确保空构造存在 } }
WebHandler:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
package com.bjsxt.server; import java.util.ArrayList; import java.util.List; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; public class WebHandler extends DefaultHandler{ private List<Entity> entityList; private List<Mapping> mappingList; private Entity entity; private Mapping mapping; private String beginTag ; private boolean isMap; @Override public void startDocument() throws SAXException { //文档解析开始 entityList =new ArrayList<Entity>() ; mappingList =new ArrayList<Mapping>() ; } @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { //开始元素 if(null!=qName){ beginTag=qName; if(qName.equals("servlet")){ isMap=false; entity=new Entity(); }else if(qName.equals("servlet-mapping")){ isMap=true; mapping=new Mapping(); } } } @Override public void characters(char[] ch, int start, int length) throws SAXException { //处理内容 if(null!=beginTag){ String str =new String(ch,start,length); if(isMap ){ if(beginTag.equals("servlet-name")){ mapping.setName(str); }else if(beginTag.equals("url-pattern")){ mapping.getUrlPattern().add(str); } }else{ if(beginTag.equals("servlet-name")){ entity.setName(str); }else if(beginTag.equals("servlet-class")){ entity.setClz(str); } } } } @Override public void endElement(String uri, String localName, String qName) throws SAXException { //结束元素 if(null!=qName){ if(qName.equals("servlet")){ entityList.add(entity); }else if(qName.equals("servlet-mapping")){ mappingList.add(mapping); } } beginTag=null; } @Override public void endDocument() throws SAXException { //文档解析结束 } /*public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException { //获取解析工厂 SAXParserFactory factory =SAXParserFactory.newInstance(); //获取解析器 SAXParser sax =factory.newSAXParser(); //指定xml+处理器 WebHandler web = new WebHandler(); sax.parse(Thread.currentThread().getContextClassLoader() .getResourceAsStream("com/bjsxt/server/demo4/web.xml") ,web); System.out.println(web.getEntityList()); }*/ public List<Entity> getEntityList() { return entityList; } public void setEntityList(List<Entity> entityList) { this.entityList = entityList; } public List<Mapping> getMappingList() { return mappingList; } public void setMappingList(List<Mapping> mappingList) { this.mappingList = mappingList; } }
合群是堕落的开始 优秀的开始是孤行