JAVA实现Web服务端程序

本文档详细介绍了如何使用JAVA实现一个基于Http协议的Web服务端程序。从创建MAVEN项目开始,逐步讲解了如何导入dom4j包,创建WebServer、ClientHandler、HttpRequest、HttpResponse等核心类,并利用DOM4J解析配置文件,处理不同类型的HTTP请求,以及如何响应客户端。内容涵盖服务器启动、客户端请求处理、HTTP协议解析和响应等关键步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

基于Http协议的Web服务端程序
(使用MAVEN项目,并要导入包dom4j)
(准备主页面index.html,404页面notfound.html,标签图–页面标签左边那个图-favicon.ico 均放入文件夹webapps中)
步骤:
1.创建一个MAVEN项目,并导入dom4j(在pom.xml中下载dom4j 这是使用的是1.6.1版)
2.在主目录下创建www.core包 主目录-src/main/java
3.创建类WebServer用于启动服务器
package www.core;

import java.net.ServerSocket;
import java.net.Socket;

public class WebServer {
private ServerSocket server;

public WebServer() throws Exception{
    try {
        server=new ServerSocket(8080);//设置端口号
    } catch (Exception e) {
        e.printStackTrace();
        throw e;
    }
}
public static void main(String[] args) {
    try {
            WebServer server=new WebServer();
            server.start();
            ClientHandler ch=new ClientHandler(socket);
            Thread t=new Thread(ch);
            t.start();


    } catch (Exception e) {
        e.printStackTrace();
        System.out.println("服务器启动失败");
    }

}
public void start(){
    try {
        System.out.println("等待服务器连接...");
        Socket socket=server.accept();
    } catch (Exception e) {
        e.printStackTrace();
    }

}

}

4.创建类ClientHandler用于处理客户端请求
package www.core;

import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

