实践任务 Java Web开发基础知识

1.目的

(1)了解文件编码的重要性。

(2)了解两种网址的区别:以“/”结尾的网址与不以“/”结尾的网址。

(3)编写Web程序,将Web程序部署到Tomcat,通过浏览器访问、运行该程序。

(4)掌握将Web程序部署到Tomcat的方法。

(5)掌握Web项目虚拟路径的概念。

2.环境

Web服务器主机:JDK 8、Tomcat 9。

编辑器:记事本。

浏览器:Chrome。

3.准备工作

(1)启动Tomcat。

(2)编写Web程序前,要确保显示文件的扩展名。方法是:打开控制面板→文件夹选项→查看选项卡→取消如图所示的选择→确定。

场景1 文件字符编码的重要性

场景1步骤

(1)在Tomcat的ROOT目录下,新建文本文档,重命名为“abc.jsp”。用记事本打开文件,输入如下代码,然后保存文件并关闭记事本。


<%
System.out.println("你好,Tomcat控制台"); 
String realPath = request.getServletContext().getRealPath(""); 
response.getWriter().print("Web项目的根目录或部署后的绝对物理路径是" + realPath); 
%> 

说明1:JSP程序中,起始标记为“<%”,结束标记为“%>”,其间可以输入Java代码。

说明2:System.out.println(str)负责在控制台输出信息;response.getWriter().print(str)负责在HTML页面中输出信息(实际上是将str字符串添加到response响应对象的缓存中,参考4.4.1节内容)。

说明3:request和response都是JSP的内置对象,无须创建和初始化,可以直接在JSP程序中使用这些内置对象。

说明4:Web项目部署后的绝对物理路径是指,Web项目部署到Tomcat服务器上的磁盘位置。

说明5:路径分为物理路径和URL路径。

物理路径:物理路径描述了磁盘上物理文件的路径,物理路径分为绝对物理路径和相对物理路径。以磁盘根目录开始的路径就是绝对物理路径,例如C:\a\b\c.txt\就是绝对物理路径;不以磁盘根目录开始的路径就是相对物理路径。Web开发过程中,经常使用绝对物理路径实现文件的上传和下载、XML文件读取、Properties文件读取等功能。

URL路径:URL路径用于定位互联网上的物理文件。例如,在浏览器地址栏中输入URL路径就可以访问Web服务器上的物理文件,有关URL路径的更多知识参考2.3节内容。

(2)打开浏览器,输入网址:http://localhost:8080/abc.jsp。JSP程序的执行结果出现如图所示的中文字符乱码问题。

同时Tomcat控制台也出现中文字符乱码问题,如图所示。

说明

本例Web项目部署后的绝对物理路径是C:\apache-tomcat-9.0.29\webapps\ROOT\。

(3)再次使用记事本打开文件,将文件另存为新文件,“编码”处选择UTF-8,如图所示,替换原有文件。

注意

在简体中文Windows操作系统中,新建的文本文档字符编码默认采用ANSI。

(4)重新执行步骤(2),观察前台页面和Tomcat控制台,中文字符乱码问题已解决。

结论:相同的JSP程序,文件的字符编码不同,结果可能不同。

知识扩展1:字符集

字符:字符(Character)是人类语言最小的表义符号,例如“A”“B”等。

字符编码:给定一系列字符,并对每个字符匹配一个数值,用数值来代表对应的字符,这个数值就是字符编码(Character Encoding)。例如,假设给字符“a”匹配整数97,给字符“b”匹配整数98,则97就是字符“a”的编码,98就是字符“b”的编码。

字符集:给定一系列字符并匹配对应的编码后,所有这些“字符和编码对”组成的集合就是字符集(Character Set)。常见的字符集有UTF-8、GBK、GB2312和ISO-8859-1等,其中GBK、GB2312、UTF-8支持中文字符,GB2312是GBK的子集。

