java 手写服务器httpserver_201_封装Request_储存参数_处理中文_练习

package 手写服务器httpserver_201_封装Request_储存参数_处理中文;

import java.io.IOException;
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;

/**

  • Request封装 请求端
    /
    public class Request {
    //请求方式
    private String method;//method方法
    private String url;//请求资源
    //请求参数:Map映射;List目录,可能是多个;parameterMapValues参数映射值
    private Map<String,List> parameterMapValues;
    //内部常量
    //定义一个字符串常量 便于后面使用
    public static final String CRLF = “\r\n”;//final最终的;CRLF换行符
    //定义空格便于后面使用
    public static final String BLANK = " “;//BLANK空格
    private InputStream is;//输入流
    //请求信息
    private String requestInfo;//requestInfo请求信息
    public Request() {//空参
    //初始化 避免空指针异常
    method = “”;
    url = “”;
    //在界面获取的都是字符串 ,以后需要什么类型在转
    parameterMapValues = new HashMap<String,List>();
    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 (IOException e) {
    return ;//如果报错 就停止
    }
    parseRequestInfo();//分析头信息
    }
    //创建方法;分析请求信息 即分解字符串
    private void parseRequestInfo(){//parseRequestInfo解析请求信息
    //如果为空或者 遇到空格就停止
    if(null==requestInfo||(requestInfo=requestInfo.trim()).equals(”")){
    return;
    }
    /
    *
    * ================================================
    *1.从信息的首行分解出:请求方式,请求路径,请求参数 (get可能存在)
    * 如:GET /index.html?uname=aaa&pwd=1234567 HTTP/1.1
    *2.如果为post方式,请求参数可能在正文最后中
    * 思路:1.请求方法:找出第一个/截取即可 2.请求资源:找出第一个/HTTP
    */
    String paramString = “”;//接收请求参数;paramString参数的字符串
    //获取请求方式 firstLine第一行;substring子字符串;indexOf 查找字符或者子串第一次出现的地方
    String firstLine = requestInfo.substring(0,requestInfo.indexOf(CRLF));//获取第一行0至换行
    //获取第一行首位字符串
    int idx = requestInfo.indexOf("/");//记录’/‘的位置
    this.method = firstLine.substring(0,idx).trim();//trim修剪,整理
    String urlstr = firstLine.substring(idx,firstLine.indexOf(“HTTP/”)).trim();//indexOf 查找字符或者子串第一次出现的地方
    //这里只判断2种方式
    if(this.method.equalsIgnoreCase(“post”)){//IgnoreCase忽略大小写
    this.url = urlstr;
    paramString = requestInfo.substring(requestInfo.lastIndexOf(CRLF)).trim();//lastIndexOf 查找字符或者子串是最后一次出现的地方
    }else if(this.method.equalsIgnoreCase(“get”)){
    if(urlstr.contains("?")){//是否存在参数;contains包含
    //如果存在 就要分割数组
    String[] urlArray = urlstr.split("\?");//如果使用split’;’?'是特殊符号需要加\
    this.url = urlArray[0];//开始位置
    paramString = urlArray[1];//接收请求参数

     	}else{
     		this.url = urlstr;
     	}
     }
     //判断
     if(paramString.equals("")){//不存在请求参数   
     	return;
     }
     //如果从存在就封装到Map里面
     parseParams(paramString);//这个方法不是任何时候都调用,只有paramString =  urlArray[1];存在时才调用	  
    

    }
    //将 请求参数封装到Map中 好处是快速获取

    private void parseParams(String paramString){//parseParams解析参数;paramString参数的字符串
    //分割;将字符串转成数组;StringTokenizer字符分解器
    StringTokenizer token = new StringTokenizer(paramString,"&");
    while(token.hasMoreTokens()){//hasMoreTokens得到更多的标记字符串
    String keyValue = token.nextToken();//nextToken下一个标记字符串
    //继续分割
    String[] keyValues = keyValue.split("=");//split分割
    //判断
    if(keyValues.length1){
    keyValues = Arrays.copyOf(keyValues, 2);//数组的拷贝
    keyValues[1] = null;
    }
    //设置键与值
    String key = keyValues[0].trim();
    //这里增加中文解码方法decode();gbk简体中文(GBK)
    String value = null
    keyValues[1]?null:decode(keyValues[1].trim(),“gbk”);//先判断如果等于null就是1即本身;否则就去下空
    //转成Map 如果不存在就放进去
    if(!parameterMapValues.containsKey(key)){//containsKey判断是否包含查找的是键
    parameterMapValues.put(key,new ArrayList());//ArrayList数组列表;put放
    }

     	List<String> values = parameterMapValues.get(key);//拿到容器
     	values.add(value);//加个多个
     }	 
    

    }
    /**

    • 增加 中文解码方法

    • decode解码器
      /
      private String decode(String value, String code){//value值;code代码
      try {
      return java.net.URLDecoder.decode(value,code);//java.net.URLDecoderjavanet URL解码器;(value,code)解码value及编码格式code
      } catch (UnsupportedEncodingException e) {
      //e.printStackTrace();
      }
      return null;
      }
      /
      *

    • 根据页面name 获取对应的多个值

    • @param name

    • @return
      */
      public String[] getParameterValues(String name){

      List values = null;
      if((values=parameterMapValues.get(name))==null){
      return null;
      }else{
      return values.toArray(new String[0]);
      }
      }
      /**

    • 根据页面获取对应的值;这是一个值

    • @param args
      */
      public String getParameter(String name){
      String[] values = getParameterValues (name);
      if(null==values){
      return null;
      }
      return values[0];
      }
      public String getUrl() {
      return url;
      }

}
//------------服务器端-------------------------------------------
package 手写服务器httpserver_201_封装Request_储存参数_处理中文;

