Tomcat概述

1、怎么描述tomcat?

Servlet规范把能够发布和运行Javaweb应用的web服务器称为’Servlet容器’,因此,可以理解为Tomcat就是一个servlet容器。

常见的web服务器(servlet容器)

  • webLogic:oracle公司,大型的JavaEE服务器,支持所有的JavaEE规范,收费的。
  • webSphere:IBM公司,大型的JavaEE服务器,支持所有的JavaEE规范,收费的。
  • JBOSS:JBOSS公司的,大型的JavaEE服务器,支持所有的JavaEE规范,收费的。
  • Tomcat:Apache基金组织,中小型的JavaEE服务器,仅仅支持少量的JavaEE规范 servlet/jsp。开源的,免费的。

2、tomcat作为servlet容器的基本功能:

就是负责接收和解析来自客户的请求,同时把客户的请求传送给响应的servlet,并把servlet的响应结果返回给客户。

3、Servlet规范规定,Servlet容器 接收请求访问特定Servlet的流程

  1. 客户发出访问特定Servlet的请求
  2. Servlet容器接收客户请求,解析请求
  3. Servlet容器创建一个ServletRequest对象,其包含客户所有请求信息。如请求头,请求正文,客户端IP地址等
  4. Servlet容器创建一个ServletResponse对象
  5. Servlet容器调用客户请求的Servlet的service()服务方法,并且把ServletRequest对象和ServletResponse对象作为参数传给该方法。
  6. Servlet从ServletRequest对象获取客户的请求信息
  7. Servlet利用ServletResponse对象生成响应结果
  8. Servlet容器把Servlet生成的响应结果发送给客户

4、tomcat的目录结构

5、tomcat处理http服务请求

servlet容器以及servlet接口,是用来实现http服务器和业务类之间的解耦。(servlet接口和servlet容器这一套规范叫做servlet规范)

tomcat按照servlet规范的要求实现了servlet容器,具有HTTP服务器的功能,提供http访问的统一入口。

6、tomcat两个核心组件

连接器 --》对外

容器 --》对内

7、coyote连接器简介

coyote是tomcat连接器框架的名称,是tomcat提供的供客户端访问的外部接口,客户端通过coyote与服务器建立连接,发送请求并接收响应 。

coyote底层封装了底层的网络通信(支持socket请求以及响应的处理),为catalina容器提供了统一的接口,是的catalina容器与具体的请求协议和IO操作方式完全解耦。

coyote将socket输入转换封装成request对象,交给catalina处理,处理完成后,通过coyote提供的response对象将结果写入输出流。

coyote作为独立的模块,只负责具体的协议和IO相关的操作,和servlet规范的实现没有直接关系,coyote生成的response和request 是通过CoyoteAdapter的service方法进一步封装servletReuqest  和 servletResponse

8、coyote中的IO模型和协议

IO模型,自8.5版本起,tomcat传输层移除了对BIO的支持,默认协议是NIO

应用层协议

tomcat为了实现支持多种IO模型和应用层协议,一个容器可以对应多个连接器(如6中的图),单独的容器或者连接器不能对外提供服务,需要组装起来才可以工作,组装后的整体叫做service组件。tomcat支持配置多个service,这样可以实现通过不同端口号来访问同一台机器上部署的不同应用。

9、coyote中的组件

1、endpoint:

通信端点,就是监听通信的端口,是具体的socket接收和发送处理器,endpoint用来实现TCP/IP协议。 Tomcat 并没有EndPoint 接口,而是提供了一个抽象类AbstractEndpoint (NioEndpoint ,Nio2Endpoint ,AprEndpoint 都继承了AbstractEndpoint) ---tomcat10.1.1源码没看到AprEndpoint

在AbstractEndpoint类中,重点关注两个内部类 (Acceptor和SocketProcessor)

1、Acceptor(tomcat10.1.1中这个已经不是内部类了)

Acceptor用于监听socket请求,代码在run()方法中

2、SocketProcessor

