Servlet/JSP(二)

这篇文章介绍Servlet如何编写和部署

FirstServlet

如果想要打好基础,不要着急先从JSP开始学起,要先从Servlet开始了解,我们知道,JSP终究会被编译成Servlet,所以只要了解了Servlet,JSP也就学会了一半
开发环境,服务器选择Tomcat,IDE 为eclipse,我们除了要了解Servlet/JSP的原理和之外,还要学习如何使用开发工具来提高我们编程效率

首先利用Eclipse创建工程,先写一个简单的Servlet,代码如下

@WebServlet("/FristServlet")
public class FristServlet extends HttpServlet {             // 继承 HttpServlet


    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        response.setContentType("text/html; charset=UTF-8");        // 设置响应的内容类型字符型

        PrintWriter out = response.getWriter();                     // 取得输出对象
        String getName = request.getParameter("name");              // 取得 请求参数

        // 输出内容
        out.println("<html>");
        out.println("<head>");
        out.println("<titile>Frist Servlet</title>");
        out.println("</head>");
        out.println("<body>");
        out.println("<h1>Hello" + getName +"</h1>");
        out.println("</body>");
        out.println("</html>");

        out.close();

    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    }

}

Servlet 继承了 HttpServlet,并重写了 doGet()方法,当使用 GET 请求时,会调用该方法,在doGet 方法上可以看到 HttpServletResponse,HttpServletRequest 这2个参数,容器接收到 HTTP请求之后,会收集HTTP请求中的信息,并分别创建代表请求与响应的 Java 对象,而后在调用 doGet 时将这2个对象当做参数传入,我们可以在 HttpServletRequest 对象中得到有关HTTP 请求的相关信息,如 我们使用 getParamater() 方法来取得用户发送的请求值

@Override 作用是协助检查是否正确重新定义了父类中继承下来的某个方法,对于Servlet来说,并没有影响,后面我们后说明该注解的作用

由于HttpServletResponse 对象代表对客户端的响应,因此可以通过 setContentType() 方法来设置内容类型, text/html 表示响应要使用 html 来解析,charset = utf-8 表示字符编码为 utf-8 ,使用 getWriter() 方法取得代表输出的 PrintWriter对象,通过 println() 方法来对浏览器输出响应的文字信息

容器是如何处理Servlet

我们编写完上上面的 Servlet 之后,再运行成功之后可以输出相应的结果,那么这一切是如何进行的呢,我们的 IDE 又为我们做了上面工作,以下我们进行分析

  • HttpServlet
    我们首先来了解该类的继承结构
    // TODO 继承结构

