Servlet 基础详解

1. Servlet简介
     Servlet是服务器端的重要组件,直译为服务端的小程序,它属于动态资源,用来处理请求,服务器接收到请求后会调用Servlet来处理请求。
     Servlet的主要作用 : 接收请求 , 处理请求 , 完成响应 。
     例如:
     当我们要完成一个登录功能时,用户会将输入的用户名和密码以POST请求的形式发送到服务器,但是服务器本身并不具有能力来读取用户发送的用户名和密码,也就不可能对用户名和密码进行验证,所以当服务器收到这类请求后需要将请求转个一个Servlet处理。
     Servlet实现类由我们编写,而由Web服务器(Servlet容器)调用,每个Servlet都必须实现javax.servlet.Servlet

2.HelloServlet
(1) 创建一个类并实现Servlet接口
public class HelloServlet implements Servlet {

    @Override
    public void init(ServletConfig config) throws ServletException {
    }

    @Override
    public ServletConfig getServletConfig() {
        return null;
    }

    /**
     * service方法是Servlet最重要的方法,Servlet每次接收请求时
     * 都会调用service方法
     * request:代表的是请求报文,是浏览器发送给服务器的
     * response:代表的是响应报文,是服务器发送给浏览器的
     */
    @Override
    public void service(ServletRequest request, ServletResponse response)
            throws ServletException, IOException {
        System.out.println("这是我的第一个Servlet!!");
        //向浏览器返回一个内容
        //获取一个输出流
        PrintWriter out = response.getWriter();
        //通过流向浏览器输出一个内容
        out.print(new Date());
    }

    @Override
    public String getServletInfo() {
        return null;
    }

    @Override
    public void destroy() {
    }

}
(2) 在WEB-INF目录下的web.xml文件中注册映射Servlet.
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
  <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>
</web-app>

<!--
   注册servlet
     servlet-name:Servlet的别名,在服务器中Servlet所有的配置都是通过别名,这个名字是给程序员用的,程序员通过别名对Servlet进行配置。
     servlet-class:Servlet的全类名,用来创建Servlet实例, 这个名字是给服务器使用的,服务器通过全类名来创建Servlet实例。
     url-pattern:为Servlet映射的请求地址,通过该地址可以访问我们创建的Servlet,这个名字是给用户使用的,用户通过该地址来访问Servlet。
-->
3.Servlet的生命周期:Servlet对象从被创建到被销毁的过程。
当我们第一次访问Servlet时,有三个方法被调用了: 构造器 ,init ,service 。
第一次以后每次访问,只会调用: service
当服务器停止时: destroy
(1) 构造器
    当Servlet第一次接收请求的时候调用,用来创建Servlet对象,只调用了一次。
    Servlet是一个单例的,在服务器中同一个Servlet只有一个实例。
    它是以多线程的形式调用service方法
    Servlet不是线程安全,所以在service方法尽量不要操作全局变量
(2) init()
    在构造器调用之后马上被调用,用来初始化Servlet,只调用了一次。
(3) service()
    每次处理请求时,service都会调用,用来处理请求,会调用多次。
(4) destroy()
    当停止服务器时(项目卸载、Servlet对象销毁前),用来做一些收尾工作,只会调用一次。
4. ServletConfig
(1) 代表:SerlvetConfig代表的是Servlet的配置信息,具体来说就是Servlet标签中的内容,每一个Servlet都有其唯一的ServletConfig
(2) 获取:该对象由服务器创建,最终会作为参数传递到init()方法,我们可以在init中直接使用
(3) 功能
     ① 可以获取Servlet的别名
     ② 可以获取当前Servlet的初始化参数
     ③ 获取ServletContext对象:
@Override
    public void init(ServletConfig config) throws ServletException {

        //获取Servlet的别名
        String servletName = config.getServletName();
        System.out.println(servletName);

        //获取当前Servlet的初始化参数
        String user = config.getInitParameter("user");
        String pwd = config.getInitParameter("password");
        System.out.println(user+"--"+pwd);

        //获取ServletContext对象
        ServletContext servletContext = config.getServletContext();
        System.out.println(servletContext);
    }
