Servlet:服务器端小程序,可以提供动态页面,可以与后台交互,运行在servlet容器中。

Servlet的三个关键:

① url-pattern:用户通过指定的url访问servlet,并不知道这个servlet名如何映射到服务器上的目录和文件。

② servlet-name:servlet在tomcat服务器中的唯一标识,用于部署servlet。不必与url-pattern相同,也不是必须为简单类名或者全类名,习惯使用简单类名。

③ servlet-class:servlet的全类名,tomcat使用全类名创建servlet实例。

编写Servlet的步骤:
1.创建一个类并实现Servlet接口
2.在服务器中对Servlet进行配置(web.xml)


xml配置文件内的格式:


<servlet>
<servlet-name>HelloServlet</servlet-name>
<servlet-class>com.atguigu.servlet.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>HelloServlet</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>

ServletRequest和ServletResponse:

- ServletRequest是由容器创建并传递到service()方法中,容器所创建的对象实际上是HTTPServletRequest,所以开发中我们都会将ServletRequest强转成HttpServletRequest。

- HttpServletRequest的方法:
>String getParameter(String paramName):获取指定请求参数的值;
>String getMethod():获取请求方法,例如get或post;
>String getHeader(String name):获取指定请求头的值;
>void setCharacterEncoding(String encoding):设置请求体的编码,因为GET请求没有请求体,所以这个方法
只对POST请求有效。当调用request.setCharacterEncoding("utf-8")之后,再通过getParameter()方法获取参数值时
那么参数值都已经通过了转码,即转换成了utf-8编码。所以,这个方法必须在调用getParameter()方法之前调用。
- HttpServletResponse的方法
>PrintWriter getWriter():获取字符响应流,使用该流可以向客户端输出响应信息。
例如response.getWriter().print(“<h1>Hello JavaWeb!</h1>”);
>ServletOutputStream getOutputStream():获取字节响应流,当需要向客户端响应字节数据时,需要使用这个流
例如向客户端响应图片;
>void setCharacterEncoding(String encoding):用来设置字符响应流的编码,例如在调用setCharacterEncoding("utf-8");
之后,再response.getWriter()获取字符响应流对象,这时的响应流的编码为utf-8,使用response.getEriter()输出
的中文都会转换成utf-8编码后发送给客户端。
>void setHeader(String name, String value):向客户端添加响应头信息,例如setHeader("Refresh", "3;url=http://www.atguigu.com"),
表示3秒后自动刷新到http://www.atguigu.com;
>void setContentType(String contentType):该方法是setHeader("content-type","xxx")的简便方法,即用来添加
名为content-type响应头的方法。content-type响应头用来设置相应数据的MIME类型,例如要向客户端响应jpg的图片,
那么可以setContentType("image/jepg"),如果相应数据为文本类型,那么还要同时设置编码,
例如setContentType("text/html;chartset=utf-8")表示响应数据类型为文本类型中的html类型,并且该方法会调用
setCharacterEncoding("utf-8")方法;
>void sendError(int code, String errorMsg):向客户端发送状态吗,以及错误消息
例如给客户端发送404:response(404, "您要查找的资源不存在!");

ServletConfig
- ServletConfig对象对应着web.xml文件中的一个<servlet>元素,例如,想要获取元素中的<servlet-name>的值,
那么可以使用servletConfig.getServletName()方法来获取。
- ServletConfig对象同样有容器创建,然后作为参数传递给init()方法,可以在init()方法中使用。
- ServletConfig的方法:
>String getServletName():获取Servlet在web.xml文件中的配置名称,即<servlet-name>指定的名称。
>ServletContext getServletContext():用来获取ServletContext对象;
>String getInitParameter(String name):用来获取在web.xml中配置的初始化参数,通过参数名来获取参数值。
>Enumeration getInitParameterNames():用来获取在web.xml中配置的所有初始化参数名称。
>每一个init-param表示一个初始化参数,通过getInitParameter(String name)可以根据param-name的值获取到param-value的值。
>每个servlet中可以配置多个init-param,servlet只能获取自身的初始化参数,而不能获取其他servlet的初始化参数。


