简单web服务器

回忆socket

创建客服端(在httpClient_1包下)

public class Client {
   public static void main(String[] args) {
       //1.创建socket对象
       Socket client=null;

       DataOutputStream dos = null;
       DataInputStream dis =null;
       try {
           client = new Socket("localhost", 8888);
           //2.获取输出流请求
           dos = new DataOutputStream(client.getOutputStream());
           dos.writeUTF("我是客服端:服务器你好!");
           //3.获取输出流响应
           dis = new DataInputStream(client.getInputStream());
           System.out.println(dis.readUTF());
      } catch (IOException e) {
           e.printStackTrace();
      } finally {
           //4.关闭流
           IOClose.closeAll(dis,dos,client);
      }


  }

创建IOClose类

public class IOClose {
   //关闭全部的工具类
   public static void closeAll(Closeable...c){
       for (Closeable closeable : c) {
           if (closeable!=null){
               try {
                   closeable.close();
              } catch (IOException e) {
                   e.printStackTrace();
              }
          }
      }

创建服务端(在httpserver_1包下)

package com.feng.server;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

public class Server {
   public static void main(String[] args) {
       //1.创建ServerSocket对象
       ServerSocket server = null;
       Socket client =null;
       DataInputStream dis =null;
       DataOutputStream dos =null;
       try {
           server = new ServerSocket(8888);
           //2.监听是否有客服端发送请求
           client = server.accept();
           //3.获取Socket对象
           //4.获取输入流 ->得到客服端的请求
           dis = new DataInputStream(client.getInputStream());
           System.out.println(dis.readUTF());
           //5.获取输出流 ->给客服端响应结果
           dos = new DataOutputStream(client.getOutputStream());
           dos.writeUTF("客服端你好,我是服务器,我接受到了你的信息");
      } catch (IOException e) {
           e.printStackTrace();
      } finally {
           IOClose.closeAll(dos,dis,client,server);
      }

同样创建IOClose

在CS结构server(2)

package com.feng.server;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

public class Server2 {
   public static void main(String[] args) {
       //1.创建ServerSocket对象
       ServerSocket server = null;
       Socket client =null;

       BufferedReader br = null;
       try {
           server = new ServerSocket(8888);
           //2.监听是否有客服端发送请求
           client = server.accept();
           //获取来自浏览器的请求信息
           br = new BufferedReader(new InputStreamReader(client.getInputStream(), "utf-8"));
           String str=null;
           while ((str=br.readLine()).length()>0) {
               System.out.println(str);
          }
      } catch (IOException e) {
           e.printStackTrace();
      } finally {
           IOClose.closeAll(br,client,server);
      }
  }
}

创建HTML

<!DOCTYPE html>
<html lang="en">
<head>
   <meta charset="UTF-8">
   <title>javaWeb</title>
</head>
<body>
   <h1>HelloWorld</h1>
   <form action="http://localhost:8888/index.html" method="post">
       <p>用户名:<input type="text" id="uname" name="username"></p>
       <p>密码:<input type="password" id="pwd" name="password"></p>
       <p><input type="submit" value="登入"/></p>
   </form>
</body>
</html>

创建server3

获取来自浏览器的请求信息

//获取来自浏览器的请求信息
is = client.getInputStream();
byte[] buf = new byte[20480];
int len = is.read(buf);
System.out.println(new String(buf,0,len));

对web浏览器做出响应

添加参数

String CRLF="\r\n";
String BLANK=" ";
InputStream is = null;
/**对web浏览器做出响应*/
StringBuilder sb = new StringBuilder();
StringBuilder sbContent = new StringBuilder(); //响应的文本
sbContent.append("<html><head><title>响应结果</title></head>");
sbContent.append("<body>登入成功</body></html>");

//1拼接响应头
sb.append("HTTP/1.1").append(BLANK).append(200).append(BLANK).append("OK");
sb.append(CRLF);
sb.append("Content-Type: text/html;charset=UTF-8");
sb.append(CRLF);
sb.append("Content-Length:").append(sbContent.toString().getBytes().length).append(CRLF);
sb.append(CRLF);//带表响应头与响应正文部分之间的换行
sb.append(sbContent);
//2通过输出流
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(client.getOutputStream(),"UTF-8"));
bw.write(sb.toString());
bw.flush();
bw.close();

整合server3

public class Server3 {
   public static void main(String[] args) {
       //1.创建ServerSocket对象
       ServerSocket server = null;
       Socket client =null;
       String CRLF="\r\n";
       String BLANK=" ";
       InputStream is = null;
       try {
           server = new ServerSocket(8888);
           //2.监听是否有客服端发送请求
           client = server.accept();
           //获取来自浏览器的请求信息
           is = client.getInputStream();
           byte[] buf = new byte[20480];
           int len = is.read(buf);
           System.out.println(new String(buf,0,len));
           /**对web浏览器做出响应*/
           StringBuilder sb = new StringBuilder();
           StringBuilder sbContent = new StringBuilder(); //响应的文本
           sbContent.append("<html><head><title>响应结果</title></head>");
           sbContent.append("<body>登入成功</body></html>");

           //1拼接响应头
           sb.append("HTTP/1.1").append(BLANK).append(200).append(BLANK).append("OK");
           sb.append(CRLF);
           sb.append("Content-Type: text/html;charset=UTF-8");
           sb.append(CRLF);
           sb.append("Content-Length:").append(sbContent.toString().getBytes().length).append(CRLF);
           sb.append(CRLF);//带表响应头与响应正文部分之间的换行
           sb.append(sbContent);
           //2通过输出流
           BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(client.getOutputStream(),"UTF-8"));
           bw.write(sb.toString());
           bw.flush();
           bw.close();
      } catch (IOException e) {
           e.printStackTrace();
      } finally {
           //6.关闭流
           IOClose.closeAll(is,client,server);
      }


  }
}

手写服务器 整体架构,编写XML文件

创建Request,Response,Server,WebApp(在server包下)

创建Servlet,LoginServlet(在servlet包下)

创建IOCloseUtil(在util包下)

创建web.xml(在WEB_INFO包下)

<?xml version="1.0" encoding="UTF-8"?>
<web-app >
   <servlet>
       <servlet-name>login</servlet-name>
       <servlet-class>com.feng.servlet.LoginServlet</servlet-class>
   </servlet>
   <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>

</web-app>

创建Entity,Mapping,ServletContext,WebDom4j,创建IOClose在util包下

配置解析XML文件

补充实体类

package com.feng.server;

public class Entity {  //servlet-name或每一个servlet-name所对应得实体类
   private String name;
   private String clazz;

   public Entity() {
  }

   public Entity(String name, String clazz) {
       this.name = name;
       this.clazz = clazz;
  }

   public String getName() {
       return name;
  }

   public void setName(String name) {
       this.name = name;
  }

   public String getClazz() {
       return clazz;
  }

   public void setClazz(String clazz) {
       this.clazz = clazz;
  }
}

补充Mapping类

package com.feng.server;

import java.util.ArrayList;
import java.util.List;

public class Mapping { //映射关系,多个路径可以访问资源
   private String name; //servlet-name
   private List<String> urlPattern;//url-pattern

   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;
  }

   public Mapping() {
       this.urlPattern = new ArrayList<String>();
  }

   public Mapping(String name, List<String> urlPattern) {
       this.name = name;
       this.urlPattern = urlPattern;
  }
}

配置dom4j

package com.feng.server;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.File;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class WebDom4j { //用于解析xml
   private List<Entity> entityList; //用于储存实体类,每一个实体类一个servlet-name对应一个servlet-class
   private List<Mapping> mappingList;//用于储存映射类,每一个servlet-name对应一个url-pattern
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;
}

//构造方法
public WebDom4j() {
   entityList = new ArrayList<Entity>();
   mappingList = new ArrayList<Mapping>();
}

//获取Document对象的方法
public Document getDocument(){

   try {
       //创建SAXReader对象
       SAXReader reader = new SAXReader();
       //调用read方法
       return reader.read(new File("web/WEB-INF/web.xml"));
  } catch (DocumentException e) {
       e.printStackTrace();
  }
   return null;
}
//获取元素
public void parse(Document doc) {
   //1获取根元素
   Element root = doc.getRootElement(); //web-app
   //2获取servlet子元素
   for (Iterator<Element> ite = root.elementIterator("servlet"); ite.hasNext();) {
       Element subElement = ite.next(); //得到每一个servlet
       //创建一个实体类
       Entity ent = new Entity(); //用于储存servlet-name与servlet-class
       for (Iterator<Element> subIte = subElement.elementIterator(); subIte.hasNext();) {
           Element ele = subIte.next(); //servlet-name与servlet-class都有可能
           if ("servlet-name".equals(ele.getName())) {
               ent.setName(ele.getText());
          } else if ("servlet-class".equals(ele.getName())) {
               ent.setClazz(ele.getText());
          }
      }
       entityList.add(ent);//放到集合中
  }
   //测试
  /* for (Entity entity : entityList) {
       System.out.println(entity.getName() + "\t" + entity.getClazz());
   }*/

   //解析servlet-mapping

   for (Iterator<Element> ite = root.elementIterator("servlet-mapping"); ite.hasNext();){
       Element subEle = ite.next();//得到每一个servlet-mapping
       //创建一个mapping对象
       Mapping map = new Mapping();
       //解析mapping下面每一个子元素
       for (Iterator<Element> subIte = subEle.elementIterator(); subIte.hasNext();){
           Element ele = subIte.next();//可能是name,也可能是url
           if ("servlet-name".equals(ele.getName())) {
               map.setName(ele.getText());
          } else if ("url-pattern".equals(ele.getName())) {
               //获取集合对象,调用集合对象的添加方法,添加元素
               map.getUrlPattern().add(ele.getText());
          }
      }
       mappingList.add(map);

  }
   //测试
   /*for (Mapping m : mappingList) {
       System.out.println(m.getName());
       for (String s : m.getUrlPattern()) {
           System.out.println(s);
       }
   }*/
}

//用于测试
   public static void main(String[] args) {
       WebDom4j web = new WebDom4j();
       web.parse(web.getDocument());
  }
}

更新编写XML

<?xml version="1.0" encoding="UTF-8"?>
<web-app>
   <servlet>
       <servlet-name>login</servlet-name>
       <servlet-class>com.feng.servlet.LoginServlet</servlet-class>
   </servlet>
   <servlet-mapping>
       <servlet-name>login</servlet-name>
       <url-pattern>/log</url-pattern>
       <url-pattern>/login</url-pattern>
   </servlet-mapping>
   <servlet>
       <servlet-name>register</servlet-name>
       <servlet-class>com.feng.servlet.RegisterServlet</servlet-class>
   </servlet>
   <servlet-mapping>
       <servlet-name>register</servlet-name>
       <url-pattern>/reg</url-pattern>
       <url-pattern>/regis</url-pattern>
       <url-pattern>/register</url-pattern>
   </servlet-mapping>
 
</web-app>

编写servletContext Servlet 上下文,容器用于存储映射关系

package com.feng.server;

import java.util.HashMap;
import java.util.Map;

/**
*ServletContext 上下文 就是一个容器

*/
public class ServletContext { //Entity与Mapping之间的映射关系
    private Map<String, String> servlet;//key是servlet-name(实体类中的name),值servlet-class,实体类中的值
    private Map<String, String> mapping;//key是url-pattern(Map中的每一个元素),值servlet-name,实体类中的name

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;
}

public ServletContext(){
    servlet = new HashMap<String, String>();
    mapping = new HashMap<String, String>();
}
}

