《深入浅出 Servlet:Java Web 开发的基石》(二)

发布于:2024-12-23 ⋅ 阅读:(19) ⋅ 点赞:(0)
  1. ServletConfig(熟练)

ServletConfig对象对应web.xml文件中的<servlet>元素。例如你想获取当前Servlet在web.xml文件中的配置名,那么可以使用servletConfig.getServletName()方法获取!

你不能自己去创建ServletConfig对象,Servlet的init()方法的参数就是ServletConfig类型的。Tomcat在调用init()方法时,会传递ServletConfig对象。你可以在init()方法中使用它!

<servlet>
    <servlet-name>hello</servlet-name>
    <servlet-class>cn.tx.servlet.Servlet1</servlet-class>
    <init-param>
        <param-name>username</param-name>
        <param-value>root</param-value>
    </init-param>
    <init-param>
        <param-name>password</param-name>
        <param-value>txjava</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

String username = Cservletonfig.getInitParameter("username");
System.out.println("username:"+username);
Enumeration<String> parameterNames = servletConfig.getInitParameterNames();
while (parameterNames.hasMoreElements()){
    String element = parameterNames.nextElement();
    System.out.println(element+":"+servletConfig.getInitParameter(element));
}

添加了两个初始化参数,第一个参数的名称为paramName1,第一个参数的值为paramValue1;第二个参数的名称为paramName2,第二个参数值为paramValue2。

在<servlet>元素中可以加载多个<init-param>,每个<init-param>表示一个参数。<init-param>下有两个子元素:<param-name>和<param-value>,其中<param-name>表示参数的名称,而<param-value>元素参数的值。

注意,<init-param>是添加到<servlet>元素中,而不是<servlet-mapping>中。

  使用ServletConfig对象的getInitParameter(String paramName)方法可以获取指定参数名称的参数值。getInitParameterNames()方法返回所有参数的名字,返回值类型为Enumeration。

  1. Servlet路径映射(熟练)

