参阅资料推荐
Tomcat--各个目录详解(二) - 啤酒大泡泡 - 博客园
早期的web应用文件是手动往tomcat文件夹下复制的,由于每改动一次代码就得重新往tomcat的目录下部署一次,后来集成到了IDEA中,只需要重新运行程序即可热启动。
下面看一个demo带你了解一下tomcat
Servelet demo
观察这个demo运行起来的页面
真正部署到tomcat中的是 out---->artifacts---->ServeletPractice_war_exploded
1、路径问题如果想要访问相应的页面,只需在根路径“/”下访问文件名即可,另外jsp文件就是写html的文件。
http://localhost:port/index.jsp
http://localhost:port/index2.jsp
Web-INF中的文件客户端的浏览器是不能直接访问的
比如Servelet01.class字节码文件无法访问
http://localhost:8080/WEB-INF/classes/com/test/app/Servelet01.class
http://localhost:8080/WEB-INF/classes/com/test/app/Servelet01
均无法访问
2、通过映射的方式访问WEB-INF文件夹下的class字节码文件
客户端的浏览器不能直接访问servlet文件只能通过映射间接访问servlet
web.xml中可以添加映射
Servlet001 com.test.app.Servlet01 Servlet001 /servlet
访问的时候出现了中文乱码
去Servlet01.java文件的service方法中设置它的servletResponse.setContentType("text/html;charset=UTF-8"); //设置编码格式
3、带参访问java文件资源
http://localhost:8080/servlet?id=1
在Servlet01.java中添加程序
String id=servletRequest.getParameter("id") ;
4、注解方式
@WebServlet("/servlet")
可以达到相同的效果
5、Servlet的生命周期@WebServlet("/servlet")
public class Servlet01 implements Servlet {
@Override
public void init(ServletConfig servletConfig) throws ServletException {
System.out.println("Serverlet init");
}
@Override
public ServletConfig getServletConfig() {
return null;
}
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("Servlet service");
servletResponse.setContentType("text/html;charset=UTF-8");
PrintWriter writer =servletResponse.getWriter();
writer.write("hello! Client~!");
writer.write("你好,客户端!");
String id=servletRequest.getParameter("id");
writer.write("收到id="+id);
}
@Override
public String getServletInfo() {
return null;
}
@Override
public void destroy() {
System.out.println("Servlet destroy");
}
}
init service destroy属于生命周期的方法
创建 使用 回收
c++中是这样的
java 由于有GC机制,你只需要创建对象使用即可,不需要考虑回收
回车
回到idea
多次回车访问http://localhost:8080/servlet
当第一次访问的时候会调用init方法,当有了对象后就不会再调用init了,会值接调用service方法
存在对象直接调用,不存在再去创建,有点类似于字符串常量池
只需要一个对象,反复去使用,相当于单例模式
当你关闭程序的时候,会调用destroy释放servlet对象
6、模拟收到请求后tomcat处理Servlet对象创建的过程访问http:localhost:8080/servlet的时候 程序会到web.xml一解析拿到全类名,通过反射机制去创建对象
1、当浏览器访问Servlet的时候,Tomcat 会查询当前Servlet的实例化对象是否存在,如果不存在,则通过反射机制动态创建对象,如果存在,直接执行第3步。
2、调用init方法完成初始化操作。
3、调用service方法完成业务逻辑操作。
4、关闭Tomcat时,会调用destory方法,释放当前对象所占用的资源。Servlet 的生命周期方法:无参构造函数、init、service、destory
1、无参构造函数只调用一次,创建对象。
2、init 只调用一次,初始化对象。
3、service 调用N次,执行业务方法。
4、destory 只调用一次,卸载对象。
下面有一段代码,如果不讲servlet.jar引入到JavaSE环境中,就会报错,无法使用Servlet。
因为在javaSE环境中加载不了Servlet01 实现的那个implements Servlet会报错
所以去tomcat解压的目录下找到servlet.jar复制到当前工程下的lib目录下手动导入一下
public static void main(String[] args) {
// 模拟tomcat创建对象的过程
// http:localhost:8080/servlet到web.xml一解析拿到全类名,通过反射机制去创建对象
String str = "com.test.app.Servlet01";
Class clazz = null;
try {
clazz = Class.forName(str);
Constructor constructor = clazz.getConstructor();
System.out.println(constructor);//会报错
// 因为在javaSE环境中加载不了Servlet01 实现的那个implements Servlet报错了
// 去tomcat解压的目录下找到servlet.jar复制到当前工程下的lib目录下手动导入一下
// 打印出:public com.test.app.Servlet01()
Object object= constructor.newInstance();
System.out.println(object);// com.test.app.Servlet01@43556938
} catch (Exception e) {
e.printStackTrace();
}
}
Servlet01.java
package com.test.app;
import javax.servlet.*;
import javax.servlet.annotation.WebServlet;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Constructor;
@WebServlet("/servlet")
public class Servlet01 implements Servlet {
public Servlet01() {
System.out.println("Servlet01的无参构造函数,在init之前,肯定是先有对象再去初始化");
}
@Override
public void init(ServletConfig servletConfig) throws ServletException {
System.out.println("Serverlet init");
}
@Override
public ServletConfig getServletConfig() {
return null;
}
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("Servlet service");
servletResponse.setContentType("text/html;charset=UTF-8");
PrintWriter writer = servletResponse.getWriter();
writer.write("hello! Client~!");
writer.write("你好,客户端!");
String id = servletRequest.getParameter("id");
writer.write("收到id=" + id);
}
@Override
public String getServletInfo() {
return null;
}
@Override
public void destroy() {
System.out.println("Servlet destroy");
}
public static void main(String[] args) {
// 模拟tomcat创建对象的过程
// http:localhost:8080/servlet到web.xml一解析拿到全类名,通过反射机制去创建对象
String str = "com.test.app.Servlet01";
Class clazz = null;
try {
clazz = Class.forName(str);
Constructor constructor = clazz.getConstructor();
System.out.println(constructor);//会报错
// 因为在javaSE环境中加载不了Servlet01 实现的那个implements Servlet报错了
// 去tomcat解压的目录下找到servlet.jar复制到当前工程下的lib目录下手动导入一下
// 打印出:public com.test.app.Servlet01()
Object object= constructor.newInstance();
System.out.println(object);// com.test.app.Servlet01@43556938
} catch (Exception e) {
e.printStackTrace();
}
}
}
7、ServletConfig
该接口是用来描述Servlet的基本信息的。
getServletName()返回Servlet的名称,全类名(带着包名的类名)getlnitParameter(String key)
获取init参数的值(web.xml)
getlnitParameterNames()
返回所有的initParamter的name值,一般用作遍历初始化参数
getServletContext()
返回ServletContext对象,它是Serviet 的上 下又,wl 3eive-。
ServletConfig和ServletContext的区别:
ServletConfig作用于某个Servlet实例,每个Servlet都有对应的ServletConfig,ServletContext作用于整个Web应用,一个Web应用对应一个ServletContext,多个Servlet实例对应一个ServletContext。
public interface ServletConfig {
String getServletName();
ServletContext getServletContext();
String getInitParameter(String var1);
Enumeration getInitParameterNames();
}
获取servletName()
在init方法中,即可 String servletName=servletConfig.getServletName();
从web.xml读取参数
web.xml
param0 value0 Servlet001 com.test.app.Servlet01 userName admin Servlet001 /servlet
servlet.java(因为要从web.xml读取初始化参数,所以一定要把@WebServlet注释掉)
//@WebServlet("/servlet") 由于本次演示在web.xml中定义了此servlet的映射,这里先注释掉,否则重复映射了就。
public class Servlet01 implements Servlet {
public Servlet01() {
System.out.println("Servlet01的无参构造函数,在init之前,肯定是先有对象再去初始化");
}
public String userName = "";
@Override
public void init(ServletConfig servletConfig) throws ServletException {
//1
String servletName = servletConfig.getServletName();// com.test.app.Servlet01
//2
//程序加载的时候可以设定一些初始化的参数,和servletRequest.getParameter()不一样,人家是从浏览器地址栏获取参数的。
//ServletConfig.getInitParameter()是从web.xml获取参数的
//基于注解取不到这样的东西,另外它用的很少。
this.userName = servletConfig.getInitParameter("userName");
//3.1
Enumeration enStr = servletConfig.getInitParameterNames();//Enumeration有点类似于set集合,只是过时了抛弃了。
//3.2
Enumeration enumeration = servletConfig.getInitParameterNames();
//4
//servletConfig倾向于Servlet的实例的配置
//servletContext倾向于全局的一个配置的信息
ServletContext servletContext = servletConfig.getServletContext();//servlet上下文,整个servlet的管理者
String servletContextName = servletContext.getServletContextName();
String contextPath = servletContext.getContextPath();
String serverInfo = servletContext.getServerInfo();
// ServletContext同样有getInitParameter和getInitParameterNames
//web.xml中
//
// param0
// value0
//
// String xxxx = servletContext.getInitParameter("xxxx");
//Enumeration initParameterNames = servletContext.getInitParameterNames();
System.out.println(servletContextName+"n"+contextPath+"n"+serverInfo);
System.out.println("Serverlet init");
System.out.println("tServerlet Name:" + servletName);//Serverlet Name:Servlet001
System.out.println("tServerlet Init Parame:" + this.userName);//Serverlet Init Parame:admin
System.out.println("tServerlet ParameterName:" + enStr);
//遍历3.1 Enumeration enStr
while (enStr.hasMoreElements()) {
String element = enStr.nextElement();
System.out.println("tServerlet ParameterName:" + element);
System.out.println("tServerlet ParameterVlaue:" + servletConfig.getInitParameter(element));
}
//遍历3.2 Enumeration enumeration
while (enumeration.hasMoreElements()) {
String element = (String) enumeration.nextElement();
System.out.println("tServerlet ParameterName:" + element);
System.out.println("tServerlet ParameterVlaue:" + servletConfig.getInitParameter(element));
}
}
@Override
public ServletConfig getServletConfig() {
return null;
}
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("Servlet service");
servletResponse.setContentType("text/html;charset=UTF-8");
PrintWriter writer = servletResponse.getWriter();
writer.write("hello! Client~!");
writer.write("你好,客户端!");
String id = servletRequest.getParameter("id");
writer.write("收到id=" + id);
}
@Override
public String getServletInfo() {
return null;
}
@Override
public void destroy() {
System.out.println("Servlet destroy");
}
public static void main(String[] args) {
// 模拟tomcat创建对象的过程
// http:localhost:8080/servlet到web.xml一解析拿到全类名,通过反射机制去创建对象
String str = "com.test.app.Servlet01";
Class clazz = null;
try {
clazz = Class.forName(str);
Constructor constructor = clazz.getConstructor();
System.out.println(constructor);//会报错
// 因为在javaSE环境中加载不了Servlet01 实现的那个implements Servlet报错了
// 去tomcat解压的目录下找到servlet.jar复制到当前工程下的lib目录下手动导入一下
// 打印出:public com.test.app.Servlet01()
Object object = constructor.newInstance();
System.out.println(object);// com.test.app.Servlet01@43556938
} catch (Exception e) {
e.printStackTrace();
}
}
}
问题:
解决方案:
8、Servlet层次结构探究HttpServlet
@WebServlet("/servlet02")
public class Servlet02 extends HttpServlet {
//顶端接口------------------------>底端接口
//Servlet---->GenericServlet---->HttpServlet
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//地址栏发送的请求是get请求
resp.getWriter().write("HtteServlet doGet");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//如果想要客户端发送post请求,要么写一个表单发送,要么用postman等工具发送post请求
resp.getWriter().write("HtteServlet doPost");
}
}
//本类:Servlet03=====手动写了一个GenericServlet,让Servlet04去继承,目的是模拟GenericServlet的用法
//@WebServlet("/servlet03")
public class Servlet03 implements Servlet {
@Override
public void init(ServletConfig servletConfig) throws ServletException {
}
@Override
public ServletConfig getServletConfig() {
return null;
}
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
//在客户端中,无论get请求还是post请求
//http://localhost:port/servlet03
//请求的响应都是 hello world,它不会区分post请求和get请求
servletResponse.getWriter().write("hello world");
}
@Override
public String getServletInfo() {
return null;
}
@Override
public void destroy() {
}
}
@WebServlet("/servlet04")
public class Servlet04 extends Servlet03 {
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws IOException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
//获取请求类型
String method = request.getMethod();//会返回GET或者POST
System.out.println(method);
switch (method) {
case "GET":
this.doGet(request, response);
break;
case "POST":
this.doPost(request, response);
break;
}
}
//这里是让父类做个分发
public void doGet(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws IOException {
}
//这里是让父类做个分发
public void doPost(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws IOException {
}
}
@WebServlet("/servlet05")
public class Servlet05 extends Servlet04 {
@Override
public void doGet(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws IOException {
httpServletResponse.setContentType("text/html;charset=UTF-8");
httpServletResponse.getWriter().write("山寨版HttpServlet doGet");
}
@Override
public void doPost(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws IOException {
httpServletResponse.setContentType("text/html;charset=UTF-8");
httpServletResponse.getWriter().write("山寨版HttpServlet doPost");
}
}
Get请求
Post请求



