深度理解Tomcat底层机制
Tomcat
- Tomcat
大家好呀,我是小笙,我和大家分享下我学习Javaweb的笔记
Tomcat
概述
BS 与 CS 开发介绍
(1) 兼容性 , 浏览器的种类很多
(2) 安全性, 通常情况下,BS 安全性不如 CS 好控制
(3) 易用性, BS 好于 CS, 浏览器方便在线使用
(4) 扩展性, BS 相对统一,只需要写 Server
常用服务器
-
Tomcat:由 Apache 组织提供的一种 Web 服务器,提供对 jsp 和 Servlet 的支持。它 是一种轻量级的 javaWeb 容器(服务器),也是当前应用最广的 JavaWeb 服务器(免费),Tomcat 本质就是一个 Java 程序, 但是这个 Java 程序可以处理来自浏览器的 HTTP 请求
Tomcat下载网址
-
Jboss:是一个遵从 JavaEE 规范的、它支持所有的 JavaEE 规范(免费)
-
GlassFish: 由 Oracle 公司开发的一款 JavaWeb 服务器,是一款商业服务器,达到产品级质量(应用很少)
-
Resin:是 CAUCHO 公司的产品,是一个非常流行的服务器,对 servlet 和 JSP 提供了 良好的支持, 性能也比较优良(收费)
-
WebLogic:是 Oracle 公司的产品,支持 JavaEE 规范, 而且不断的完善以适 应新的开发要求,适合大型项目(收费,用的不多,适合大公司)
Tomcat 目录结构
Web应用
Tomcat 服务中部署 WEB 应用
概念:Web应用通常也称之为web应用程序(网站),WEB应用是多个web资源的集合
组成
在Tomcat 下的 conf 目录\Catalina\localhost\ 下,配置文件,比如XXX.xml(提醒:通过Tomcat配置,可以把一个web应用,映射到指定的目录,可以解决磁盘空间分配问题
浏览器请求资源过程
注意:http://localhost , 默 认 是 访 问 80 端 口 , 即 http://localhost 等 价 http://localhost:80
IDEA 开发 JavaWeb 注意事项
1.热加载选项说明
2.修改端口,只会影响当前的项目,但是不会去修改tomcat文件中server.xml文件的端口
3.当tomcat启动时,会生成out目录,该目录就是原项目资源的映射,我们浏览器访问的资源是 out 目录
Maven
基本介绍
概述:一个项目管理工具,可以对 Java 项目进行构建、依赖管理
IDEA创建Maven项目说明
pom.xml文件说明
<dependencies> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> <scope>provided</scope> </dependency> </dependencies>
实现Tomcat底层机制
框架图
实现案例
题目要求
-
可以访问静态资源addSum.html
-
可以通过提交按钮,跳转到求和解结果
文件目录说明
xml文件
<myTomcat> <myServlet> <Servlet-name>myTomcat</Servlet-name> <Servlet-class>com.al_tair.myTomcat.myServlet.CalServlet</Servlet-class> </myServlet> <myServlet-mapping> <Servlet-name>myTomcat</Servlet-name> <url-pattern>/myTomcat</url-pattern> </myServlet-mapping></myTomcat>
静态资源
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>Title</title></head><body><form action="http://localhost:9999/myTomcat" method="get"> <h1>求和</h1> 第一个数字:<input type="text" name="firstNum"><br> 第二个数字:<input type="text" name="secondName"><br> <button type="submit">提交</button></form></body></html>
网络监听
public class Connector { // 存放 public static final ConcurrentHashMap<String, MyHttpServlet> nameToServlet = new ConcurrentHashMap<>(); // 存放 public static final ConcurrentHashMap<String, String> urlToName = new ConcurrentHashMap<>(); public static void main(String[] args) throws IOException, InterruptedException { // 在端口9999监听 ServerSocket serverSocket = new ServerSocket(9999); while(!serverSocket.isClosed()){ init(); // 创建套接字 socket System.out.println("listening..."); Socket socket = serverSocket.accept(); RequestHandler rh = new RequestHandler(socket); new Thread(rh).start(); } } public static void init(){ String path = Connector.class.getResource("/").getPath(); SAXReader saxReader = new SAXReader(); try { Document document = saxReader.read(new File(path + "web.xml")); // 得到根元素 Element rootElement = document.getRootElement(); // 得到根元素下的所有元素 List<Element> myServlet = rootElement.elements(); for (Element element: myServlet ) { if("myServlet".equalsIgnoreCase(element.getName())){ Element element1 = element.element("Servlet-name"); Element element2 = element.element("Servlet-class"); nameToServlet.put(element1.getText(),(MyHttpServlet)Class.forName(element2.getText()).newInstance()); }else if("myServlet-mapping".equalsIgnoreCase(element.getName())){ Element element1 = element.element("Servlet-name"); Element element2 = element.element("url-pattern"); urlToName.put(element2.getText(),element1.getText()); } } } catch (Exception e) { e.printStackTrace(); } }}
线程处理请求和响应
public class RequestHandler implements Runnable{ private Socket socket = null; public RequestHandler(Socket socket) { this.socket = socket; } @Override public void run() { MyHttpRequest Request = null; MyHttpResponse Response = null; try { Request = new MyHttpRequest(socket.getInputStream()); Response = new MyHttpResponse(socket.getOutputStream()); String uri = Request.getUri(); System.out.println(uri); String path = RequestHandler.class.getResource("/").getPath(); if(Connector.urlToName.containsKey(uri)){ String name = Connector.urlToName.get(uri); if(Connector.nameToServlet.containsKey(name)){ MyHttpServlet myHttpServlet = Connector.nameToServlet.get(name); try { myHttpServlet.service(Request,Response); } catch (Exception e) { e.printStackTrace(); } }else{ OutputStream outputStream = Response.getOutputStream(); int index = uri.indexOf("."); if(uri.substring(index+1).equalsIgnoreCase("html")){ try {FileReader fileReader = new FileReader(path + "/static" + uri);BufferedReader br = new BufferedReader(fileReader);String str = "";outputStream.write(Response.getResponseHeader().getBytes());while((str = br.readLine()) != null){ outputStream.write(str.getBytes());}outputStream.flush();outputStream.close(); } catch (Exception e) {e.printStackTrace(); } }else{ outputStream.write((Response.responseHeader + "404,没有找到该资源
").getBytes()); outputStream.flush(); outputStream.close(); } } }else{ OutputStream outputStream = Response.getOutputStream(); int index = uri.indexOf("."); if(uri.substring(index+1).equalsIgnoreCase("html")){ try { FileReader fileReader = new FileReader(path + "/static" + uri); BufferedReader br = new BufferedReader(fileReader); String str = ""; outputStream.write(Response.getResponseHeader().getBytes()); while((str = br.readLine()) != null){outputStream.write(str.getBytes()); } outputStream.flush(); outputStream.close(); } catch (Exception e) { e.printStackTrace(); } }else{ outputStream.write((Response.responseHeader + "404,没有找到该资源
").getBytes()); outputStream.flush(); outputStream.close(); } } socket.close(); } catch (IOException e) { throw new RuntimeException(); } }}
请求类和响应类
/** * 封装http请求数据简化 */public class MyHttpRequest { private String uri; private String method; private HashMap<String,String> parameters = new HashMap<>(); private InputStream inputStream = null; public MyHttpRequest(InputStream inputStream) {this.inputStream = inputStream;init(); } public String getUri() { return uri; } public String getMethod() { return method; } public void init(){ try { // 将字节流转换成字符流,方便读取数据 BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, "utf-8")); String request = bufferedReader.readLine(); String[] requestLine = request.split(" "); // GET /servlet?name=18 HTTP/1.1 method = requestLine[0]; int index = requestLine[1].indexOf("?"); if(index == -1){ // uri后面没有数据 uri = requestLine[1]; }else{ uri = requestLine[1].substring(0,index); String parameter = requestLine[1].substring(index+1); String[] params = parameter.split("&"); if(parameter != null && !params.equals("")){ for (String param:params ) { String[] split = param.split("="); if(split.length == 2){parameters.put(split[0],split[1]); } } } } }catch (IOException e){ throw new RuntimeException(); } } public String Parameter(String name){ if(parameters.containsKey(name)){ return parameters.get(name); }else{ return null; } }}/** * http响应头封装简化 */public class MyHttpResponse { private OutputStream outputStream = null; public String responseHeader = "HTTP/1.1 200OK\r\n" + "Content-Type:text/html;charset=utf-8\r\n\r\n"; public MyHttpResponse(OutputStream outputStream) { this.outputStream = outputStream; } public OutputStream getOutputStream() { return outputStream; } public String getResponseHeader() { return responseHeader; }}
Servlet接口实现
// Servlet接口public interface MyServlet { void init() throws Exception; void service(MyHttpRequest var1, MyHttpResponse var2) throws Exception; void destroy();}// 抽象类public abstract class MyHttpServlet implements MyServlet{ @Override public void service(MyHttpRequest request, MyHttpResponse response) throws Exception { if("GET".equals(request.getMethod())){ this.doGet(request,response); }else if("POST".equals(request.getMethod())){ this.doPost(request,response); } } @Override public void init() throws Exception { } @Override public void destroy() { } public abstract void doGet(MyHttpRequest request, MyHttpResponse response); public abstract void doPost(MyHttpRequest request, MyHttpResponse response);}// Servlet资源public class CalServlet extends MyHttpServlet{ @Override public void doGet(MyHttpRequest request, MyHttpResponse response) { String num1 = request.Parameter("firstNum"); String num2 = request.Parameter("secondName"); int sum = Utils.StringToInteger(num1, num2); OutputStream outputStream = response.getOutputStream(); try { outputStream.write((response.responseHeader + "求和: "
+ sum + "").getBytes()); outputStream.flush(); outputStream.close(); } catch (IOException e) { e.printStackTrace(); } } @Override public void doPost(MyHttpRequest request, MyHttpResponse response) { doPost(request,response); }}
工具类
public class Utils { /** * 字符串转成整数求和 */ public static int StringToInteger(String var1,String var2){ try{ return Integer.parseInt(var1) + Integer.parseInt(var2); }catch (Exception e){ System.out.println("格式输入错误"); } return 0; }}
注意细节
- 如果想要分割点号必须转义 split(“\\.”)