Servlet基础入门学习1

2022-09-29 15:53:44 浏览数 (1)

[TOC]

0x01 快速入门

描述:在进行JavaWeb开发学习的时候必不可少就是Tomcat Web 容器服务器,因为它开源免费、便于上手,并且使用安装简单。

简单介绍: Tomcat是一款开源软件、免费的Web容器软件,由Apache基金会旗下采用JAVA进行开发,Tomcat是一款Web容器自身不能作为负载均衡的软件; 主要应用于发布网页代码,提供网页信息服务,用户通过浏览可以实现界面的访问;Tomcat默认可以处理静态的网页,也可以处理动态的网页;

在这里我们就详细演示安装流程了,在我其他的Tomcat运维文章中有它的详细以及优化配置等.

学习环境准备:

  • Java的JDK8(并且配置好环境变量)
  • Tomcat 7.0.100 : http://tomcat.apache.org/download-70.cgi
  • Eclipse IDE

WeiyiGeek.Tomcat

Tomcat 7.0目录结构说明

代码语言:javascript复制
* bin:Tomcat 启用binary以及一些启动jar包
* conf:Tomcat配置文档
* lib:Tomcat运行所依赖的jar文件
* logs:运行过程中的日志文件
* temp:临时文件
* webapps:项目发布的目录,以及war解压的目录;
* work:JSPbuild成为java文件的临时存放地
0x02 项目发布

描述:如何将项目发布到Tomcat中运行?

方式1:移动项目到Webapps目录(使用较多) 描述:冷部署可以直接将项目文件夹拖入Webapps目录之中并需要重新启动Tomcat;

代码语言:javascript复制
#Tomcat控制台提示
# 信息: 把web 应用程序部署到目录 [W:apache-tomcat-7.0.100webappsDemo1]
# 二月 15, 2020 10:40:11 下午 org.apache.catalina.util.SessionIdGeneratorBase crea
# eSecureRandom

WeiyiGeek.方式1

方式2:Host配置虚拟路径 描述:通过在Conf/Server.xml配置文件中HOST元素接地添加上<Content>属性 130 行左右;该方式的区别不同于第一种是在于它不会在Tomcat控制终端日志中显示。

代码语言:javascript复制
 <Host name="localhost"  appBase="webapps" unpackWARs="true" autoDeploy="true">
    <Context 
    docBase="D:apache-tomcat-7.0.100webappsDemo1"  
    path="/Demo2" 
    override="true">
    </Context>
    <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
            prefix="localhost_access_log." suffix=".txt"
            pattern="%h %l %u %t &quot;%r&quot; %s %b" />
</Host>

<!-- 
属性解释:
1.docBase=存放web应用程序的文档基础(也称为上下文根)目录或者web应用程序存档文件(如果此web应用程序直接从WAR文件执行)。
2.path=网页访问的路径
3.override=设置为true可以忽略全局或主机默认上下文中的任何设置。默认情况下将使用默认上下文的设置,但是可能会被上下文的设置显式地覆盖相同的属性。 
-->

参考地址:http://127.0.0.1:8080/docs/config/context.html#Defining_a_context 访问地址效果如上面图显示一致:http://127.0.0.1:8080/Demo2/index.xml

方式3:Engine配置虚拟路径 描述:与方式2大致相同不同的是进行加载的目录不同而已依赖于Engine进行单独的上下文元素可将Context元素复制到引擎文件中即可;

代码语言:javascript复制
#$CATALINA_BASE/conf/[enginename]/[hostname]/
Server.xml
<Engine name="Catalina" defaultHost="localhost">
..
</Engome>

#由此可知路径为 Conf/Catalina/localhost 并在目录下建立一个Demo3.xml (访问时候便以/Demo3作为访问路径)
#即D:apache-tomcat-7.0.100confCatalinalocalhostDemo3.XML注意docBase指向Webapps中目录会报错
<?xml version='1.0' encoding='utf-8'?>
<Context docBase="D:xampphtdocs" override="true"></Context>

WeiyiGeek.Engine配置虚拟路径

根据上面的分析可以总结出Tomcat主要包含了 2 个核心组件:连接器(Connector)容器(Container),

  • 1.一个Tomcat是一个Server,
  • 2.而一个Server下有多个Service,也就是我们部署的多个应用,一个应用下有多个连接器(Connector)和一个容器(Container)容器下有多个子容器;
  • 3.Engine下有多个Host子容器,Host下有多个Context子容器,Context下有多个Wrapper子容器。

WeiyiGeek.


0x03 项目打包

描述:在实际的开发中我们需要将我们的web工程打压成为war包或者jar包进行tomcat部署或者在jvm虚拟机中运行;

问:如何将项目打包成为jar?

  • 1.右键工程选择Export选择other在java目录下选择jar;

WeiyiGeek.

  • 2.进行导出jar配置一般默认就行;

WeiyiGeek.

0x04 Servlet基础

描述:Servlet[ /ˈsɜːvlɪt/ ] API 是运行在Tomcat Web服务器容器中的小型Java程序伺服小程式;小服务程,通过HTTP(超文本传输协议)接收和响应来自Web客户端的请求;更多的是配合动态资源做项目,当然也可以使用到Servlet只不过在Tomcat里面已经定义了一个DefaultServlet;

1.Hello World

描述:在上面Tomcat安装好后它给我们提供了一个示例页面,进行使用和学习 Servlet ( Servlet Examples with Code ) ; 地址: http://127.0.0.1:8080/examples/servlets/