ASCII里的字符都是单字节字符。同一个单字节字符在ISO-8859-1、GBK、GB2312、UTF-8中的编码相同,因为这些字符集都向下兼容ASCII。例如小写字母“a”,在ISO-8859-1、GBK、GB2312、UTF-8中的编码都是“01100001”,对应十六进制数“61”(十进制数97)。正因为单字节字符的ISO-8859-1编码、GBK编码、GB2312编码、UTF-8编码相同,所以单字节字符不存在乱码问题。这就是输出到Tomcat控制台的“Tomcat”没有乱码的原因。

但是,汉字属于多字节字符,在GBK字符集或者GB2312字符集中,汉字需要占用2个字节(同一个汉字的GBK编码和GB2312编码相同);在UTF-8字符集中,汉字需要占用3个字节。同一个汉字的GBK编码与UTF-8编码并不相同、GBK编码与UTF-8编码不兼容,以及ISO-8859-1编码不支持中文字符等,是导致Web开发过程中中文字符乱码问题发生的主要原因。

以汉字“中”为例,GBK(或GB2312)编码为2个字节,“11010110 11010000”,对应十六进制数“D6D0”;UTF-8编码为3个字节,“11100100 10111000 10101101”,对应十六进制数“E4B8AD”。可见汉字“中”的GBK编码与UTF-8编码的不兼容。此外,ISO-8859-1不支持中文字符,如图所示。

知识扩展2:Windows操作系统中的ANSI编码

在Windows操作系统中新建文本文档时,文本文档中的字符默认采用ANSI编码。简体中文Windows操作系统中的ANSI编码等效于GBK字符集,繁体中文Windows操作系统中的ANSI编码等效于BIG5字符集,日文Windows操作系统中的ANSI编码等效于Shift_JIS字符集。使用不同语言文字的Windows操作系统的ANSI编码各不相同。

UTF-8、GBK和ISO-8859-1是标准字符集;而ANSI编码只适用于Windows操作系统,并不是标准字符集。

知识扩展3:中文字符乱码问题产生的原因和解决方案

新建的abc.jsp文件默认采用ANSI编码,而ANSI编码并不是标准字符集,导致Tomcat采用默认的ISO-8859-1编码“识别”abc.jsp文件中的字符,以单字节为单位识别abc.jsp文件中的汉字,故而产生中文字符乱码问题。

将abc.jsp文件另存为新文件,字符编码选择UTF-8。UTF-8是标准字符集,Tomcat采用UTF-8编码“识别”abc.jsp文件中的字符,可解决中文字符乱码问题。

场景2 网址末尾斜杠问题

说明

本场景依赖于场景1。

场景2步骤

(1)删除场景1的abc.jsp文件的扩展名,重命名为abc(注意此时文件的编码是UTF-8)。

(2)打开浏览器,输入网址:http://localhost:8080/abc。执行结果如图所示。

说明

网址中abc后面没有斜杠。

结论1:网址http://localhost:8080/abc访问的是ROOT目录下的abc文件。

结论2:场景1中,abc.jsp文件的扩展名是“.jsp”,因此Tomcat将abc.jsp文件中的Java代码交由Servlet容器解释执行,并将执行结果返回给浏览器。场景2中,abc文件的扩展名不是“.jsp”,因此Tomcat将abc文件中的Java代码作为“普通文本”返回给浏览器。

(3)打开浏览器,输入网址:http://localhost:8080/abc/。执行结果如图所示。

结论:网址中abc后面有斜杠,斜杠前面的abc代表的是abc目录(并不是abc文件)。继续进行以下步骤可以印证这一结论。

(4)将ROOT目录下的abc.jsp文件重命名为test.jsp,在ROOT目录下创建abc目录。将ROOT目录下的test.jsp文件复制到abc目录下,再将其修改为index.jsp。

注意

该步骤较为复杂,是因为操作系统中,同一目录下,目录名和文件名不能同名。

(5)重新执行步骤(3)和步骤(2),执行结果虽然相同(如图所示),但过程却不相同。

结论1:重新执行步骤(3)时,网址中abc后面有斜杠,明确访问的是abc目录下的默认资源文件index.jsp。因此,浏览器只发出一次请求,Web服务器只做出一次响应,浏览器就显示了执行结果。

结论2:重新执行步骤(2)时,浏览器地址栏abc后会自动添加斜杠。