首先看到Servlet接口,定义了Servlet应当具有的基本行为,例如 init,destroy,service 方法
实现Servlet接口的类是 GenericServlet ,还实现了 ServletConfig接口,将容器调用 init() 方法时所常茹的 ServletConfig 实例封装起来,而 service() 方法直接标示为 abstract 没有任何的实现, GenericServlet 并没有规范任何与 HTTP 的相关的方法,而是由继承的 HttpServlet 来定义的,在最初定义的 Servlet中,并不限定只能使用 HTTP,所以没有将HTTP相关的服务流程定义在 GenericServlet 中,而是定义在了 HttpServlet 的 service() 方法中,我们从源码来分析该方法

 protected void service(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException {

        String method = req.getMethod(); // 取得请求的方法

        if (method.equals(METHOD_GET)) {
           //.....
                doGet(req, resp);
        } else if (method.equals(METHOD_HEAD)) {
         //.....
            doHead(req, resp);
        } else if (method.equals(METHOD_POST)) {
            doPost(req, resp);
        } else if (method.equals(METHOD_PUT)) {
            doPut(req, resp);
        } else if (method.equals(METHOD_DELETE)) {
            doDelete(req, resp);
        } else if (method.equals(METHOD_OPTIONS)) {
            doOptions(req,resp);
        } else if (method.equals(METHOD_TRACE)) {
            doTrace(req,resp);
        } else {
         //.....
            resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
        }
    }

当请求来到之后,容器会调用Servlet 的 service 方法,来判断 HTTP 的请求方式,再分别调用 doGet() doPost() 等方法,所以 我们想对 GET、POST 方法进行处理,才会需要继承 HttpServlet 重新定义 doGet doPost 等方法,这种设计 为设计模式中的 Template Method 模式,所以我们不应该在继承了 HttpServlet 之后重新定义 service() 方法,这回覆盖掉 HttpServlet 中定义的对 HTTP 预设处理的流程

  • 使用注解 @WebServlet
    写好Servlet之后,我们要告诉Web容器有关Servlet 的信息,在 Servlet3.0 中,可以使用注解的方式来告诉容器哪些Servlet会提供服务以及额外的信息,比如
    @WebServlet(“/hello.vier”)
    我们只要在 Servlet 上设置该注解之后,容器就会自动读取当中的信息,告诉容器请求的URL 是 /hello.view,由 注解的 Servlet 提供服务,我们还可以使用 @WebServlet 来提供更多的信息
@WebServlet{
    name = "hello",
    urlPatterns = {"/hello.view"},
    loadOnStartup = 1
}

上面@WebServlet 告诉容器,要访问的Servlet的名称是 Hello,由name属性指定,而如果客户端请求的 URL 是 /hello.view 则由 Hello 名称的Srevlet来处理,由 urlPatterns 属性来指定,如果没有设置的属性,我们使用默认值比如 name 属性的默认值就是 Servlet 的完整名称
当我们的程序启动之后,事实上并没有创建所有的 Servlet 实例,容器会在首次请求要某个Servlet服务时,才将对应的Servlet 类实例化、进行初始化操作,然后再处理请求,这也就是说第一次请求Servlet,必须要等待Servlet 实例化,进行初始化所必须的时间,才能真正得到请求的处理
如果我们希望程序启动之后,就先将Servlet类加载,实例化并做好初始化的工作,使用 loadOnStartup 进行设置,设置大于0 的值(默认为-1),表示启动只有就先初始化Servlet,数字代表了Servlet 的初始顺序,容器必须保证有加载顺序从小到大,如果我们使用相同的数字,那么则由容器实现的厂商来决定要如何加载

  • web.xml
    注解功能是 Servlet 3.0 之后采用的功能,我们在之前的版本中,需要在 web.xml 中配置Servlet 先关信息,web.xml 在 WEB-INF目录下,一般创建工程的时候,IDE 会帮助我们自动创建,一个简单web.xml 结构如下
<?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_3_0.xsd"
         id="WebApp_ID" 
         version="3.0">  
  <servlet>
    <servlet-name>FirstServlet</servlet-name>
    <servlet-class>com.gnf.ts.FirstServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
    <init-param>
        <param-name>message</param-name>
        <param-value>welcome to servlet</param-value>
    </init-param>
  </servlet>

  <servlet-mapping>
    <servlet-name>FirstServlet</servlet-name>
    <url-pattern>/FirstServlet</url-pattern>
  </servlet-mapping>

</web-app>

这种文件也叫做 部署描述文件,使用web.xml定义比较麻烦,不过web.xml 中的设置会覆盖@WebServlet,可以用来当做注解的默认值

文件说明:<servlet-name><servlet-class> 属性是必须配置的, <servlet-name> 配置Servlet的名称,<servlet-class>配置Servlet的类名,<servlet-name>可以是任意的字符串,但是必须保证该名称在 web.xml 里面是唯一的,这个名称由后面的其他标签比如 <servlet-mapping> <filter>等使用

使用<init-param>标签可以配置一个初始化的参数,包括一个参数名称,和参数值,类似 Map 集合的键值对模式, 一个Servlet 可以配置多个初始化参数,在Servlet 中可以通过 getServletContext().getInitParam(String paramName) 来获取配置的初始化参数

<load-on-startup>配置Servlet的加载模式,我们在上面提到过,实际项目中一些框架如 Struts/JSF/Spring都使用来预加载 框架中最核心的Servlet

<servlet-mapping> 配置Servlet 的访问方式,<servlet-name> 指明采用该访问方式的 Servlet的名称,也就是前面在<servlet> 里配置的 Servlet 名称, 配置Servlet 的访问方式,一般为Web应用程序的 路径
<url-pattern>中允许使用通配符 * 和 ? ,* 表示任意字符长度,代表容易字符,比如 <url-pattern>配置为 /servlet/FirstServlet.* 就使用 http://localhost:8080/FristServlet.xxx 来访问该应用,xxx 表示任意类型后缀,在Struts、JSF 中也使用通配符映射,把 例如 xxx.do xxx.jspa 等格式的所有 URL 都映射到某个核心的Servlet 上。从Java EE5 开始,<servlet-mapping> 可以配置多个<url-pattern> 比如我们可以这样配置

<servlet-mapping>
    <servlet-name>FirstServlet</servlet-name>
    <url-pattern>/servlet/FirstServlet</url-pattern>
    <url-pattern>/servlet/FirstServlet.asp</url-pattern>
    <url-pattern>/servlet/FirstServlet.jsp</url-pattern>
    <url-pattern>/servlet/FirstServlet.php</url-pattern>
    <url-pattern>/servlet/FirstServlet.aspx</url-pattern>
</servlet-mapping>

无论使用何种后缀访问,都会正常显示,可以实现隐藏编程语言的目的,用户无法通过URL 来判断该程序使用 PHP 还是 ASP 来编写的

一个完整的 Servlet 包括 Servlet 类,<servlet>配置、<servlet-mapping>配置,缺一个都不行

  • 文件组织与部署
    *我们的IDE 未来管理项目资源,会有该 IDE 专属的文件组织,但这并不是真正上传到 Web 容器之后的架构,Web 容器要求部署时,有专用的结构,如下

这里写图片描述

WEB-INF:目录名称是固定的,一定位于应用的根目录下,放置在 WEB-INF 中的文件或是目录,对外界来说是封闭的,也是客户端无法使用 HTTP 的如何方式直接访问到的,如果有,我们需要通过Servlet/JSP 的请求转发,如果我们不想让外界存取资源,可以放置该目录下
web.xml: 这是Web 程序的部署描述文件,文件名称,目录都是固定的
lib:放置JAR文件
classes:放置编译之后的.class文件

我们可以把项目导出成 war 包之后,看到这种目录结构

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值