静态项目创建流程:

  • 1.采用Eclipse建立一个Web工程,首先切换到 Java EE 视图,然后选择Server选项卡并且配置好Tomcat服务器;

WeiyiGeek.Step1

  • 2.选择完成的Tomcat 7 Server 进行最后一步配置Web项目存放到新建立的wtpWebapps目录中保存即可,即D:apache-tomcat-7.0.100wtpwebapps;

WeiyiGeek.Step2

  • 3.新建一个动态的Web工程(Dynamic Web Project),设置项目名称为HelloWorld;

WeiyiGeek.Step3

  • 4.测试一个Web工程,在WebContent目录中建立一个静态资源index.html来测试应用服务器,选择项目进行Run on Server也可以快捷键ALT SHIFT X,R,第一次运行按照提示即可发布; 访问地址:http://localhost:8080/HelloWorld/

WeiyiGeek.Step4

注释:实际上是采用上面部署的第二种方法,在Server.xml中添加了一句<Context docBase="D:apache-tomcat-7.0.100wtpwebappsHelloWorld" path="/HelloWorld" reloadable="true" source="org.eclipse.jst.jee.server:HelloWorld"/>

Servelet项目创建流程:

  • 5.在项目的JAVA Resource中的src中创建一个测试Servlet的pakeage,并且建立一个java文件实现Servlet;

/HelloWorld/src/cn/weiyigeek/servlet/HelloWorld.java

代码语言:javascript复制
package cn.weiyigeek.servlet;
import java.io.IOException;
import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

/**
 * @author Administrator
 *  说明:测试验证Servlet
 */
// 1.实现Servlet接口
public class HelloWorld implements Servlet {
  
  //2.重写里面的方法
  @Override
  public void service(ServletRequest arg0, ServletResponse arg1) throws ServletException, IOException {
    // TODO Auto-generated method stub
    System.out.println("<p style='color:red'>Hello World, Servlet!</p>");
    
  }
  @Override
    ..... 
}

WeiyiGeek.Step5

6.配置Servlet项目在WebContent > WEB-INF > web.xml添加Servlet的名称以及类.包名称cn.weiyigeek.servlet.HelloWorld,然后添加注册一个Servlet映射url访问路径,重新发布项目即可;

代码语言:javascript复制
<?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_2_5.xsd" id="WebApp_ID" version="2.5">
  <display-name>HelloWorld</display-name>
  <!-- 默认的首页地址 -->
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>default.html</welcome-file>
    <welcome-file>default.htm</welcome-file>
    <welcome-file>default.jsp</welcome-file>
  </welcome-file-list>

<!-- 1.告知Tomcat我们应用中有个Servlet,名字叫做HelloHelloWorld,以及包.类的路径名称; -->
  <servlet>
  	<servlet-name>HelloWorld</servlet-name>
  	<servlet-class>cn.weiyigeek.servlet.HelloWorld</servlet-class>
  </servlet>


<!-- 2.注册Servlet映射以及URL匹配访问的路径 -->
  <servlet-mapping>
  	<servlet-name>HelloWorld</servlet-name>
  	<url-pattern>/hello</url-pattern>
  </servlet-mapping>

<web-app>

WeiyiGeek.Step6

响应流程: (1) 当用户访问http://127.0.0.1:8080/HelloWorld/hello时候,匹配到了注册的Servlet映射的url路径,反向找到servlet-name应用名称 (2) 再从Servlet应用中查询出该servlet name名称的应用,并反向找到其包名.类名称; (3) 编译并且创建cn.weiyigeek.servlet.HelloWorld该类的实例,然后Tomcat通过Java VM虚拟机运行其所产生的字节码文件; (4) 继而执行该Servlet中的services方,并且反馈输出到我们的控制台之中;

2.HttpServlet

描述:在Eclipse中选择接口名称按CTRL T键,显示其继承层级已经实现了Servlet接口的一些通用写法,来避免重复重写Servlet中的方法;

代码语言:javascript复制
Servlet 接口 -> GenericServlet -> HttpServlent (用于处理HTTP的请)

WeiyiGeek.通用写法

我们参照Tomcat给我们提供的helloworld.html示例文档进行实现,在上面的基础之上添加一个新的class文件,进行继承HttpServlet以及复习doGet和doPost方法;

基础示例:

代码语言:javascript复制
// cn.weiyigeek.servlet.HttpHelloWorld
package cn.weiyigeek.servlet;

import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @author Administrator
 * 说明:实现 Generial通用httpServet继承的复写
 */

public class HttpHelloWorld extends HttpServlet {
  
  //1.get请求
  @Override
  protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //设置响应文本内容类型
    resp.setContentType("text/html");
        //实例化并设置响应文本内容
    PrintWriter out = resp.getWriter();
    out.print("<!DOCTYPE HTML><html><head><title>HttpServlet Hello</title></head><body><h1>Hello World,HttpServlet!</h1></body></html>");
  }
  
  //2.post请求
  @Override
  protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    super.doPost(req, resp);
  }
}

// Web.xml:添加 servlet 映射
<web-app ...>
 <servlet>
  	<servlet-name>HttpHelloWorld</servlet-name>
  	<servlet-class>cn.weiyigeek.servlet.HttpHelloWorld</servlet-class>
  </servlet>
  <servlet-mapping>
  	<servlet-name>HttpHelloWorld</servlet-name>
  	<url-pattern>/web</url-pattern>
  </servlet-mapping>
</web-app>

WeiyiGeek.