分析:重新执行步骤(2)时,网址中abc后面没有斜杠,说明访问的是abc资源。注意这里使用abc资源更为恰当,因为abc文件是abc资源,abc目录也是abc资源。浏览器先将abc资源看作abc文件,访问ROOT目录下的abc文件,但该文件并不存在(注意这是浏览器发出的第一次请求)。

Web服务器ROOT目录下如果没有abc文件,也没有abc目录,请求和响应就会结束。但Web服务器“善良无比”,检测到ROOT目录下虽然没有abc文件,却有abc目录,abc目录也叫作abc资源;于是将拥有abc目录的事情“告诉”浏览器,并“控制”浏览器,让浏览器重新访问abc目录(注意这是浏览器发出的第二次请求),浏览器最终访问了abc目录下的默认资源文件index.jsp。

假设ROOT目录下没有abc文件,也没有abc目录,重新执行步骤(2),若网址中abc后面没有斜杠,浏览器会发送几次请求呢?答案是一次。

结论3:在浏览器地址栏输入网址时,千万不要忽视末尾的斜杠“/”。如果末尾没有斜杠,可能引发二次请求问题。作为Web开发人员,必须谨记:为了避免浏览器发出二次请求,要尽量避免网址中的资源名与Web服务器物理路径的目录名同名。

知识汇总:Tomcat服务器查找资源的策略(以ROOT目录为例)。

策略1:在浏览器输入网址http://localhost:8080/abc/时,Tomcat服务器查找ROOT目录下abc目录下的默认资源文件,分为两种情形(整个过程,浏览器只发出一次请求)。

情形1:如果查找不到默认资源文件,则直接返回404错误,请求/响应结束。

情形2:如果查找到默认资源文件,则返回默认资源文件,请求/响应结束。

策略2:在浏览器输入网址http://localhost:8080/abc时,浏览器发出第一次请求,Tomcat服务器查找ROOT目录下的abc资源(abc文件和abc目录都是abc资源),Tomcat服务器优先查找abc文件,如果查找到abc文件,则直接返回该文件,请求/响应结束(整个过程,浏览器只发出一次请求)。如果没有查找到abc文件,Tomcat服务器则查找abc目录,分为两种情形。

情形1:如果查找不到abc目录,则直接返回404错误,请求/响应结束(整个过程,浏览器只发出一次请求)。