5.ServletContext
(1) 代表:ServletContext代表的是整个的WEB应用,每一个WEB应用都有其唯一的一个ServletContext
(2) 获取:通过ServletConfig的getServletContext()方法获取
(3) 功能:
     ① 获取整个WEB应用的初始化参数
     ② 获取资源的真实路径(主要用来做文件的上传和下载)
                 String realPath = servletContext.getRealPath("index.html");
                 真实路径(物理路径):C:\Users\lilichao\Desktop\day07\note\笔记.txt
                 虚拟路径:http://localhost:8080/08_WEB_Servlet/BServlet
      ③ 作为一个域对象在不同的WEB资源之间共享数据
@Override
    public void service(ServletRequest req, ServletResponse res)
            throws ServletException, IOException {
        //获取ServletContext
        ServletContext servletContext = config.getServletContext();
        //获取整个web应用的初始化参数
        String phone = servletContext.getInitParameter("phone");
        System.out.println("phone = "+phone);
        //获取index.html的真实路径
        String realPath = servletContext.getRealPath("hello.html");
        System.out.println(realPath);
    }
6.GenericServlet
     在显示开发中我们如果直接实现servlet接口功能也是可以正常实现的,但是所面临的问题是:如果我直接实现Servlet接口,那接口中的所有方法都必须要实现,但是这些方法有的我们用不到,而有的方法实现起来很麻烦而且没给servlet实现的代码都差不多,于是我们就需要一个抽象类来帮助我们实现servlet接口,实现一些通用的方法,而我们只需要继承GenericServlet就可以了,这样的好处是我们不在需要重写全部方法,而只需要重写必须的和我们需要的方法就可以。

7. HttpServlet
     HttpServlet是GenericServlet的子类,他是Tomcat中专门处理HttpServlet的Servlet(实际上Tomcat只处理Http类型的请求)所以在一般情况下我们都会通过继承HttpServlet来实现servlet。
     HttpServlet和GenericServlet一样都是一个抽象类,也就是不能对它们进行实例化,与GenericServlet不同HttpServlet中没有任何抽象方法,所以需要我们根据实际需求来重写它的方法。
     在GenericServlet中service(ServletRequest req, ServletResponse res)方法是一个抽象方法,必须要由子类实现,而在HttpServlet中已经被实现,而在HttpServlet的实现的方法中会被强制转换成HttpServletRequest和HttpServletResponse(不用担心会出现类型转换异常,因为传过来的对象本身就是该类型)。转换类型之后会调用HttpServlet中的一个重载的service(HttpServletRequest req, HttpServletResponse resp)方法。也就是说如果我们要重写service()方法不必再去重写GenericServlet的service()方法了,而可以直接重写HttpServlet重载的service()方法就可以了。
     在service(HttpServletRequest req, HttpServletResponse resp)方法中,会对它的请求类型进行判断,然后根据请求类型的不同再去调用不同的方法。如:post类型的请求回去调用doPost(),get请求回去调用doGet(),delete请求回去调用doDelete(),以此类推。但是在实际应用中我们只会使用到doPost()和doGet(),所以一般情况下我们不会去重写service()方法,而是去重写更简单的doGet()或者doPost()。
    
8.HttpServletRequest 和  HttpServletResponse
(1)  HttpServletRequest
     代表:代表的是浏览器发送给服务器的请求报文
     获取:该对象由服务器创建最终作为参数传递doGet()或者doPost()方法中,我们可以在这两个方法中直接使用。
     功能:
     ① 获取用户发送的请求参数
     ② 获取项目的名字(主要用来设置绝对路径)
     ③ 可以作为一个域对象在不同的web资源之间共享数据。
     ④ 可以做请求的转发: 转发就是Servlet收到请求以后,自己不去处理请求,而是调用服务器内部的其他资源去处理请求
(2)  HttpServletResponse
     代表:代表是服务器发送给浏览器响应报文。
     获取:该对象由服务器创建最终作为参数传递doGet()或者doPost()方法中,我们可以在这两个方法中直接使用。
     功能:
     ① 向浏览器输出一个页面片段,这个方法实际上是在设置响应报文的响应体。
     ② 做请求的重定向
          所谓的重定向,指Servlet收到浏览器发送的请求以后,返回给浏览器一个特殊的响应,这个特殊的响应告诉浏览器,再去向另一个地址发送请求。
     ③ 重定向的特点:
     【1】重定向时浏览器发送了 2 次请求。
     【2】重定向是在浏览器端发生。
     【3】重定向时浏览器的地址栏会发生变化。
     【4】浏览器可以知道重定向的发生。  