SocketProcessor用于处理接收到的Socket请求,它实现Runnable接口,在Run方法里 调用协议处理组件Processor进行处理。为了提高处理能力,SocketProcessor被提交到线程池来执行。而这个线程池叫作执行器(Executor)

2、processer: coyote协议处理接口

简单来说:EndPoint是用来实现TCP/IP协议;Processor用来实现HTTP协议

Processor接收来自EndPoint的Socket,读取字节流解析成Tomcat Request和Response对象,并通过Adapter将其提交到容器处理, Processor是对应用层协议的抽象。

3、ProtocolHandler : Coyote 协议接口

ProtocolHandler: Coyote 协议接口, 通过Endpoint 和 Processor , 实现针对具体协议的处理能力。

Tomcat 按照协议和I/O 提供了6个实现类 :

  • AjpNioProtocol
  • AjpAprProtocol (tomcat10.1.1中没有看到)
  • AjpNio2Protocol
  • Http11NioProtocol
  • Http11Nio2Protocol
  • Http11AprProtocol(tomcat10.1.1中没有看到)

通过Service标签中连接器Connector 的属性 protocol="HTTP/1.1 指定协议名称

 <Service name="Catalina"><Connector port="8080" protocol="HTTP/1.1"connectionTimeout="20000"redirectPort="8443" /><Connector executor="tomcatThreadPool"port="8080" protocol="HTTP/1.1"connectionTimeout="20000"redirectPort="8443" /><Connector protocol="AJP/1.3"address="::1"port="8009"redirectPort="8443" /></Service>

4、Adapter

adapter负责将request,response 转换为 servletRequest, servletResponse

调用的是CoyoteAdapter中的service方法,对请求进行解析适配后,调用容器,其中getcontianer()返回的就是Engine对象。

10、tomcat中的容器,catalina概述

Tomcat 本质上就是一款 Servlet 容器, 因此Catalina 才是 Tomcat 的核心 , 其他模块都是为Catalina 提供支撑的。

  • 通过Coyote 模块提供链接通信
  • Jasper 模块提供JSP引擎
  • Naming 提供JNDI 服务
  • Juli 提供日志服务。

11、Catalina简介,其组件的职责

Catalina负责管理Server,而Server表示着整个服务器。Server下面有多个服务Service,每个服务都包含着多个连接器组件ConnectorCoyote 实现)和一个容器组件Container。在Tomcat 启动的时候, 会初始化一个Catalina的实例。 

12、container容器的结构

Tomcat设计了4种容器,分别是Engine、Host、Context和Wrapper。这4种容器不是平行关系,而是父子关系。 Tomcat通过一种分层的架构,使得Servlet容器具有很好的灵活性。

Tomcat 采用了组件化的设计,它的构成组件都是可配置的,其中最外层的是Server,其他组件 按照一定的格式要求配置在这个顶层容器中。这些可以在配置文件server.xml中进行配置

13、tomcat如何管理定义的四种容器?

所有容器组件都实现了Container接口,因此组合模 式可以使得用户对单容器对象和组合容器对象的使用具有一致性。这里单容器对象指的是最底层的Wrapper,组合容器对象指的是上面的Context、Host或者Engine。

Container接口中有parent/child相关的方法,用于标识父子关系。

此外,Container接口扩展了LifeCycle接口,LifeCycle接口用来统一管理各组件的生命周期。

14、tomcat启动流程

总结:初始化或者启动父组件自身,然后调用子组件。

启动步骤:

  • 启动tomcat , 需要调用 bin/startup.bat (在linux 目录下 , 需要调用 bin/startup.sh) , 在startup.bat 脚本中, 调用了catalina.bat。
  • 在catalina.bat 脚本文件中,调用了BootStrap 中的main方法。
  • 在BootStrap 的main 方法中调用了 init 方法 , 来创建Catalina 及 初始化类加载器。
  • 在BootStrap 的main 方法中调用了 load 方法 , 在其中又调用了Catalina的load方 法。
  • 在Catalina 的load 方法中 , 需要进行一些初始化的工作, 并需要构造Digester 对象, 用 于解析 XML。
  • 然后在调用后续组件的初始化操作 。。。 加载Tomcat的配置文件,初始化容器组件 ,监听对应的端口号, 准备接受客户端请求。

