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

相关文章

JavaWeb-WebSocket浏览器服务器双向通信方式

《JavaWeb-WebSocket浏览器服务器双向通信方式》文章介绍了WebSocket协议的工作原理和应用场景,包括与HTTP的对比,接着,详细介绍了如何在Java中使用WebSocket,包括配... 目录一、概述二、入门2.1 POM依赖2.2 编写配置类2.3 编写WebSocket服务2.4 浏

配置springboot项目动静分离打包分离lib方式

《配置springboot项目动静分离打包分离lib方式》本文介绍了如何将SpringBoot工程中的静态资源和配置文件分离出来,以减少jar包大小,方便修改配置文件,通过在jar包同级目录创建co... 目录前言1、分离配置文件原理2、pom文件配置3、使用package命令打包4、总结前言默认情况下,

Java文件与Base64之间的转化方式

《Java文件与Base64之间的转化方式》这篇文章介绍了如何使用Java将文件(如图片、视频)转换为Base64编码,以及如何将Base64编码转换回文件,通过提供具体的工具类实现,作者希望帮助读者... 目录Java文件与Base64之间的转化1、文件转Base64工具类2、Base64转文件工具类3、

java获取图片的大小、宽度、高度方式

《java获取图片的大小、宽度、高度方式》文章介绍了如何将File对象转换为MultipartFile对象的过程,并分享了个人经验,希望能为读者提供参考... 目China编程录Java获取图片的大小、宽度、高度File对象(该对象里面是图片)MultipartFile对象(该对象里面是图片)总结java获取图片

Java通过反射获取方法参数名的方式小结

《Java通过反射获取方法参数名的方式小结》这篇文章主要为大家详细介绍了Java如何通过反射获取方法参数名的方式,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1、前言2、解决方式方式2.1: 添加编译参数配置 -parameters方式2.2: 使用Spring的内部工具类 -

Java如何获取视频文件的视频时长

《Java如何获取视频文件的视频时长》文章介绍了如何使用Java获取视频文件的视频时长,包括导入maven依赖和代码案例,同时,也讨论了在运行过程中遇到的SLF4J加载问题,并给出了解决方案... 目录Java获取视频文件的视频时长1、导入maven依赖2、代码案例3、SLF4J: Failed to lo

如何使用Spring boot的@Transactional进行事务管理

《如何使用Springboot的@Transactional进行事务管理》这篇文章介绍了SpringBoot中使用@Transactional注解进行声明式事务管理的详细信息,包括基本用法、核心配置... 目录一、前置条件二、基本用法1. 在方法上添加注解2. 在类上添加注解三、核心配置参数1. 传播行为(

在Java中使用ModelMapper简化Shapefile属性转JavaBean实战过程

《在Java中使用ModelMapper简化Shapefile属性转JavaBean实战过程》本文介绍了在Java中使用ModelMapper库简化Shapefile属性转JavaBean的过程,对比... 目录前言一、原始的处理办法1、使用Set方法来转换2、使用构造方法转换二、基于ModelMapper

JAVA调用Deepseek的api完成基本对话简单代码示例

《JAVA调用Deepseek的api完成基本对话简单代码示例》:本文主要介绍JAVA调用Deepseek的api完成基本对话的相关资料,文中详细讲解了如何获取DeepSeekAPI密钥、添加H... 获取API密钥首先,从DeepSeek平台获取API密钥,用于身份验证。添加HTTP客户端依赖使用Jav

Java实现状态模式的示例代码

《Java实现状态模式的示例代码》状态模式是一种行为型设计模式,允许对象根据其内部状态改变行为,本文主要介绍了Java实现状态模式的示例代码,文中通过示例代码介绍的非常详细,需要的朋友们下面随着小编来... 目录一、简介1、定义2、状态模式的结构二、Java实现案例1、电灯开关状态案例2、番茄工作法状态案例