javaWeb--手写Servlet容器--增加cookiesession版

2024-02-07 23:32

本文主要是介绍javaWeb--手写Servlet容器--增加cookiesession版,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

主类:

public class Catalina {static {try {Container.WEB_CONFIG.load(Catalina.class.getClassLoader().getResourceAsStream("web.properties"));} catch (IOException e) {e.printStackTrace();}}public static void main(String[] args) throws Exception{ServerSocket server = new ServerSocket();server.bind(new InetSocketAddress(7777));while (true){Socket accept = server.accept();//★获得请求:StringBuilder sb = new StringBuilder();InputStream in = accept.getInputStream();int len;byte[] buf = new byte[512];while ((len = in.read(buf)) != -1) {sb.append(new String(buf, 0, len));if (len < buf.length) {accept.shutdownInput();}}// 把请求封装成request对象  构建一个请求对象Request request = Request.buildRequest(sb.toString());request.setRemoteHost(accept.getInetAddress().getHostAddress());String url = request.getUrl();if("/favicon.ico".equals(url)){continue;}//先去容器里找,通过请求的url获取一个servlet,如果有则返回Servlet servlet = Container.SERVLET_CONTAINER.get(url);if(servlet==null){★★★//若容器里没有,去★★★配置文件★★★中找★★//url是个变量,对应着配置文件中各种servlet。String fullClassName = Container.WEB_CONFIG.getProperty(url);if(!"".equals(fullClassName) && fullClassName!=null){servlet = (Servlet)Class.forName(fullClassName).newInstance();}else {servlet = new IndexServlet();}Container.SERVLET_CONTAINER.put(url,servlet);}//构建一个响应Response response = new Response();response.setOs(accept.getOutputStream());
if(request.getHeaders().get("cookie")==null || !request.getHeaders().get("cookie").contains("jsessionid")) {String jsessionid = UUID.randomUUID().toString();Container.SESSIONS.put(jsessionid,new HashMap<>(8));response.addHeader("set-cookie","jsessionid="+jsessionid);}
//          把请求和响应交给servlet处理servlet.service(request,response);}}
}

容器:

public class Container {public final static Properties WEB_CONFIG=new Properties(); //存配置信息public final static HashMap<String,Servlet> SERVLET_CONTAINER =new HashMap<>(8);
public final static Map<String, Map<String,Object>> SESSIONS =new HashMap<>(8);}

Servlet接口:

public interface Servlet {void init();void service(Request request,Response response);void destroy();
}

Request:

public class Request {private String type;private String url;private String protocol;private String contentType;private String remoteHost;private Map<String,String> headers = new HashMap<>(8);private Map<String,String> attributes = new HashMap<>(8);public String getType() {return type;}public void setType(String type) {this.type = type;}public String getUrl() {return url;}public void setUrl(String url) {this.url = url;}public String getProtocol() {return protocol;}public void setProtocol(String protocol) {this.protocol = protocol;}public String getContentType() {return contentType;}public void setContentType(String contentType) {this.contentType = contentType;}public Map<String, String> getHeaders() {return headers;}public void setHeaders(Map<String, String> headers) {this.headers = headers;}public Map<String, String> getAttributes() {return attributes;}public void setAttributes(Map<String, String> attributes) {this.attributes = attributes;}public String getRemoteHost() {return remoteHost;}public void setRemoteHost(String remoteHost) {this.remoteHost = remoteHost;}@Overridepublic String toString() {return "Request{" +"type='" + type + '\'' +", url='" + url + '\'' +", protocol='" + protocol + '\'' +", contentType='" + contentType + '\'' +", headers=" + headers +", attributes=" + attributes +'}';}// 通过请求的报文字符串构建一个请求对象public static Request buildRequest(String requestStr){Request request = new Request();String[] split = requestStr.split("\r\n\r\n");// 请求行String[] lineAndHeader = split[0].split("\r\n");String[] lines = lineAndHeader[0].split(" ");request.setType(lines[0]);request.setUrl(lines[1]);request.setProtocol(lines[2]);// 遍历,获取请求头for (int i = 1; i < lineAndHeader.length; i++) {String[] header = lineAndHeader[i].split(": ");request.getHeaders().put(header[0].trim().toLowerCase(),header[1].trim());}request.setContentType(request.getHeaders().get("content-type"));// 处理请求体if (split.length == 2){// 可以自己使用postman模拟一个post请求进行分割和存储}return request;}
}

Response:

public class Response {private String protocol = "HTTP/1.1";private Integer code = 200;private String msg = "OK";private String ContentType = "text/html;charset=utf-8";private String ContentLength;private Map<String,String > headers = new HashMap(){{put("content-type",ContentType);}};private String data;private OutputStream os;public Response(){}public Response(String protocol, Integer code, String msg) {this.protocol = protocol;this.code = code;this.msg = msg;}/*** 构建响应* @return*/public String buildResponse(){StringBuilder sb = new StringBuilder();sb.append(this.getProtocol()).append(" ").append(this.getCode()).append(" ").append(this.getMsg()).append("\r\n");for (Map.Entry<String,String> entry : this.getHeaders().entrySet()){sb.append(entry.getKey()).append(": ").append(entry.getValue()).append("\r\n");}sb.append("\r\n").append(this.getData());return sb.toString();}/*** 输出响应* @param*/public void write(){try {os.write(buildResponse().getBytes());} catch (IOException e) {e.printStackTrace();} finally {if(os != null){try {os.close();} catch (IOException e) {e.printStackTrace();}}}}public void write(String content){this.setData(content);this.write();}/*** 加一个响应头* @param key* @param value*/public void addHeader(String key,String value){this.getHeaders().put(key,value);}public String getProtocol() {return protocol;}public void setProtocol(String protocol) {this.protocol = protocol;}public Integer getCode() {return code;}public void setCode(Integer code) {this.code = code;}public String getMsg() {return msg;}public void setMsg(String msg) {this.msg = msg;}public Map<String, String> getHeaders() {return headers;}public String getData() {return data;}public void setData(String data) {this.data = data;this.setContentLength(data.getBytes().length+"");}public OutputStream getOs() {return os;}public void setOs(OutputStream os) {this.os = os;}public String getContentType() {return this.getHeaders().get("content-type");}public void setContentType(String contentType) {this.getHeaders().put("content-type",contentType);}public String getContentLength() {return  this.getHeaders().get("content-length");}public void setContentLength(String contentLength) {this.getHeaders().put("content-length",this.data.getBytes().length + "");}
}

配置文件web.properties:

/index=com.itnls.Tomcat.servlet.IndexServlet
/home=com.itnls.Tomcat.servlet.HomeServlet
/order=com.itnls.Tomcat.servlet.OrderServlet
/user=com.itnls.Tomcat.servlet.UserServlet

HttpUtils:

public class HttpUtils {// 使用流获得页面的字符串public static String getPage(String url){StringBuilder sb = new StringBuilder();try {if ("".equals(url) || "/".equals(url) || url == null){url = "index.html";}// 寻找绝对的父路劲String path = Test.class.getProtectionDomain().getCodeSource().getLocation().getPath();path = path.substring(0,path.lastIndexOf("/")) + "/pages/";url = path + url;boolean exists = new File(url).exists();if (!exists){url = path +"404.html";}InputStream resource = new FileInputStream(url);byte[] buf = new byte[1024];int len;while ((len = resource.read(buf)) != -1){sb.append(new String(buf,0,len));}} catch (Exception e){e.printStackTrace();}return sb.toString();}}

GenericServlet抽离冗余方法:

/*** 抽离冗余代码,新建servlet的时候就不必再实现一遍两个方法了*/public abstract class GenericServlet implements Servlet {@Overridepublic void init() {}@Overridepublic void destroy() {}
}

OrderServlet继承GenericServlet:

public class OrderServlet extends GenericServlet {@Overridepublic void service(Request request, Response response) {}
}

HttpServlet继承genericservlet:

public class HttpServlet extends GenericServlet {@Overridepublic void service(Request request, Response response) {if("GET".equals(request.getType())){this.doGet(request,response);}else if("POST".equals(request.getType())){this.doPost(request,response);}}public void doGet(Request request, Response response){}public void doPost(Request request, Response response){}
}

UserServlet继承HttpServlet:

public class UserServlet extends HttpServlet {@Overridepublic void doGet(Request request, Response response) {response.write("<h1>hahaha,user!</h1>");}
}

IndexServlet实现Servlet接口(有cookie):

public class IndexServlet implements Servlet {//让init在创建的时候就开始执行一次public IndexServlet(){init();}/*** init只会调用一次*/@Overridepublic void init() {}@Overridepublic void service(Request request, Response response) {String cookie = request.getHeaders().get("cookie");if(cookie==null){response.write("<h1>login please!!</h1>");}else{String sessionId = cookie.split("=")[1];Map<String, Object> session = Container.SESSIONS.get(sessionId);session.put("user","zhangsan");response.write("<h1>登陆成功!</h1>");}}@Overridepublic void destroy() {}
}

HomeServlet实现Servlet接口(有cookie):

public class HomeServlet implements Servlet {public static final List<String> BLACK_NAMES =new ArrayList(){{add("192.168.67.66");}};public HomeServlet(){init();}@Overridepublic void init() {}@Overridepublic void service(Request request, Response response) {String cookie = request.getHeaders().get("cookie");if(cookie==null){response.write("<h1>login please!!</h1>");}else{String sessionId = cookie.split("=")[1];Map<String, Object> session = Container.SESSIONS.get(sessionId);if(session==null || session.get("user")==null){response.write("<h1>未登录</h1>");}else{response.write("<h1>你好"+ session.get("user") +"</h1>");}}}@Overridepublic void destroy() {}
}

这篇关于javaWeb--手写Servlet容器--增加cookiesession版的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/689248

相关文章

Spring boot整合dubbo+zookeeper的详细过程

《Springboot整合dubbo+zookeeper的详细过程》本文讲解SpringBoot整合Dubbo与Zookeeper实现API、Provider、Consumer模式,包含依赖配置、... 目录Spring boot整合dubbo+zookeeper1.创建父工程2.父工程引入依赖3.创建ap

SpringBoot结合Docker进行容器化处理指南

《SpringBoot结合Docker进行容器化处理指南》在当今快速发展的软件工程领域,SpringBoot和Docker已经成为现代Java开发者的必备工具,本文将深入讲解如何将一个SpringBo... 目录前言一、为什么选择 Spring Bootjavascript + docker1. 快速部署与

Spring Boot spring-boot-maven-plugin 参数配置详解(最新推荐)

《SpringBootspring-boot-maven-plugin参数配置详解(最新推荐)》文章介绍了SpringBootMaven插件的5个核心目标(repackage、run、start... 目录一 spring-boot-maven-plugin 插件的5个Goals二 应用场景1 重新打包应用

SpringBoot+EasyExcel实现自定义复杂样式导入导出

《SpringBoot+EasyExcel实现自定义复杂样式导入导出》这篇文章主要为大家详细介绍了SpringBoot如何结果EasyExcel实现自定义复杂样式导入导出功能,文中的示例代码讲解详细,... 目录安装处理自定义导出复杂场景1、列不固定,动态列2、动态下拉3、自定义锁定行/列,添加密码4、合并

Spring Boot集成Druid实现数据源管理与监控的详细步骤

《SpringBoot集成Druid实现数据源管理与监控的详细步骤》本文介绍如何在SpringBoot项目中集成Druid数据库连接池,包括环境搭建、Maven依赖配置、SpringBoot配置文件... 目录1. 引言1.1 环境准备1.2 Druid介绍2. 配置Druid连接池3. 查看Druid监控

Java中读取YAML文件配置信息常见问题及解决方法

《Java中读取YAML文件配置信息常见问题及解决方法》:本文主要介绍Java中读取YAML文件配置信息常见问题及解决方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要... 目录1 使用Spring Boot的@ConfigurationProperties2. 使用@Valu

创建Java keystore文件的完整指南及详细步骤

《创建Javakeystore文件的完整指南及详细步骤》本文详解Java中keystore的创建与配置,涵盖私钥管理、自签名与CA证书生成、SSL/TLS应用,强调安全存储及验证机制,确保通信加密和... 目录1. 秘密键(私钥)的理解与管理私钥的定义与重要性私钥的管理策略私钥的生成与存储2. 证书的创建与

浅析Spring如何控制Bean的加载顺序

《浅析Spring如何控制Bean的加载顺序》在大多数情况下,我们不需要手动控制Bean的加载顺序,因为Spring的IoC容器足够智能,但在某些特殊场景下,这种隐式的依赖关系可能不存在,下面我们就来... 目录核心原则:依赖驱动加载手动控制 Bean 加载顺序的方法方法 1:使用@DependsOn(最直

SpringBoot中如何使用Assert进行断言校验

《SpringBoot中如何使用Assert进行断言校验》Java提供了内置的assert机制,而Spring框架也提供了更强大的Assert工具类来帮助开发者进行参数校验和状态检查,下... 目录前言一、Java 原生assert简介1.1 使用方式1.2 示例代码1.3 优缺点分析二、Spring Fr

java使用protobuf-maven-plugin的插件编译proto文件详解

《java使用protobuf-maven-plugin的插件编译proto文件详解》:本文主要介绍java使用protobuf-maven-plugin的插件编译proto文件,具有很好的参考价... 目录protobuf文件作为数据传输和存储的协议主要介绍在Java使用maven编译proto文件的插件