import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Date;

/**

  • 创建服务器并启动

  • 1.请求

  • 2.响应 :在接收客户端
    */
    public class Server5 {//Server 服务器
    private ServerSocket server;
    //定义一个字符串常量 便于后面使用
    public static final String CRLF = “\r\n”;//final最终的;CRLF换行符
    //定义空格便于后面使用
    public static final String BLANK = " ";//BLANK空格

    public static void main(String[] args) {
    Server5 server = new Server5();
    server.start();//调用
    }

    /**

    • 创建一个方法 便于使用:启动
      /
      public void start(){//start启动
      try {
      server = new ServerSocket(8888);
      this.receive();//调用;启动时就准备接收
      } catch (IOException e) {
      e.printStackTrace();
      }
      }
      /
      *

    • 接收客户端
      */
      private void receive(){//receive接收
      try {
      Socket client = server.accept();//Server 服务器;accept接受
      //请求
      Request req = new Request(client.getInputStream());

      //响应 封装
      Response rep = new Response(client.getOutputStream());
      rep.println("<html><head><title>HTTP响应示例</title>");
      //获取请求
      rep.println("</head><body>");
      rep.println("欢迎:").println(req.getParameter("uname")).println("回来");
      rep.println("</body></html>");		
      //发送命令
      rep.pushToClient(200);//pushToClient推动客户
      

      } catch (IOException e) {

      }
      }
      /**

    • 停止服务器
      */
      public void stop(){//stop停止
      }
      }
      //------响应端-----------------------------------------------------------------
      package 手写服务器httpserver_201_封装Request_储存参数_处理中文;

import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.util.Date;