15、tomcat中各个组件的默认实现类

接口 默认实现
Server StanderdServer
Service StanderdService
Engine StanderdEngine
Host StanderdHost
Context StanderdContext
Endpoint 提供一个抽象类AbstractEndpoint
Processor

见图

ProtocolHandler 封装endpoint和processor,实现对具体协议的处理功能

16、tomcat的请求处理流程

tomcat中,Mapper组件实现了将用户请求的URL定位到一个Servlet的功能。使得tomcat实现每个请求都可以精准的找到对应的servlet。

Mapper组件工作原理:

Mapper组件里保存了Web应用的配置信息,其实就是容器组件与访问路径的映射关系,比如Host容器里配置的域名、Context容器里的Web应用路径,以及Wrapper容器里Servlet映射的路径,你可以想象这些配置信息就是一个多层次的Map。

当一个请求到来时,Mapper组件通过解析请求URL里的域名和路径,再到自己保存的Map里去查找,就能定位到一个Servlet。请你注意,一个请求URL最后只会定位到一个Wrapper容器,也就是一个Servlet。

具体步骤:

  1. Connector组件Endpoint中的Acceptor监听客户端套接字连接并接收Socket。
  2. 将连接交给线程池Executor处理,开始执行请求响应任务。
  3. Processor组件读取消息报文,解析请求行、请求体、请求头,封装成Request对象。
  4. Mapper组件根据请求行的URL值和请求头的Host值匹配由哪个Host容器、Context容器、Wrapper容器处理请求。
  5. CoyoteAdaptor组件负责将Connector组件和Engine容器关联起来,把生成的Request对象和响应对象Response传递到Engine容器中,调用 Pipeline。
  6. Engine容器的管道开始处理,管道中包含若干个Valve、每个Valve负责部分处理逻辑。执行完Valve后会执行基础的 Valve–StandardEngineValve,负责调用Host容器的Pipeline。
  7. Host容器的管道开始处理,流程类似,最后执行 Context容器的Pipeline。
  8. Context容器的管道开始处理,流程类似,最后执行 Wrapper容器的Pipeline。
  9. Wrapper容器的管道开始处理,流程类似,最后执行 Wrapper容器对应的Servlet对象的处理方法。

在Tomcat中定义了Pipeline 和 Valve 两个接口,Pipeline 用于构建责任链, Valve代表责任链上的每个处理器。Pipeline 中维护了一个基础的Valve,它始终位于Pipeline的末端(最后执行),封装了具体的请求处理和输出响应的过程。当然,我们也可以调用addValve()方法, 为Pipeline 添加其他的Valve, 后添加的Valve 位于基础的Valve之前,并按照添加顺序执行。Pipiline通过获得首个Valve来启动整合链条的执行 。

17、tomcat中的Jasper简介

JSP页面中编写 Java代码,添加第三方的标签库,以及使用EL表达式。但是无论经过何种形式的处理,最终输出到客户端的都是标准的HTML页面(包含js ,css…),并不包含任何的java相关的语法。 故jsp看做是一种运行在服务端的脚本。

服务器如何将 JSP页面转换为HTML页面?

Jasper模块是Tomcat的JSP核心引擎,JSP本质上是一个Servlet。Tomcat使用Jasper对JSP语法进行解析,生成Servlet并生成Class字节码,用户在进行访问jsp时,会访问Servlet,最终将访问的结果直接响应在浏览器端 。另外,在运行的时候,Jasper还会检测JSP文件是否修改,如果修改,则会重新编译JSP文件。

18、JSP的编译方式

tomcat并不会在启动web程序的时候自动编译jsp文件,而是在客户端第一次请求时,才编译需要访问的jsp文件。(如果安装了Apache Ant,则可以使用ant进行预编译)