编写WebAPP 初始化程序数据

package com.feng.server;

import com.feng.servlet.Servlet;

import java.util.List;
import java.util.Map;

public class WebApp {  //应用程序
   private static ServletContext context;
   static {
       context = new ServletContext();
       //分别获取对应关系的Map集合
       Map<String, String> servlet = context.getServlet();
       Map<String, String> mapping = context.getMapping();
       //创建解析XML文件对象
       WebDom4jTest web = new WebDom4jTest();
       //解析xml
       web.parse(web.getDocument());
       //获取解析xml之后的List集合
       List<Entity> entityList = web.getEntityList();
       List<Mapping> mappingList = web.getMappingList();

       //将List集合储存到map集合中
       for (Entity entity : entityList) {
           servlet.put(entity.getName(),entity.getClazz());
      }
       //System.out.println(servlet);
       for (Mapping map : mappingList) {
           //遍历url-pattern的集合
           List<String> urlPattern = map.getUrlPattern();
           for (String s : urlPattern) {
               mapping.put(s,map.getName());
          }
      }
       //System.out.println(mapping);
  }

   /*
   * 根据url创建不同的Servlet对象
   * */
   public static Servlet getServlet(String url){
       if (url ==null||url.trim().equals("")){
           return null;
      }
       try {
       //如果url正确
       //根据url的key获取servlet-name的值
       String servletName = context.getMapping().get(url);
       //根据servlet-name找到对应得servlet-class
       String servletClass = context.getServlet().get(servletName);
       //得到的是一个完整的包+类名的字符串

       //使用反射创建servlet对象
       Class<?> clazz = Class.forName(servletClass);
       Servlet servlet = (Servlet) clazz.newInstance();
       return servlet;
      } catch (ClassNotFoundException e) {
           e.printStackTrace();
      } catch (InstantiationException e) {
           e.printStackTrace();
      } catch (IllegalAccessException e) {
           e.printStackTrace();
      }
       return null;
  }
   public static void main(String[] args) {
       System.out.println(getServlet("/log"));
       System.out.println(getServlet("/login"));
  }
}