3.Servlet生命周期

问:什么是生命周期?什么是生命周期方法?

从创建到销毁的一段时间,从创建到销毁的所调用的方法;

Servlet生命周期流程:

  • 1.init() 初始化:在创建该Servlet实例时候执行该方法(也可以提前进行初始化后面代码实现),在生命周期内只会在启动后初次访问时候触发一次,后续访问不会再触发;
  • 2.service() 服务请求:当客户端每来一个请求就要触发执行该方法;
  • 3.destory() 销毁:该项目从tomcat应用中移出的时候以及tomcat服务器正常shutdown的时候会触发执行该方法;

提前Servlet初始化: 描述:在有时候我们可能需要在init初始化这个方法中执行一些初始化工作,甚至做一些比较耗时的操作的逻辑,那么这时我们可以将初始化的时机进行提前到应用启动的时候; 配置:在需要的servlet提前初始化运行的servlet名称下添加load-on-startup元素;

基础示例: cn.weiyigeek.servlet.Lifecycle

代码语言:javascript复制
package cn.weiyigeek.servlet;
import java.io.IOException;
import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

/**
 * 
 * @author Administrator
 *   说明:Servlet 声明周期的验证
 */
public class Lifecycle implements Servlet {
  static int num = 0;
  
  @Override
  public void init(ServletConfig config) throws ServletException {
    // TODO Auto-generated method stub
    System.out.println("1.Lifecycle 初始化操作 ...");
  }

  @Override
  public ServletConfig getServletConfig() {
    // TODO Auto-generated method stub
    return null;
  }

  @Override
  public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
    // TODO Auto-generated method stub
    num  ;
    System.out.println("2.Lifecycle 服务提供操作,您访问了 " num " 次!");
  }

  @Override
  public String getServletInfo() {
    // TODO Auto-generated method stub
    return null;
  }

  @Override
  public void destroy() {
    // TODO Auto-generated method stub
    System.out.println("3.Lifecycle 销毁操作...");
  }
}



//web.xml
<web-app ...>
  <!-- 声明周期验证并提前初始化 -->
  <servlet>
  	<servlet-name>Lifecycle</servlet-name>
  	<servlet-class>cn.weiyigeek.servlet.Lifecycle</servlet-class>
  	<load-on-startup>3</load-on-startup>
  </servlet>
   <servlet-mapping>
   	<servlet-name>Lifecycle</servlet-name>
   	<url-pattern>/lifecycletest</url-pattern>
   </servlet-mapping>
</web-app>

执行结果:

代码语言:javascript复制
信息: Starting Servlet Engine: Apache Tomcat/7.0.100
二月 17, 2020 12:21:37 上午 org.apache.catalina.util.SessionIdGeneratorBase createSecureRandom
警告: Creation of SecureRandom instance for session ID generation using [SHA1PRNG] took [293] milliseconds.

1.Lifecycle 初始化操作 ...
二月 17, 2020 12:21:37 上午 org.apache.catalina.startup.HostConfig deployDescriptor
信息: 部署描述符[D:apache-tomcat-7.0.100confCatalinalocalhostDemo3.xml]的部署已在[69]ms内完成

二月 17, 2020 12:21:37 上午 org.apache.catalina.core.ApplicationContext log
信息: SessionListener: contextInitialized()


信息: 开始协议处理句柄["http-bio-8080"]
二月 17, 2020 12:21:38 上午 org.apache.catalina.startup.Catalina start
信息: Server startup in 1887 ms

2.Lifecycle 服务提供操作,您访问了 1 次!
2.Lifecycle 服务提供操作,您访问了 2 次!
2.Lifecycle 服务提供操作,您访问了 3 次!

信息: Pausing ProtocolHandler ["http-bio-8080"]
二月 17, 2020 12:32:36 上午 org.apache.catalina.core.StandardService stopInternal
信息: 正在停止服务[Catalina]

3.Lifecycle 销毁操作...
二月 17, 2020 12:32:36 上午 org.apache.catalina.core.ApplicationContext log
信息: SessionListener: contextDestroyed()
二月 17, 2020 12:32:36 上午 org.apache.coyote.AbstractProtocol stop
信息: 正在停止ProtocolHandler ["http-bio-8080"]
二月 17, 2020 12:32:36 上午 org.apache.coyote.AbstractProtocol destroy
信息: 正在摧毁协议处理器 ["http-bio-8080"]

注意事项:

  • 1.生命周期方法是指,从对象创建到销毁一定会执行的方法,而doGet和doPost不算生命周期方法因为他们可能会执行或者不会执行;
  • 2.Servlet初始化提前load-on-startup值越小优先级越高且是一个正值;
4.Servlet配置对象

描述:我们可以利用Servlet配置对象进行获取或检测web.xml中的servlet配置信息; 在未来我们进行实际开发时候,采用其他人开发出来的servlet类,我们使用它的jar进行导入到我们的工程之中,然后它设置的servlet必须注册某一个参数才可以使用,否则爆出异常;

如何声明init-params和init-values?

在Web.xml中的servlet元素中加入<init-param><param-name>name</param-name><param-value>WeiyiGeek</param-value></init-param>等子元素和孙子元素;

基础示例:

代码语言:javascript复制
///HelloWorld/src/cn/weiyigeek/servlet/SevletConfig.java
package cn.weiyigeek.servlet;

import java.io.IOException;
import java.util.Enumeration;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 
 * @author Administrator
 * Descript: 验证ServletConfig的使用获取web.xml配置的信息
 */
