IDEA集成Tomcat服务器
配置简介
更新资源(update resources ):变更了资源,表示当修改了静态资源,比如HTML、css等,可以使用资源变更
更新类和资源(update classes and resources ):对类的修改使用这个选项不生效,所以不建议使用
重新部署(Redeploy ):重部署,当只对代码进行了修改,可以重新部署项目到服务器,当修改了web.xml时,重部署不会生效
重启服务器(restart server ):当修改了代码或者对web.xml进行修改,重启服务器
项目部署简介
在IDEA中编写了Servlet并且能够成功访问后,打开Tomcat的Webapps目录,发现目录中并没有部署当前访问的项目文件。这是因为IDEA将Tmocat中的重要文件进行了复制(conf配置相关文件、logs日志相关文件、work运行中的缓存文件),并指定了Tomcat到指定的目录中去加载项目
这样做的好处是针对每个项目单独处理,可以单独配置互不影响
(这个输出目录就是IDEA为Tomcat指定的目录)
web.xml的配置
通过web.xml配置了Servlet所在类的全路径,配置了Servlet访问的映射路径。(web.xml会在服务器启动后进行加载)
配置Servlet的几种方式
<servlet>
<servlet-name>自定义名</servlet-name>
<servlet-class>包名+类名</servlet-class>
</servlet>
<servlet-mapping>
<!--
servlet-name:这里的名字一定要和上面配置的servlet-name 一样!!!
url-pattern:配置url的映射路径,也就是你的这个Servlet需要浏览器通过什么请求路径访问你
浏览器路径需要这样写:http://ip地址:端口号/项目名/你的url-pattern
-->
<servlet-name>HelloServlet</servlet-name>
<!-- 一个servlet可以配置多个url-pattern,但是多个servlet不能配置相同的 url-pattern
这样的话请求过后tomcat不知道该调用哪个servlet处理 -->
<url-pattern>/HelloServlet</url-pattern>
<!-- /名字 代表只能使用指定形式访问 -->
<url-pattern>/aa</url-pattern>
<!-- /*.do *代表0-多个字符,意思是只要是为.do结尾的url都可以访问得到 -->
<url-pattern>*.do</url-pattern>
<!-- / 表示拦截所有请求,但是不会拦截.jsp文件(jsp文件可以显示)
除了访问jsp外,访问其他的资源都会访问到该Servlet -->
<url-pattern>/</url-pattern>
<!-- /* 表示拦截所有请求 不管是什么形式什么结尾都会访问到该Servlet -->
<url-pattern>/*</url-pattern>
<!-- /文件名/UserServlet 多级目录的方式 指定形式才能访问 -->
</servlet-mapping>
配置默认欢迎页面
默认欢迎页就是指,浏览器发出的请求路径中没有指定具体的访问资源时,默认就会访问的页面。在Tomcat中的conf/web.xml中配置了全局的几个默认欢迎页。欢迎页可以配置多个,匹配优先级自上而下。
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
(一般在我们项目中要设置默认欢迎页的话,在自己项目的web.xml中设置即可。不要改Tomcat中的conf/web.xml进行设置。)
Servlet
tomcat服务器提供了Servlet规范的实现。我们写的代码要想被服务器调用,也必须遵守Servlet规范。
为什么自定义类不直接继实现Servlet接口,原因是:
该接口中方法较多,Servlet接口有它的一系列实现类,我们继承实现类即间接的实现了Servlet接口。
Servlet的继承结构
Servlet接口
init(),创建Servlet对象后立即调用该方法完成一些初始化工作。
service(),处理客户端请求,执行业务操作,可以利用响应对象响应客户端请求。
destroy(),在销毁Servlet对象之前调用该方法。
getServletConfig(),ServletConfig是容器向servlet传递参数的载体。
getServletInfo(),获取servlet相关信息。
ServletConfig接口
String getServletName(),返回 Servlet 的名字,即 web.xml 中 <servlet-name>元素的值。
ServletContext getServletContext(),返回一个代表当前 Web 应用的 ServletContext 对象。
String getInitParameter(String name),根据初始化参数名返回对应的初始化参数值。
Enumeration getInitParameterNames(),返回一个 Enumeration 对象,其中包含了所有的初始化参数名。
GenericServlet抽象类
GenericServlet是实现了Servlet接口的抽象类。在GenericServlet中进一步的定义了Servlet接口的具体实现,其设计的目的是为了和应用层协议解耦,在GenericServlet中包含一个Service抽象方法。
HttpServlet类
继承自 GenericServlet,针对于处理 HTTP 协议的请求所定制。实际开发中, 直接继承 HttpServlet, 并根据请求方式复写 doXxx() 方法即可。
总结
Servlet的生命周期
Servlet的生命周期是由Tomcat容器管理的,会经历三个阶段
1.通过反射来获取该Servlet的实例化对象同时进行初始化的操作 init()
2.执行服务 service()
3.销毁 destroy()
问题
问题1:Servlet对象创建、初始化并使用完后会销毁吗?
Servlet对象在创建、初始化并使用后不应该销毁。如果使用完(请求处理完)就销毁,那么下次过来请求又得去创建Servlet对象。
自始至终都使用同一个Servlet对象去处理请求,如果同时有10个请求过来访问Tomcat服务器,服务器会创建10个线程来处理请求,避免使用全局变量, 多个线程操作全局变量存在线程安全的问题, service()方法中的局部变量不存在线程安全问题。
问题2:Servlet对象会被创建及初始化几次?
Servlet对象只会被创建及初始化一次。之后会驻留在内存当中。
问题3:Servlet对象是在什么时候创建及初始化的?
Servlet的创建与初始化的时机有两个:
Servlet在第一次被浏览器访问的时候创建与初始化的(目前我们的代码用的就是这种方式,默认就是这种)
Servlet在启动服务器的时候被创建与初始化的(该方式需要在web.xml中做load-on-startup配置,告诉Tomcat服务器在启动的时候就创建Servlet对象)
问题4:Servlet对象什么时候销毁?
Servlet对象是由Tomcat服务器创建的,之后就一直驻留在内存中处理请求。直到服务器停止后,Servlet才会被销毁。
Servlet生命周期小总结
-
没有配置load-on-startup的情况:
-
配置了load-on-startup的情况:
当客户端浏览器第一次请求Servlet时,容器会实例化这个Servlet,然后调用一次init方法,并在新的线程中执行service方法处理请求。service方法执行完毕后容器不会销毁这个Servlet而是做缓存处理,当客户端浏览器再次请求这个Servlet时,容器会从缓存中直接找到这个Servlet对象,并再一次在新的线程中执行Service方法。当容器在销毁Servlet之前对调用一次destroy方法。
Servlet在Tomcat中运行的原理
启动Tomcat服务器(以下动作只在服务器启动的时候执行):
1.解析web项目的web.xml文件
1.默认的servlet
解析web.xml,解析出url-partten(访问路径)和servlet-class(包名+类名)。
2.配置了load-on-startup
解析web.xml,解析出的url-partten(访问路径)作为key,获取到servlet-class中的包名和 类名,通过反射获取到构造器对象创建Servlet对象(Class clazz=Class.forName(“包名+类 名”); Servlet servlet=clazz.newInstance();)将实例化的Servlet对象作为value存储在map 集合中。
2.Tomcat服务器接收到来自客户端的请求
3.Tomcat服务器解析请求,并查找请求的资源
-
默认的servlet
根据url中解析结果,找到web.xml中匹配的url-partten,获取包名和类名,利用反射完成方法的调用。
Class clazz= Class.forName("包名+类名");
Servlet servlet = aClass.getConstructor().newInstance();
servlet.service();
-
配置了load-on-startup
根据url中解析结果,在map集合中根据key(url-partten)获取对应的实例化对象。
Class clazz= Class.forName("包名+类名");
Servlet servlet = aClass.getConstructor().newInstance();
map.set("url-partten中解析的值", servlet );
Servlet servlet = map.get(key);
servlet.service();
注意: 该流程由Tomcat底层接收请求后自动执行,我们是看不到的,我们需要做的是将实现了Servlet接口的代码提前放到Tomcat服务器中。
Servlet使用流程
代码编写流程
-
在项目的src目录下创建一个com.bjsxt.servlet包,在包中创建自己的类继承HttpServlet。
-
重写service方法,doGet方法,doPost方法,在方法中写的就是处理请求的业务逻辑代码。
-
在web.xml中配置映射关系
配置servlet的访问路径。
-
启动tomcat服务器
tomcat服务器会解析web.xml。
-
在浏览器输入路径访问Servlet
tomcat接收到客户端的请求后,会创建请求与响应对象,调用请求的serlvet执行service方法,将创建的请求与响应对象以参数的形式传递到service方法中。在service方法中根据需求进行操作。
代码执行流程
-
tomcat服务器启动时,会加载解析我们项目的web.xml文件。
-
tomcat服务器根据解析的结果,创建所有在web.xml中配置的Servlet对象(假设都配置了load-on-startup)。
-
tomcat服务器将所有创建好的Servlet对象以键值对的形式放在内存中,键是你配置的url-pattern,值是Servlet对象。
-
在浏览器地址栏输入url地址,比如:http://localhost:8080/demo/Hello。
-
tomcat服务器接收到浏览器发送的http请求,然后进行解析,得到本次请求的两个对象,HttpServletRequest和HttpServletResponse。
-
tomcat服务器解析url地址中要访问的资源,根据资源路径找到提前创建好的Servlet对象。
-
tomcat服务器根据反射调用Servlet对象的service方法,并将此次请求解析出的request和response对象传递给service执行。
-
service方法执行完后,tomcat会按照http响应的格式将数据响应给浏览器。
-
浏览器接收到tomcat的响应结果后,对其进行解析,以网页的形式展示给用户看。
GET请求方式与POST的区别
GET请求会被浏览器主动cache,而POST不会,除非手动设置。
GET请求只能进行url编码,而POST支持多种编码方式。
GET请求参数会被完整保留在浏览器历史记录里,而POST中的参数不会被保留。
GET请求在URL中传送的参数是有长度限制的,而POST则没有。
对参数的数据类型GET只接受ASCII字符,POST既可是字符也可是字节。
GET相比POST来说不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息。
GET参数通过URL传递,POST放在Request body中。
请求对象(HttpServletRequest)
1.service方法体
service方法中写业务逻辑代码的话,大概是如下三步:
接收请求(获取请求数据)
处理请求
完成响应
2.request对象的使用
-
request对象获取请求行数据
-
request对象获取请求头数据
-
request对象获取请求体数据
-
request对象获取其他数据
请求数据乱码问题解决
Tomcat服务器接收到请求后,会解析请求,并将请求中的数据给封装到HttpServletRequest对象中。所以,我们对request对象中的数据进行重新编码即可。
在service方法中第一行加入如下代码:
req.setCharacterEncoding("utf-8");
注意:这行代码必须要放在req.getParameter()之前才能生效!!!
响应对象(HttpServletResponse)
1.response对象的使用
response对象是由Tomcat收到请求后实例化创建的,我们直接调用它的响应方法即可,Tomcat底层会将response响应的内容自动转换为HTTP协议的格式,输出给浏览器。
响应方法:
response.getWriter().write(“响应内容”);
底层是本质就是网络编程的流输出。
注意:响应内容可以直接是数据,也可以是数据+HTML标签+CSS样式+JS脚本。
响应数据乱码问题解决
因为Tomcat服务器默认使用utf-8的编码格式编码响应数据,而浏览器默认使用ISO-8859-1来解析响应数据。
解决:告诉浏览器使用utf-8的方式来解析数据。
resp.setContentType("text/html;charset=utf-8");