(3) 代码说明
public class FServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;   
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        /**
         * 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);
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        /**
         * HttpServletResponse
         *     代表:代表是服务器发送给浏览器响应报文。
         *     获取:该对象由服务器创建最终作为参数传递doGet()或者doPost()方法中,我们可以在这两个方法中直接使用。
         *  功能:
         *      [1]向浏览器输出一个页面或者是页面片段
         *      [2]做请求的重定向
         */
        //向浏览器输出一个页面片段
        //这个方法实际上是在设置响应报文的响应体
        //1.获取一个输出流
        PrintWriter out = response.getWriter();
        //2.通过这个流向浏览器输出一段信息
        out.print("<h1>Hello Servlet!</h1>");
        //做请求的重定向
        response.sendRedirect("target.html");
    }
}

(4) 转发和重定向的对比:

     在一般情况下,用户名验证码等都正确就重定向到成功页面,如果失败就转发到失败页面。例如:
     重定向:response.sendRedirect(request.getContextPath()+ "/pages/user/regist_success.html" );
     转  发 :request.getRequestDispatcher( "/pages/user/regist_error.html" ).forward(request,response);
   
9.字符编码
     计算机在传输字符,需要将字符转换为二进制数据来传输,读取内容时又需要将二进制数据转换为字符,编码和解码所使用的规则,我们称为字符集,常见的字符集: ASCII、ISO-8859-1、GBK、GB2312、UTF-8。
     产生乱码问题的根本原因:编码和解码所采用的字符集不同。
     解决方案:统一编码和解码所采用的字符集为utf-8。         
(1) 请求:浏览器 --> 服务器 : 浏览器编码,服务器解码
     ① 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"  connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443"/>
(2) 响应:服务器 --> 浏览器 : 服务器编码,浏览器解码。
      解决方案:在向浏览器返回响应之前,调用如下代码: response.setContentType("text/html;charset=utf-8");

10.路径问题
    URL地址的格式:http://主机地址:端口号/项目名/资源路径/资源名
(1) 相对路径:
    相对路径相对于:http://主机地址:端口号/项目名/资源路径/
    由于转发的出现,相对路径非常容易出错,所以在开发中我们不使用相对路径,而是使用绝对路径。
(2) 绝对路径
    绝对路径使用 "/" 开头;
    由浏览器去解析的绝对路径,这个"/"代表的是服务器的根目录,http://主机地址:端口号/
         注意:由浏览器解析的绝对路径,我们需要添加上项目名。
    由服务器解析的绝对路径,这个"/"代表的是项目的根目录
         即:http://主机地址:端口号/项目名/所以由服务器解析路径不需要加上项目名。
(3) 常见的路径:
     ① url-pattern:
     ② 转发的路径:               
          url-pattern和转发的路径都是由服务器所解析的,是以项目的根目录为根目录, 即: "/"代表的是项目的根目录:http://主机地址:端口号/项目名/
     ③  重定向的路径:
     ④  页面中的路径:
           重定向和页面中的路径都是由浏览器解析的,是以服务器的根目录为根目录,即: "/"代表的是服务器的根目录:http://主机地址:端口号/
(5) base标签(HTML页面的处理方式):
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>

<!-- base标签中的href属性,将会作为页面中所有相对路径的前缀 -->
<!-- base标签的作用就是让我们可以以使用相对路径的方式使用绝对路径 -->
<!-- base标签只对相对路径起作用 -->
<base href="http://localhost:8080/10_WEB_Path/" />

</head>
<body>
    <h1>我是网站的首页</h1>

    <!-- 使用绝对路径 -->
    <a href="/10_WEB_Path/hello/1.html">去1.html</a>

    <hr />

    <!-- 使用base标签 -->
    <a href="hello/1.html">去1.html</a>

</body>
</html>

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员学习圈

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值