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 @RestControllerAdvice全局异常处理最佳实践

《SpringBoot@RestControllerAdvice全局异常处理最佳实践》本文详解SpringBoot中通过@RestControllerAdvice实现全局异常处理,强调代码复用、统... 目录前言一、为什么要使用全局异常处理?二、核心注解解析1. @RestControllerAdvice2

Spring IoC 容器的使用详解(最新整理)

《SpringIoC容器的使用详解(最新整理)》文章介绍了Spring框架中的应用分层思想与IoC容器原理,通过分层解耦业务逻辑、数据访问等模块,IoC容器利用@Component注解管理Bean... 目录1. 应用分层2. IoC 的介绍3. IoC 容器的使用3.1. bean 的存储3.2. 方法注

Spring事务传播机制最佳实践

《Spring事务传播机制最佳实践》Spring的事务传播机制为我们提供了优雅的解决方案,本文将带您深入理解这一机制,掌握不同场景下的最佳实践,感兴趣的朋友一起看看吧... 目录1. 什么是事务传播行为2. Spring支持的七种事务传播行为2.1 REQUIRED(默认)2.2 SUPPORTS2

怎样通过分析GC日志来定位Java进程的内存问题

《怎样通过分析GC日志来定位Java进程的内存问题》:本文主要介绍怎样通过分析GC日志来定位Java进程的内存问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、GC 日志基础配置1. 启用详细 GC 日志2. 不同收集器的日志格式二、关键指标与分析维度1.

Java进程异常故障定位及排查过程

《Java进程异常故障定位及排查过程》:本文主要介绍Java进程异常故障定位及排查过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、故障发现与初步判断1. 监控系统告警2. 日志初步分析二、核心排查工具与步骤1. 进程状态检查2. CPU 飙升问题3. 内存

java中新生代和老生代的关系说明

《java中新生代和老生代的关系说明》:本文主要介绍java中新生代和老生代的关系说明,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、内存区域划分新生代老年代二、对象生命周期与晋升流程三、新生代与老年代的协作机制1. 跨代引用处理2. 动态年龄判定3. 空间分

Java设计模式---迭代器模式(Iterator)解读

《Java设计模式---迭代器模式(Iterator)解读》:本文主要介绍Java设计模式---迭代器模式(Iterator),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,... 目录1、迭代器(Iterator)1.1、结构1.2、常用方法1.3、本质1、解耦集合与遍历逻辑2、统一

Java内存分配与JVM参数详解(推荐)

《Java内存分配与JVM参数详解(推荐)》本文详解JVM内存结构与参数调整,涵盖堆分代、元空间、GC选择及优化策略,帮助开发者提升性能、避免内存泄漏,本文给大家介绍Java内存分配与JVM参数详解,... 目录引言JVM内存结构JVM参数概述堆内存分配年轻代与老年代调整堆内存大小调整年轻代与老年代比例元空

深度解析Java DTO(最新推荐)

《深度解析JavaDTO(最新推荐)》DTO(DataTransferObject)是一种用于在不同层(如Controller层、Service层)之间传输数据的对象设计模式,其核心目的是封装数据,... 目录一、什么是DTO?DTO的核心特点:二、为什么需要DTO?(对比Entity)三、实际应用场景解析

Java 线程安全与 volatile与单例模式问题及解决方案

《Java线程安全与volatile与单例模式问题及解决方案》文章主要讲解线程安全问题的五个成因(调度随机、变量修改、非原子操作、内存可见性、指令重排序)及解决方案,强调使用volatile关键字... 目录什么是线程安全线程安全问题的产生与解决方案线程的调度是随机的多个线程对同一个变量进行修改线程的修改操