关于Url-Pattern的配置:

  • 完全路径匹配  以/开头    例如  /aaa   /aaa/bbb  
  • 目录匹配 以/开头    例如  /aaa/*   /*   
  • 扩展名匹配 不能以/开头   例如  *.do   *.action  ....

优先级: 完全路径匹配 > 目录匹配 > 扩展名匹配

经典错误:  /*.do

举例:

对于如下的一些映射关系:

  • Servlet11 映射到 /abc/*
  • Servlet22 映射到 /*
  • Servlet33 映射到 /abc
  • Servlet44 映射到 *.do

问题:

  • URL为“/abc/a.html”,“/abc/*”和“/*”都匹配,哪个servlet响应

Servlet引擎将调用Servlet1。同样是目录匹配所限定范围更精确的先匹配

  • URL为“/abc”时,“/abc/*”和“/abc”都匹配,哪个servlet响应

Servlet引擎将调用Servlet3。

  • URL为“/abc/a.do”时,“/abc/*”和“*.do”都匹配,哪个servlet响应

Servlet引擎将调用Servlet1。

  • URL为“/a.do”时,“/*”和“*.do”都匹配,哪个servlet响应

Servlet引擎将调用Servlet2.

  • URL为“/xxx/yyy/a.do”时,“/*”和“*.do”都匹配,哪个servlet响应

Servlet引擎将调用Servlet2。

 服务器端路径 /demo4 (转发、包含...)

  1. 相对路径和绝对路径(熟练)

Java中使用的路径,分为两种:绝对路径和相对路径。归根结底,Java本质上只能使用绝对路径来寻找资源。所有的相对路径寻找资源的方法,都不过是一些便利方法。不过是API在底层帮助我们构建了绝对路径,从而找到资源的!

我们以下面的项目路径来进行举例:

    1. 相对路径

相对路径,根据当前资源路径 与 目标资源路径,寻找相对位置关系,通过 . (当前目录) 和 .. (上一级目录) 访问目标资源;

综上所述,我们发现相对路径总需要分析当前路径与目标路径对应关系,编写规则会根据当前路径不同而不同

    1. 绝对路径

绝对路径是指目录下的绝对位置,直接到达目标位置

带有协议完整路径 (跨网站) http://localhost/day5/hello

以/ 开始路径 (同一个站点内) : /day5/hello

服务器端和客户端对于/ 的区别

客户端访问路径:/day5/hello

服务器内部路径:/hello, 多用于服务器跳转, 页面包含(jsp)

    1. 测试结果

  1. ServletContext(熟练)
    1. ServletContext介绍

ServletContext是一个全局的储存信息的空间,服务器开始,其就存在,服务器关闭,其才释放。request,一个用户可有多个;session,一个用户一个;而servletContext,所有用户共用一个。所以,为了节省空间,提高效率,ServletContext中,要放必须的、重要的、所有用户需要共享的线程又是安全的一些信息。

  • WEB容器在启动时,它会为每个WEB应用程序都创建一个对应的ServletContext对象,它代表当前web应用。
  • 由于一个WEB应用中的所有Servlet共享同一个ServletContext对象,因此Servlet对象之间可以通过ServletContext对象来实现通讯。ServletContext对象通常也被称之为context域对象。
  • 查看ServletContext API文档,了解ServletContext对象的功能。
    1. ServletContext API

 Object

getAttribute(String name) 
          Returns the servlet container attribute with the given name, or null if there is no attribute by that name.

 String

getContextPath() 
          Returns the context path of the web application.

 String

getInitParameter(String name) 
          Returns a String containing the value of the named context-wide initialization parameter, or null if the parameter does not exist.

 String

getRealPath(String path) 
          Returns a String containing the real path for a given virtual path

 void

setAttribute(String name, Object object) 
          Binds an object to a given attribute name in this servlet context.

 InputStream

getResourceAsStream(String path) 
          Returns the resource located at the named path as an InputStream object.

    1. ServletContext使用
      1. 常规应用:
  • 获取WEB应用的全局初始化参数
  • 通过ServletContext对象实现数据共享

<context-param>
    <param-name>company</param-name>
    <param-value>达内教育</param-value>
</context-param>

ServletContext servletContext = config.getServletContext();
String company = servletContext.getInitParameter("company");
System.out.println("company:"+company);

示例:

统计站点访问次数

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    doPost(request, response);
}

@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    ServletContext servletContext = getServletContext();
    Integer visitNums = (Integer)(servletContext.getAttribute("visitNums"));
    visitNums = visitNums == null ? 0 : visitNums;
    servletContext.setAttribute("visitNums",++visitNums);
    response.setCharacterEncoding("UTF-8");
    response.getWriter().write("当前网站访问人次:"+visitNums);
}

      1. 通过ServletContext对象读取资源文件

第一种方法,通过ServletContext.getRealPath()方法;

// 获得到ServletContext对象
ServletContext servletContext = config.getServletContext();

// 获得工程目录web下文件的绝对路径 D:\workspace\idea\servlet-demo1\out\artifacts\servlet_demo1_war_exploded\tx.properties
// getRealPath的参数内容不会被校验,只有真正要用这个路径的时候才知道路径对不对
// String path = servletContext.getRealPath("tx.properties");

String path = servletContext.getRealPath("tx.properties");
System.out.println(path);
try {
    InputStream is = new FileInputStream(path);
    Properties p = new Properties();
    p.load(is);
    String username = p.getProperty("username");
    System.out.println(username);
} catch (Exception e)


    e.printStackTrace();
}

第二种方法,使用servletContext.getResourceAsStream()方法;

//获得工程目录web下文件的流第一个/代表项目的根目录
InputStream is = servletContext.getResourceAsStream("/WEB-INF/tx1.properties");

第三种方法,使用getClass().getClassLoader().getResourceAsStream()方法;

//使用类加载器的方式来读取classpath下的资源文件,好处不依赖与ServletContext,任何类都可以获得classpath下的资源文件,
//不需要再自己指定/WEB-INF/classes
InputStream is = this.getClass().getClassLoader().getResourceAsStream("tx2.properties");

  1. Servlet相关资料(熟练)
    1. 面试题
      1. 单例的Servlet  单例多线程

因为Servlet实例是由Tomcat来创建的,但Tomcat只会创建一个Servlet实例,所以Servlet就是单例的!这与我们自己写的单例模式不太一样。因为这种单例是通过容器tomcat来管理而实现的!

一个实例需要在同一个时间点上处理多个请求!

同步就是安全,但效率太低

Servlet是线程不安全的!

  • 不写属性;
  • 不写可以存储数据的属性!
      1. Servlet的生命周期
  • Servlet 通过调用 init () 方法进行初始化。
  • Servlet 调用 service() 方法来处理客户端的请求。
  • Servlet 通过调用 destroy() 方法终止(结束)。
  • 最后,Servlet 是由 JVM 的垃圾回收器进行垃圾回收的。
  1. 学习目标
  • 了解Servlet概念和JavaWeb的三大组件都包含哪些组件;
  • 创建一个Servlet实现javax.servlet.Servlet接口,并自行验证Servlet的生命周期;
  • 创建一个Servlet继承javax.servlet.http.HttpServlet类,提供一个初始化属性,并在Servlet初始化时打印它;
  • 自己实现统计网址访问人次的功能;
  • 熟练掌握两道面试题