编写服务


public class Server { //服务器,用于启动或停止服务
   private ServerSocket server;

   public static void main(String[] args) {
       Server server = new Server();//创建服务器
       server.start();
  }

   private void start() {
       this.start(8888);
  }

   public void start(int port){
       try {
           server = new ServerSocket(port);
           this.receive();//调用接受请求的方式
      } catch (IOException e) {
           e.printStackTrace();
      }
  }

   private void receive() {

       try {
         
               //1监听
               Socket client = server.accept();
               //创建线程类
               Dispatcher dis = new Dispatcher(client);
               //创建代理线程
               new Thread(dis).start();
           
           //获取用户的请求
           /**InputStream is = client.getInputStream();
           byte[] buf = new byte[20480];
           int len = is.read(buf);
           System.out.println(new String(buf, 0, len));*/
            //封装请求信息
           Request req = new Request(client.getInputStream());
           req.show();
         
      } catch (IOException e) {
           e.printStackTrace();
      }

  }
   public void stop(){

  }
}

编写Request

package com.feng.server;

import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.security.PrivateKey;
import java.util.*;

public class Request { //请求

   //输入流
   private InputStream is;
   private String requestInfo; //请求字符串,请求方式,请求路径,参数,协议,协议版本,请求正文。。
   private String method;//请求的方式
   private String url;//请求的路径

