JavaWeb-Servlet

来源:互联网 发布:马家军调查知乎 编辑:程序博客网 时间:2024/06/01 10:35

话说:

我们前面一系列的JavaWeb-JDBC,都是用最最原始的方法写的,各个页面之间的跳转也都是采用上古的方法(页面中处理请求并跳转),优化空间非常之大。Servlet早就应该出场了。今天有空,做个整理。

1、什么是Servlet?
2、Servlet有什么用?

个人理解,Servlet就是一个容器,类似Tomcat这样Web服务器一样的容器。它是一种技术,一种负责处理页面请求,并且负责页面跳转的技术。本质就是一个Java源码翻译、编译后的.class文件,形成的文件在Tomcat根目录下面的work文件里。

2、Why Servlet?

如果读者看过笔者前面写的一些列JDBC,就会明白页面之间的跳转,都采用的是最古老的在页面中写JSP代码来负责处理请求和页面跳转(request 、 request.getRequestDispatcher...)这些事。JSP本质就是一种显示技术,我们只想让它专注的显示,这样才符合《国富论》中的分工理论嘛!分工越细,效率越高,结构越清晰。Servlet就是来做这些事:处理页面请求、页面跳转,本身不做任何业务逻辑处理。

IDE——IntelliJ IDEA 2017.2.5 x64(Ultimate)

案例1_——到底什么是Servlet?如何创建呢?

创建Servlet有三种方法:    1)实现Servlet接口    2)继承GenericServlet类    3)继承HttpServlet类我们采用第三种方法。因为它们三者之间的关系是这样的:

这里写图片描述
详细关系,请参考在线JavaEE文档。
http://tool.oschina.net/apidocs/apidoc?api=javaEE6

package com.hmc.servlet;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;/** * User:Meice * 2017/10/2 */public class HiServlet extends HttpServlet{    @Override    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {        System.out.println("大家好,我是service.....");    }    @Override    public void destroy() {        System.out.println("大家好,我是destory.....");    }    @Override    public void init() throws ServletException {        System.out.println("大家好,我是init.....");    }}
上面,我们自己新建了一个HiServlet的类,继承了HttpServlet类,重写了三个方法,其中init()方法是不带参的。PS:如果你发现没有HttpServlet,请给这个Module导入对应的Tomcat的lib即可。如何调用这些方法呢?直接New这个类,然后调用嘛?当然不是!Servlet的存在意义是处理页面请求的,是针对BS端的,所以我们还需要做一个配置。配置web.xml

案例2 ——配置Servlet
在web.xml中配置Servlet.

<?xml version="1.0" encoding="UTF-8"?><web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"         version="3.1">    <!--配置Servlet-->    <servlet>        <servlet-name>hello</servlet-name><!--Servlet名字-->        <servlet-class>com.hmc.servlet.HiServlet</servlet-class><!--类全名(包名+类名)-->    </servlet>    <!--配置Servlet映射-->    <servlet-mapping>        <servlet-name>hello</servlet-name><!--映射的是名称为hello的Servlet与上面的Servlet-name保持一致-->        <url-pattern>/hello</url-pattern><!--B端请求路径-->    </servlet-mapping></web-app>

启动Tomcat,在页面访问:localhost:8080/JavaWeb_Servlet/hello
其中,JavaWeb_Servlet是项目名称,/hello是我们配置的Servlet-mapping的请求路径。

如果出现端口占用,要么重启可以解决,要么netstat -antp | findstr “被占用端口号” ,kill掉。
访问页面,页面不会报404之类的错误,而是在控制台输出:

这里写图片描述

一旦关闭猫,就会调用destory()方法

[2017-10-02 07:23:18,475] Artifact JavaWeb_Servlet:war exploded: Artifact is being deployed, please wait...大家好,我是destory.....[2017-10-02 07:23:19,848] Artifact JavaWeb_Servlet:war exploded: Artifact is deployed successfully[2017-10-02 07:23:19,848] Artifact JavaWeb_Servlet:war exploded: Deploy took 1,373 milliseconds

案例3 ——带参的init()

前面,我们重写的这是无参的init()方法,如果也重写带参的init()方法,重新访问,会是什么结果?会调用哪个方法?

大家好,我是带参的init.....大家好,我是service.....大家好,我是service.....

事实证明,调用的是带参的init()方法。按理说,这里的Init()类似我们的构造方法,页面一旦访问,马上被调用。无参构造方法随着类的加载而加载,套用在这里 ,就是随着页面访问而被调用;带参的构造方法,只有赋予参数调用的时候才会被调用,但是在这里就不生效了呢!可见,Servlet不遵循这个规则。它自有它的逻辑于风格。

