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

相关文章

Java 正则表达式URL 匹配与源码全解析

《Java正则表达式URL匹配与源码全解析》在Web应用开发中,我们经常需要对URL进行格式验证,今天我们结合Java的Pattern和Matcher类,深入理解正则表达式在实际应用中... 目录1.正则表达式分解:2. 添加域名匹配 (2)3. 添加路径和查询参数匹配 (3) 4. 最终优化版本5.设计思

Java使用ANTLR4对Lua脚本语法校验详解

《Java使用ANTLR4对Lua脚本语法校验详解》ANTLR是一个强大的解析器生成器,用于读取、处理、执行或翻译结构化文本或二进制文件,下面就跟随小编一起看看Java如何使用ANTLR4对Lua脚本... 目录什么是ANTLR?第一个例子ANTLR4 的工作流程Lua脚本语法校验准备一个Lua Gramm

Java字符串操作技巧之语法、示例与应用场景分析

《Java字符串操作技巧之语法、示例与应用场景分析》在Java算法题和日常开发中,字符串处理是必备的核心技能,本文全面梳理Java中字符串的常用操作语法,结合代码示例、应用场景和避坑指南,可快速掌握字... 目录引言1. 基础操作1.1 创建字符串1.2 获取长度1.3 访问字符2. 字符串处理2.1 子字

Java Optional的使用技巧与最佳实践

《JavaOptional的使用技巧与最佳实践》在Java中,Optional是用于优雅处理null的容器类,其核心目标是显式提醒开发者处理空值场景,避免NullPointerExce... 目录一、Optional 的核心用途二、使用技巧与最佳实践三、常见误区与反模式四、替代方案与扩展五、总结在 Java

基于Java实现回调监听工具类

《基于Java实现回调监听工具类》这篇文章主要为大家详细介绍了如何基于Java实现一个回调监听工具类,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录监听接口类 Listenable实际用法打印结果首先,会用到 函数式接口 Consumer, 通过这个可以解耦回调方法,下面先写一个

使用Java将DOCX文档解析为Markdown文档的代码实现

《使用Java将DOCX文档解析为Markdown文档的代码实现》在现代文档处理中,Markdown(MD)因其简洁的语法和良好的可读性,逐渐成为开发者、技术写作者和内容创作者的首选格式,然而,许多文... 目录引言1. 工具和库介绍2. 安装依赖库3. 使用Apache POI解析DOCX文档4. 将解析

Java字符串处理全解析(String、StringBuilder与StringBuffer)

《Java字符串处理全解析(String、StringBuilder与StringBuffer)》:本文主要介绍Java字符串处理全解析(String、StringBuilder与StringBu... 目录Java字符串处理全解析:String、StringBuilder与StringBuffer一、St

springboot整合阿里云百炼DeepSeek实现sse流式打印的操作方法

《springboot整合阿里云百炼DeepSeek实现sse流式打印的操作方法》:本文主要介绍springboot整合阿里云百炼DeepSeek实现sse流式打印,本文给大家介绍的非常详细,对大... 目录1.开通阿里云百炼,获取到key2.新建SpringBoot项目3.工具类4.启动类5.测试类6.测

Spring Boot循环依赖原理、解决方案与最佳实践(全解析)

《SpringBoot循环依赖原理、解决方案与最佳实践(全解析)》循环依赖指两个或多个Bean相互直接或间接引用,形成闭环依赖关系,:本文主要介绍SpringBoot循环依赖原理、解决方案与最... 目录一、循环依赖的本质与危害1.1 什么是循环依赖?1.2 核心危害二、Spring的三级缓存机制2.1 三

在Spring Boot中浅尝内存泄漏的实战记录

《在SpringBoot中浅尝内存泄漏的实战记录》本文给大家分享在SpringBoot中浅尝内存泄漏的实战记录,结合实例代码给大家介绍的非常详细,感兴趣的朋友一起看看吧... 目录使用静态集合持有对象引用,阻止GC回收关键点:可执行代码:验证:1,运行程序(启动时添加JVM参数限制堆大小):2,访问 htt