   public String getUrl() {
       return url;
  }

   /*
   * 输入框的name为key,值为value
   * */
   private Map<String, List<String>> parameterMapValues;//参数
   private static final String CRLF="\r\n";//换行
   private static final String BLANK =" ";//空格
   //构造方法,初始化属性
   public Request(){
       parameterMapValues=new HashMap<String, List<String>>();
       method="";
       url="";
       requestInfo="";
  }
   public Request(InputStream is){
       this();//调用本类无参构造方法
       this.is=is;

       try {
           byte[] buf = new byte[20480];
           int len = this.is.read(buf);
           requestInfo = new String(buf, 0, len);
      } catch (IOException e) {
           return;
      }
       //调用本类中的分解信息的方法
       this.parseRequestInfo();
  }
   //分解请求信息的方法
   /**
   * 请求方式
   * 请求路径
   * 请求的参数
   * */
   public void parseRequestInfo() {
       String paraString="";//用于存储请求参数
       //获取参数的第一行
       String firstLine = requestInfo.substring(0, requestInfo.indexOf(CRLF)).trim();//从0开始到第一个换行的位置
       //分解出请求方式
       int index = firstLine.indexOf("/");
       this.method = firstLine.substring(0, index).trim();
       //分解url ,get可能包含的参数,也可能不包含的参数post
       String urlString = firstLine.substring(index, firstLine.indexOf("HTTP/")).trim();
       //判断请求方式是GET或POST
       if ("get".equalsIgnoreCase(this.method)) {   //包含请求参数
           if (urlString.contains("?")){
               String[] urlArray = urlString.split("\\?");
               this.url=urlArray[0];
               paraString=urlArray[1];
          }else {
               this.url=urlString;
          }
      }else {//post不包含请求参数
           this.url=urlString;
           paraString=requestInfo.substring(requestInfo.lastIndexOf(CRLF)).trim();
        }
       if (paraString.equals("")){
           return;
      }
       //请求参数
       System.out.println(paraString);
     
  }
   //用于测试
   public void show(){
       System.out.println(this.url);
       System.out.println(this.method);
  }

 
}

编写login.html

<!DOCTYPE html>
<html lang="en">
<head>
   <meta charset="UTF-8">
   <title>登入</title>
</head>
<body>
   <form action="http://localhost:8888/log" method="post">
       <p>用户名:<input type="text" name="username" id="username"></p>
       <p>密码:<input type="password" name="pwd" id="password"></p>
       <p>
          爱好:<input type="checkbox" name="hobby" value="ball"/>足球
                <input type="checkbox" name="hobby" value="read"/>读书
               <input type="checkbox" name="hobby" value="paint"/>画画
       </p>
       <p><input type="submit" value="登入"></p>
   </form>