[1] Servlet 的生命周期
>Servlet的生命周期是Servlet对象从被创建到被销毁的过程。
>Servlet 的生命周期方法:
- 构造器
- Servlet第一次处理请求时调用。
- 用来创建Servlet实例。
- 只调用一次,说明Servlet是单例,且Servlet不是线程安全的,它是以多线程的方式去调用service()方法。
所以尽量不要在service()方法中操作全局变量。

- init()
- 构造器调用之后马上执行。
- 用来初始化Servlet。
- 只会调用一次。

- service()
- 每次处理请求时都会调用。
- 用来处理用户的请求,会调用多次。

- destroy()
- Servlet对象被销毁之前调用
- 主要用来作一些收尾工作,比如释放资源,存储数据等。
- 只会调用一次。

> ServletConfig
- 代表的当前Servlet的配置信息。
- 每一个Servlet都有其唯一对应的ServletConfig。
- 该对象由服务器创建,最终作为参数传递到init() 方法中,我们可以在这个方法中直接使用。
- 如果通过继承HttpServlet来创建一个Servlet,可以直接调用它的方法。
- 作用:
[1] 获取Servlet的别名
[2] 获取当前Servlet的初始化参数。

<servlet>
<servlet-name>BServlet</servlet-name>
<servlet-class>com.atguigu.servlet.BServlet</servlet-class>
<init-param>
 <param-name>user</param-name>
 <param-value>root</param-value>
</init-param>
<init-param>
 <param-name>password</param-name>
 <param-value>123123</param-value>
</init-param>
 </servlet>

String password = config.getInitParameter("password");
System.out.println(username);


[3] 获取ServletContext对象。


>ServletContext
- 代表的是整个WEB应用
- 每一个WEB应用都有其唯一对应ServletContext对象。
- ServletContext对象在项目启动时创建,在项目停止时销毁。
- 如果是HttpServlet的子类,则可以直接调用getServletContext()方法
- 功能:
[1] 获取整个web应用的初始化参数。

<context-param>
<param-name>phone</param-name>
<param-value>1388888888</param-value>
</context-param>


[2] 获取资源的真实路径(物理路径),主要用来做文件的上传和下载。
[3] 作为一个域对象在不同的web资源之间共享数据。

[2] HttpServletRequest
* HttpServletRequest
* 代表:代表的是浏览器发送给服务器的请求报文
*  获取:该对象由服务器创建最终作为参数传递doGet()或者doPost()方法中,我们可以在这两个方法中直接使用。
*  功能:
*   [1]获取用户发送的请求参数
*   [2]获取项目的名字(主要用来设置绝对路径)
*   [3]可以作为一个域对象在不同的web资源之间共享数据。
*   [4]可以做请求的转发

//获取用户发送的请求参数
String username = request.getParameter("um");
String password = request.getParameter("password");
//将用户名输出到页面中
response.getWriter().print("username = "+username +"<br />");
response.getWriter().print("password = "+password);

//获取项目名
String contextPath = request.getContextPath();
System.out.println(contextPath);

//发起请求的转发
//1.获取一个请求的派发器
RequestDispatcher dispatcher = request.getRequestDispatcher("target.html");
//2.使用派发器发起转发
dispatcher.forward(request, response);


[3] HttpServletResponse
* HttpServletResponse
* 代表:代表是服务器发送给浏览器响应报文。
* 获取:该对象由服务器创建最终作为参数传递doGet()或者doPost()方法中,我们可以在这两个方法中直接使用。
*  功能:
*   [1]向浏览器输出一个页面或者是页面片段
*   [2]做请求的重定向

转发和重定向:
转发:
*转发就是Servlet收到请求以后,自己不去处理请求,而是调用服务器内部的其他资源去处理请求
*转发的特点:
* 1.转发时浏览器发送了 1 次请求 。
*  2.转发是在服务器内部进行。
*  3.转发时浏览器地址栏不会发生改变。
*  4.浏览器不知道转发的发生。

重定向:
* 所谓的重定向
* 指Servlet收到浏览器发送的请求以后,返回给浏览器一个特殊的响应,
* 这个特殊的响应告诉浏览器,再去向另一个地址发送请求。
* 这个特殊的响应是:
* HTTP/1.1 302 Found
Location: http://localhost:8080/08_WEB_Servlet/target.html

这个特殊响应的响应状态码是302,同时会有一个Location响应头,这个头指向了一个新的地址。
当浏览器收到302响应状态吗,它就会去找Location响应头,然后再次向Location指向的地址发送请求。

