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中的@Autowired自动注入的工作原理及实践应用

《深入浅出Spring中的@Autowired自动注入的工作原理及实践应用》在Spring框架的学习旅程中,@Autowired无疑是一个高频出现却又让初学者头疼的注解,它看似简单,却蕴含着Sprin... 目录深入浅出Spring中的@Autowired:自动注入的奥秘什么是依赖注入?@Autowired

Spring 依赖注入与循环依赖总结

《Spring依赖注入与循环依赖总结》这篇文章给大家介绍Spring依赖注入与循环依赖总结篇,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录1. Spring 三级缓存解决循环依赖1. 创建UserService原始对象2. 将原始对象包装成工

Java中如何正确的停掉线程

《Java中如何正确的停掉线程》Java通过interrupt()通知线程停止而非强制,确保线程自主处理中断,避免数据损坏,线程池的shutdown()等待任务完成,shutdownNow()强制中断... 目录为什么不强制停止为什么 Java 不提供强制停止线程的能力呢?如何用interrupt停止线程s

SpringBoot请求参数传递与接收示例详解

《SpringBoot请求参数传递与接收示例详解》本文给大家介绍SpringBoot请求参数传递与接收示例详解,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋... 目录I. 基础参数传递i.查询参数(Query Parameters)ii.路径参数(Path Va

SpringBoot路径映射配置的实现步骤

《SpringBoot路径映射配置的实现步骤》本文介绍了如何在SpringBoot项目中配置路径映射,使得除static目录外的资源可被访问,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一... 目录SpringBoot路径映射补:springboot 配置虚拟路径映射 @RequestMapp

Java MCP 的鉴权深度解析

《JavaMCP的鉴权深度解析》文章介绍JavaMCP鉴权的实现方式,指出客户端可通过queryString、header或env传递鉴权信息,服务器端支持工具单独鉴权、过滤器集中鉴权及启动时鉴权... 目录一、MCP Client 侧(负责传递,比较简单)(1)常见的 mcpServers json 配置

GSON框架下将百度天气JSON数据转JavaBean

《GSON框架下将百度天气JSON数据转JavaBean》这篇文章主要为大家详细介绍了如何在GSON框架下实现将百度天气JSON数据转JavaBean,文中的示例代码讲解详细,感兴趣的小伙伴可以了解下... 目录前言一、百度天气jsON1、请求参数2、返回参数3、属性映射二、GSON属性映射实战1、类对象映

Web服务器-Nginx-高并发问题

《Web服务器-Nginx-高并发问题》Nginx通过事件驱动、I/O多路复用和异步非阻塞技术高效处理高并发,结合动静分离和限流策略,提升性能与稳定性... 目录前言一、架构1. 原生多进程架构2. 事件驱动模型3. IO多路复用4. 异步非阻塞 I/O5. Nginx高并发配置实战二、动静分离1. 职责2

Java Stream 并行流简介、使用与注意事项小结

《JavaStream并行流简介、使用与注意事项小结》Java8并行流基于StreamAPI,利用多核CPU提升计算密集型任务效率,但需注意线程安全、顺序不确定及线程池管理,可通过自定义线程池与C... 目录1. 并行流简介​特点:​2. 并行流的简单使用​示例:并行流的基本使用​3. 配合自定义线程池​示

从原理到实战解析Java Stream 的并行流性能优化

《从原理到实战解析JavaStream的并行流性能优化》本文给大家介绍JavaStream的并行流性能优化:从原理到实战的全攻略,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的... 目录一、并行流的核心原理与适用场景二、性能优化的核心策略1. 合理设置并行度:打破默认阈值2. 避免装箱