</body>
</html>

储存参数,处理中文

/**
  *username = admin
   * pwd = 123
   * hobby =ball
   * hobby = paint
   * */
  public void parseParam(String prarString){
      String[] token = prarString.split("&");
      for (int i=0;i<token.length;i++){
          String keyValues = token[i];
          String[] keyValue = keyValues.split("=");//把=分割掉,得到K和V
          if (keyValue.length==1){   //username=
              keyValue = Arrays.copyOf(keyValue, 2);
              keyValue[1] = null;
          }
          //将表单中的元素的name与name对应的值储存到Map集合
          String key = keyValue[0].trim();
          String value = keyValue[1]==null?null:decode(keyValue[1].trim(),"utf-8");
          //放到集合中存储
          if (!parameterMapValues.containsKey(key)) {  //键不存在就创建
              parameterMapValues.put(key,new ArrayList<String>());
          }
          List<String> values = parameterMapValues.get(key);
          values.add(value); //创建一个集合添加值
      }

  }
   //根剧表单元素的name获取多个值
   public String [] getParamterValues(String name) {
      //根据key获取value
       List<String> values = parameterMapValues.get(name);
       if (values == null ){
           return null;
      } else {
           return values.toArray(new String[0] );
      }
  }
   public String getParamter(String name){
      //调用本类中根据name获取单个值的方法
       String[] values = this.getParamterValues(name);
       if (values ==null){
           return null;
      } else {
           return values[0];
      }
  }
    //处理中文,因浏览器对中文进行了编码,进行解码
       private String decode(String value,String code){
           try {
               return URLDecoder.decode(value,code);
          } catch (UnsupportedEncodingException e) {
               e.printStackTrace();
          }
           return null;
      }
 

   public static void main(String[] args) {
       Request req = new Request();
       //调用分解参数的方法
       req.parseParam("username=中文加密&pwd=123&hobby=ball&hobby=read");
       System.out.println(req.parameterMapValues);

       //调用获取多个值的方法
       String[] str = req.getParamterValues("hobby");
       for (String string : str) {
           System.out.println(string);
      }
       //调用单个获取值的方法
       System.out.println(req.getParamter("pwd"));
  }

加到Server类中,测试响应

  //封装请求信息
           Request req = new Request(client.getInputStream());
           //req.show();
           /**
            * 做出响应
            * */
           StringBuilder sb = new StringBuilder();
           sb.append("HTTP/1.1").append(" ").append(200).append(" ").append("OK").append("\r\n");
           sb.append("Content-Type:text/html;charset=utf-8").append("\r\n");
           //内容
           String str = "<html><head><title>响应结果</title></head><body>成功</body></html>";
           sb.append("Content-Length:"+str.getBytes("utf-8").length).append("\r\n");
           sb.append("\r\n");
           sb.append(str);

           //通过输出流发送出去
           BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(client.getOutputStream(),"utf-8"));
           bw.write(sb.toString());
           bw.flush();
           bw.close();

编写Response

package com.feng.server;
import com.feng.util.IOCloseUtil;
import java.io.*;

public class Response { //响应
   private StringBuilder headInfo;  //响应头
   private StringBuilder content; //响应内容
   private int length; //响应内容的长度

   //流
   private BufferedWriter bw;

   //两个常量,换行和空格
   private static final String CRLF="\r\n";  //换行
   private static final String BLANK=" ";  //空格

   //构造方法
   public Response() {
       headInfo= new StringBuilder();
       content = new StringBuilder();
  }
   //带构造方法

   public Response(OutputStream os) {
       this();//调用本类的无参构造方法
       try {
           bw = new BufferedWriter(new OutputStreamWriter(os,"utf-8"));
      } catch (UnsupportedEncodingException e) {
           e.printStackTrace();
      }
  }
   //构造正文部分
   public Response print(String info){
       content.append(info);
       try {
           length+= info.getBytes("utf-8").length;
      } catch (UnsupportedEncodingException e) {
           e.printStackTrace();
      }
       return this;
  }
   public Response printLn(String info){
       content.append(info).append(CRLF);
       try {
           length+=(info+CRLF).getBytes("utf-8").length;
      } catch (UnsupportedEncodingException e) {
           e.printStackTrace();
      }
       return this;
  }

