Java开发工程师(Web方向) - 02.Servlet技术 - 第1章.Servlet

Posted on 2017-08-05 09:20  FudgeBear  阅读(573)  评论(0编辑  收藏  举报

第1章--Servlet

Servlet简介

Servlet应用于?

浏览器发出HTTP请求,服务器接收请求后返回响应给浏览器。

接收请求后到返回响应之间:

服务器将请求对象转交给Servlet容器

Servlet容器根据HTTP请求的具体路径将请求转交给具体的Servlet

Servlet在收到请求后进行相应的处理逻辑后,将处理返回给服务器

服务器将HTTP响应返回给浏览器

Servlet是什么?

Servlet = Server + Applet -- 运行于Server的Applet

Applet (在web环境下运行与客户端的Java组件):没有main method,不能独立运行于JVM,需要特殊的容器装载运行,由容器管理生成销毁

Servlet:一个Servlet就是一个Java类,并提供基于请求-响应模式的Web服务

Servlet容器:装载和管理Servlet;为一个服务端程序,用于转交请求给Servlet

Eclipse中的Servlet配置:

prerequisite: Tomcat, Eclipse, Eclipse Maven插件

配置tomcat用户:

tomcat/conf/tomcat-users.xml文件

将文件中所有内容删除,加入以下内容并保存;

<?xml version='1.0' encoding='utf-8'?>
  <tomcat-users>
  <role rolename="manager-gui"/>
  <role rolename="manager-script"/>
  <user username="admin" password="123456" roles="manager-gui,manager-script"/>
</tomcat-users>

 

保存后启动tomcat,范围localhost:8080

点击右侧Manager App按钮,登陆,表明tomcat管理员配置成功

Maven中配置Tomcat服务器:

修改maven的配置文件~/.m2/settings.xml (different from maven/conf/settings.xml)

增加tomcat服务器:在<servers></servers>直接增加子元素

<server>
    <id>tomcat</id>
    <username>admin</username>
    <password>123456</password>
</server>

 

Tomcat Maven插件配置:

在 web app的pom.xml 文件中的<plugins></plugins>直接增加子元素,增加代码:

<plugin>
    <groupId>org.apache.tomcat.maven</groupId>
    <artifactId>tomcat7-maven-plugin</artifactId>
    <version>2.2</version>
    <configuration>
        <url>http://localhost:8080/manager/text</url>
        <path>/web_project_template</path>
        <uriEncoding>UTF-8</uriEncoding>  
        <finalName>web_project_template</finalName>
        <server>tomcat</server>
    </configuration>
</plugin>

 

Servlet Hello World:

在web.controller包下New Class -- Superclass: HttpServlet

Override methods: doGet(HttpServletRequest, HttpServletResponse); service(HttpServletRequest, HttpServletResponse);

在service()中:syso.println("service method");

重写doGet():

System.out.println("doGet method");
PrintWriter pw = resp.getWriter();
pw.print("hello world");
pw.close();

src->main->webapp->WEB-INF->web.xml 配置对应的Servlet 

<servlet>
    <servlet-name>TestServlet</servlet-name>
    <servlet-class>com.netease.server.example.web.controller.TestServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>TestServlet</servlet-name>
    <url-pattern>/hello</url-pattern>
</servlet-mapping>

运行:

Eclipse中对应项目,右键Run As--Run Configuration--双击左侧菜单Maven Build 以创建新的maven build--Name: maven deploy; Browser Workspace: 所要部署的项目; Goals: tomcat7:deploy

启动tomcat,点击run即可进行部署。

// Eclipse内置Tomcat-plugin:http://www.jianshu.com/p/8da9ca8c0667

Eclipse internal web browser:Window->Show View->Other->Internal Web Browser.

路径:http://localhost:8080/$project-path/$page-path

project-path: pom.xml中配置的<plugin>tomcat7-maven-plugin的path: /web_project_template

page-path: web.xml中配置的<servlet-mapping>url-pattern: /hello

Error:

[INFO] tomcatManager status code:200, ReasonPhrase:

[INFO] FAIL - Application already exists at path [/web_project_template]

solution: https://stackoverflow.com/questions/22671420/how-to-redeploy-a-war-on-remote-tomcat-7-using-maven-tomcat-plugin --> http://tomcat.apache.org/maven-plugin-2.2/tomcat7-maven-plugin/deploy-mojo.html#update

Now--it works. -- http://localhost:8080/web_project_template/hello

Servlet处理流程:

浏览器中输入地址 http://localhost:8080/web_project_template/hello

Servlet容器根据地址和配置文件web.xml找到对应的servlet: TestServlet.java

同时将请求传递给对应servlet的service方法

service方法是servlet的核心,每当客户端请求一个servlet对象时,会调用该对象的service方法,并传递给service方法一个HttpServletRequest对象和一个HttpServletResponse对象作为参数。

使用HTTP的get方法访问的servlet,则service方法会将相应的请求传递给doGet()处理,post同理

在doGet()方法中通过HttpServletResponse对象将"Hello World"返回给客户端

 

Servlet接口与实现类

Servlet生命周期:初始化、请求处理、销毁

初始化:init():客户端第一次请求servlet时,servlet容器会创建servlet对象的实例,此时servlet容器会调用servlet的init();如果在配置文件中配置了loadOnSetup元素,则servlet会在容器启动时做相应的加载。

请求处理:service():将不同的http请求转发给不同的servlet方法,常用doGet()/diPost()。

销毁:destroy():由servlet容器对servlet进行资源回收和清理

进入tomcat主页右边点击app manager,会看到所有部署的引用,点击web-project-template的stop,会执行destroy();

想要在servlet进行逻辑处理之前做一些准备工作,或在servlet实例销毁之前进行资源回收或清理的工作:

i.e. override method: init(); destroy();

init(); or init(ServletConfig config); ? 一般情况选择init();

init()中:syso.println("init method");

destroy()中:syso.println("destroy method");

get与post的区别:

get:传输方式-HTTP header;url可见;设计目的:获取数据;安全性低

post:传输方式-HTTP body;url不可见;设计目的:发送数据;安全性高

i.e.

/src/main/webapp下有静态页面getPostTest.html,

包含两个表单form,分别使用get和post方法,action="servlet/GetPostServlet"

对应有servlet对象GetPostServlet.java 

@Override
protected void doGet(HttpServletRequest request,
        HttpServletResponse response) throws ServletException, IOException {
    response.setContentType("text/html;charset=UTF-8");
    PrintWriter out = response.getWriter();
    String name1 = request.getParameter("name1");
    String pw1 = request.getParameter("pw1");

    out.println("<HTML>");
    out.println("  <HEAD><TITLE>A Servlet</TITLE></HEAD>");
    out.println("  <BODY>");
    out.print("   调用doGet 方法 ");
    out.println("<br></br>");
    out.println("用户名:" + name1);
    out.println("<br></br>");
    out.println("密码:" + pw1);
    out.println("  </BODY>");
    out.println("</HTML>");
    out.flush();
    out.close();
}

@Override
protected void doPost(HttpServletRequest request,
        HttpServletResponse response) throws ServletException, IOException {
    response.setContentType("text/html;charset=UTF-8");
    PrintWriter out = response.getWriter();
    String name2 = request.getParameter("name2");
    String pw2 = request.getParameter("pw2");
    out.println("<HTML>");
    out.println("  <HEAD><TITLE>A Servlet</TITLE></HEAD>");
    out.println("  <BODY>");
    out.print("    调用doPost 方法 ");
    out.println("<br></br>");
    out.println("用户名:" + name2);
    out.println("<br></br>");
    out.println("密码:" + pw2);
    out.println("  </BODY>");
    out.println("</HTML>");
    out.flush();
    out.close();
} 

在web.xml对应servlet元素 

<servlet>
    <servlet-name>GetPostServlet</servlet-name>
    <servlet-class>com.netease.server.example.web.controller.GetPostServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>GetPostServlet</servlet-name>
    <url-pattern>/servlet/GetPostServlet</url-pattern>
</servlet-mapping>

部署后,地址栏 http://localhost:8080/web-project-template/getPostTest.html

点击按钮会跳转到 web_project_template/servlet/GetPostServlet

不同的是,get提交后的url为http://localhost:8080/web_project_template/servlet/GetPostServlet?name1=admin1&pw1=nopass.a1

而post提交后的url为http://localhost:8080/web_project_template/servlet/GetPostServlet

 

Servlet配置参数:

将配置信息以硬编码方式固定,是不好的习惯--代码维护成本高

那么如何配置呢?:ServletConfig

特点:

在Servlet初始化过程中,<init-param>参数将被封装到ServletConfig中

每个Servlet支持设置一个或者多个<init-param>

以Servlet为单位,不是全局共享

web.xml中,在<servlet>子元素中添加

<servlet>
    <init-param>
        <param-name>data1</param-name>
        <param-value>value1</param-value>
    </init-param>
    <init-param>
        <param-name>data2</param-name>
        <param-value>value2</param-value>
    </init-param>
    <servlet-name>ServletConfigServlet</servlet-name>
    <servlet-class>com.netease.server.example.web.controller.ServletConfigServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>ServletConfigServlet</servlet-name>
    <url-pattern>/servlet/ServletConfig</url-pattern>
</servlet-mapping>

从Servlet中获取对应的参数:

首先,拿到ServletConfig对象

然后配置对应的参数值即可 

@Override
public void init() throws ServletException {
    ServletConfig config = this.getServletConfig();
    String v1 = config.getInitParameter(data1);
    System.out.println("v1 = " + v1);
    String v2 = config.getInitParameter(data2);
    System.out.println("v2 = " + v2);
}

NB: DO NOT FORGET TO ADD A DOGET() METHOD TO HANDLE THE RESPONSE STUFF. 

 

不同Servlet共享的配置信息:ServletContext

Servlet容器在启动的时候,会对每个web应用创建一个对应的ServletContext对象(全局只有一个)

在web.xml中进行ServletContext的配置:

<context-param>
    <param-name>globalData1</param-name>
    <param-value>123</param-value>
</context-param>
<!-- could be several pairs -->
<!-- no mapping to servlet -->

在任意Servlet中获取配置即可:

ServletContext ctx = this.getServletContext();
String globalValue1 = ctx.getInitParameter("globalData1");
String globalValue2 = ctx.getInitParameter("globalData2");
System.out.println("global value1: " + globalValue1 + "; global value2: " + globalValue2);

  

如果这些配置是事先不知道的呢?--ServletContext也支持动态信息-Attribute(Key-Value)

i.e. 通过ServletContext的动态属性,来完成信息的共享

在servlet a中:ctx.setAttribute("attribute" ,"111");    // set key-value pair

在servlet b中:String attribute1 = (String) ctx.getAttribute("attribute");    // get the value of attribute1

 

如果想要从外部资源里而不是web.xml中读取配置信息呢?

getResource();

getResourceAsStream();

getRealPath();

i.e. 使用ServletContext读取log4j的配置信息:

1. getResource();

URL url = ctx.getResource("/WEB-INF/classes/log4j.properties"); --import java.net;

--try catch: MalformedURLException

InputStream in = url.openStream(); --import java.io;

--try catch: IOException

写方法String getProperty(String, InputStream);

public static String getPropery(String key, InputStream in) {
    Properties props = new Properties();
    try {
        props.load(in);
    } catch (IOException e) {
        e.printStackTrace();
    }
    String value = props.getProperty(key);
    return value;
}

 

调用该方法获取对应value

String propertyValue = GeneralUtil.getProperty("log4j.rootLogger", in);

即可。

完整代码:

try {
    URL url = ctx.getResource("/WEB-INF/classes/log4j.properties");
    InputStream in = url.openStream();
    String propertyValue = GeneralUtil.getPropery("log4j.rootLogger", in);
    System.out.println("property value: " + propertyValue);
} catch (MalformedURLException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
}

  

2. getResourceAsStream();

InputStream in = ctx.getResourceAsStream("/WEB-INF/classes/log4j.properties");

String p = GeneralUtil.getProperty("log4j.rootLogger", in);

 

3. getRealPath();

String path = ctx.getRealPath("/WEB-INF/classes/log4j.properties");

System.out.println("real path:" + path);

File file = new File(path);

InputStream in = new FileInputStream(file);

// try catch FileNotFoundException

String p = GeneralUtil.getProperty("log4j.rootLogger", in);

 

Servlet配置 

Web应用程序的基本结构:

webapp:

1. 公共资源:通过url可以访问到的静态资源,如css, js, images, html,不同类型资源分类于不同目录

2. META-INF目录:定义了jar包的源信息,定义了包拓展属性、类加载路径、自定义属性等

3. WEB-INF目录:不提供给用户,无法通过浏览器访问。放置类文件和类所依赖的库。

包括两个子目录:classes和lib 和一个web.xml文件。classes放置编写的代码和编译后的类文件。lib放置web依赖的jar包。

web.xml部署描述服务,用于描述一个web应用。

web.xml文件:

用于设置web应用程序的组件部署信息。

Servlet容器需要支持部署描述符的所有元素。

web.xml文件中的配置:

1. Servlet声明

<servlet>

<servlet-name>servlet类的名称</servlet-name>

<servlet-class>servlet类的实际路径</servlet-class>

</servlet>

<servlet-mapping> 

<servlet-name>和上面对应的servlet类名</servlet-name>

<url-pattern>servlet对外映射的相对路径(一般以/开头)</url-pattern>

<url-pattern>可有多个mapping路径 & "*"可做模糊匹配</url-pattern>

</servlet-mapping>

Servlet-Mapping匹配规则:

若两个servlet的url-pattern重复了,则

a. 精确路径匹配,完全匹配;

b. 最长路径匹配,最长前缀匹配(路径匹配最多的);

c. 扩展名匹配;

d. default servlet;

e. 如果没有default servlet,则放弃匹配返回报错。

规则从上往下按优先级顺序

i.e.  

/hello --a--> Servlet1

/hello/world/index --b--> Servlet3

/admin.jsp --c--> Servlet4

/world --d--> Servlet5

/hello.jsp --c--> Servlet4

/hello/world/hello.jsp --b--> Servlet3

 

2. ServletConfig配置--位于Servlet元素

<servlet>

<init-param> 可有多个

<param-name> key </param-name>

<param-value> value </param-value>

</init-param>

<servlet-name>

...

3. ServletContext配置--全局

<context-param>

<param-name> key </param-name>

<param-value> value </param-value>

</context-param>

4. 若需要在Servlet容器启动时执行操作(init()为找Servlet第一次收到请求时的操作)

"load-on-startup"改变Servlet默认初始化时间--负数/无设置:第一次请求时加载

<servlet>

<load-on-startup>0</load-on-startup>

<servlet-name>...

...

5. 配置自定义错误页面 <error-page>

<error-page>

<error-code>404</error-code>

<location>/404.html</location>

</error-page>

更高级的做法:添加exception-type元素捕获一个Java异常类型

6. 若用户在地址栏输入web app路径的url,如:http://localhost:8080/web_project_template/

会出现一个登录页面--index.html页面(首页/欢迎页面)

对应在部署描述中为<welcome-file-list>可包含一个或多个<welcome-file>子元素

指定多个欢迎页面的加载顺序:<welcome-file>在<welcome-file-list>中的顺序

7. 对于静态资源 打开文件 or 下载文件?

MIME(Multi-purpose Internet Mail Extensions)多用途互联网邮件扩展类型--发展为描述消息内容类型的互联网标准。

--设置某种扩展名文件的打开方式

<mime-mapping>定义扩展文件名映射类型

<extension>

<mime-type>

</mime-mapping>

 

下章预告:

Servlet session配置

Servlet filter配置

Servlet listener配置

 

Servlet单元测验

本次得分为:46.00/46.00, 本次测试的提交时间为:2017-08-06, 如果你认为本次测试成绩不理想,你可以选择再做一次。
1单选(2分)

Servlet有什么特征?

  • A.其它选项都是正确2.00/2.00
  • B.运行在Servlet容器里的程序
  • C.Web服务
  • D.一个Java类
2单选(2分)

Servlet容器是什么?

  • A.装载和管理Servlet的服务端程序2.00/2.00
  • B.保存Servlet的程序
  • C.Tomcat
  • D.其它选项都不对
3单选(2分)

以下哪种关系跟Servlet与Servlet容器关系最接近?

  • A.遥控器和电视机
  • B.螺丝和螺丝刀
  • C.子弹和枪2.00/2.00
  • D.CD与CD机
4单选(2分)

下面哪些内容不是部署描述符中的配置?

  • A.<servlet>
  • B.<list>2.00/2.00
  • C.<welcome-file-list>
  • D.<error-page>
5单选(2分)

下面哪些是标准web应用程序包括的内容?

  • A.web.xml
  • B.公共资源
  • C.WEB-INF
  • D.其它选项都是2.00/2.00
6
单选(2分)

如果现在有以下7个servlet,且其url-pattern与对应的servlet的关系如下: 

url-pattern

servlet

/abc

Servlet1

/abcd

Servlet2

/abc/*

Servlet3

/abc/def

Servlet4

/abc/def/*

Servlet5

*.jsp

Servlet6

/

Servlet7

 

 

 

 

 

 

 

 

 

 

 

如果现在请求的相对路径是/abc/def/gh,请求将发到哪个servlet?

  • A.Servlet4
  • B.Servlet3
  • C.Servlet1
  • D.Servlet52.00/2.00
7单选(2分)

如果现在请求的相对路径是/abcd.jsp,请求将会发到哪个Servlet?

  • A.Servlet62.00/2.00
  • B.Servlet7
  • C.Servlet3
  • D.Servlet2
8单选(2分)

如果现在请求的相对路径是/abc/def/gh.jsp,请求将会发到哪个Servlet?

  • A.Servlet4
  • B.Servlet3
  • C.Servlet6
  • D.Servlet52.00/2.00
9单选(2分)

下面的描述中哪项是ServletContext的作用?

  • A.其它选项都是2.00/2.00
  • B.读取外部资源文件信息
  • C.通过配置文件共享全局信息
  • D.Servlet转发
10单选(2分)

下面哪项描述是正确的?

  • A.http get方法,需要传输的数据是在http协议的header里,http post方法,需要传输的数据是在http协议的body里
  • B.其它选项都是2.00/2.00
  • C.从设计目的上看,http get方法是获取数据,post方法是发送数据
  • D.一般而言,http post方法比get方法更安全
11多选(3分)

Servlet生命周期包括哪些回调方法?

  • A.init1.00/3.00
  • B.service1.00/3.00
  • C.destroy1.00/3.00
  • D.main
12多选(3分)

ServletContext读取外部配置文件的方法有哪些?

  • A.getResource1.00/3.00
  • B.getPath
  • C.getResourceAsStream1.00/3.00
  • D.getRealPath1.00/3.00
13判断(2分)

部署描述符一定是xml文件,且命名必须是web.xml

  • A.×
  • B.√2.00/2.00
14判断(2分)

Servlet-mapping中支持多个url-pattern对应同一个servlet

  • A.×
  • B.√2.00/2.00
15判断(2分)

Servlet-mapping中的url-pattern支持模糊匹配

  • A.√2.00/2.00
  • B.×
16判断(2分)

load-on-startup设置的值越小,servlet启动越晚

  • A.×2.00/2.00
  • B.√
17判断(2分)

部署描述符中可以设置多个欢迎页面

  • A.×
  • B.√2.00/2.00
18判断(2分)

ServletConfig对象只能在init方法中获取

  • A.√
  • B.×2.00/2.00
19判断(2分)

ServletConfig只能配置一对init-param参数

  • A.√
  • B.×2.00/2.00
20判断(2分)

Servlet init方法在其生命周期中只会被调用一次

  • A.√2.00/2.00
  • B.×
21判断(2分)

Servlet destroy方法在请求结束后会被调用

  • A.×2.00/2.00
  • B.√
22判断(2分)

ServletConfig中配置的参数可以在其它Servlet中获取

  • A.√
  • B.×2.00/2.00