目录
四、Servlet-api.jar包导入和Content-Type问题
9.3 ServletContext应用域对象相关API方法
13.1.3 System.out.println()乱码问题
一、Servlet简介
动态资源与静态资源:
- 静态资源:程序在运行之前就已经生产好的数据资源、无需在程序运行期间来生成的资源,如:html、css、js以及音视频等。
- 动态资源:在程序运行期间由程序根据用户需求来现场生成的资源数据,如servlet(运行Java代码生成响应数据给前端用户)
就好比一个人去蛋糕店,如果是直接买柜台上已事先做好的蛋糕就是静态资源、要求柜员现做蛋糕就是动态资源。
二、Servlet运行流程
说明:不是所有的Java类对象都能接收处理并响应数据给客户端浏览器,只有是实现了Servlet接口的类对象才能处理用户浏览器的请求并响应数据。因此,我们可以称Servlet为web应用中的控制器。Servlet是运行在服务端的所以Servlet必须在web项目中开发且在Tomcat这样的服务容器中运行。
- 用户浏览器发送请求到Tomcat服务器。
- Tomcat服务器收到用户的请求后就会事先创建一个HttpServletRequest类对象(将用户的请求报文信息封装到此对象中)和HttpServletResponse对象(后面Servlet就会将要响应给浏览器的数据封装在此对象中)。
- Tomcat根据用户浏览器的请求访问资源路径(也称作应用上下文路径)去找相应的Servlet类并将其实例化(首次访问此Servlet才会被实例化),然后调用Servlet对象中的server()方法并将事先生成好的HttpServletRequest对象和HttpServletResponse对象作为实参传递给此方法的对应形参。
- Tomcat就会根据开发人员在Servlet的service()方法中编写的Java代码来处理用户的请求并将要响应给用户浏览器的数据封装在HttpServletRequest对象中。
- service()方法执行完毕后,Tomcat会将HttpServletRequest对象中的数据转化为Http响应报文发送给用户浏览器。
- 用户浏览器收到Tomcat的响应报文后,根据响应头中的Content-Type属性值来解析响应体中的数据并将其结果渲染到浏览器标签页上。
三、Servlet开发流程
- 首先创建一个普通的Java项目
- 为Java项目添加Servlet要使用依赖的类库即jar包。
- 为Java项目添加WEB资源组件(会在项目中生成一个WEB目录),使其成为一个JavaWeb项目。
- 编写前端页面html代码。
- 定义一个Java类并实现Servlet接口,即重写service方法service(HttpServLetRequest req,HttpServLetResponse resp)
- 在web.xml中,配置ServLet对应的请求映射路径。
- 将开发好的web项目部署到Tomcat中运行。
四、Servlet-api.jar包导入和Content-Type问题
4.1 Servlet-api.jar导入问题
此jar包中存放着与Servlet相关的已经编写好的供开发人员使用的第三方类库。如:Servlet接口、HttpServlet类等。
说明:
- 在web/WEB-INF/lib目录中导入的jar包,在项目构建后会将lib目录中导入的jar包也放在构建好的项目中。而当将构建好的项目部署到Tomcat的webapps目录中后,实际上Tomcat的lib目录下的所有jar包,包括 Servlet-api.jar都会共享给webapps目录中的所有web项目使用。因此,构建后的JavaWeb项目中就没必要也携带一些Tomcat服务中已经有的jar包了。一般在web/WEB-INF/lib目录中导入目需要使用的第三方jar包类库。
- 如果想让构建好的项目中不携带Servlet-api.jar包,只需要在项目的项目结构中找到依赖设置模块,并按此方式添加所需jar包即可。
4.2 Http报文头中的Content-Type属性
此属性也被称作MIME类型、媒体类型、文件类型或响应的数据类型。此属性用于告诉http报文的接收者以什么样的方式来处理解析http报文体中的数据内容。
说明:Tomcat会根据用户浏览器请求的文件扩展名去读取apache-tomcat-10.1.19\conf\web.xml配置文件中定义的此种扩展名对应的mime类型,然后将其值作为响应报文中的Content-Type属性的值响应给用户浏览器。如果Tomcat在web.xml文件中没有找到用户请求的文件扩展名对用的mime类型,则Tomcat响应给浏览器的报文头中就不会携带Content-Type属性值,默认浏览器以text/html方式来解析响应体中的数据并将其渲染到标签页中。
五、Servlet_url-pattern请求映射路径设置
Tomcat服务器收到用户的请求后会根据用户请求的项目查看其下的web.xml配置文件中servlet映射路径,如果用户请求的项目名下的URL路径匹配某个Servlet类的url-pattern标签,Tomcat就会将用户的请求交给匹配的Sevlet类对象并调用其service()方法来处理用户的请求。
5.1 url-pattern方式
- 精确匹配,如: /servlet1
- 模糊匹配:
* : 表示匹配任意多个字符
/: 表示匹配全部,不包含jsp文件
/a/*: 匹配前缀后缀模糊
*.action: 匹配后缀前缀模糊
5.2 注解方式配置servlet
@webServlet注解相关属性
- name: 给Servlet起别名。类似与web.xml中的<servlet-name>双标签。
- value和urlpatterns: 指定Servlet的上下文访问路径,其中若要是给value属性赋值则可以直接写成@webServlet("/访问路径"),Patterns属性以一维字符串数组的形式可以给一个Servlet对象指定多个请求访问路径。
六、Servlet生命周期
①实例化Servlet(Tomcat根据用户请求的Servlet映射路径实例化对应的Servlet对象)----->调用构造器-------->默认为用户首次请求执行一次或设置为Tomcat服务启动项目运行时实例化一次(一次)。
②初始化------->调用Servlet继承的有参init(ServletConfig config)方法,此方法内调用我们重写的无参init()方法(构造完毕),----->构造完毕执行一次(一次)
③接收用户请求、处理和响应数据------>调用Servlet对象的service()方法-------->用户浏览器每次请求执行一次(多次)
④销毁Servlet对象------->销毁之前调用destory()方法----------->关闭Tomcat服务时执行一次(一次)。
说明: Servlet在Tomcat中是单例的,也就是说多个用户并发请求同一个Servlet时,用户之间使用同一个内存中的Servlet对象。因此,任意一个用户对Servlet成员变量的修改都会导致其他的用户同名变量值更改,不建议在service方法中修改成员变量的值。
设置Servlet在项目开启运行时实例化:
- web.xml配置文件方式
- @WebServlet注解方式
说明: Tomcat的conf/web.xml文件是所有项目的全局配置文件,一些项目的公共配置都放在此文件中,其中包括一些Tomcat自带的Servlet设置为服务开启时实例化的Servlet类,如:DefaultServlet。因此1-5序号的Servlet都被Tomcat默认占用了,虽然当Servlet设置为启动实例化的序号冲突时Tomcat会自动协调但建议在设置时使用5序号以下的。
说明:Tomcat服务收到用户的请求后会根据用户的上下文访问路径(url),将请求发给对应匹配的Servlet处理;若用户请求的url路径没有与之匹配的Servlert映射路径,则Tomcat默认将请求发给Tomcat内置的DefaultServlet处理,然后DefaultServlet对象在通过IO流找到并读取用户请求的静态资源文件将其放到HttpServletResponse对象中,并根据全局web.xml配置文件找到对应的mime类型设置响应报文头的content-type属性放到HttpServletResponse对象中。最后Servlet执行完毕,Tomcat将HttpServletResponse对象转化为响应报文发送给客户端(*用户请求的静态资源都是由DefaultServlet处理的)。
七、Servlet继承结构
7.1 Servlet接口
7.2 GenericServlet抽象类
此抽象类中实现了除service方法以外的所有Servlet接口中的抽象方法。
7.3 HttpServlet抽象类
此抽象类继承了GenericServlet抽象类并重写service方法。
用户自定义的Servlet类中也可以通如下方式来处理用户浏览器发送过来的请求:
八、ServletConfig类
ServletConfig对象用来为要实例化的Servlet提供键值对形式的初始配置参数。
当Tomcat要实例化一个Servlet对象时、在调用Servlet的有参init方法前会先根据项目下的web.xml配置文件中<init-param>双标签或注解的方式,将开发者提供的Servlet初始参数封装到ServletConfig对象中,然后Tomcat再调用Servlet的有参init方法时,在将ServletConfig对象以实参的形式传递给init方法的形参并将其作为用户自定义Servlet对象所在父类的私有属性,用户自定的Servlet可以调用方法来获取ServletConfig对象,从而获取到里面封装的初始化参数。
说明:每个Servlet都有各自的一个ServletConfig对象,供本Servlet使用。
web.xml方式配置Servlet初始参数:
注解方式配置Servlet初始参数:
九、ServletContext类
此ServletContext对象被称作上下文对象或应用域对象,其主要功能有:①为app下所有Servlet提供初始参数 ②获取项目中某文件所在物理磁盘路径或项目访问的上下文路径即虚拟目录。
9.1 为项目下所有Servlet提供初始参数
9.2 获取项目下某文件物理磁盘路径或项目访问上下文URL
9.3 ServletContext应用域对象相关API方法
用于存储和传递数据的对象我们称之为域对象(如生活中的快递站点),根据域对象传递数据的范围不同(作用域不同)域对象有不同的称呼如:应用域、会话域、请求域。
十、HttpServletRequest请求对象
HttpServletRequest是一个接口其父接口是ServletRequest。它是由Tomcat收到用户浏览器的请求报文转化而来,里面封装了请求报文的所有信息。Tomcat在将用户请求转发给Servlet时会自动将该对象传给service方法的形参,开发者可以在service方法中通过该对象获取用户请求报文中的所有信息。
HttpServletRequest常见API:
- 获取请求行信息
- 获取请求头信息
- 获取请求参数
- 其它API
十一、HttpServletResponse对象
HttpServletResponse是一个接口其父接口是ServletResponse。此对象是由Tomcat接收用户请求后自动创建的,并在将请求转发给Servlet时传递给service方法。HttpServletResponse对象代表着服务端要响应给客户端的响应报文信息,在Servlet方法执行完毕后Tomcat会将此对象转化为响应报文发送给客户端浏览器。因此,可以使用此对象设置要响应给客户端的响应报文中的内容。
HttpServletResponse常见API:
- 设置响应行
- 设置响应头
- 设置响应体
- 其它API
十二、请求转发与响应重定向
12.1 请求转发
用户向ServletA发送请求------>ServletA收到用户请求后将请求信息转发给项目内的其它资源------>项目内其它资源响应客户端信息。
特点:
- 请求转发是通过HttpServletRequest对象实现的。
- 请求转发由服务器内部完成,客户端是感知不到的且其地址栏没有变化。
- 在请求转发过程中客户端只发送了一次请求,服务端也只产生了一对request和response对象。
- 在转发过程中请求参数也会包含在request对象中继续传递
- 转发到的目标资源可以是项目内的动态资源(其它Servlet)、也可以是静态资源(html文件),包括受保护的WEB-INF目录下的资源(也是访问WEB-INF目录下资源的唯一方式)
- 转发到的目标资源不能是外部其它网站的资源。
12.2 响应重定向
用户向ServletA发送请求-------->Tomcat收到请求产生一对request和response对象并将其交给ServletA处理请求;ServletA收到请求后回应客户端一个响应状态码为302、响应头location="目标资源访问路径"的响应报文------->客户端收到ServletA的响应报文后根据其报文中的location属性值向目标资源发送请求------>目标资源服务器如Tomcat收到请求后又产生新的一对request和response对象并将其交给ServletB处理请求------>ServletB处理客户端请求并发送响应报文给客户端。
特点:
- 响应重定向是通过HttpServletResponse对象实现的
- 响应重定向是服务端回应客户端目标资源路径、由客户端再次向目标资源发请求
- 客户端地址栏会发生变化
- 在响应重定向环境下,客户端总共下来至少要发送两次请求报文
- 客户端请求多次、服务端就会产生多次新的request和response对象。因此,客户端请求报文中的参数是不会继续传递给重定向到的目标资源。
- 响应重定向到的目标资源可以是除Tomcat服务中WEB-INF目录下受保护资源以外的任意资源,包括其它网站资源。
说明:要实现页面跳转优先考虑使用响应重定向方式。
十三、Web乱码和路径问题
13.1 乱码问题
数据在存储介质中都是以二进制01的形式来存储的,我们使用的字符必须转换为二进制的数字才能存到计算机中。字符集就是规定了我们生活中使用的字符在存储到计算机时对应的二进制数,类似于英汉互译字典。为了方便人们可阅读字符集到二进制数的映射关系,通常在查看字符集编码时某个字符对应存储到计算机的二进制数会以十进制的形式供读者阅读查看。一般不管什么样的字符集其英文字符编码的二进制数都是一样的,因此英文在任意字符集中都不会出现乱码。
产生乱码的根本原因:
- 文件数据在存储时使用的编码和在读取文件时使用的解码不是同一个字符集。
- 使用了不支持某种语言文字的字符集。
13.1.1 HTML文件渲染到标签页乱码问题
说明: 在IDEA中对charset属性值的修改,IDEA会自动调整设置文件编码使用的字符集。
13.1.2 IDEA控制台乱码问题
IDEA控制台打印日志时之所以出现乱码是因为,默认情况下我们系统控制台在打印日志解码时使用的字符集是GBK,而Tomcat产生的日志数据使用的编码字符集是UTF-8,从而导致控制台输出日志时出现乱码。
解决方案一:可以通过找到Tomcat服务器的日志配置文件logging.properties,修改日志生成时使用的字符编码与控制台解码使用的字符集一样即可,通常设置为GBK。
解决方案二:设置IDEA控制台解码使用的字符集与日志编码使用的字符集一致。
13.1.3 System.out.println()乱码问题
之所以产生sout乱码,是因为我们在对源文件进行编译生成的".class"文件使用的编码字符集(通常为UTF-8)与JVM在读取运行".class"文件时使用的解码字符集不一致导致的。
解决方案: 设置JVM在启动加载项目时使用的解码字符集为UTF-8。
13.1.4 GET请求参数乱码问题
html文件head头标签中"<meta charset="GBK">"设置的字符集不仅指明了浏览器要使用什么样的字符集来读取html文件,同时也指定了html文件中的form表单提交时使用什么样的字符集来编码请求参数。
Tomcat服务端接收到用户get请求发送的参数之后出现乱码现象,是因为用户参数提交时编码使用的字符集与Tomcat解码get请求参数所使用的字符集不一致导致的。
说明:GET方式提交的参数默认会以键值对的形式被放在请求报文行URI的后面。
解决方案一: 修改html文件<meta charset="GBK">的字符集(一般改为utf-8)使其与Tomcat解析请求参数使用的字符集保持一致。
解决方案二:修改Tomcat解码请求参数使用的字符集与html文件中<meta charset="GBK">指定的字符集保持一致。
13.1.5 POST请求参数乱码问题
POST方式提交的参数同样是根据html文件中<meta charset="GBK">的字符集来进行编码的。并且这些参数会被放在请求报文体中发送给服务端。Tomcat服务器默认使用UTF-8来对请求体中的数据进行解码的,也可以在Servlet中使用HttpServletRequest对象的setCharacterEncoding方法来指定Tomcat对请求体内容解码使用的字符集。
解决方案一: 使用HttpServletRequest对象的setCharacterEncoding方法设置Tomcat解码请求体中的内容使用的字符集与参数charset指定的字符集保持一致。
解决方案二: 修改表单头标签中charset指定的字符集为UTF-8。
13.1.6 响应数据乱码问题
所谓的响应乱码是指Tomcat使用HttpServletResponse对象给客户端响应的数据、客户端浏览器在将响应体中的数据渲染到标签页上后出现乱码现象。
原因:Tomcat在使用HttpServletResponse对象的getWriter().write()向响应体中添加的数据默认使用的编码字符集为UTF-8,而客户端在解析响应体中的数据时,由于不知道使用什么字符集来解码响应体中的数据而默认使用GBK字符集(中文系统IE浏览器),从而导致响应体中的数据编码时使用字符集与浏览器解码时使用的字符集不一致,客户端出现乱码想象。
解决方案一:使用HttpServletResponse对象的setCharacterEncoding方法设置Tomcat在向响应体中添加数据时使用的编码字符集为GBK(不推荐)。
解决方法二: 使用HttpServletResponse对象的setContentType方法设置响应体的Content-Type响应头为UTF-8字符集。这样浏览器在解码响应体中的数据时就会根据响应头Content-type指定的字符集来解析响应体中的数据。
13.2 路径问题
13.2.1前端相对路径问题
- 相对路径规则是:从当前文件所在目录为出发点去寻找目标资源。在file协议下相对的是磁盘路径,在http协议下相对的是当前文件所在的url访问路径。
- 相对路径不以"/"开头,"."表示在当前目录路径下(可省略不写),“..”表示返回到上一层目录。
注意: 在http协议下目标资源的相对路径在书写时,相对是当前所请求文件url访问路径下,去寻找目标资源的所在路径;而不是相对所请求文件所在的物理磁盘路径下去寻找目标资源路径(是客户端浏览器来处理路径问题而不是服务端)。
13.2.2 前端绝对路径问题
- 绝对路径始终以固定的路径作为出发点去寻找目标资源。
- 在Tomcat中绝对路径的出发点即根路径是“http://主机名:端口号/”。
- 在代码层面使用“/”表示绝对路径的出发点即根路径。
优点:不管当前文件的访问路径如何变化,目标资源的访问路径不用做出任何改变。
缺点: 在使用绝对路径寻找目标资源文件时需要加上项目的上下文访问路径,当项目的上下文访问路径做了修改后,此绝对路径就会失效。如下是解决此绝对路径问题的两种方式:
方式一:用html文件中的head>base>href属性,定义相对路径公共前缀路径,这样客户端在请求目标资源时都会在相对路径前面补充公共路径。
方式二:在项目部署到Tomcat上时设置项目的访问上下文路径为"/",表示用户浏览器直接通过“http:主机名:端口号”就可以直接访问到本项目。这样在通过绝对路径找目标资源时就只需在目标资源路径前加上个"/"就代表着本项目。
13.2.3后端请求转发路径问题
- 后端请求转发相对路径的写法跟前端的写法类似。
- 后端请求转发绝对路径的根路径出发点是“http://主机名:端口号/项目访问上下文/”,因此请求转发绝对路径在书写时不能添加项目访问上下文,其它场景都需要。
说明: 后端请求重定向的相对路径和绝对路径的写法可以参考Web前端路径问题。
@声明:“山月润无声”博主知识水平有限,以上文章如有不妥之处,欢迎广大IT爱好者指正,小弟定当虚心受教!