   //构造响应头
   private void createHeadInfo(int code){
       headInfo.append("HTTP/1.1").append(BLANK).append(code).append(BLANK);
       switch (code){
           case 200:
               headInfo.append("OK");
               break;
           case 500:
               headInfo.append("SERVER ERROR");
           default:
               headInfo.append("NOT FOUND");
               break;
      }
       headInfo.append(CRLF);
       headInfo.append("Content-Type:text/html;charset=utf-8").append(CRLF);
       headInfo.append("Content-Length:"+length).append(CRLF);
       headInfo.append(CRLF);
  }

   /**
    * 推送到客户机的浏览器
    * */
   public void pushToClient(int code){
       if (headInfo==null){
           code=500;
      }
       //调用本类中的构造响应头
       this.createHeadInfo(code);
       try {
           bw.write(headInfo.toString());
           bw.write(content.toString());
           bw.flush();
           this.close();
      } catch (IOException e) {
           e.printStackTrace();
      }

  }

   public void close() {
       IOCloseUtil.closeAll(bw);
  }
}

然后再把Server里面做出响应那段代码注释掉

package com.feng.server;

import com.feng.servlet.Servlet;
import com.feng.util.IOCloseUtil;

import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;

public class Server { //服务器,用于启动或停止服务
   private ServerSocket server;
 
   public static void main(String[] args) {
       Server server = new Server();//创建服务器
       server.start();
  }

   private void start() {
       this.start(8888);
  }

   public void start(int port){
       try {
           server = new ServerSocket(port);
           this.receive();//调用接受请求的方式
      } catch (IOException e) {
            e.printStackTrace();
      }
  }

   private void receive() {

       try {
           //1监听
           Socket client = server.accept();
           //创建线程类
           Dispatcher dis = new Dispatcher(client);
           //创建代理线程
           new Thread(dis).start();
           
           //获取用户的请求
          /* InputStream is = client.getInputStream();
           byte[] buf = new byte[20480];
           int len = is.read(buf);
           System.out.println(new String(buf, 0, len));*/
          //封装请求信息
           Request req = new Request(client.getInputStream());
           //req.show();
           /**
            * 做出响应
            * */
           /*StringBuilder sb = new StringBuilder();
           sb.append("HTTP/1.1").append(" ").append(200).append(" ").append("OK").append("\r\n");
           sb.append("Content-Type:text/html;charset=utf-8").append("\r\n");
           //内容
           String str = "<html><head><title>响应结果</title></head><body>成功</body></html>";
           sb.append("Content-Length:"+str.getBytes("utf-8").length).append("\r\n");
           sb.append("\r\n");
           sb.append(str);

           //通过输出流发送出去
           BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(client.getOutputStream(),"utf-8"));
           bw.write(sb.toString());
           bw.flush();
           bw.close();*/
           Response rep = new Response(client.getOutputStream());
           Servlet servlet = WebApp.getServlet(req.getUrl());
           int code=200;
           if (servlet ==null){
               code=404;
          }
           //调用Servlet中的服务方法
           try {
               servlet.service(req,rep);
          } catch (Exception e) {
               e.printStackTrace();
          }
           rep.pushToClient(code);
           IOCloseUtil.closeAll(client);  //单线程已被删除
      } catch (IOException e) {
           e.printStackTrace();
      }

  }
   public void stop(){

  }
}

封装Response

编写servlet

public abstract class Servlet { //是所有请求servlet的父类
   public void service(Request req, Response rep) throws Exception {
       this.deGet(req,rep);
       this.doPost(req,rep);
  }

   public abstract void deGet(Request req, Response rep) throws Exception;
   public abstract void doPost(Request req, Response rep) throws Exception;

}

编写LoginServlet

public class LoginServlet extends Servlet {
   @Override
   public void deGet(Request req, Response rep) throws Exception {
       //获取请求参数
       String name = req.getParamter("username");
       String pwd = req.getParamter("pwd");

       if (this.login(name,pwd)) {
           //调用响应中的构建内容的方法
           rep.printLn(name+"登入成功");
      }else {
           rep.printLn(name+"登录失败,对不起,账号和密码不准确");
      }
  }
   private boolean login(String name,String pwd){
       if ("admin".equals(name)&&"123".equals(pwd)) {
           return true;
      }
       return false;
  }

   @Override
   public void doPost(Request req, Response rep) throws Exception {

  }
}

封装分发器,实现多线程

package com.feng.server;

import com.feng.servlet.Servlet;
import com.feng.util.IOCloseUtil;

import java.io.IOException;
import java.net.Socket;