public class SevletConfig extends HttpServlet{
  
  private static final long serialVersionUID = 1L;

  @Override
  protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    //1.获得Servlet配置对象专门用于配置servlet的信息
    ServletConfig config = getServletConfig();
    
    //2.可以获取具体servlet配置中的名称;
    String servletName = config.getServletName();
    System.out.println("Servlet-Name = "   servletName);
    
    //3.检测参数是否存在被设置进行非法参数异常抛出(值得学习 illeal 英 /ɪˈliːɡl/ )
    String myself = config.getInitParameter("WeiyiGeek");
    if(myself == null) {
      throw new IllegalArgumentException("在Servlet配置中未找到WeiyiGeek参数,请核验Web.xml文件!");
    } else {
      System.out.println("WeiyiGeek load ....");
    }
    
    //4.获取单个具体参数
    String name = config.getInitParameter("name");
    System.out.println("配置文件中  name 值为"   name);
    
    //5.遍历配置中设置的多个参数
    Enumeration<String> para = config.getInitParameterNames();
    while(para.hasMoreElements()) {
      String key = para.nextElement();
      String value = config.getInitParameter(key);
      System.out.println("参数" key ",值=" value);
    }
  }
}

web.xml:

代码语言:javascript复制
<web-app>
    <!-- 4.验证ServletConfig配置 -->
    <servlet>
    	<servlet-name>ServletConfig</servlet-name>
    	<servlet-class>cn.weiyigeek.servlet.SevletConfig</servlet-class>
    	<init-param>
    		<param-name>WeiyiGeek</param-name>
    		<param-value>ServletConfig</param-value>
    	</init-param>
    	<init-param>
    		<param-name>name</param-name>
    		<param-value>WeiyiGeek</param-value>
    	</init-param>
    	<init-param>
    		<param-name>age</param-name>
    		<param-value>88</param-value>
    	</init-param>
    </servlet>
    <servlet-mapping>
    	<servlet-name>ServletConfig</servlet-name>
    	<url-pattern>/config</url-pattern>
    </servlet-mapping>
</web-app>

执行结果:

WeiyiGeek.Servlet配置对象

5.Servlet配置方式

描述:Servlet 配置方式常用的有三种: 1) 全路径匹配

web.xml 中的 <servlet> </servlet> 标签中以 / 开始 /a 或者 /aa/bb 访问: 127.0.0.1:8080/项目名称/aa//bb 访问即可

2)路径匹配,前版本匹配

以 / 开始,但是以 结束 /a/ 或者 /*; 访问: localhost:8080/项目名称/aa/bb

3) 以扩展名开始

没有 / 而是以 开始 .扩展名称,比如 *.aa 或者 .bb 访问:localhost:8080/项目名称/weiyigeek.aa

在下面我演示Servlet的第二种配置方式:

  • 1.右键新建立一个Servlet文件,需要您提供包package和类名称;

WeiyiGeek.

2.删除建立的ServletMethod文件中不需要的方法,并且查看web.xml 默认生成的servlet配置;

代码语言:javascript复制
<servlet>
    <description></description>
    <display-name>ServletMethod</display-name>
    <servlet-name>ServletMethod</servlet-name>
    <servlet-class>cn.weiyigeek.servlet.ServletMethod</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>ServletMethod</servlet-name>
    <url-pattern>/ServletMethod</url-pattern>
  </servlet-mapping>

3.验证上面的配置方式的一种将url-pattern进行更改

代码语言:javascript复制
-- 1. <url-pattern>/aa/bb</url-pattern>
-- 2. <url-pattern>/aa/*</url-pattern>
-- 3. <url-pattern>*.weiyigeek</url-pattern>

执行结果:

代码语言:javascript复制
package cn.weiyigeek.servlet;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Servlet implementation(实现) class ServletMethod
 */
public class ServletMethod extends HttpServlet {
  private static final long serialVersionUID = 1L;
    