接下来,我们做个总结吧。

案例3 ——Servlet的生命周期

你我皆凡人,没有生杀予夺的权力。但是在代码的江湖里,我们的确可以控制Servlet的生命。厉害吧!它的生命周期4个阶段:1)加载和实例化2)初始化3)处理请求4)销毁串在一起来说,也很简单,就是当我们在页面敲:localhost:8080/JavaWeb_Servlet/hello一旦 敲到/hello的时候,还没有调用init()方法,这时候Servlet就处于加载和实例化的阶段,通俗点比方,就是怀孕了;当回车确定的时候,页面直接找到web.xml配置信息,先在Servlet-mapping里面找Servlet-name,我要知道你访问我,到底是想找谁啊。然后根据<servlet>的name也就是hello找到servlet-class(类全名),找到我们的类,直接调用默认的几个方法。方法什么的,后期可以灵活控制。这个时候,就初始化了,也就是控制台会输出init,相当于孩子诞生!多次访问,init()只一次就可以,因为孩子诞生一次就可以了嘛!然后就是service(),也就是业务逻辑代码,类似于孩子的成长中的各种事件;当你关掉猫的时候,调用destory()方法,也就是Servlet生命结束。相当于孩子老去,落叶归根。

有什么卵用呢?作用就是我们后期继续优化JavaWebJDBC的时候,我们完全不必要在页面来写JSP代码来处理请求和页面跳转,直接在service()方法里面处理就好。各司其职,凸显专业精神。

案例4 ——初始化参数

接下来,我们认真了解下每个方法的奥妙吧。先看init(),destory()比较简单,也就先放下。知道了Servlet的生命周期,我们就可以扮演上帝,在Servlet的生命周期的各个阶段来为它的生命增加写色彩!在Init()阶段,我们可以初始化一些参数。这些参数,我们都可以通过对应的方法获取到。

1)配置web.xml里面的初始化参数。

 <servlet>        <servlet-name>hello</servlet-name><!--Servlet名字-->        <servlet-class>com.hmc.servlet.HiServlet</servlet-class><!--类全名(包名+类名)-->        <init-param>            <param-name>encoding</param-name>            <param-value>utf-8</param-value>        </init-param>    </servlet>

请注意的位置。参数有严格的位置呢!我只有先能找到是哪个Servlet,才能够初始化,所以,在之后。否则报错!
以后类似编码等问题,我们在初始化的时候,就处理掉。而不用手动每次类似JavaWebJDBC里面那样,每个页面都先处理编码,累不累啊!所以,在哪个阶段,做哪些事,很重要。这就是生命周期的本质作用。要知道,你扮演的可是上帝的角色啊!

如何获取?
补充一下,Servlet有多种方法,基本同JSP,关于请求的HttpServletRequest这个借口中都可以找到。详细方法请看文档。
http://tool.oschina.net/apidocs/apidoc?api=javaEE6

用的很多的方法除了以上三个方法之外,还有:
ServletRequest——处理请求,类似JSP的response
ServletResponse——创建响应,将处理结果返回客户端,类似JSP内置对象response。
ServletConfig——包含了Servlet初始化参数信息
所以,我们要想输出初始化的一些信息,就需要在带参(config)的初始化方法里获取。

2)获取单个初始化参数值

 @Override    public void init(ServletConfig config) throws ServletException {        System.out.println("大家好,我是带参的init.....");        //输出单个初始化参数值      String encoding =  config.getInitParameter("encoding");      System.out.println("国庆快乐!我是单个初始化参数encoding的值:"+encoding);    }
大家好,我是带参的init.....国庆快乐!我是单个初始化参数encoding的值:utf-8大家好,我是service.....

3)获取多个初始化参数名称:

<servlet>        <servlet-name>hello</servlet-name><!--Servlet名字-->        <servlet-class>com.hmc.servlet.HiServlet</servlet-class><!--类全名(包名+类名)-->        <init-param>            <param-name>encoding</param-name>            <param-value>utf-8</param-value>        </init-param>        <init-param>            <param-name>name</param-name>            <param-value>孙行者</param-value>        </init-param>        <init-param>            <param-name>hobby</param-name>            <param-value>PyayingComputerGames</param-value>        </init-param>        <init-param>            <param-name>sex</param-name>            <param-value>man</param-value>        </init-param>    </servlet>
 @Override    public void init(ServletConfig config) throws ServletException {        System.out.println("大家好,我是带参的init.....");        //输出单个初始化参数值      String encoding =  config.getInitParameter("encoding");      System.out.println("国庆快乐!我是单个初始化参数encoding的值:"+encoding);      //输出多个初始化参数名        Enumeration<String> enums =  config.getInitParameterNames();        /**         * 提示这么遍历不行。可以知道,Enumeration<E>属于java.util下面滴,参考帮助文档。         */        /* for(String en : enums){        }*/        //这里遍历方法类似ResultSet,Enumeration<E>虽然陌生,但是类似集合。        while (enums.hasMoreElements()) {            System.out.println(enums.nextElement());        }    }
大家好,我是带参的init.....国庆快乐!我是单个初始化参数encoding的值:utf-8sexnameencodinghobby大家好,我是service.....

案例5 ——service中的方法

来,知道了init()如何用,下来使用service,会觉得更加实用。
在service()里面,我们主要做的事情是处理页面请求和页面响应,主要用的方法就是request,response之类的。

目标:访问页面的时候传参,在页面获取到参数值(EL);页面跳转(转发、重定向),以及session传参的区别。

  @Override    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {        System.out.println("大家好,我是service.....");        //我们在访问页面的时候,让页面做个响应,调用的是getWriter()方法        response.getWriter().write("Hello,My name is service");        //输出请求传递的参数        String username= request.getParameter("username");        System.out.println("我是页面传递的参数"+username);    }//页面访问:http://localhost:8080/JavaWeb_Servlet/hello?username=国庆http://localhost:8080/JavaWeb_Servlet/hello?username=Xiaomei
我是页面传递的参数Xiaomei大家好,我是service.....我是页面传递的参数??????i

你会发现,一旦页面传参是中文,就有乱码。处理方式有两种:
1、request.setCharacterEnconding()
2、配置Tomcat根目录下conf目录下的server.xml(根源解决中文乱码问题);但是不利于乱码处理学习。
这里写图片描述

增加设置编码代码:

    @Override    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {        //处理编码,避免中文乱码        request.setCharacterEncoding("utf-8");        response.setCharacterEncoding("utf-8");        System.out.println("大家好,我是service.....");        //我们在访问页面的时候,让页面做个响应,调用的是getWriter()方法        response.getWriter().write("Hello,My name is service");        //输出请求传递的参数        String username= request.getParameter("username");        System.out.println("我是页面传递的参数"+username);    }

奇怪的是,处理后重新部署,中文传参依旧乱码。先放着。
接下来,实现页面跳转传递值,在service()方法里面增加以下代码:

  //输出请求传递的参数        String username= request.getParameter("username");        System.out.println("我是页面传递的参数"+username);        //我们让页面跳转到weclome.jsp,然后把参数传递过去,在页面用EL获取参数值。        //页面跳转(转发)        request.setAttribute("username",username);        //request.getRequestDispatcher("index.jsp").forward(request,response);        //用session来传递值,看转发和重定向页面跳转是否影响到session的传值       HttpSession  session =  request.getSession();       session.setAttribute("sessUsername",username);        //页面跳转(重定向)        response.sendRedirect("index.jsp");

页面访问:

http://localhost:8080/JavaWeb_Servlet/hello?username=Xiaomei//当然这里是英文,如果是中文,就会是乱码//奇怪的是,我已经加了request.setCharacterEncoding但是,还是乱码。所以如果想从根源处理,就修改server.xml。

session的传值是不受页面跳转方式影响的(转发或者重定向都行)

JSP默认是支持EL表达式的,用EL表达式的时候,注意变量名正确。最好复制,一不小心搞错了,还以为是没有EL包的原因,折腾了好久。

index.jsp页面:

 <h1>Servlet页面请求传参</h1>    <%--转发的时候,有值;毫无悬念,重定向是不能携带参数的,如果一旦用重定向,那么request的作用域就没有值了--%>   request作用域: ${username}<br>   session作用域:  ${sessUsername}

session.Scope可以指定EL表达式在session里面找这个传递的变量,不然EL默然寻找变量的顺序是:当前页面–》request–>session–>application

好了,总结:


1、Servlet是什么,有什么用?

2、Servlet的生命周期,我们可以选择在合适的周期进行干预;

3、初始化获取参数,获取多个初始化参数,尤其是Enumeration的遍历;

4、service()方法里面处理各种请求。

到了这里,所有铺垫已经做好,前期那一系列的JavaWebJDBC在这里就用Servlet做整体优化。去除多余的页面跳转代码(doAdd.jsp ,doUpdate.jsp,doDel.jsp)


晚安!

原创粉丝点击