当容器启动时,会读取在webapps目录下所有的web应用中的web.xml文件,然后对xml文件进行解析,并读取servlet注册信息。然后,将每个应用中注册的servlet类都进行加载,并通过反射的方式实例化(Tomcat 创建servlet类实例的方法和原理)

Tomcat 在默认的web.xml 中配置了一个**org.apache.jasper.servlet.JspServlet**,用于处理所有的**.jsp **** .jspx **结尾的请求,该Servlet 实现即是运行时编译的入口。

   <servlet><servlet-name>jsp</servlet-name><servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class><init-param><param-name>fork</param-name><param-value>false</param-value></init-param><init-param><param-name>xpoweredBy</param-name><param-value>false</param-value></init-param><load-on-startup>3</load-on-startup></servlet><!-- The mapping for the default servlet --><servlet-mapping><servlet-name>default</servlet-name><url-pattern>/</url-pattern></servlet-mapping><!-- The mappings for the JSP servlet --><servlet-mapping><servlet-name>jsp</servlet-name><url-pattern>*.jsp</url-pattern><url-pattern>*.jspx</url-pattern></servlet-mapping>

 编译过程:

1、调用JspServlet的service方法,里面会获取jsp文件路径,如果界面没有传,会根据配置文件配置的servlet-mapping进行查找(上面xml里面有写)

判断当前请求是否是预编译请求,然后执行serviceJspFile()方法

/

2、 在serviceJspFile()方法中获取JspServletWrapper,然后调用JspServletWrapper的service方法

3 、 若是第一次调用,则需要编译,在JspServletWrapper的service方法中通过调用JspCompilationContext的compile()方法,在调用Compiler的compile()方法,生成Java文件和class文件。

4 、生成文件之后,JspServletWrapper的service方法加载编译并实例化之后的servlet,然后调用其service()方法,这个service方法就是编译生成的service方法。

编译结果:

1、如果在 tomcat/conf/web.xml 中配置了参数scratchdir , 则jsp编译后的结果,就会存储在该目录下。

<init-param><param-name>scratchdir</param-name><param-value>D:/tomcat-temp</param-value></init-param>

2、如果没有配置该选项, 则会将编译后的结果,存储在Tomcat安装目录下的work/Catalina(Engine名称)/localhost(Host名称)/Context名称

3、如果使用的是 IDEA 开发工具集成Tomcat 访问web工程中的jsp , 编译后的结果,存放在 :C:\Users\用户名\AppData\Local\JetBrains\IntelliJIdea2020.1\tomcat\Unnamed_Tomcat8_0\work\Catalina\localhost\jsp_demo\org\apache\jsp

19、Jasper编译文件简介。

分析:

  1. 编译后的类继承自 org.apache.jasper.runtime.HttpJspBase,是HttpServlet的子类,因此jsp本质上就是一个servlet
  2. 通过属性 _jspx_dependants 保存了当前JSP页面依赖的资源, 包含引入的外部的JSP页面、导入的标签、标签所在的jar包等,便于后续处理过程中使用(如重新编译检测, 因此它以Map形式保存了每个资源的上次修改时间)。
  3. 通过属性 _jspx_imports_packages 存放导入的 java 包, 默认导入 javax.servlet ,javax.servlet.http, javax.servlet.jsp 。
  4. 通过属性 _jspx_imports_classes 存放导入的类, 通过import 指令导入的DateFormat 、SimpleDateFormat 、Date 都会包含在该集合中。_jspx_imports_packages 和 _jspx_imports_classes 属性主要用于配置 EL 引擎上下文。
  5. 请求处理由方法 _jspService 完成 , 而在父类 HttpJspBase 中的service 方法通过模板方法模式 , 调用了子类的 _jspService 方法。
  6. _jspService 方法中定义了几个重要的局部变量 : pageContext 、Session、application、config、out、page。由于整个页面的输出有 _jspService 方法完成,因此这些变量和参数会对整个JSP页面生效。 这也是我们为什么可以在JSP页面使用这些变量的原因。
  7. 指定文档类型的指令 (page) 最终转换为 response.setContentType() 方法调用。
  8. 对于每一行的静态内容(HTML) , 调用 out.write 输出。
  9. 对于 <% … %> 中的java 代码 , 将直接转换为 Servlet 类中的代码。 如果在 Java代码中嵌入了静态文件, 则同样调用 out.write 输出。