/**

  • 封装响应信息

*/
public class Response {
//定义一个字符串常量 便于后面使用
public static final String CRLF = “\r\n”;//final最终的;CRLF换行符
//定义空格便于后面使用
public static final String BLANK = " ";//BLANK空格
//推送流
private BufferedWriter bw;
//正文
private StringBuilder content;//StringBuilder可变的字符序列;content内容
//存储头信息
private StringBuilder headInfo;//StringBuilder可变的字符序列;headInfo头信息
//存储正文长度
private int len = 0;
//构造器
public Response() {
headInfo = new StringBuilder();
content = new StringBuilder();
//重新构建 正文长度有可能是变化的
len = 0;
}

public Response(OutputStream  os) {
	this();//构造器的相互调用
	bw = new BufferedWriter(
			new OutputStreamWriter(os));
} 

public Response(Socket client) {
	this();//构造器的相互调用
	try {
		bw = new BufferedWriter(
				new OutputStreamWriter(client.getOutputStream()));//处理异常
	} catch (IOException e) {
		headInfo = null;//如果报错 就为空 在下面'推送到客户端'增加一个判断
	}
} 

/**
 * 正文是外部构建
 * @return 
 */
public Response println(String info){//Response响应
	//不断构建
	content.append(info).append(CRLF);//getBytes
	 //长度不断变化
	len+=(info+CRLF).getBytes().length;//getBytes中文字符串;因为CRLF也占位置所以加上
			
	return this;
}  
/**
 * 构建响应头;内部构建
 */
private void createHeadInfo(int code){//createHeadInfo创建的头信息;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");//NOT FOUND无法找到
			break;
		case 500:
			headInfo.append("SEVER ERROR");//SEVER ERROR服务器错误
			break;	
	}
	headInfo.append(CRLF);//加入空格BLANK
	//2.响应头(Response Head)
	headInfo.append("Server:bjsxt Server/0.0.1").append(CRLF);//0.0.1版本号
	//日期
	headInfo.append("Date:").append(new Date()).append(CRLF);//获取当前时间
	//正文的类型及编码格式
	headInfo.append("Content-Type:Text/html;charset=gbk").append(CRLF);//GBK汉字内码扩展规范简体中文
	//处理正文的长度   
	headInfo.append("Content-Length:").append(len).append(CRLF);
	//分隔符
	headInfo.append(CRLF);//与正文分开的空格区域
}
/**
 * 推送到客户端方法
 * @throws IOException 
 */
void pushToClient(int code) throws IOException{//pushToClient推动客户
	if(null==headInfo){
		code = 200;
	}
	//构建头
	createHeadInfo(code);
	//头信息+分隔符
	bw.append(headInfo.toString());//处理异常
	//正文
	bw.append(content.toString());
	bw.flush();
}
/**
 * 关闭
 */
public void close(){
	CloseUtil.closeIO(bw);
}

}
//-----------关闭流方法--------------------------------------
package 手写服务器httpserver_201_封装Request_储存参数_处理中文;

import java.io.Closeable;
import java.io.IOException;
import java.net.DatagramSocket;
import java.net.ServerSocket;
import java.net.Socket;

/**

  • 关闭流的方法
    /
    public class CloseUtil {//CloseUtil关闭所有的
    /
    *

    • 关闭IO流

    • @param io
      /
      /public static void closeIO(Closeable…io){//closeAll全部关闭;Closeable可关闭的参数
      //判断
      for(Closeable temp:io){
      try {
      if(null!=temp){
      temp.close();//处理异常
      }
      } catch (IOException e) {
      e.printStackTrace();
      }
      }
      }
      /
      /
      *

    • 使用泛型实现关闭IO流
      */
      public static void closeIO(T…io){
      for(Closeable temp:io){
      try {
      if(null!=temp){
      temp.close();//处理异常
      }
      } catch (IOException e) {
      e.printStackTrace();
      }
      }
      }
      public static void closeSocket(ServerSocket socket){
      try {
      if(null!=socket){
      socket.close();//处理异常
      }
      } catch (IOException e) {
      e.printStackTrace();
      }
      }
      public static void closeSocket(Socket socket){
      try {
      if(null!=socket){
      socket.close();//处理异常
      }
      } catch (IOException e) {
      e.printStackTrace();
      }
      }
      public static void closeSocket(DatagramSocket socket){

       if(null!=socket){
       	socket.close();//处理异常
       }
      

    }
    }
    //结果-------------------------------------------------
    浏览器运行出现乱码 解决方法
    编码要一致
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

在这里插入图片描述
1.启动服务器
2.启动浏览器 输入内容 密码随意
在这里插入图片描述
测试结果成功
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值