话说:
我们前面一系列的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-8
sex
name
encoding
hobby
大家好,我是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)
晚安!
本文介绍Servlet的基本概念及其在Java Web开发中的应用。涵盖Servlet的创建、配置、生命周期及初始化参数的设置等内容,同时探讨如何利用Servlet处理页面请求与响应。

被折叠的 条评论
为什么被折叠?