  /**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
  protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    // TODO Auto-generated method stub
    response.getWriter().append("Served at: ").append(request.getContextPath());
    System.out.println("有人访问了一个请求...!!");
  }

  /**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
  protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    // TODO Auto-generated method stub
    doGet(request, response);
  }
}

WeiyiGeek.Servlet配置方式


0x05 Servlet进阶
1.ServletContext对象

描述:每个JAVA虚拟机中的WEB application应用工程只有一个ServletContext对象,简单的说就是不管在哪一个servlet里面获得到的这个类的对象都是同一个;

ServletContext对象的作用

  • 1.获取全局配置参数
  • 2.获取Web工程中的资源
  • 3.存取数据Servlet间共享数据(域对象)

ServletContext 生命周期 问题:ServletContext何时创建,何时销毁?

创建:服务器启动的时候,会为托管的每一个Web应用程序,创建一个ServletContext对象; 销毁:从服务器移除托管或者是关闭服务器;

ServletContext 作用范围:同一个项目之中共享数据,但是如果是不同的项目之间存取值是不一样的(取不到),因为ServletContext的对象不同;

1) 采用ServletContext获取资源文件 在工程中的web.xml中建立的context-param参数是全局的上下文参数或者在WebContext中建立一个文件夹存储Properties文件;

代码语言:javascript复制
<!-- 1.在Servlet中采用getServletContext获取对象-->
ServletContext context = getServletContext();

<!-- 2.全局上下文参数-->
<context-param>
  	<param-name>name</param-name>
  	<param-value>WeiyiGeek</param-value>
  </context-param>
  
  <context-param>
    <param-name>age</param-name>
  	<param-value>100</param-value>
  </context-param>

<!--3.在WebContext目录中建立一个目录和prop文件-->
Config/WeiyiGeek.Properties;

基础示例:

代码语言:javascript复制
package cn.weiyigeek.servlet;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


public class Servletcontext1 extends HttpServlet {
  private static final long serialVersionUID = 1L;
  protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
    //方式1:ServletContext获取资源文件
    Scmethod1(response);

    //方式2:ServletContext   Propersties 获取资源文件
    Scmethod2(response);
  
    //方式3:ServletContext资源文件获取
    ServletContext sc = getServletContext();
    Properties prop = new Properties();
    //给相对路径然后直接获取文件绝对地址和读取文件转化成为流对象
    InputStream is = sc.getResourceAsStream("Config/WeiyiGeek.Properties"); 
    prop.load(is);
    System.out.println("n方式三:ServletContext资源文件获取n");
    System.out.println("Name = "   prop.getProperty("name")   "n");
    System.out.println("Age = "   prop.getProperty("age"));
  }

  
  //方式2
  public void Scmethod2(HttpServletResponse response) throws FileNotFoundException, IOException {
    //1.获取上下文对象
    ServletContext context = getServletContext();
    //2.或者Properties中的参数值采用ServletContext进行读取
    Properties prop = new Properties();
    String proppath = context.getRealPath("Config/WeiyiGeek.Properties"); //获取到了WeiyiGeek.Properties绝对路径
    System.out.println("Properties 配置文件路径 = "   proppath);
    //Properties 配置文件路径 = D:apache-tomcat-7.0.100wtpwebappsHelloWorldConfigWeiyiGeek.Properties

    //3.指定properties数据源(但是需要注意这里是web应用,如果想获取web工程的下资源需要采用ServletContext获取配置文件路径)
    InputStream is = new FileInputStream(proppath);
    prop.load(is);
    
    //4.获取属性的值
    String name = prop.getProperty("name");
    String age = prop.getProperty("age");
    response.getWriter().append("n ------------------ n");
    response.getWriter().append("ServletContext-> Properties Param Name = ").append(name    "n");
    response.getWriter().append("ServletContext-> Properties Param Age = ").append(age);
  }
  
  //方式1
  public void Scmethod1(HttpServletResponse response) throws IOException {
    //1.获取上下文对象
    ServletContext context = getServletContext();
    
    //2.获取web.xml中Context-param中设置全局配置参数的key和value;
    response.getWriter().append("ServletContext Param Name = ").append(context.getInitParameter("name")   "n");
    response.getWriter().append("ServletContext Param Age = ").append(context.getInitParameter("age"));
  }
}

WeiyiGeek.

注意事项:

  • 1.在Web工程按照我们前面学习的Properites进行读取配置文件是不行,如果您将prop文件建立在src中在web项目部署的时候会保存到WEB-INF/CLASSES/目录中,导致FileInputStream不能够正常读取到该文件则properties方式也不能获取到参数的值,因为此时FIleInputStream流程读取是bin/src/xxx.Properties;
  • 2.解决注意1的方式是采用ServletContext中的getRealPath方法获取到webContext的绝对路径,然后在指定dir/xx.Properties之后常规读取即可
  • 3.对注意2进行优化可以直接采用ServletContext中的getResoureAsStream方法读取文件流,然后采用prop.load()加载此对象即可;

2) 使用ClassLoader获取资源文件 描述:采用ClassLoader可以直接读取当前工程下的字节码文件和配置文件;

基础案例:

代码语言:javascript复制
package cn.weiyigeek.servlet;

import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


public class Servletcontext2 extends HttpServlet {
  private static final long serialVersionUID = 1L;
  protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //1.打印getClassLoader路径
    System.out.println(this.getClass().getClassLoader());
    
       //2.实例化Properties和InputStream对象
    Properties prop = new Properties();
    InputStream is = this.getClass().getClassLoader().getResourceAsStream("../../Config/WeiyiGeek.Properties");
    prop.load(is);
    System.out.println("姓名:"   prop.getProperty("name")   ",年龄 : "   prop.getProperty("age") );
    is.close();
  }
}

访问:

代码语言:javascript复制
#运行结果:
WebappClassLoader
  context: /HelloWorld
  delegate: false
  repositories:
    /WEB-INF/classes/   #因为默认是在这个目录之中,而我们建立的是在WebContext中则需要两次回到上级目录之中
----------> Parent Classloader:
java.net.URLClassLoader@7440e464

姓名:WeiyiGeek,年龄 : 2020

3) ServletContext存取数据 描述:此处采用ServletContext进行获取登录成功的总数,具体流程如下:

  1. 获取提交过来的数据
  2. 判断账号密码数据是否有误
  3. 如果正确进行页面的跳转并且输出”该用户是网站成功登陆的第几人”,采用Servlet记录其值;
  4. 如果错误输出”登录失败”;

补充说明:一个请求URL对应一个Servlet文件进行处理;

基础语法说明:

代码语言:javascript复制
//获取设置的属性值
getServletContext().getAttribute("key")

//设置属性值
getServletContext().setAttribute("key",value);

实例演示:

代码语言:javascript复制
//Servlet Class 类
Login
CountTotal

//HTML页面
Login.html
Success.html

WeiyiGeek.

基础代码:

代码语言:javascript复制
<!-- Login.html -->
<!-- 注意 action 这里由于login.html 与 Login 是处于同一级目录的,您也可以写 /项目名称/Login -->
<form action="Login" method="get">
  用户名:<input type="text" name="username"/>
  密    码:<input type="password" name="password"/>
  <input type="submit" value="登录"/>
</form>

<!-- Success.html -->
<h1> 尊敬的用户您已成功登陆! </h1>
<hr/>
<a href="CountTotal">获取成功登陆的次数</a>

java代码:

代码语言:javascript复制
//Servlet -> Login
public class Login extends HttpServlet {
  private static final long serialVersionUID = 1L;
  protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    //1.获取登录页面传递的参数
    String user = request.getParameter("username");
    String pass = request.getParameter("password");
    System.out.println("Get 请求获取的参数 :user = "   user   "?pass = "   pass );
    
    //2.判断用户输入账号密码是否正确
    if("admin".equals(user) && "123".equals(pass)) 
        {
      
      //3.登录成功在响应和终端控制台进行打印
      response.getWriter().append("登录成功!");
      
      //4.记录和获取在Servlet中存储登录成功的值
      int count = 0;
      Object ob = getServletContext().getAttribute("total"); //获取ServletContext属性
      if(ob != null )
      {
        count = (int) ob;
      }
      getServletContext().setAttribute("total",   count); //设置存储ServletContext属性
      System.out.println("登录成功! 您累积成功登陆 "   count  "次");

      //5.设置登录成功跳转页面
      response.setStatus(302); //设置状态码
      response.setHeader("Location", "success.html"); //设置跳转头
    }else {
      response.getWriter().print("登录失败,账号或者密码错误!");
      System.out.println("账号或者密码错误!");
    }
  }
}


//Servlet -> CountTotal
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    //1.在ServletContext中获取成功登陆的次数
    int total = (int) getServletContext().getAttribute("total");
    
    //2.打印输出成功的次数
    response.getWriter().append("尊敬的用户您成功登陆 "   total  " 次");
}
2.HttpServletRequest

1) Request获取请求头 基础语法:

代码语言:javascript复制
request.getHeaderNames(); //返回一个枚举合集Enumeration请求头
request.getHeader("请求头部"); //获取该请求的响应头值

2) Request请求信息提取 基础语法:

代码语言:javascript复制
System.out.println("当前客户端协议  :"   request.getProtocol());
System.out.println("当前请求编码 :"   request.getCharacterEncoding());
System.out.println("项目名称 :"   request.getContextPath());
System.out.println("项目URL:"   request.getRequestURI());
System.out.println("本机信息 :"   request.getLocalName()   " - "   request.getLocalAddr()    " - "   request.getLocalPort());
System.out.println("客户端信息 : "   request.getRemoteUser()   " - "   request.getRemoteAddr()   " - "   request.getRemoteHost()   " - "   request.getRemotePort());

3) Request请求数据拿取 基础语法:

代码语言:javascript复制
//请求参数值获取单个
request.getParameter("key")
//方式1.获取多个请求参数为集合
request.getParameterMap();  // Map Set Iterator 等
//方式2:获取多个请求参数为集合
request.getParameterNames(); // 获得参数名称
request.getParameterValues("key") //利用参数名称查询其值

4) Request请求中文乱码解决 描述:在客户端进行Get/POST请求的时候在URL地址已经经过了url编码,而Tomcat获取到的这批数据getParameter默认使用ISO-8859-1去解码,所以会导致答应中文乱码;

解决办法:

代码语言:javascript复制
//1.终端/网页显示不乱码(推荐形式-成功)
String val = new String(value[i].getBytes("ISO-8859-1"),"utf-8");

//2.网页回显不乱码(POST 请求 - 未验证成功)
request.setCharacterEncoding("UTF-8");  //输入的格式不乱码 (需要写在获取参数之前 - POST 请求使用)

//3.直接在Tomcat中进行配置以后GET请求的数据永远都是UTF-8编码
//conf/server.xml
<Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443" URLEncoding="UTF-8" />

基础示例(1):

代码语言:javascript复制
package cn.weiyigeek.httpServletRequest;

import java.io.IOException;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class HttpHeader extends HttpServlet {
  private static final long serialVersionUID = 1L;
  protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //0.采用网页进行回显
    request.setCharacterEncoding("utf-8");  //输入的格式不乱码
    response.setContentType("text/html");   //输出格式
        
    //1.枚举集合
    response.getWriter().append("------- 请求头获取  ------- <br/>");
    Enumeration<String> headers = request.getHeaderNames();
    
    //2.循环迭代请求头
    while(headers.hasMoreElements())
    {
      String reqname = headers.nextElement();
      String reqvalue = request.getHeader(reqname);
      //3.向网页中进行输出
      response.getWriter().append(reqname   ":"   reqvalue   "<br/>");
    }
    
    response.getWriter().append("<br/> ------- 获取多个参数 ------- <br/>");
    //4.方式1:获取多个请求参数(值得学习)
    Map<String, String[]> map= request.getParameterMap(); //map 集合
    Set<String> keySet = map.keySet();  //Set 集合
    Iterator<String> iterator = keySet.iterator(); //迭代器
    while(iterator.hasNext()) {
      String key = (String) iterator.next();
      String[] value = map.get(key);  //默认以首次出现的参数名称为准
      
      //5.验证存在多个相同的参数
      if(value.length > 1){
        for (int i = 0; i < value.length; i  ) {
          String val = new String(value[i].getBytes("ISO-8859-1"),"utf-8"); // 防止输入输出的中文乱码(终端|网页)
          response.getWriter().append(key  ":"   val   "<br/>");
        }
      }else {
        response.getWriter().append(key  ":"   value[0]   "<br/>");
      }
    }
    
    //6.方式2:获取请求的参数(中文输出不乱码)
  	    Enumeration<String> para = request.getParameterNames();
  	    while(para.hasMoreElements())
  	    {
  	    	String paraname = para.nextElement();
  	    	String[] value = request.getParameterValues(paraname);
  	    	if(value.length > 1) {
  	    		for (int j = 0; j < value.length; j  ) {
  	  				String val = new String(value[j].getBytes("ISO-8859-1"),"utf-8"); // 防止输入输出的中文乱码(终端|网页)
  	  	    		System.out.println(paraname    " = "   val);
        }
  	    	}else {
  	    		 System.out.println(paraname    " = "   value[0]   "n");

  	    	}
  	    }		
  }
}

WeiyiGeek.执行结果

基础示例(2):POST请求验证输入输出不乱码和请求信息获取;

代码语言:javascript复制
public class HttpPostInfo extends HttpServlet {
  private static final long serialVersionUID = 1L;
  protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    //2.POST请求输出不乱码
    request.setCharacterEncoding("UTF-8");
    
    //3.获取输出POST请求的参数
    System.out.println("编码设置后 ---  name = "   new String(request.getParameter("name").getBytes("ISO-8859-1"),"UTF-8")   "n----");
    
    //4.获取客户端的信息
    System.out.println("当前客户端协议  :"   request.getProtocol());
    System.out.println("当前请求编码 :"   request.getCharacterEncoding());
    System.out.println("项目名称 :"   request.getContextPath());
    System.out.println("项目URL:"   request.getRequestURI());
    System.out.println("本机信息 :"   request.getLocalName()   " - "   request.getLocalAddr()    " - "   request.getLocalPort());
    System.out.println("客户端信息 : "   request.getRemoteUser()   " - "   request.getRemoteAddr()   " - "   request.getRemoteHost()   " - "   request.getRemotePort());
  }

  protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    //1.POST 请求入口
    System.out.println("POST 请求.....");
    System.out.println("编码设置前 ---  name = "   request.getParameter("name"));
    doGet(request, response);
  }
}

//基础信息
POST 请求.....
编码设置前 ---  name = ??????
编码设置后 ---  name = 张伟
----
当前客户端协议  :HTTP/1.1
当前请求编码 :UTF-8
项目名称 :/HelloWorld
项目URL:/HelloWorld/HttpPostInfo
本机信息 :HackOne - 192.168.1.3 - 8080
3.HttpServletResponse

描述: 服务器端返回给客户端的内容信息; 1) 响应数据 基础语法:

代码语言:javascript复制
response.getWriter().write("<h1>字符集</h1>"); //以字符流的方式写数据
response.getOutputStream().write("Hello World!".getBytes()); //字节流的方式写数据

2) 响应中文乱码 描述:在请求响应中有中文字符乱码的存在,在使用Tomcat的Servlet进行写出去的文字默认是以ISO-8859-1编码写出,所以我们需要采用指定编码进行写出防止乱码; 基础语法:

代码语言:javascript复制
// 以字符流的方式 
response.setHeader("Content-type","text/html; charset=UTF-8"); //规定浏览器显示什么编码
response.setCharacterEncoding("UTF-8"); //响应内容编码(根据浏览器有关)
response.getWriter().write("<h1>字符集</h1>"); //以字符流的方式写数据

// 以字节流的方式
response.setContentType("text/html; charset=UTF-8");   //响应内容格式和编码
response.getOutputStream().write("中文字符串".getBytes("UTF-8")); //默认输出是UTF-8

总结:

  • 不管是字节流还是字符流直接使用setContentType()方法进行响应格式和编码,之后直接写数据即可;

3) 响应头设置

基础语法:

代码语言:javascript复制
response.setStatus(302) //响应状态码设置
response.setHeader("Location","WeiyiGeek.top") //响应头设置

4) Servlet请求重定向和转发 描述:重定向与转发的区别;

  • 1.客户端显示URL不同:前者重定向的地址(此时request对象存储的数据中原来的参数将不会被带人),后者用户访问的Servlet地址(会将参数一起待入到转发的页面);
  • 2.请求次数的不同:前者由于返回302状态码Clint请求了两次,后者只请求了一次;
  • 3.跳转的限制:前者任意工程跳转,后者自己项目工程调整;
  • 4.效率对比:前者效率较后者低;

基础语法:

代码语言:javascript复制
//重定向早期案例
response.setStatus(302);
response.setHeader("Location","Login_Success.html");
//重定向常用案例(即重新定位方向即Login_Success.html网页地址)
response.sendRedirect("Login_Success.html")

//请求转发案例(但是请求的URL还是原地址不是Login_Success.html,服务器内部进行处理了后续的工作)
//带参数和跳转位置进行拼接到请求的Servlet
response.getRequestDispatcher("Login_Success.html").forward(request,response);

WeiyiGeek.区别

5) 资源下载

  • 1.采用超连接的形式下载定位静态资源,但是遇到jpg或者txt类型的数据还是可以下载,只不过要右键另存为,所以当我们没有写Servlet文件进行处理,也能进行解析,原因是由于Tomcat里有个默认的Servlet叫DefaultServlet专门处理放在Tomcat服务器上的静态资源;
  • 2.手动编码进行下载,设置响应头Content-Disposition: attachment; filename="文件名称";

基础示例:资源下载

代码语言:javascript复制
public class HttpFileDown extends HttpServlet {
  private static final long serialVersionUID = 1L;
  protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    //1.返回给客户端的文字内容使用的默认编码
    response.setCharacterEncoding("UTF-8");
    
    //2.指定浏览器解析数据的格式和编码
    //response.setHeader("Content-Type", "text/html; charset=UTF-8");
    
    //3.采用字符流进行输出中文不乱码
    String filename = new String(request.getParameter("filename").getBytes("ISO-8859-1"),"UTF-8"); //下载文件带中文字符
    //response.getWriter().write("1.字符流(方式):当前您下载的文件是  "    filename   "<br/>");
        //String csn = Charset.defaultCharset().name();		//getBytes()默认码表
        //response.getWriter().append("2.getBytes()默认码表:"   csn);

    //4.采用字节流进行指定编码输出中文不乱码(其实getBytes()方法的默认码表就是UTF-8与Tomcat默认码表无关系)
    //response.setContentType("text/html; charset=UTF-8");   //响应内容格式和编码
    
    String path = getServletContext().getRealPath("Config/" filename);
    String name = "3.字节流(方式):当前您下载的文件路径是  :"    path; 
    //response.getOutputStream().write(name.getBytes("UTF-8"));  //注意不能和字符流同时存在;
    //response.getOutputStream().print(name);
    
    //5.设置下载文件的响应头并且如果存在中文名称需要对其进行编码;
    /*
		 * 如果IE或者Chrome使用的URLEncoding编码
		      如果是Firefox使用的是base64编码
		 */
    