Tomcat 配置文件

tomcat服务器的主要配置文件都集中在tomcat/conf目录下

1、server.xml

server.xml是tomcat的核心配置文件,包含了servlet容器的所有配置,下面列举一些重要的配置。

1.1 Server

Server是server.xml的根元素,用于创建一个server实例,代码里的默认实现类是StandarServer。

port:tomcat监听的关闭服务器的端口,默认9005,建议改成-1,即关闭该端口

shutdown:关闭服务器的指令字符串,建议修改。

<Server port="9005" shutdown="SHUTDOWN">
。。。
</Server>

Server内嵌的子元素为:Listener(监听器),GlobalNamingResources(全局命名),Service

1.2 Service

用于创建Service实例,代码默认使用StandarService,默认情况下,tomcat仅仅指定了Service的名称“Catalina”, Service可以内嵌的元素包括

  • Listener:为Service添加生命周期监听器
  • Executor: 配置Service共享线程池
  • Connector: 配置Service包含的连接器
  • Engine: 配置Service中连接器对应的servlet容器引擎

1.3 Executor

默认情况下,Service没有添加共享线程池配置,catalina各个组件在用到线程池时会独立创建。

如果想要配置共享线程成,可以在<Service>下添加如下配置

1.4 Connector

Connector用于创建连接器实例,默认情况下,server.xml配置了两个连接器,一个支持HTTP协议,一个支持AJP协议,因此大多数情况下,不需要新增连接器配置,只根据自己需要对已有的连接器进行优化即可。

  • port:端口号,Connector用于创建服务端socket并进行监听客户端的请求连接,如果端口号设置为0,则tomcat会随机选用一个可用的端口号给当前Connector使用
  • protocol:当前Connector支持的访问协议,默认是HTTP/1.1,并采用自动切换机制,选择一个机遇Java NIO 的连接器或者机遇本地APR的连接器(这个也要看是否含有tomcat的本地库),如果不希望自动切换,可以明确指定协议(如:org.apache.coyote.http11.Http11NioProtocol)
  • connectionTimeout:Connector接收链接请求后的等待超时时间,单位为毫秒,-1表示不超时。
  • redirectPort:当前Connector不支持SSL请求,接收到的请求符合security-constraint约束,需要SLL传输,catalina会自动将请求重定向到指定的端口。
  • excutor:指定共享线程池的名称,也可以通过maxThreads、minSpareThreads等属性配置内部线程池。
  • URIEncoding: 用于指定URI的字符编码,tomcat8.x版本后默认是UTF-8。

1.5 Engine

Engine作为servlet引擎的顶级元素,内部可以嵌入:Cluster,Listener,Realm,Valve, Host等;如果在Engine 下配置了Realm,则此配置在当前Engine下的所有Host共享

  • name:用于指定Engine的名称,默认是Catalina,这个名称会影响一部分Tomcat的存储路径(如临时文件)
  • defaultHost: 默认使用的虚拟主机名称,当客户请求指向的主机无效时,将交由默认的虚拟主机处理,默认为localhost。

1.6 Host

Host元素用于配置一个虚拟主机。如果在Host下配置了Realm,则此配置在当前Host下的所有Context中共享

name: 当前Host通用的网络名,必须与DNS服务器上的注册信息一致,而且,必须要存在一个Host的name与Engine中defaultHost一致。

appBase:当前Host的应用基础目录,当前Host上部署的web应用均在该目录下,默认webapps

unpackWARs: 设置为true,Host在启动时会将appBase目录下的war包解压为目录,设置为false,Host则直接从war包启动

autoDepoly: 控制tomcat是否定期检测并自动部署新增或者变更的web应用。

1.7 Context

用于配置一个web应用,默认配置如下

2、tomcat部署项目的几个方式

1、直接将项目放到webapps的目录下即可