/**
* 一个请求与响应就是一个Dispatcher
*
* @author asus
* */
public class Dispatcher implements Runnable {
   private Request req;
   private Response rep;
   private Socket client;
   private int code =200;//状态码

   //构造方法初始化属性

   public Dispatcher(Socket client) {
       this.client = client;
       try {
           req=new Request(this.client.getInputStream());
           rep=new Response(this.client.getOutputStream());
      } catch (IOException e) {
           code=500;
           return;
      }

  }

   @Override
   public void run() {
       //根据不同的url创建指定的servlet对象
       Servlet servlet = WebApp.getServlet(req.getUrl());
       if (servlet==null){
           this.code=404;
      }else {
           //调用响应的servlet中service方法
           try {
               servlet.service(req,rep);
          } catch (Exception e) {
               this.code=500;
          }
      }
       //将有响应的结果推送到客户端的浏览器
       rep.pushToClient(code);
       IOCloseUtil.closeAll(client);
  }
}

实现多线程

package com.feng.server;

import com.feng.servlet.Servlet;
import com.feng.util.IOCloseUtil;

import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;

public class Server { //服务器,用于启动或停止服务
   private ServerSocket server;
   private boolean isShutDown=false; //默认没有出错

   public static void main(String[] args) {
       Server server = new Server();//创建服务器
       server.start();
  }

   private void start() {
       this.start(8888);
  }

   public void start(int port){
       try {
           server = new ServerSocket(port);
           this.receive();//调用接受请求的方式
      } catch (IOException e) {
           isShutDown=true;
      }
  }

   private void receive() {

       try {
           while (!isShutDown){
               //1监听
               Socket client = server.accept();
               //创建线程类
               Dispatcher dis = new Dispatcher(client);
               //创建代理线程
               new Thread(dis).start();
          }
         
      } catch (IOException e) {
           e.printStackTrace();
      }

  }
   public void stop(){
isShutDown=true;
IOCloseUtil.closeAll(server);
  }
}

可能会出现空指针异常

缺少favicon映射类,在xml里面配置

<?xml version="1.0" encoding="UTF-8"?>
<web-app>
   <servlet>
       <servlet-name>login</servlet-name>
       <servlet-class>com.feng.servlet.LoginServlet</servlet-class>
   </servlet>
   <servlet-mapping>
       <servlet-name>login</servlet-name>
       <url-pattern>/log</url-pattern>
       <url-pattern>/login</url-pattern>
   </servlet-mapping>
   <servlet>
       <servlet-name>register</servlet-name>
       <servlet-class>com.feng.servlet.RegisterServlet</servlet-class>
   </servlet>
   <servlet-mapping>
       <servlet-name>register</servlet-name>
       <url-pattern>/reg</url-pattern>
       <url-pattern>/regis</url-pattern>
       <url-pattern>/register</url-pattern>
   </servlet-mapping>
   <servlet>
       <servlet-name>favicon</servlet-name>
       <servlet-class>com.feng.servlet.FaviconServlet</servlet-class>
   </servlet>
   <servlet-mapping>
       <servlet-name>favicon</servlet-name>
       <url-pattern>/favicon.ico</url-pattern>
   </servlet-mapping>

</web-app>

添加FaviconServlet

package com.feng.servlet;

import com.feng.server.Request;
import com.feng.server.Response;

public class FaviconServlet extends Servlet {
   @Override
   public void deGet(Request req, Response rep) throws Exception {

  }

   @Override
   public void doPost(Request req, Response rep) throws Exception {

  }
}

