[TOC]
描述:在进行JavaWeb开发学习的时候必不可少就是Tomcat Web 容器服务器,因为它开源免费、便于上手,并且使用安装简单。
简单介绍: Tomcat是一款开源软件、免费的Web容器软件,由Apache基金会旗下采用JAVA进行开发,Tomcat是一款Web容器自身不能作为负载均衡的软件; 主要应用于发布网页代码,提供网页信息服务,用户通过浏览可以实现界面的访问;Tomcat默认可以处理静态的网页,也可以处理动态的网页;
在这里我们就详细演示安装流程了,在我其他的Tomcat运维文章中有它的详细以及优化配置等.
学习环境准备:
Java的JDK8(并且配置好环境变量)Tomcat 7.0.100 : http://tomcat.apache.org/download-70.cgiEclipse IDEWeiyiGeek.Tomcat
Tomcat 7.0目录结构说明
* bin:Tomcat 启用binary以及一些启动jar包 * conf:Tomcat配置文档 * lib:Tomcat运行所依赖的jar文件 * logs:运行过程中的日志文件 * temp:临时文件 * webapps:项目发布的目录,以及war解压的目录; * work:JSPbuild成为java文件的临时存放地
描述:如何将项目发布到Tomcat中运行?
方式1:移动项目到Webapps目录(使用较多) 描述:冷部署可以直接将项目文件夹拖入Webapps目录之中并需要重新启动Tomcat;
#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控制终端日志中显示。
<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 "%r" %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元素复制到引擎文件中即可;
#$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.
描述:在实际的开发中我们需要将我们的web工程打压成为war包或者jar包进行tomcat部署或者在jvm虚拟机中运行;
问:如何将项目打包成为jar?
1.右键工程选择Export选择other在java目录下选择jar;WeiyiGeek.
2.进行导出jar配置一般默认就行;WeiyiGeek.
描述:Servlet[ /ˈsɜːvlɪt/ ] API 是运行在Tomcat Web服务器容器中的小型Java程序伺服小程式;小服务程,通过HTTP(超文本传输协议)接收和响应来自Web客户端的请求;更多的是配合动态资源做项目,当然也可以使用到Servlet只不过在Tomcat里面已经定义了一个DefaultServlet;
描述:在上面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"/>
:
5.在项目的JAVA Resource中的src中创建一个测试Servlet的pakeage,并且建立一个java文件实现Servlet;/HelloWorld/src/cn/weiyigeek/servlet/HelloWorld.java
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访问路径,重新发布项目即可;
<?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方,并且反馈输出到我们的控制台之中;
描述:在Eclipse中选择接口名称按CTRL+T键,显示其继承层级已经实现了Servlet接口的一些通用写法,来避免重复重写Servlet中的方法;
Servlet 接口 -> GenericServlet -> HttpServlent (用于处理HTTP的请)
WeiyiGeek.通用写法
我们参照Tomcat给我们提供的helloworld.html示例文档进行实现,在上面的基础之上添加一个新的class文件,进行继承HttpServlet以及复习doGet和doPost方法;
基础示例:
// 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.
问:什么是生命周期?什么是生命周期方法?
从创建到销毁的一段时间,从创建到销毁的所调用的方法;
Servlet生命周期流程:
1.init() 初始化:在创建该Servlet实例时候执行该方法(也可以提前进行初始化后面代码实现),在生命周期内只会在启动后初次访问时候触发一次,后续访问不会再触发;2.service() 服务请求:当客户端每来一个请求就要触发执行该方法;3.destory() 销毁:该项目从tomcat应用中移出的时候以及tomcat服务器正常shutdown的时候会触发执行该方法;提前Servlet初始化: 描述:在有时候我们可能需要在init初始化这个方法中执行一些初始化工作,甚至做一些比较耗时的操作的逻辑,那么这时我们可以将初始化的时机进行提前到应用启动的时候; 配置:在需要的servlet提前初始化运行的servlet名称下添加load-on-startup元素;
基础示例: cn.weiyigeek.servlet.Lifecycle
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>
执行结果:
信息: 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值越小优先级越高且是一个正值;描述:我们可以利用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>等子元素和孙子元素;
基础示例:
///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:
<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配置对象
描述:Servlet 配置方式常用的有三种: 1) 全路径匹配
web.xml 中的 <servlet> </servlet> 标签中以 / 开始 /a 或者 /aa/bb 访问: 127.0.0.1:8080/项目名称/aa//bb 访问即可
2)路径匹配,前版本匹配
以 / 开始,但是以 或者 /*; 访问: localhost:8080/项目名称/aa/bb
3) 以扩展名开始
没有 / 而是以 .扩展名称,比如 *.aa 或者 .bb 访问:localhost:8080/项目名称/weiyigeek.aa
在下面我演示Servlet的第二种配置方式:
1.右键新建立一个Servlet文件,需要您提供包package和类名称;WeiyiGeek.
2.删除建立的ServletMethod文件中不需要的方法,并且查看web.xml 默认生成的servlet配置;
<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进行更改
-- 1. <url-pattern>/aa/bb</url-pattern> -- 2. <url-pattern>/aa/*</url-pattern> -- 3. <url-pattern>*.weiyigeek</url-pattern>
执行结果:
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配置方式
描述:每个JAVA虚拟机中的WEB application应用工程只有一个ServletContext对象,简单的说就是不管在哪一个servlet里面获得到的这个类的对象都是同一个;
ServletContext对象的作用
1.获取全局配置参数2.获取Web工程中的资源3.存取数据Servlet间共享数据(域对象)ServletContext 生命周期 问题:ServletContext何时创建,何时销毁?
创建:服务器启动的时候,会为托管的每一个Web应用程序,创建一个ServletContext对象; 销毁:从服务器移除托管或者是关闭服务器;
:同一个项目之中共享数据,但是如果是不同的项目之间存取值是不一样的(取不到),因为ServletContext的对象不同;
1) 采用ServletContext获取资源文件 在工程中的web.xml中建立的context-param参数是全局的上下文参数或者在WebContext中建立一个文件夹存储Properties文件;
<!-- 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;
基础示例:
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(" 方式三:ServletContext资源文件获取 "); System.out.println("Name = " + prop.getProperty("name") + " "); 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(" ------------------ "); response.getWriter().append("ServletContext-> Properties Param Name = ").append(name + " "); 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") + " "); 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可以直接读取当前工程下的字节码文件和配置文件;
基础案例:
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(); } }
访问:
#运行结果: WebappClassLoader context: /HelloWorld delegate: false repositories: /WEB-INF/classes/ #因为默认是在这个目录之中,而我们建立的是在WebContext中则需要两次回到上级目录之中 ----------> Parent Classloader: java.net.URLClassLoader@7440e464 姓名:WeiyiGeek,年龄 : 2020
3) ServletContext存取数据 描述:此处采用ServletContext进行获取登录成功的总数,具体流程如下:
获取提交过来的数据判断账号密码数据是否有误如果正确进行页面的跳转并且输出”该用户是网站成功登陆的第几人”,采用Servlet记录其值;如果错误输出”登录失败”;补充说明:一个请求URL对应一个Servlet文件进行处理;
基础语法说明:
//获取设置的属性值 getServletContext().getAttribute("key") //设置属性值 getServletContext().setAttribute("key",value);
实例演示:
//Servlet Class 类 Login CountTotal //HTML页面 Login.html Success.html
WeiyiGeek.
基础代码:
<!-- 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代码:
//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 +" 次"); }
1) Request获取请求头 基础语法:
request.getHeaderNames(); //返回一个枚举合集Enumeration请求头 request.getHeader("请求头部"); //获取该请求的响应头值
2) Request请求信息提取 基础语法:
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请求数据拿取 基础语法:
//请求参数值获取单个 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去解码,所以会导致答应中文乱码;
解决办法:
//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):
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] + " "); } } } }
WeiyiGeek.执行结果
基础示例(2):POST请求验证输入输出不乱码和请求信息获取;
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") + " ----"); //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
描述: 服务器端返回给客户端的内容信息; 1) 响应数据 基础语法:
response.getWriter().write("<h1>字符集</h1>"); //以字符流的方式写数据 response.getOutputStream().write("Hello World!".getBytes()); //字节流的方式写数据
2) 响应中文乱码 描述:在请求响应中有中文字符乱码的存在,在使用Tomcat的Servlet进行写出去的文字默认是以ISO-8859-1编码写出,所以我们需要采用指定编码进行写出防止乱码; 基础语法:
// 以字符流的方式 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) 响应头设置
基础语法:
response.setStatus(302) //响应状态码设置 response.setHeader("Location","WeiyiGeek.top") //响应头设置
4) Servlet请求重定向和转发 描述:重定向与转发的区别;
1.客户端显示URL不同:前者重定向的地址(此时request对象存储的数据中原来的参数将不会被带人),后者用户访问的Servlet地址(会将参数一起待入到转发的页面);2.请求次数的不同:前者由于返回302状态码Clint请求了两次,后者只请求了一次;3.跳转的限制:前者任意工程跳转,后者自己项目工程调整;4.效率对比:前者效率较后者低;基础语法:
//重定向早期案例 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="文件名称";基础示例:资源下载
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); } } }
执行结果:
#使用getWriter() 1.字符流(方式):当前您下载的文件是 WeiyiGeek.Properties 2.getBytes()默认码表:GBK #使用getOutPutStream() 注意不能和字符流同时存在 3.字节流(方式):当前您下载的文件路径是 :D:apache-tomcat-7.0.100wtpwebappsHelloWorldConfigWeiyiGeek.Properties
WeiyiGeek.执行结果
注意事项:
针对于浏览器类型对下载的文件名称做编码处理,Fire采用Base64编码而IE和Google采用URLEncoding编码ServletContext 介绍:什么是ServletContext?
答:服务器在启动的时候给每一个应用程序都创建一个ServletContext,并且有且只有一个;作用:有什么用?
答:获取全局参数 / 获取工程下的资源 / 存取数据和共享数据例子:怎么用?
//获取全局参数 getServletContext().getInitParams(); //获取工程下的资源 getServletContext().getRealPath(); getServletContext().getResourceAsStream(); this.getClass().getClassLoader(); //存取的数据(在同一工程下) getServletContext.setAttribute() getServletContext.getAttribute()
实际问题:为什么使用它会产生这个样的样子,其中有其他的参数;
ServletConfig 介绍:什么是ServletConfig?
答:是在项目启动部署的时候我们在web.xml中进行对Servlet的配置当我们需要获取Servlet配置信息的时候就需要它;作用:有什么用?
答:获取在Servlet配置web.xml文件中参数;例子:怎么用?
//获取Web.xml中的Servlet配置信息 getServletConfig().getInitParams();
HttpServletResquest 介绍:
答:一个请求对象用于封装客户端提交过来的信息;作用:
答:获取头 / 获取客户端参数 / 获取提交过来的数据;例子:
request.getParameter("key");
存在问题: GET/POST请求乱码(需要设置编码)
HttpServletResquest 介绍:
答:这是一个响应对象,是服务器要给客户端返回的数据,都靠这个对象来完成;作用:
答:返回不同格式的内容 / 页面状态设置和跳转例子:
//返回不同格式(两种方式) response.setHeader("Content-Type", "text/html; charset=UTF-8"); response.setContentType("text/html; charset=UTF-8"); //状态码设置 response.setStatus(302); response.setHeader("Location","")
WordPress 通过加密隐藏 wp-login/admin 后台默认登录地址