将项目打成一个war包,在将war包放到webapps目录下即可

2、配置conf/server.xml文件

<Host> 标签提中配置<Context>标签

<Context doBase=“D:\hello” path=“/hehe”>  *doBase:项目存放的路径  *path:虚拟目录(网页usl访问的路径)

3、在tomcat\conf\Catalina\localhost下面创建任意名称的xml文件,在文件中编写<Context>标签

<Context doBase=“D:\hello” path=“/hehe”>

Tomcat 集群搭建

1、Nginx的负载均衡策略有哪几种?

1、轮询(默认策略):交替

2、权重:在轮询的基础上,指定轮询的几率,适合服务器配置差异较大的情况

3、ip_hash:指定负载均衡按照基于客户端IP的分配方式,这个方法保证了相同的客户端的请求会发送到相同的服务器,以保证session会话。

2、为什么要session共享?

Tomcat集群中,如果用户需要登录,而这个时候,Tomcat做了负载均衡,用户登录的时候就会出现问题。

如下:第一次登录操作,访问的是Tomcat1,保存了session,第二次进行业务操作,但访问到了Tomcat2,此时Tomcat2是没有记录用户的session信息的,那么权限校验就无法通过。

3、session共享的三种方案

1、ip_hash策略

通过Nginx中负载均衡的ip_hash策略,对于一个用户发起的请求,经过ip_hash计算,只会转发到同一个Tomcat服务器上,这样就解决了session共享的问题。

2、session复制

顾名思义,就是用户访问到一个Tomcat时,这个Tomcat在记录session的同时,以广播的形式告知集群中的其他Tomcat,其他Tomcat复制这个session信息,那么下次如果访问转发到其他的Tomcat上时,因为已经赋值了session,因此可以正常访问。

配置方法:

1、在sever.xml中,将如下注释放开

2、 在web.xml中,添加<distributable/>标签

因为是广播复制,因此频繁的广播和复制会消耗性能,如果超过4个节点,则不推荐使用。

3、单点登录

single sign on(SSO),是目前比较流行的企业业务整合方案之一,sso的定义是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统,也是用来解决集群环境session共享的方案之一。

简单来说,就是外部请求通过Nginx反向代理到一台Tomcat时,加一层认证服务,这个服务去redis中查询用户是否已经登录,首次登录将登录session存入到redis中,后续其他Tomcat服务器只要在redis中查到这个session信息,那么就可以认证通过。

4、Tomcat支持Https

1、生成密钥库文件

要实现https,就必须先具有tomcat证书。而JAVA中有自带的证书生成工具keytool,该命令执行完毕后,就会在本地生成一个密钥文件 tomcatkey.keystore

keytool -genkeypair -alias 'tomcat' -keyalg 'RSA' -keystore '/usr/local/tomcat/conf/tomcat.keystore

2、将密钥库文件放置在 tomcat/conf目录下

3、配置tomcat/conf/sever.xml文件

<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol" maxThreads="150" schema="https" secure="true" SSLEnabled="true"><SSLHostConfig><Certificate certificateKeystoreFile="证书位置" certificateKeystorePassword="密码"  type="RSA"/></SSLHostConfig>
</Connector>

4、接着就可以使用8443端口访问https (免费的浏览器不信任,但是可以点击高级继续访问)