手写Javaweb服务器的更多相关文章

  1. JavaSE 手写 Web 服务器(二)

    原文地址:JavaSE 手写 Web 服务器(二) 博客地址:http://www.extlight.com 一.背景 在上一篇文章 <JavaSE 手写 Web 服务器(一)> 中介绍了 ...

  2. JavaSE 手写 Web 服务器(一)

    原文地址:JavaSE 手写 Web 服务器(一) 博客地址:http://www.extlight.com 一.背景 某日,在 Java 技术群中看到网友讨论 tomcat 容器相关内容,然后想到自 ...

  3. 黑马vue---40、结合Node手写JSONP服务器剖析JSONP原理

    黑马vue---40.结合Node手写JSONP服务器剖析JSONP原理 一.总结 一句话总结: 服务端可以返回js代码给script标签,那么标签会执行它,并且可带json字符串作为参数,这样就成功 ...

  4. 【项目】手写FTP服务器-C++实现FTP服务器

    X_FTP_server 手写FTP服务器-C++实现FTP服务器 项目Gitee链接:https://gitee.com/hsby/ftp_Server 简介 一个基于libevent的高并发FTP ...

  5. 手写Tomcat服务器

    预备知识 编写服务器用到的知识点 1) Socket 编程2) HTML3) HTTP 协议4) 反射5) XML 解析6) 服务器编写 Socket编程 https://www.cnblogs.co ...

  6. 利用html 5 websocket做个山寨版web聊天室(手写C#服务器)

    在之前的博客中提到过看到html5 的websocket后很感兴趣,终于可以摆脱长轮询(websocket之前的实现方式可以看看Developer Works上的一篇文章,有简单提到,同时也说了web ...

  7. MiniCat:手写Http服务器

    minicat 项目介绍 已实现http基础协议.参数接受.servlet.filter.cookie.多文件上传等.支持NIO. 一款轻量化Http服务器.支持bio.nio两种模式.归属Coody ...

  8. 手写网站服务器~用Python手动实现一个简单的服务器,不借助任何框架在浏览器中输出任意内容

    写在前面的一些P话: 在公司网站开发中,我们往往借助于Flask.Django等网站开发框架去提高网站开发效率.那么在面试后端开发工程师的时候,面试官可能就会问到网站开发的底层原理是什么? 我们不止仅 ...

  9. 自己手写http服务器 http响应信息的封装与测试

    package cn.edu.sss.httpServer; import java.io.BufferedWriter; import java.io.IOException; import jav ...

随机推荐

  1. 一、Git是什么?

    Git是什么? Git 是一个开源的分布式版本控制系统,用于敏捷高效地处理任何或小或大的项目. Git 是 Linus Torvalds 为了帮助管理 Linux 内核开发而开发的一个开放源码的版本控 ...

  2. uniapp vue v-html,显示富文本,内容img图片超出解决办法

    uniapp h5中,v-html,img图片中style=width:auto;会显示图片原来的尺寸,会超出屏幕,替换成width:100%,这样就不会超出屏幕 重要的地方,例如<img sr ...

  3. java 并发线程池的理解和使用

    一.为什么要用线程池 合理利用线程池能够带来三个好处. 第一:降低资源消耗.通过重复利用已创建的线程降低线程创建和销毁造成的消耗. 第二:提高响应速度.当任务到达时,任务可以不需要的等到线程创建就能立 ...

  4. 多NX如何共存

    在安装NX时,本机已经装了NX其他版本,只能修改当前程序,无法安装,那么多NX如何共存? 如图:先安装了32位NX8.5,后安装64位NX 8.5时弹的框. 解决办法有两种: 1)将已经安装的NX目录 ...

  5. xss利用——BeEF#stage4(其余功能介绍)

    目录 信息收集 => 社会工程 =>网络扫描 => 结合metasploit => tunneling => xss => 维持权限 功能介绍 #1 - 信息收集 ...

  6. 记录jmeter使用beanshell断言获取复杂的json字符串参数值

    实战示例 测试场景 电商系统经常会涉及到商品的库存数量的压测,在用户下单前需要先做库存余量的判断,当余量不足时用户无法下单,保证商品的有效售卖 库存余量查询响应结果 响应结果一般是json字符串的形式 ...

  7. 票房和口碑称霸国庆档,用 Python 爬取猫眼评论区看看电影《我和我的家乡》到底有多牛

    今年的国庆档电影市场的表现还是比较强势的,两名主力<我和我的家乡>和<姜子牙>起到了很好的带头作用. <姜子牙>首日破 2 亿,一举刷新由<哪吒之魔童降世&g ...

  8. python在一个画布上画多个子图

    转载:https://blog.csdn.net/qq_26449287/article/details/103022636 matplotlib 是可以组合许多的小图, 放在一张大图里面显示的. 使 ...

  9. 【题解】[LNOI2014]LCA

    题目戳我 \(\text{Solution:}\) 这题的转化思想很巧妙-- 考虑把\(dep\)给拆掉. 首先可以明确的是,每一个\(LCA\)一定在\(root\to z\)的路径上. 考虑一个\ ...

  10. 【题解】[SHOI2007]善意的投票 / [JLOI2010]冠军调查

    Link \(\text{Solution:}\) 我们令源点和汇点分别为睡觉和不睡觉这两种互斥的决策点.把小朋友看成点,问题转化为最小割. 每一个小朋友对自己的意愿指向的汇点/源点.容量为\(1.\ ...