情形2:如果查找到abc目录,Tomcat服务器将“查找到abc目录”的消息发给浏览器,并控制浏览器发出第二次请求(第二次请求的网址是http://localhost:8080/abc/),Tomcat服务器查找abc目录下的默认资源文件(整个过程,浏览器发出了两次请求),其余过程请参考策略1。

场景3 Tomcat中webapps目录和ROOT目录优先级问题

说明

默认情况下,Tomcat安装目录的conf目录中,server.xml配置文件存在如下配置选项。这就意味着,webapps目录也可以用于存放Web程序,Tomcat会自动加载webapps目录下的Web程序。ROOT目录也位于webapps目录下,ROOT目录相当于webapps的默认资源目录。


<Host name="localhost"  appBase="webapps"
              unpackWARs="true" autoDeploy="true"> 

问题:webapps目录和ROOT目录都可以存放项目,如果项目名称相同,会优先访问哪个项目?

答案详见以下步骤。

场景3步骤

(1)接场景2的步骤(4)。

(2)在Tomcat安装目录下的webapps目录下,新建abc文件夹(空文件夹),重新执行场景2的步骤(2),执行结果如图所示。

分析:webapps目录下的abc目录的默认资源文件不存在,因此出现404错误。

结论:当webapps目录下的项目名与ROOT目录下的项目名同名时,ROOT目录下的Web项目将被“隐身”。

(3)将ROOT目录下的abc目录下的index.jsp,重命名为test.jsp。然后将test.jsp复制到ROOT目录下,删除ROOT目录下的abc目录。然后将test.jsp重命名为abc。

(4)重新执行场景2的步骤(2),执行结果如图所示。

分析:webapps目录下的abc目录的默认资源文件不存在,因此出现404错误。

结论:当webapps目录的项目名与ROOT目录下的文件名同名时,ROOT目录下的同名文件会被“隐身”。

知识汇总:webapps目录下的Web项目优先级高于ROOT目录下的Web项目。举例来说,webapps目录下的abc目录,会使ROOT目录下的abc文件或者abc目录“隐身”。

知识回顾:步骤(3)和步骤(4)中访问的目的资源是abc(不带斜杠),由于webapps目录下存在abc目录,因此在步骤(3)和步骤(4)中,浏览器地址栏abc后都会自动添加斜杠,都向Tomcat服务器发送了两次请求。Web开发人员应该避免网址中的目的资源名与Web服务器的目录名同名。

场景4 任意的物理绝对路径都可以部署Web项目(方法一)

说明

物理绝对路径中不要包含中文字符。

场景4 准备工作

(1)在C盘根目录下,创建test目录。

(2)在test目录下新建文本文档,然后重命名为“index.jsp”,参考场景1的步骤,输入场景1的代码,注意文件编码使用UTF-8。保存文件并关闭记事本。

场景4步骤

(1)打开Tomcat安装目录,打开conf目录,用记事本打开server.xml配置文件,找到如下配置选项。


<Host name="localhost"  appBase="webapps"
            unpackWARs="true" autoDeploy="true"> 

(2)在上述代码后,输入如下配置选项,然后保存server.xml配置文件并关闭记事本。


<Context docBase="C:/test/" path="/abc/" /> 

注意

Java是区分大小写的,需要注意Context、docBase和path中字母的大小写。

说明1:docBase配置了Web项目部署到Tomcat后的绝对物理路径,也称为Web项目的根目录;path配置的Web项目虚拟路径必须以“/”开头,表示以Web服务器的根目录为起始目录。该配置选项的主要目的是“告诉”Web服务器,Web项目的虚拟路径与Web项目根目录之间的对应关系。

在浏览器地址栏输入网址http://localhost:8080/abc/时,Web项目虚拟路径“/abc/”会指向Web服务器上的绝对物理路径“C:/test/”,然后访问“C:/test/”里的默认资源文件(这里是index.jsp)。

说明2:Web项目虚拟路径,通常作为URL路径的一部分。

(3)停止Tomcat服务,再次启动Tomcat服务。

Tomcat配置文件server.xml一旦被修改,就需要重启Tomcat服务,修改后的配置文件才能生效。

注意

启动Tomcat时,Tomcat会自动加载docBase指定的目录,如果参数错误或者目录不存在,就会导致Tomcat启动失败。

(4)打开浏览器,输入网址http://localhost:8080/abc,执行结果如图所示。

通过上述步骤,成功地将“C:\test\”部署为Web项目的绝对物理路径。

注意

“C:/test/”中Web项目的存在导致webapps目录下的abc项目被“隐身”。

场景5 任意的物理绝对路径都可以部署Web项目(方法二)

说明

本场景依赖于场景4准备工作。

场景5步骤

(1)打开C:\apache-tomcat-9.0.29\conf\Catalina\localhost目录,新建文本文档,重命名为hello.xml。

(2)用记事本打开hello.xml,输入如下配置选项,然后保存配置文件并关闭记事本。


<Context docBase="C:/test/" /> 

分析:hello.xml配置文件的文件名hello(不包括扩展名)配置了Web项目虚拟路径,docBase配置了Web项目部署后的绝对物理路径。

(3)无须手动重启Tomcat服务。

(4)打开浏览器,输入网址http://localhost:8080/hello,执行结果如图所示。

知识汇总:场景4和场景5中,配置了两个虚拟路径,分别是/hello/和/abc/,它们都指向C:\test\。

使用场景4的方法,需要手动重启Tomcat服务。使用场景5的方法,Tomcat服务会自动重启。

说明

取消发布的Tomcat项目时,不要忘记删除server.xml配置中对应的Context,也不要忘记删除C:\apache-tomcat-9.0.29\conf\Catalina\localhost目录下对应的XML文件,更不要忘记重启Tomcat服务。