    String clientType = request.getHeader("User-Agent");
    //注意大小写,当然为了方便您可以
    if(clientType.contains("Firefox")) 
    {
      filename = base64EncodeFileName(filename);
    } else {
      filename = URLEncoder.encode(filename,"UTF-8");
    }
    response.setHeader("Content-Disposition", "attachment; filename=" filename);	//返回文件中文不乱码


    //6.读取文件到字节流然后进行下载
    InputStream is = new FileInputStream(path); //采用绝对路径进行读取文件
    OutputStream os = response.getOutputStream(); 
    
    int len = 0;
    byte[] buf = new byte[1024];
    while((len = is.read(buf)) != -1)
    {
      //7.写出文件
      os.write(buf, 0, len);
    }
    //8.关闭输入输出流
    os.close();
    is.close();
  }

  protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    // TODO Auto-generated method stub
    doGet(request, response);
  }
  
  //进行Base64编码
  public static String base64EncodeFileName(String fileName) {
    BASE64Encoder base64Encoder = new BASE64Encoder();
    try {
      return "=?UTF-8?B?"   new String(base64Encoder.encode(fileName.getBytes("UTF-8")))   "?=";
    } catch (UnsupportedEncodingException e) {
      e.printStackTrace();
      throw new RuntimeException(e);
    }
  }
}