/**
* 处理客户端请求
*/
public class ClientHandler implements Runnable {
private Socket socket;

//参数用于接受WebServer响应的socket
public ClientHandler(Socket socket){
    this.socket=socket;
}
/**
 * 实现Runnable接口重写run方法以便用线程控制服务器响应
 */
public void run() {
    try {
        //创建输入流,读取客户端发送的数据
        InputStream in=socket.getInputStream();
        //创建输出流,用于响应客户端
        OutputStream out=socket.getOutputStream();
    } catch (Exception e) {
        e.printStackTrace();
    }finally{
        try {
            socket.close();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

}

}
5.在主目录下创建www.http包
并创建类HttpRequest用于处理客户端输入流
package www.http;

import java.io.InputStream;

/**
* 用于处理客户端输入流
*
*/
public class HttpRequest {
/*
* HTTP协议中的请求信息格式:
* 请求行
* GET /index.html HTTP/1.1CRLF
* CR:回车 LF:换行
*/
/*
* 创建三个成员变量获取上述关键字
*/
private String method;
private String uri;
private String protocol;
/**
* 创建构造方法,处理客户端的输入流,给成员变量赋值
*/
public HttpRequest(InputStream in){
try {
String line=readLine(in);
/*
* GET /index.html HTTP/1.1CRLF
* 拆分空格符获取对应的值
*/
String[]data=line.split(“\s”);
this.method=data[0];
this.uri=data[1];
this.protocol=data[2];
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 从给定的输入流中读取一行字符串并将其返回
* @param in
* @return
*/
public String readLine(InputStream in){
/*
* GET /index.html HTTP/1.1CRLF
* CR:回车-13 LF:换行-10
*/
StringBuilder builder=new StringBuilder();
try {
int ch1=-1;
int ch2=-1;
while((ch2=in.read())!=-1){
if(ch1==13&&ch2==10){
break;
}
builder.append((char)ch2);
ch1=ch2;
}
} catch (Exception e) {
e.printStackTrace();
}
return builder.toString().trim();
}

public String getMethod() {
    return method;
}
public String getUri() {
    return uri;
}
public String getProtocol() {
    return protocol;
}

}

6.返回 类ClientHandler生成HttpRequest
HttpRequest request=new HttpRequest(in);

类ClientHandler:
package www.core;

import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

import www.http.HttpRequest;

/**
* 处理客户端请求
*/
public class ClientHandler implements Runnable {
private Socket socket;

//参数用于接受WebServer响应的socket
public ClientHandler(Socket socket){
    this.socket=socket;
}
/**
 * 实现Runnable接口重写run方法以便用线程控制服务器响应
 */
public void run() {
    try {
        //创建输入流,读取客户端发送的数据
        InputStream in=socket.getInputStream();
        //创建输出流,用于响应客户端
        OutputStream out=socket.getOutputStream();
        // 生成HttpRequest表示客户端请求信息
        HttpRequest request=new HttpRequest(in);
    } catch (Exception e) {
        e.printStackTrace();
    }finally{
        try {
            socket.close();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

}

}

7.在包www.http中创建类HttpResponse
用于HTTP响应
定义存储HTTP响应信息的成员变量并添加get set方法
package www.http;

import java.io.OutputStream;

/**
* 封装Http响应
* HTTP响应格式
* 1:状态行
* 2:响应头
* 3:响应正文
*
* 状态行由3部分组成:协议版本,数字形式的状态代码,状态描述
* 如:HTTP/1.1 200 OK CRLF
*
* 响应头 响应头注明很多返回的信息,按行输出
*
* HTTP协议要求实际响应客户端时的数据格式: HTTP/1.1 200 OK CRLF 状态行
* Content-Type:text/html CRLF 响应头信息 用来指明发送给接收者的媒体类型
* Content-Length:100CRLF 响应头信息 用来指明发送给接收者实体正文的长度(发送过去的数据的字节量)
* CRLF 单独发送
* CRLF 指明响应头全部发送完毕
* DATA 实际数据
*/
public class HttpResponse {
/*
* 响应格式中需要的信息
*/
private OutputStream out;
private int status;
private String contentType;
private int contentLength;

public HttpResponse(OutputStream out){
    this.out=out;
}

public OutputStream getOut() {
    return out;
}

public int getStatus() {
    return status;
}
public void setStatus(int status) {
    this.status = status;
}
public String getContentType() {
    return contentType;
}
public void setContentType(String contentType) {
    this.contentType = contentType;
}
public int getContentLength() {
    return contentLength;
}
public void setContentLength(int contentLength) {
    this.contentLength = contentLength;
}
public Map<Integer, String> getStatusMap() {
    return statusMap;
}   

}

因为有很多数据需要记录所以需要另一个类来封装
将这些数据作为常量封装到另一个类中,通过类名点来调用

8.在主目录下创建www.common包并创建
类HttpContext用于定义HTTP协议中相关信息
package www.common;
/**
* 定义HTTP协议中相关信息
*
*/
public class HttpContext {
//回车 换行
public static final int CR=13;
public static final int LF=10;

//状态码及状态描述
public static final int STATUS_CODE_OK=200;
public static final String STATUS_VALUE_OK="OK";
public static final int STATUS_CODE_NOT_FOUND=404;
public static final String STATUS_VALUE_NOT_FOUND="Not Found";
public static final int STATUS_CODE_ERROR=500;
public static final String STATUS_VALUE_ERROR="Internal Server Error";

}

9.回到类ClientHandler
定义response 用于响应客户端 并判断客户端请求的uri及找到请求位置(准备请求页面,在根目录下创建文件夹webapps,并准备index.html作为首页,及notfound.html作为未找到页面时的页面)
为了方便找到请求页面,(在根目录(WebServer3项目目录并创建xml文件)下创建目录config)将页面地址写到config的server.xml中(index.html及notfound.html随意准备一下即可)
server.xml


webapps
notfound.html

10.在包www.common中创建类ServerContext用于记录服务端相关信息,将其封装
以便后期会有修改
package www.common;

import java.io.File;
import java.io.FileInputStream;

import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
/**
* 记录服务端相关信息
*
*/
public class ServerContext {
public static String web_root;
public static String notFoundPage;
static{
init();
}
private static void init(){
try {
SAXReader reader=new SAXReader();
Document doc=reader.read(new FileInputStream(“config”+File.separator+”server.xml”));
Element root=doc.getRootElement();//根目录为server

        Element serviceEle=root.element("service");

        web_root=serviceEle.elementText("webroot");
        notFoundPage=serviceEle.elementText("not-found-page");

    } catch (Exception e) {
        e.printStackTrace();
    }
}

}

11.回来类ClientHandler
获取客户端请求的页面,若页面存在则为response的成员变量赋值(状态 文件类型 文件长度)
并将文件类型封装成方法便于使用
HttpResponse response=new HttpResponse(out);
if(request.getUri()!=null){
File file=new File(ServerContext.web_root+File.separator+request.getUri());
if(file.exists()){
response.setStatus(HttpContext.STATUS_CODE_OK);
response.setContentType(getContentTypeByFile(file));
response.setContentLength((int)file.length());
}
}
//获取文件类型(实际就是截取文件的后缀名)
private String getContentTypeByFile(File file){
String fileName=file.getName();
String[] data=fileName.split(“\.”);
return data[1];
}

12.因为常见的Content-Type:有多种,而第11步中只能获取后缀并不能
正确表示该类型,所以可以将所有后缀对应的类型以XML标签属性的方式
写到server.xml中,并在类ServerContext中用MAP的方式存储起来
(该标签与service同级,均在server标签中)








定义成员变量:
public static Map

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值