重定向的特点:
1.重定向时浏览器发送了 2 次请求。
2.重定向是在浏览器端发生。
3.重定向时浏览器的地址栏会发生变化。
4.浏览器可以知道重定向的发生。

对比:
转发 重定向
请求次数 1 2
发生的位置 服务器内部浏览器
浏览器的地址栏 不变 改变
浏览器的感知 不知道 知道

[4] 字符编码
- 计算机在传输字符,需要将字符转换为二进制数据来传输,读取内容时又需要将二进制数据转换为字符。
- 编码
- 将字符转换为二进制编码的过程叫编码
- 解码
- 将二进制字符转换为字符的过程叫解码
- 编码和解码所使用的规则我们称之为字符集
- 常见的字符集:
ASCII、ISO-8859-1、GBK、GB2312、UTF-8
- 产生乱码问题的根本原因:编码和解码所采用的字符集不同。
- 解决方案:统一编码和解码所采用的字符集为utf-8。

- 请求:
请求:浏览器 --> 服务器 , 浏览器编码,服务器解码
- 浏览器会自动根据当前网页的字符集去编码。而我们的页面中使用的编码全都是utf-8,所以浏览器会使用utf-8去编码。

post请求
- post请求是在Servlet中解码的。
- Servlet中默认使用的是iso-8859-1,而它不支持中文,所以肯定乱码。
- 所以post请求我们只需要去指定request使用的字符集即可。
- 解决方案:
- 在 request.getParameter() 方法第一次调用之前调用一下代码:(重要)
request.setCharacterEncoding("utf-8");

get请求
- get请求是通过url地址来传递请求参数的,它会由Tomcat服务器自动解码,而服务器默认使用的是iso-8859-1。
- 解决方案:修改服务器默认的解码字符集
- 在server.xml配置文件中,在Connector标签中,添加一个URIEncoding="utf-8"。
<Connector URIEncoding="utf-8" connection Timeout="20000" port="8080" protocol="HTTP/1.1" redirectProt="8443"/>

请求中post请求需要调用setCharacterEncoding() 方法改变编码。get请求改了一次之后后面就不用管了。

- 响应
响应:服务器 --> 浏览器
服务器编码,浏览器解码
- 服务器默认使用的是iso-8859-1编码,所以我们需要修改服务器编码规则。
- 设置response编码:
response.setCharaterEncoding("utf-8");

虽然这里设置了服务器的编码规则,但是浏览器默认使用的是gb2312解码,所以我们还需要去指定浏览器的解码规则。
我们需要通过一个响应头来告诉浏览器,我们网页所使用的字符集,这样浏览器就会自动使用该字符集去解码。
需要的响应头:Content-Type:text/html;charset=utf-8
设置一个响应头:
reponse.setHeader("Content-Type" , "text/html;charset=utf-8");
或者:(重要)
response.setContentType("text/html;charset=utf-8");

[5] 路径问题
URL地址的格式:
http://主机地址:端口号/项目名/资源路径/资源名
①相对路径和绝对路径
- 相对路径:
相对于当前资源所在的路径
相对路径相对于:http://主机地址:端口号/项目名/资源路径/
由于转发的出现,相对路径非常容易出错,所以在开发中我们不使用相对路径。而是使用绝对路径。

- 绝对路径:
绝对路径使用 “/” 开头
由浏览器去解析的绝对路径,这个 “/” 代表的是服务器的根目录
http://主机地址:端口号/
注意由浏览器解析的绝对路径我们需要添加上项目名

由服务器解析的绝对路径这个 “/” 代表的是项目的根目录
http://主机地址:端口号/项目名/
所以由服务器解析路径不需要加上项目名

②常见的路径:
url-pattern:
转发的路径:
- url-pattern和转发的路径都是由服务器锁解析的,是以项目的根目录为根目录
"/"代表的是项目的根目录:
http://主机地址:端口号/项目名/

重定向的路径:
页面中的路径:
- 重定向和页面中的路径都是由浏览器解析的,是以服务器的根目录为根目录的,
"/"代表的是服务器的根目录:
http://主机地址:端口号/

另:在一个页面的上面加上
<base href="http://localhost:8080/WEB_Path/" />
base标签就可以相当于给整个页面的相对路径前面都加上了这个路径,注意调整。