执行结果:

代码语言:javascript复制
#使用getWriter()
1.字符流(方式):当前您下载的文件是 WeiyiGeek.Properties
2.getBytes()默认码表:GBK

#使用getOutPutStream() 注意不能和字符流同时存在
3.字节流(方式):当前您下载的文件路径是  :D:apache-tomcat-7.0.100wtpwebappsHelloWorldConfigWeiyiGeek.Properties

WeiyiGeek.执行结果

注意事项:

  • 针对于浏览器类型对下载的文件名称做编码处理,Fire采用Base64编码而IE和Google采用URLEncoding编码

0x06 本文总结

ServletContext 介绍:什么是ServletContext?

  • 答:服务器在启动的时候给每一个应用程序都创建一个ServletContext,并且有且只有一个;

作用:有什么用?

  • 答:获取全局参数 / 获取工程下的资源 / 存取数据和共享数据

例子:怎么用?

代码语言:javascript复制
//获取全局参数
getServletContext().getInitParams();

//获取工程下的资源
getServletContext().getRealPath();
getServletContext().getResourceAsStream();
this.getClass().getClassLoader();

//存取的数据(在同一工程下)
getServletContext.setAttribute()
getServletContext.getAttribute()

实际问题:为什么使用它会产生这个样的样子,其中有其他的参数;

ServletConfig 介绍:什么是ServletConfig?

  • 答:是在项目启动部署的时候我们在web.xml中进行对Servlet的配置当我们需要获取Servlet配置信息的时候就需要它;

作用:有什么用?

  • 答:获取在Servlet配置web.xml文件中参数;

例子:怎么用?

代码语言:javascript复制
//获取Web.xml中的Servlet配置信息
getServletConfig().getInitParams();

HttpServletResquest 介绍:

  • 答:一个请求对象用于封装客户端提交过来的信息;

作用:

  • 答:获取头 / 获取客户端参数 / 获取提交过来的数据;

例子:

代码语言:javascript复制
request.getParameter("key");

存在问题: GET/POST请求乱码(需要设置编码)

HttpServletResquest 介绍:

  • 答:这是一个响应对象,是服务器要给客户端返回的数据,都靠这个对象来完成;

作用:

  • 答:返回不同格式的内容 / 页面状态设置和跳转

例子:

代码语言:javascript复制
//返回不同格式(两种方式)
response.setHeader("Content-Type", "text/html; charset=UTF-8");
response.setContentType("text/html; charset=UTF-8"); 

//状态码设置
response.setStatus(302);
response.setHeader("Location","")

0 人点赞