javaEE Web(Tomcat)深度理解 和 Servlet的本质
javaEE Web(Tomcat)深度理解 和 Servlet的本质
每博一文案
我所有的进步,只为更接近你。
上天没有给予人们公平的人生,有人拥有出奇的才能,便有人只能不辞辛苦的攀登阶梯,我默默地守望着一缕光芒,小心翼翼,如掬如束,可若长久凝望,一点会让自己,也受烫灼。
平凡的人生或是悲惨的际遇,可能还不是最糟糕的,我害怕的是,如果始终懦弱不堪,会让哪怕是一份小小的心意,也永远无法传达。
竭尽力量的小勇敢,小心愿,一点会被许多人笑话的吧,那么,会被一个人了解吗,逝水比喻时光荏苒,十年了,我一直在努力的改变自己,夕语,你呢,你变成什么样子了?
不经意抬头看到的躲闪目光,低头侧目时不断加速的心跳,还有慌张间来不及带走的心思,以及追寻一个背影时的迟疑步伐。
过去的千丝万缕才刚浮动显现,穿过遮掩长久的黑暗,未来我们再相见时,希望所有眼泪,都能消失无形吧,曾经那个丢掉记忆逃跑的男孩,再见了。
上一次离开,我是那样决绝,我以为自己不会再回来了,再次相见时,本以为时隔多年,命运会再次垂青于我,可是兜兜转转,像是上天给我开了一个玩笑,错的一直是我。
我渴望的爱情如同虚幻泡沫,我想要挽回的友情,也没有了机会,此时此刻,我已经失去了留下来的力量。
所有成熟的大人,都曾是受伤的小孩,那个小孩可能会长大,但永远不会离开,我一直都在你的世界,看着你一点点改变,只是你,常常遗忘过去的自己。
今后我所有的牵挂 所有的向往 都和你一样
—————— 《我是江小白》
—————— 来源《https://www.bilibili.com/read/cv16491270》
@
说明: 该博客是在基于安装了 Tomcat 的前提下操作的。 详细安装 Tomcat 的步骤大家可以移步至:(Tomcat 的安装以及其中配置环境原理的详细说明_tomcat要在什么环境下运行_ChinaRainbowSea的博客-CSDN博客
1. 实现一个最基本的web应用(这个web应用中没有java小程序)
我们首先编写一个关于静态的网页的页面:一个简单的 百度链接:如下
<!--index.html文件-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>实现一个最基本的web应用(这个web应用中没有java小程序) </title>
</head>
<body style="text-align:center">
<h3>百度链接</h3>
<a href="https://www.baidu.com/">进入百度</a>
</body>
</html>
具体步骤如下:
第一步: 找到我们安装 Tomcat 中的路径找到一个名为 webapps 的目录。
注意: 我们所有的 web的 app 都要放到该 webapps 目录下,(没有为什么,这是 Tomcat 服务器的要求,如果不放到这里,Tomcat 服务器是无法到你的应用的app,并运行的)。
如下图所示:
第二步: 在我们找到的这个 webapps 目录下创建一个子目录,名为 Mytest 的目录。
注意: 这个目录名 test 就是你这个运行 webapp的名字。
第三步: 将我们上面编写的 html 静态文件,添加到该 Mytest目录下。
第四步: 启动我们的 Tomcat 服务器,打开我们的浏览器在地址栏上输入:http://127.0.0.1:8080/项目名/index.html
:具体如下:http://127.0.0.1:8080/Mytest/index.html
,最后回车,就可以访问到我们编写的 index.html 这个静态网页了。
重点:
我们在浏览器上直接输入一个 URL,然后回车,这个操作和点击一个
超链接
是本质是一样的都是静态访问,既然都是一样的了。那我们完全可以使用超链接,访问我们在 Tomcat 服务器上编写的index.html
资源文件了。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>访问我们部署到Tomcat中的index.html资源文件</title>
</head>
<body>
<!--注意:我们目前前端上的路径都以“/”开始的,都是加项目名的。-->
<a href="http://127.0.0.1:8080/Mytest/index.html">index.html</a>
</body>
</html>
在同一个部署到同一个项目下的,资源文件是可以相互访问的。例如:我们编写一个名为 index2.html 文件,通过 index.html 访问 index2.html 资源文件。
<!--index2.html 文件-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>部署到Tomcat服务器中的index2.html资源文件</title>
</head>
<body style="text-align:center">
<h1 >你好世界</h1>
<!--部署到Tomcat同一个项目下的之间的访问,不需要添加:http://127.0.0.1:8080-->
<!--注意:我们目前前端上的路径都以“/”开始的,都是加项目名的。-->
<a href="/Mytest/index.html">访问我们部署到Tomcat中同一个项目中的的index.html资源文件</a>
</body>
</html>
同样放到我们安装 Tomcat 服务器的 webapps 中我们建立的项目 Mytest目录下
上述这种资源的访问:我们可以称之为是 静态资源 。所谓的静态资源就是,固定的,数据是不会更新的,从一开始就写死了的。
怎么能变成动态资源 ,显然是需要连接数据库的 。
连接数据库需要用 JDBC 程序,也就是需要编写 Java程序连接数据库,数据库中右多少条记录的信息,页面会根据数据库的记录的信息,进行一个动态的显示。这种技术被称为动态网页技术 。(动态网页技术并不是说页面中有 flash 动画。动态网页技术是说页面中的数据是动态的,是根据数据库中存储的数据进行一个时时动态更新变化的 )。这个操作在本博客的后半部分有详细说明。
2. 一个动态 Web 页面中所包含的 “角色” 和 “协议”
如下是一个简易的 Web 通信图
2.1 角色
根据上图分析:在整个BS结构的系统当中 有哪些人参与进去了
- 浏览器软件的开发团队 :(浏览器软件太多了:谷歌浏览器,火狐浏览器,IE 浏览器...)
- Web Serve的开发团队 : Web Server 这个软件也是太多了:Tomcat,Jetty,WebLogic ,JBOSS,WebSphere...
- DB Server的开发团队: DB Server 也是不少的:Oracle,MySQL...
- Web app的开发团队: Web 应该程序是我们作为 Java web 程序员 开发的。
2.2 协议
协议: 所谓的协议就是一种规范,大家都要遵守的规范。不过不遵守规范的话。相互之间是无法通信交流的。就不如说:两个人之间交流:一个人说英语,一个人说中文,这两个人之间使用的语言不同,也就是遵守的规范不同,两个人就无法交流了。各自都听不明白。如果两个人都遵守同一个规范,都是说中文,或者英文,相互之间就可以明白各自在说什么了,相互交流了。
同理: 浏览器前端 与 服务器后端之间想要相互交流数据信息,也是要遵守规范。服务器后端 与 数据库也是一样的。
-
Brower(浏览器) 与 WebServer 之间有一套传输协议:HTTP (超文本传输协议)
-
Web Server 与 webapp 之间有一套规范:JavaEE规范比如 Servlet规范 :
-
Webapp 和 DB Server 之间有一套规范:JDBC 规范,关于 JDBC 的详细内容,大家可以移步至:?????? 初始 JDBC_ChinaRainbowSea的博客-CSDN博客
-
Servlet 规范的作用是 : Web Server 和 Webapp 解耦合(让 Webapp 可以在不同的服务器上运行,提高代码的移植性)。
- Servle 规范包括什么呢? 规范了哪些接口,规范了哪些类
- 规范了一个 web 应用中应该有哪些配置文件。
- 规范了一个web应用之哦个你配置文件的名字:web.xml
- 规范了一个web应用中配置文件存放的路径:\webapps\crm\WEB-INF\ 这个目录下
- 规范了一个web应用中配置文件的内容:XML标签中的类名...
- 规范了一个合法有效的web应用它的目录结构应该是怎样的
webapproot |------WEB-INF |------classes(存放字节码) |------lib(第三方jar包) |------web.xml(注册Servlet) |------html |------css |------javascript |------image ....
- Servle 规范包括什么呢? 规范了哪些接口,规范了哪些类
模拟 Servlet 通信
SUN公司把Server 接口/规范制定出来了
package MyJavaWeb;
/**
* 我们现在充当的角色是SUN公司。
* SUN公司把Server 接口/规范制定出来了。
*/
public interface Servlet {
// 一个专门提供服务的方法
public abstract void service();
}
充当的角色为:webapp开发者 三个
package MyJavaWeb;
/**
* 充当的角色为:webapp开发者
* 只要我们webapp开发者的 XXXServlet 都要实现 Servlet 接口
*/
public class BankServlet implements Servlet{
@Override
public void service() {
System.out.println("BankServlet is service...");
}
}
package MyJavaWeb;
public class UserLoginServlet implements Servlet{
@Override
public void service() {
System.out.println("UserLoginServlet is Servlet...");
}
}
package MyJavaWeb;
public class UserListServlet implements Servlet{
@Override
public void service() {
System.out.println("UserListServlet is Servlet...");
}
}
充当Tomcat服务器的开发者
package MyJavaWeb;
import java.io.FileReader;
import java.util.Properties;
import java.util.ResourceBundle;
import java.util.Scanner;
/**
* 充当Tomcat服务器的开发者
*/
public class Tomcat {
public static void main(String[] args) throws Exception {
System.out.println("Tomcat 服务器启动成功,开始接收用户的访问...");
// 简单的使用Scanner来模拟一下用户的请求
// 用户访问服务器是通过浏览器上的“请求路径”
// 也就是说用户请求路径不同,后台执行的Servlet 不同
/*
/userList UserListServlet
/login UserLoginServlet
/bank BankServlet
*/
System.out.print("请输入您访问的路径:");
Scanner scanner = new Scanner(System.in);
// 用户的请求路径:
String key = scanner.nextLine(); // Tomcat 服务器已经获取到了用户的请求路径了
// Tomcat 服务器应该通过用户的请求路径找到对应的 XXXServlet
// 请求路径和XXXServlet 之间的关系应该由谁指定呢? wedapps 的开发者
// 对应Tomcat 服务器来说需要解析配置文件
//ResourceBundle bundle = ResourceBundle.getBundle("web.properties");
FileReader reader = new FileReader("servlet01/src/MyJavaWeb/web.properties");
Properties properties = new Properties();
properties.load(reader);
reader.close();
// 通过 key 获取value
String className = properties.getProperty(key);
// 通过反射机制创建对象,注意:需要无参构造器
Class clazz = Class.forName(className);
Object o = clazz.newInstance();
//因为这里使用的是多态:所有的 XXXServlet 都实现了其Servlet 接口
// 但是Tomcat 服务器的开发者知道: 你写的XXXServlet 一定实现了 Servlet 接口
Servlet servlet = (Servlet) o;
servlet.service();
}
}
模拟的 Web.xml配置文件
/aaa=MyJavaWeb.BankServlet
/bbb=MyJavaWeb.UserLoginServlet
/ccc=MyJavaWeb.UserListServlet
# 注意不要有空格
运行
3. 开发一个带有Servlet(Java小程序)的webapp(重点)
具体步骤如下:
第一步: 在我们的 安装Tomcat的中的 webapp 目录下新建一个目录,起名为 crm (注意:这个crm就是我们的web项目的名称),当然我们也可以建立其他的项目,比如银行项目,可以创建一个目录 bank,办公系统可以创建一个 oa。等等 注意: crm就是我们这个项目的根了。
第二步: 在我们新建的 crm 目录下面新建一个名为 WEB-INF 的子目录。
注意: 这个目录的名字是被 Servlet 强制规范的,必须全部大写,必须是 WEB-INF 名,不可以是其他的。
第三步: 在我们刚刚创建的 WEB-INF 目录下新建一个子目录:classes
注意: 这个目录的名字必须是全部小写的 classes ,名字必须是这个,这也是被 Servlet 强制规范的。另外这个目录下,存放的是 java程序编译之后的 class文件(这里存放的是字节码文件)
第四步: 在我们上述创建的 WEB-INF 目录下创建一个名为 lib 的子目录。
注意: 这个目录不是必须要创建的,但如果你的一个 webapp项目需要第三方的 jar包的话,这个 jar 包要放到这个 lib 目录下,例如:java语言连接数据库需要数据库的驱动 jar 包,那么这个jar 包就一定要放到 lib 目录下。这个目录的名字也不能随便写,必须是全部小写,而且目录名必须是 lib ,这也是 Servlet 强制规范了的。
第五步: 编写一个 Java程序 ,这个小Java程序也不能随便开发的,我们开发的这个Java程序必须实现 Servelt 接口。
注意: 这个 Servlet 接口的信息是不在 JDK 当中的,(因为 Servelt 不是 JavaSE中的内容,Servlet 是属于 JavaEE的,是另外的一套类库)。
Servlet 接口(Servlet.class文件)是由 Oracle 提供的。(最初是 SUN公司提供的)。Servlet 接口是 JavaEE的规范的一员。
Tomcat 服务器实现了 Servlet 规范,所以 Tomcat 服务器也需要使用 Servlet 接口。Tomcat 服务器汇总应该有这个接口。在 Tomcat 服务器的这样一个目录下 apache-tomcat-8.5.82\lib\
有这么一个 servlet-api.jar
文件,将其解压这个 servlet-api.jar之后,你会看到有一个 Servlet.class
的字节码文件
注意: 从 JakartaEE9 开始,Servlet 接口的全名变成了 : jakarta.servlet.Servlet
不是上述 Tomcat 8 这样的目录路径了。
如下是我们编写的一个 java 小程序。
package com.RainbowSea.servlet; // 包名
import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
public class HelloServlet implements Servlet {
@Override
public void init(ServletConfig servletConfig) throws ServletException {
}
@Override
public ServletConfig getServletConfig() {
return null;
}
@Override
public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {
// 设置一下响应的内容类型是普通文本或Html代码
// 需要在获取流对象之前设置,才有效果
response.setContentType("text/html");
System.out.println("My First Servlet, Hello Servlet"); // 在命令行中输出显示
// 怎么将一个信息直接输出到浏览器上?
// 需要使用ServletResponse接口 : response
// response 表示响应:从服务器向浏览器发送数据叫响应
PrintWriter out = response.getWriter();
out.print("Hello Servlet, You are My first servlet!"); // 在浏览器上输出显示
// 这是一个输出流,负责输出字符串到浏览器
// 这个输出流不需要我们刷新,也不需要我们关闭,这些都由Tomcat来维护即可
/*
out.flush();
out.close();
*/
// 浏览器是能够识别 html 代码的,哪我们是不是应该输出一段HTML代码呢?
out.print("<h1>Hello Servlet<h1> <br>");
}
@Override
public String getServletInfo() {
return null;
}
@Override
public void destroy() {
}
}
我们需要将这个Java程序,编译一下,生成一个 class 的字节码文件,将我们这个Java程序编译生成的字节码文件,放到我们在 WEB-INF 子目录下的 classes 目录下。注意: Java源代码你原意在哪里就放在哪里,这个无所谓,但是你必须把其编译后生成的class字节码文件存放到 classes 目录下。这是被 Servlet 规范强制规定的。你只有将该Java小程序的字节码文件放到 classes 目录下,Servlet 才能识别到,并运行执行它。
第六步: 怎么能让你的 HelloServlet Java小程序编译通过呢 ?
从上述我们知道了。Servlet 接口的jar包是不在,我们的 JDK 当中的,所以如果我们直接使用命令 javac 编译的话,会存在一个问题:那就是我们识别出我们这个 HelloServlet Java代码中的 Servlet 接口,从而导致编译无法通过。如下所示
重点: 你怎么能让你的 HelloServleet 编译通过呢?配置环境变量 ClassPath。
这个 ClassPath 表示的就是类路径,作用就是当我们通过 cmd 命令执行 javac 编译的时候,其中存在的类名如果在 JDK中没有的话,会通过找 我们在 ClassPath环境变量中配置的类路径去找到对应的 类名中的 class文件并执行。具体操作如下:
将我们在 Tomcat 中自带的 servlet-api.jar 包的路径,配置到我们的 ClassPath 环境变量中就可以了。因为 Tomcat 实现了 Servlet 规范。
最后点击三个确定就配置好了。
配置好以后我们重新 javac 编译一下这个 HelloServlet Java程序就没有问题了。(注意:配置好以后,我们需要重新打开一个新的cmd命令窗口,才是使用了我们配置了信息编译的)
注意: 使用的 javac 命令
javac -encoding UTF-8 -d . *.java # 编译该包下所有的java 文件
# -endoing UTF-8 如果你的代码中存在中文注释的话,要附加上这样一条以 utf-8 编码,编译,不然它无法识别你的中文注释的而导致编译无法通过。
编译通过:
第七步: 将我们上述 HelloServlet 编译生成的 class 字节码文件,复制粘贴到我们 crm/WEB-INF/classes 目录下(注意:要连同对应是生成class字节码文件的包名路径,一起拷贝到 classes 目录下)
思考问题:以上配置的CLASSPATH和Tomcat服务器运行有没有关系?
没有任何关系,以上配置这个环境变量只是为了让你的HelloServlet能够正常编译生成class文件。
第八步: 在我们上述创建的 WEB-INF 目录下新建一个文件:web.xml
注意: 这个文件是必须的,这个文件名必须叫做 web.xml
。这个文件必须放在 WEB-INF 这个目录下。一个合法的 webapp, web.xml文件是必须的,这个 web.xml 文件就是一个配置文件,这个配置文件中描述了请求路径和 Servlet 类之间的对照关系。
这个文件最好从其他的 webapp 中拷贝,最好不要手写,没有必要,因为容易写错,而且写错了,还挺难发现的。所以我们复制粘贴就好了。
如下是从其他 webapp 复制过来的通用的 xml 位置文件内容
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee
https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd"
version="5.0"
metadata-complete="true">
</web-app>
在web.xml文件中编写配置信息,让“请求路径”和“Servlet类名”关联在一起。这一步用专业术语描述:在web.xml文件中注册Servlet类。
如下是含有 web.xml 的注释版本的:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee
https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd"
version="5.0"
metadata-complete="true">
<!--servlet 描述信息-->
<servlet>
<servlet-name>RainbowSea</servlet-name>
<!--这个位置不能随便写,必须是该类的全限定类名:带包名的类名-->
<servlet-class>com.RainbowSea.servlet.HelloServlet</servlet-class>
</servlet>
<!--servlet 映射信息-->
<!--任何一个servlet都对应这一个servlet-mapping 配置信息 -->
<servlet-mapping>
<!--这个也是随便写的,但是这里的名字要和上面的 <servlet-name></servlet-name>两者之间要保持一致-->
<!--一般是和类名一致-->
<servlet-name>RainbowSea</servlet-name>
<!--这里需要一个路径:这个路径唯一的要求就是要 / 开始
因为我们通过在浏览器上输入项目名 + 资源路径中 url 是要 / 分隔的-->
<!--这个映射路径随便写都可以,但是一定要 “/” 开头 -->
<url-pattern>/RainbowSea/Rainbow/Sea</url-pattern>
</servlet-mapping>
</web-app>
如下是没有注释信息的 web.xml 信息,因为如果我们不使用IDEA 集成开发环境编写的xml 文件,其中是不能有中文的,有中文是无法识别的
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee
https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd"
version="5.0"
metadata-complete="true">
<servlet>
<servlet-name>RainbowSea</servlet-name>
<servlet-class>com.RainbowSea.servlet.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>RainbowSea</servlet-name>
<url-pattern>/RainbowSea/Rainbow/Sea</url-pattern>
</servlet-mapping>
</web-app>
浏览器发送请求,到最终服务器调用 Server 方法中读取 web.xml 的粗略过程:
- 用户输入 URL ,或者直接点击超链接:
http://127.0.0.1:8080/crm/RainbowSea/Rainbow/Sea
。 - 然后 Tomcat 服务器接收到请求,截取路径:
/crm/RainbowSea/Rainbow/Sea
信息。 - Tomcat 服务器先找到 webapps 项目下的
crm
- Tomcat 服务器在找到我们编写的配置
web.xml
配置文件,在该配置文件中信息读取到 <servlet-mapping>:<url-pattern>/RainbowSea/Rainbow/Sea</url-pattern>
</servlet-mapping> 在通过这个信息找到 <servlet-mapping> :<servlet-name>RainbowSea</servlet-name>
</servlet-mapping>中的 Rainbows 中的信息。 - 找到 <servlet> :
<servlet-name>RainbowSea</servlet-name>
</servlet> 中的 RainbowSea信息找到 <servlet> :<servlet-class>com.RainbowSea.servlet.HelloServlet</servlet-class>
</servlet> 信息。 - 最后我们拿到了 该执行的Java程序的全限定类名:
com.RainbowSea.servlet.HelloServlet
。有了该类的全限定类名,我们Tomcat服务器就可以通过 反射机制 创建com.RainbowSea.servlet.HelloServlet
的对象了。需要注意的是:如果要使用反射机制的话:该类中必须定义了 无参构造器才行 。因为反射机制的底层是调用了 。该类的无参构造器的。 - 最后:Tomcat 服务器调用 com.RainbowSea.servlet.HelloServlet 对象中的 service 方法。执行程序。
第九步: 启动 Tomcat 服务器
第十步: 打开浏览器,在浏览器地址栏上输入一个 url ,这个 URL 必须是:http://127.0.0.1:8080/项目名/我们在web.xml中编写的映射路径
,这里是:http://127.0.0.1:8080/crm/RainbowSea/Rainbow/Sea
- http://127.0.0.1:8080/ : 表示的是本地计算机上的 Tomcat 服务器资源
- crm : 我们上述步骤编写的 webapps 项目名
- /RainbowSea/Rainbow/Sea : 我们在 web.xml 中编写的资源路径映射的路径。web.xml文件中的url-pattern
执行结果:
非常重要的一件事:浏览器上的请求路径不能随便写,这个请求路径必须和我们编写的 web.xml文件中的url-pattern 一致。
注意: 浏览器上的请求路径和 web.xml 文件中的 url-pattern 的唯一区别就是:浏览器上的请求路径带项目名:/crm
浏览器上编写的路径太复杂,可以使用超链接。注意: 这个我们编写的 html 页面只能放到 WEB-INF 目录的外面。
如下是我们编写的 index.html 信息
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>index page</title>
</head>
<body>
<a href="/crm/RainbowSea/Rainbow/Sea">hello servlet</a>
</body>
</html>
执行效果:我们在浏览器上输入:http://127.0.0.1:8080/crm/index.html
。注意 Tomcat 要保持开启状态。
以后不需要我们编写 main 方法了。因为 Tomcat 服务器负责调用 main 方法。Tomcat 服务器启动的时候执行的就是 main 方法。我们 JavaWeb 程序员只需要编写 Servlet 接口的实现类,然后将其注册到 web.xml 文件当中,即可。
3.1 Servlet 连接 MySQL8.0 数据库
上述的 Sevlet 编写的小程序是静态的,没有连接数据库中的信息。这里我们来,编写一个动态的小程序。连接了我们的 MySQL 数据库
第一步: 我们先在数据库中创建一个名为 dbtest9 的数据库,在该数据库下创建一个名为t_student 的表,表中添加一些数据。
SELECT *
FROM emps;
CREATE TABLE t_student (
`no` INT,
`name` VARCHAR(255)
);
第二步: 编写 一个名为 MySQLServlet的ava程序,并编译生成对应的 class 文件
package com.RainbowSea.servlet; // 包名
import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class MySQLServlet implements Servlet {
@Override
public void init(ServletConfig servletConfig) throws ServletException {
}
@Override
public ServletConfig getServletConfig() {
return null;
}
@Override
public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {
// 编写JDBC代码,连接数据库,查询所有学生信息
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
// 设置一下响应的内容类型是普通文本或Html代码
// 需要在获取流对象之前设置,才有效果
response.setContentType("text/html");
PrintWriter out = response.getWriter();
try {
// 1.注册驱动
Class.forName("com.mysql.cj.jdbc.Driver");
// 2. 获取连接
String url = "jdbc:mysql://localhost:3306/dbtest9";
String user = "root";
String password = "MySQL123";
connection = DriverManager.getConnection(url, user, password);
// 3. 获取到预编译的数据库连接操作对象
String sql = "select no ,name from t_student";
preparedStatement = connection.prepareStatement(sql);
// 4. 执行sql
resultSet = preparedStatement.executeQuery();
// 5. 处理查询结果集
while (resultSet.next()) {
String no = resultSet.getString("no");
String name = resultSet.getString("name");
out.print(no +"->"+name + "<br>");
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
// 6. 关闭资源
if (resultSet != null) {
try {
resultSet.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (preparedStatement != null) {
try {
preparedStatement.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (connection != null) {
try {
connection.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
@Override
public String getServletInfo() {
return null;
}
@Override
public void destroy() {
}
}
同样使用我们的 cmd 命令编译生成对应的字节码文件:
javac -encoding UTF-8 -d . *.java # 编译该包下所有的java 文件
# -endoing UTF-8 如果你的代码中存在中文注释的话,要附加上这样一条以 utf-8 编码,编译,不然它无法识别你的中文注释的而导致编译无法通过。
同样的,根据我们在该Java程序中定义的 : package com.RainbowSea.servlet
生成对应的包(目录)存放对应的 MySQLServlet.class文件。如下图所示:
第三步 :我们将我们的 MySQLServlet.class 文件拷贝到,我们webapp项目中的 `
同样的:我们需要将我们生成的 class 字节码文件的包括:包名(目录)完成的拷贝过去。如下
第四步: 编写我们在 webapps/crm/WEB-INF 目录下的 web.xml
文件。在 web.xml 文件中编写配置信息,让 “请求路径” 和 “MySQLServlet类名 ” 关联在一起。这一步专业术语被称为是: 在web.xmll 文件中注册Servlet类 。
编写的web.xml 信息内容如下: 注意: 如果我们是通过手动的方式编写的,而没有借助 IDEA 这样之类的集成开发环境环境的话。是我们识别我们在 web.xml 中编写的中文注释的,编译无法通过。所以不能有中文。
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee
https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd"
version="5.0"
metadata-complete="true">
<servlet>
<servlet-name>RainbowSea</servlet-name>
<servlet-class>com.RainbowSea.servlet.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>RainbowSea</servlet-name>
<url-pattern>/RainbowSea/Rainbow/Sea</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>MySQLServlet</servlet-name>
<servlet-class>com.RainbowSea.servlet.MySQLServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>MySQLServlet</servlet-name>
<url-pattern>/RainbowSea/student/list</url-pattern>
</servlet-mapping>
</web-app>
第五步 : 启动 Tomcat 服务器。
第六步: 在浏览器的地址栏上输入: http://127.0.0.1:8080/crm//RainbowSea/student/list
进行访问。
第七步: 验证我们的数据信息是否是:动态更新的:我们更新我们的数据库表中的信息。添加一条数据: 7 , Tomcat
INSERT INTO t_student VALUES(7,"Tomcat");
我们在访问,我们页面中的数据是否也是同步更新上的。刷新一下页面,即可。
从上述刷新运行的结果上看,我们的页面是被同步更新的。
4. 补充:
4.1 JavaEE 的版本说明
JavaEE 目前最高版本是 JavaEE8。
2017 年 8 月,Oracle(甲骨文)决定将 Java EE(Java Enterprise Edition)移交给开源组织,最后 Eclipse 基金会接手。这应该是甲骨文实现对 Java 品牌控制的最新举措,尽管之前 Sun 的资产已经被甲骨文围剿得只剩一个 VirtualBox 还能喘口气。不过,甲骨文可不允许开源组织用 Java 的名号,于是 Eclipse 选出了 "Jakarta EE" 和"Enterprise Profile"两个后续按名字,最终前者以 64.4% 的票数获胜。所以就把 JavaEE 改名了,以后就不叫 JavaEE了,以及就叫做 了 Jakarta EE 。从 JavaEE8 版本升级之后的 JavaEE9 ,就不再是这个 “JavaEE9” 这个名字了,而是叫做了 Jakarta EE9 了。
因为本名都被修改了,所以其中对应的类存在的包名也是被修改了的。具体如下。
注意点:
- JavaEE8 版本对应的 Servlet 全限定类名是:
javax.servlet.Servlet
。如下是 Tomcat 8 中 Servlet .java的存放路径
- JakartaEE9 版本的时候对应的 Servlet 全限定类名是:
jakarta.servlet.Servlet
(包名都被换了)如下是 Tomcat 10 中 Servlet.java的存放路径。
- 如果你之前的项目还是使用 Tomcat 8 中的
javax.servlet.Servlet
,那么你的项目无法直接部署到 Tomcat 10+版本上。你只能部署到 Tomcat 9- 版本之后上,在 Tomcat 9 以及 Tomcat 9 之前的版本中还是能够识别javax.servlet
这个包的。 - 当然也是有解决方法的。在 Tomcat 的官网上有所说明:https://tomcat.apache.org/
4.2 解决Tomcat服务器在DOS命令窗口中的乱码问题(控制台乱码)
将CATALINA_HOME/conf/logging.properties文件中的内容修改如下:
java.util.logging.ConsoleHandler.encoding = GBK
具体的可以移步至:?????? Tomcat 的安装以及其中配置环境原理的详细说明_tomcat要在什么环境下运行_ChinaRainbowSea的博客-CSDN博客
5. 总结:
-
理解一个 web 页面中所包含的 角色 和 协议:
- 角色 : 浏览器开发团体,Web Serve服务器开发团队,webapps 开发团队,DB数据库开发团队。
- 协议:
- 浏览器页面 与 web Serve 服务器之间的协议是 :HTTP 超文本传输协议
- web Server 服务器与 webapps 之间的协议是:Java EE 的 中 规范,比如 Servlet 等等等
- webapps 与 DB 数据库之间的协议是:JDBC
-
Servle 规范包括什么呢? 规范了哪些接口,规范了哪些类 : 规范了 web 应用中的配置文件,以及配置文件名 web.xml,配置文件的存放路径:\webapps\crm\WEB-INF\ ,配置文件的内容:XML 标签中的类名(在web.xmll 文件中注册Servlet类),规范了一个合法有效的 web 应用它的目录结构应该是怎样的。
-
总结一下:一个合法的webapp目录结构应该是怎样的?
webapproot
|------WEB-INF
|------classes(存放字节码)
|------lib(第三方jar包)
|------web.xml(注册Servlet)
|------html
|------css
|------javascript
|------image
....
-
关于 JavaEE 的版本说明:Servlet 包名的改变所带来的影响后果:jakartaEE9 版本的时候对应的 Servlet 全限定类名是:
jakarta.servlet.Servlet
。如果你之前的项目还是使用 Tomcat 8 中的javax.servlet.Servlet
,那么你的项目无法直接部署到 Tomcat 10+版本上。你只能部署到 Tomcat 9- 版本之后上,在 Tomcat 9 以及 Tomcat 9 之前的版本中还是能够识别javax.servlet
这个包的。 这个问题在 Tomcat 的官网上有已有解决方法。https://tomcat.apache.org/
-
理解web.xml 中编写的内容信息。
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee
https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd"
version="5.0"
metadata-complete="true">
<!--servlet 描述信息-->
<servlet>
<servlet-name>RainbowSea</servlet-name>
<!--这个位置不能随便写,必须是该类的全限定类名:带包名的类名-->
<servlet-class>com.RainbowSea.servlet.HelloServlet</servlet-class>
</servlet>
<!--servlet 映射信息-->
<!--任何一个servlet都对应这一个servlet-mapping 配置信息 -->
<servlet-mapping>
<!--这个也是随便写的,但是这里的名字要和上面的 <servlet-name></servlet-name>两者之间要保持一致-->
<!--一般是和类名一致-->
<servlet-name>RainbowSea</servlet-name>
<!--这里需要一个路径:这个路径唯一的要求就是要 / 开始
因为我们通过在浏览器上输入项目名 + 资源路径中 url 是要 / 分隔的-->
<!--这个映射路径随便写都可以,但是一定要 “/” 开头 -->
<url-pattern>/RainbowSea/Rainbow/Sea</url-pattern>
</servlet-mapping>
</web-app>
-
浏览器发送请求,到服务器调用 Servlet 中的方法的粗略过程:
- 用户输入 URL ,或者直接点击超链接:
http://127.0.0.1:8080/crm/RainbowSea/Rainbow/Sea
。 - 然后 Tomcat 服务器接收到请求,截取路径:
/crm/RainbowSea/Rainbow/Sea
信息。 - Tomcat 服务器先找到 webapps 项目下的
crm
- Tomcat 服务器在找到我们编写的配置
web.xml
配置文件,在该配置文件中信息读取到 <servlet-mapping>:<url-pattern>/RainbowSea/Rainbow/Sea</url-pattern>
</servlet-mapping> 在通过这个信息找到 <servlet-mapping> :<servlet-name>RainbowSea</servlet-name>
</servlet-mapping> 中的 Rainbows 中的信息。 - 找到 <servlet> :
<servlet-name>RainbowSea</servlet-name>
</servlet> 中的 RainbowSea信息找到 <servlet> :<servlet-class>com.RainbowSea.servlet.HelloServlet</servlet-class>
</servlet> 信息。 - 最后我们拿到了 该执行的Java程序的全限定类名:
com.RainbowSea.servlet.HelloServlet
。有了该类的全限定类名,我们Tomcat服务器就可以通过 反射机制 创建com.RainbowSea.servlet.HelloServlet
的对象了。需要注意的是:如果要使用反射机制的话:该类中必须定义了 无参构造器才行 。因为反射机制的底层是调用了 。该类的无参构造器的。 - 最后:Tomcat 服务器调用 com.RainbowSea.servlet.HelloServlet 对象中的 service 方法。执行程序。
- 用户输入 URL ,或者直接点击超链接:
6. 最后:
限于自身水平,其中存在的错误,希望大家给予指教,韩信点兵——多多益善,谢谢大家,江湖再见,后会有期!!!