tomcat 黑马学习笔记相关推荐

  1. 一、Web服务器——Tomcat Servlet学习笔记

    今日内容 web相关概念回顾 web服务器软件:Tomcat Servlet入门学习 一.web相关概念回顾 软件架构 C/S:客户端/服务器端 B/S:浏览器/服务器端 资源分类 静态资源:所有用户 ...

  2. Mysql黑马学习笔记

    Mysql黑马笔记 一.数据定义DDL 对数据库的常用操作 --查看所有表 show databases;--创建数据库mydb1 create database mydb1:--创建数据库mydb1 ...

  3. Jenkins deploy to container部署war到tomcat(学习笔记十六)

    /** * lihaibo * 文章内容都是根据自己工作情况实践得出. *如有错误,请指正 * 版权声明:本博客欢迎转发,但请保留原作者信息! http://www.cnblogs.com/horiz ...

  4. JAVA 黑马学习笔记记录 for switch while do...while

    根据运算符的功能,我们把运算符分成哪几类? 逻辑运算符(与(&) 或(|) 非(!) 短路与(&&有假就假) 短路或(||有真就真) ^异或(相同为假,不同为真) 条件 boo ...

  5. Python黑马学习笔记Day01

    # 注释 # 单行注释:#号 # 多行注释:三个引号,单引号多引号都可以 # 快捷键: #ctrl + / ,在要注释的那一行输入这个快捷键就可以令那一行变成注释行,也可以一次选中多行,然后输入快捷键 ...

  6. 黑马学习笔记_常用API总结(二)

    --- android培训.java培训.期待与您交流! ---- 正则表达式 规则字符在java.util.regex Pattern类中 A: 字符x 字符 x.举例:'a'表示字符a\\ 反斜线 ...

  7. 小程序基础入门(黑马学习笔记)

    一.宿主环境--组件 1.scroll-view(滚动效果) scroll-y 属性:允许纵向滚动 scroll-x 属性:允许横向滚动 注意:使用竖向滚动时,必须给scroll-view 一个固定高 ...

  8. JavaWeb黑马旅游网-学习笔记01【准备工作】

    Java后端 学习路线 笔记汇总表[黑马程序员] JavaWeb黑马旅游网-学习笔记01[准备工作] JavaWeb黑马旅游网-学习笔记02[注册功能] JavaWeb黑马旅游网-学习笔记03[登陆和 ...

  9. Servlet和HTTP请求协议-学习笔记01【Servlet_快速入门-生命周期方法、Servlet_3.0注解配置、IDEA与tomcat相关配置】

    Java后端 学习路线 笔记汇总表[黑马程序员] Servlet和HTTP请求协议-学习笔记01[Servlet_快速入门-生命周期方法.Servlet_3.0注解配置.IDEA与tomcat相关配置 ...

最新文章

  1. 机器学习算法基础知识
  2. 某32岁大厂程序员吐槽:简历通过率才30%!大龄韭菜该何去何从?网友:没那么严重,同32岁,简历通过率90%!...
  3. linux spi测试程序,spidev测试方法 /how to test spidev
  4. iOS 12第二次大更新发布:曝光重磅硬件
  5. myeclipse 复制项目不包含svn或CVS目录
  6. Mac自带的实用功能
  7. SQL2016发布订阅热备操作手册
  8. js生成二维码,js 解析二维码,jsqrcode,js从url生成二维码
  9. 从零开始做UI-静电的sketch设计教室 视频教程
  10. 微信小程序中输出大于号和小于号
  11. Fabric CA的基础知识
  12. @CacheEvict-缓存
  13. jquery基础学习记录
  14. 强大的CSS:颜色、背景和剪切
  15. C++ 带逗号输入数组(大厂笔试输入出现多次)
  16. 你知道吗?除了 P站,还有这些站 ~~
  17. 读心术程序c语言流程图,无聊的时候写的读心术小程序
  18. Barrier (屏障; 障碍; 栅栏; 分界线)
  19. 对于网站过度SEO优化会有哪方面的搜索引擎原理
  20. Kong 插件ACL的使用方法(访问控制列表黑名单)

热门文章

  1. BSD学习(BSD系统的历史和目标)
  2. 2015武汉大学第八届Eming杯现场赛E题题解
  3. 开发板——X210开发板的软开关(供电置锁)
  4. 信通院5G消息工作组会员招募!
  5. PyQt5最全32 日历之QCalendarWidget日历控件
  6. pta地下迷宫探索(详解)
  7. 直流电压检测线路设计
  8. SDP最佳实践丨详解植物医生首家智能门店
  9. Whale帷幄 - 智能门店管理系统解决方案 门店管理系统哪个好用
  10. python朋友圈技巧_原创|你必须拥有的四个微信高级技巧