文章目录
servlet
动态网页
1、访问web服务器上的某个页面,访问的内容会发生变化
2、动态网页和动态HTML页面的区别
3、动态网页的源文件会随网页的变化而变化,而动态HTML页面的源文件不会发生变化
动态网页程序与引擎
1、首先使用某种编程语言编写出相应的动态网页程序
2、然后由一个专门的web服务程序模块(引擎)来解释执行
3、引擎是动态网页程序和浏览器之间的桥梁
4、浏览器、引擎、API、动态网页之间的关系
5、客户端请求的URL后缀名符合某种引擎所处理的资源名的特征,web服务将把请求转交给相应的引擎取处理。处理过程可以实现对数据库的插入、修改、删除和查询等操作。
6、常见的动态网页解决方案(服务器端的web编程技术)
常见的有CGI、ISAPI、ASP、ASP.NET、Servlet/Jsp、PHP等这些技术使用不同的编程语言
Servlet简介
Servlet技术是Sun公司提供的一种实现动态网页的解决方案,它是基于Java编程语言的web服务器端编程技术
1、一个Servlet程序就是实现了特殊接口的Java类,它由支持Servlet(具有Servlet引擎)的web服务器调用和启动运行。一个Servlet程序负责处理它所对应的一个或者多个URL地址的请求,并接收客户端发出的访问请求信息和产生相应内容。
2、Applet是用于浏览器端的Java小程序,Servlet是用于服务器短的Java小程序
3、Servlet可以完成的任务
- 获取客户端通过HTML的FORM表单递交的数据和URL后面的参数信息
- 创建对客户端的相应消息内容
- 访问服务器端的文件系统
- 连接数据库并开发基于数据库的应用
- 调用其它的Java类
C/S和B/S系统架构
C/S系统架构的特点
缺点:
- 数据库系统支持的并发连接数有限
- 软件的维护和功能扩展较为复杂
- 每个客户机都需要安装客户端程序
优点:
功能可以做的非常强大,例如:在数据库不可用时,可以将事物记录保存在本地桌面数据库中后再集中向数据库服务器发送,很容易对数据库中的数据进行实时监控和实现报警功能。
B/S系统架构
优点
- 将程序中的界面显示和业务逻辑处理移动到了web服务器中来实现,客户端只需要具有浏览器就可以作为B/S架构的操作终端
- 修改操作页面只需要在web服务器端修改相应的网页文档
- 客户端不直接与数据库建立连接,所以数据库并发连接数量有限的问题得到解决
- 作为各类信息管理系统的首选体系架构,基本已经全面取代C/S架构
Servlet开发所涉及的相关知识
- 良好的Java编程语言
- 熟悉XML、Http协议和web站点管理
- 熟悉HTML、CSS、JavaScript
- 一定的数据库理论和开发基础
Servlet程序的编写
- 一个Servlet程序就是实现了javax.servlet.Servlet接口的Java类,Servlet接口定义了Servlet引擎与Servlet程序之间通信的协议约定
- javax.servlet.GenericServlet类实现了Servlet接口,它实现了Servlet程序的特征和功能
- javax.servlet.http.HttpServlet类是GenericServlet的子类,它在GenericServlet类的基础上进行了一些针对HTTP特点的扩充。
- 客户端每次访问一个支持HTTP的Servlet程序时,Servlet引擎都将调用Servlet的service方法来进行处理。service方法接受两个参数,一个是用于封装HTTP请求消息的对象,其类型为HttpServletRequest,另一个是代表Http响应消息的对象,其类型为HttpServletResponse。
- 调用HttpServletResponse对象的getWriter方法可以获得一个文本输出流对象,像这个流对象中写入的数据将作为HTTP响应消息的实体内容部分发送给客户端。
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class HelloWorldExample extends HttpServlet {
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException
{
PrintWriter out = response.getWriter();
out.println("<html>");
out.println("<font size=30 color=red>www.baidu.com</font><br>");
out.println("<marquee>"+new java.util.Date()+"</marquee>");
out.println("</html>");
}
}
Servvlet的注册与运行
Servlet映射的优先级
/abc/* 映射到 Servlet1
/* 映射到 Servlet2
/abc 映射到 Servlet3
*.do 映射到 Servlet4
*.do的优先级最低
在Tomcat上的运行
首先在tomcat的webapps目录下创建一个项目
在test目录下创建WEB-INF
编写web.xml文件
<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0"
metadata-complete="true">
<servlet>
<servlet-name>testServlet</servlet-name>
<servlet-class>HelloWorldExample</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>testServlet</servlet-name>
<url-pattern>/show/*</url-pattern>
</servlet-mapping>
</web-app>
将编译后的Servlet类放进classes文件夹里
在tomcat的bin目录下点击startup.bat启动服务器
在浏览器中输入http://localhost:8080/test/show/xx.html
将会得到Servlet响应的页面
Servlet激活器
Tomcat5.x之后的版本取消了invoker(激活器)
Servlet缺省
- 某个Servlet映射路径仅仅为一个正斜杠(/),这个Servlet成为缺省Servlet
- web.xml文件中找不到匹配的元素的URL,它们的访问都交给缺省Servlet
- 缺省Servlet的注册在<tomcat安装目录>\conf\web.xml文件中
- 访问某个静态HTML文件和图片时,实际是在访问缺省Servlet
类装载器
- Java虚拟机使用每一个类的第一件事就是将该类的字节码装载进来,装载类字节码的功能是由类装载器完成的,类装载器负责根据一个类的名称来定位和生成类的字节码数据后返回给Java虚拟机
- 类装载器本身也是一个Java类,Java虚拟机允许开发人员编写自己的类装载器,以便通过其他各种特殊方式来产生类字节码
- 只要能够在内存中制造出给Java虚拟机调用的类字节码即可,把类加载器描述为类字节码制造器更容易理解
- 当一个类被加载后,Java虚拟机将其编译为可执行代码存储在内存中,并将索引存储在一个HashTable中,其索引关键字为与之相对应的类名
- Java程序本身也是一种事物,它可以用一个Java类描述,这个特殊的类名就叫Class。类装载器装载某个类的字节码的过程实际上就是在创建Class类的一个实例对象,这个Class类的实例对象封装的内容正好是当前加载的类的字节码数据
- 获得某个类的字节码数据的Class对象,采用三种方法:
1、类名.Class
2、对象.getClass()
3、Class.forName(“类名”)
- Java类库提供java.lang.ClassLoader来作为装载类的基类,Java虚拟机和程序都调用ClassLoader类的loadClass方法来加载类,真正类装载器必须是ClassLoeader的子类
- Class类中定义了一个getClassLoader方法,用于返回它所描述的类的类加载器对象,这个返回对象的类型就是ClassLoader
类装载器的基本策略
- 类装载器本身也是一个Java类,所以,类装载器本身也需要被类装载器装载
- Java虚拟机中内嵌了一个Bootstrap的类装载器,它属于Java虚拟机的内核,不用类装载器装载。Bootstrap类装载器加载Java核心包中的类(rt.jar文件中的类),这些类的Class.getClassLoader()返回null,即表示Bootstrap是类装载器
- ExtClassLoader类装载器负责加载<JAVA_HOME>/jre/lib/ext目录下的jar包中的类,AppClassLoader负责加载应用程序的启动执行类
/*
对类装载器的测试
获取打印System类的类加载器 null
获取打印javax.swing.Box类的类加载器 null
获取打印sun.net.spi.nameservice.dns.DNSNameService类的类加载器 sun.misc.Launcher$ExtClassLoader
获取打印ClassLoaderTest类的类加载器 sun.misc.Launcher$AppClassLoader
*/
public class ClassLoaderTest{
public static void main(String[] args){
ClassLoader c=System.class.getClassLoader();
System.out.println(c==null?"null":c.getClass().getName());
c=javax.swing.Box.class.getClassLoader();
System.out.println(c==null?"null":c.getClass().getName());
c=sun.net.spi.nameservice.dns.DNSNameService.class.getClassLoader();
System.out.println(c==null?"null":c.getClass().getName());
c=Test.class.getClassLoader();
System.out.println(c==null?"null":c.getClass().getName());
}
}
类装载器的委托模式
- 一个Java虚拟机中的所有类装载器采用具有父子关系的树形结构进行组织,在实例化每个类装载器时,需要为其指定一个父级类装载器对象,如果没有指定的话,则以ClassLoader.getSystemClassLoader()方法返回的系统类装载器作为父级类装载器对象
- 系统类装载器通常被设置为启动应用程序的AppClassLoader,可以通过java.system.class.loader系统属性来将系统类装载器设置为其它类装载器。ExtClassLoader是AppClassLoader父级类加载器,ExtClassLoader没有父级类加载器,调用ExtClassLoader类的getParent()返回为null
- 每个ClassLoader本身只能分别加载特定位置和目录中的类,但是,ClassLoader被设计成了一种委托模式,使得某一个ClassLoader可以委托它的父级类装载器去加载类,从而让应用程序可以借助某一个子级的ClassLoader去多个位置和目录中进行类的加载
- 当要加载一个类时,ClassLoader的loadclass方法先查找这个类知否已经被加载,如果没有加载,则委托其父级类装载器去加载这个类,如果父级的类加载器无法加载这个类,子级类装载器才调用自己内部的findClass方法去进行真正的加载。委托过程一直追溯到BootStrap类加载器,如果委托过程中的所有类装载器都不能完成类的装载,最终就会报告ClassNotFoundException异常
- 一个类装载器只能创建某个类的一份字节码数据,只能为某个类创建一个与之对应的Class实例对象。在一个Java虚拟机中可以存在多个类加载器,每个类加载器都拥有自己的名称空间,对于同一个类,每个类加载器都可以创建出它的一个Class实例对象
- 采用委托模式避免了一个Java虚拟机中的多个类装载器为同一个类创建多份字节码数据的情况。只要开发人员自定义的类装载器不覆盖ClassLoader的loadClass方法,而是覆盖其findClass方法,这样就可以继续采用委托模式。
线程中的类装载器
- 如果在类A中使用new关键字创建类B,Java虚拟机将使用加载类A的类装载器来加载B,如果在一个类中调用Class.forName方法来动态加载另一个类,可以通过传递给Class.forName方法的一个参数来指定另外那个类的类装载器,如果没有指定该参数,则使用加载当前类的类装载器
- 依据一个类的存放位置,这个类最终只能由一个特定的类加载器装载,对于一个已被父级类装载器装载的类来说,Java虚拟机默认也使用这个父级类装载器去装载它所调用的其他类,由于父级类装载器不会委托子级类装载器去装载类,所以,在一般情况下,一个已被父级类装载器装载的类无法调用那些只能被子级类装载器发现和装载的其它类
- 每个运行的线程都有一个关联的上下文类加载器,可以使用Thread.setContextClassLoader()方法设置线程的上下文类装载器
- 每个线程默认的上下文类装载器是其父级线程的上下文类装载器,而主线程的类装载器初始被设置为ClassLoader.getClassLoader()方法返回的系统类加载器。
- 当线程中运行的代码需要使用某个类时,它使用上下文类加载器来装载这个类,上下文类装载器首先会委托它的父级类装载器来装载这个类,如果父级的类装载器无法装载时,上下文类装载器才自己进行装载
Tomcat中的类装载器
- BootStrap为Java虚拟机内嵌的类装载器与ExtClassLoader的总称,负责加载Java核心包中的类和存放在<JAVA_HOME>/jre/lib/ext目录下的类
- System即系统类装载器,通常情况下就是APPClassLoader,负责加载CLASSPATH环境变量设置目录中的类。Tomcat不会继承操作系统上原来设置好的CLASSPATH环境变量的内容,而是将CLASSPATH环境变量重新设置为仅包含如下两个jar包:
<CATALINA_HOME>/bin/bootstrap.jar
<JAVA_HOME>/lib/tools.jar - Common类装载器负责从的<CATALINA_HOME>/common/classes中的.class类文件和<CATALINA_HOME>/common/lib中的jar包加载类
- Catalina类装载器负责从<CATALINA_HOME>/server/classes中的.class类文件和<CATALINA_HOME>/server/lib中的jar包加载类
- Shared类装载器负责从<CATALINA_HOME>/share/classes中的.class文件和<CATALINA_HOME>/share/lib中的jar包加载类
- WebappX类装载器负责从当前Web应用程序中的/WEB-INF/classes中的.class类文件和/WEB-INF/lib中的jar包加载类
自动编译工具
创建一个compile.bat批处理文件
文件内容:首先set 将sevlet的jar包加入classpath环境
将编译的文件输出到H:\ruanjian\apache-tomcat-7.0.79\webapps\test\WEB-INF\classes中
set CLASSPATH=H:\ruanjian\apache-tomcat-7.0.79\lib\servlet-api.jar;%CLASSPATH%;
javac -d H:\ruanjian\apache-tomcat-7.0.79\webapps\test\WEB-INF\classes %1
pause
最后将要编译的文件拖到compile.bat上完成编译
Servlet 的特点
- Servlet 是一个供其他java程序(Servlet引擎)调用的Java类,他不能独立运行,它的运行完全由Servlet引擎来控制和调度
- Servlet引擎是一种容器程序,他负责管理和维护所有Servlet对象的生命周期。Servlet的加载、执行流程、以及如何接收客户端的数据和如何将数据传送到客户端等具体的底层事务,都是由Servlet引擎来实现的。Servlet引擎负责将客户端的请求信息转交给Servlet和将Servlet生成的响应信息返回给客户端。
- Servlet属于一种插件,它是一个提供了一些约定方法供容器去调用的类,它只负责在自身的方法中接收并处理容器传递进来的数据,以及已生成返回给容器去使用的数据和状态信息。
- Servlet的最常见应用在于读取WEB浏览器传递给web服务器的参数和生成web服务器返回给web浏览器的动态网页文档内容;Servlet也能获取web浏览器发送的HTTP请求消息中的各个请求头和请求行信息,以及生成用于web服务器发送的HTTP响应信息中的状态行和响应头信息;Servlet还能获取web服务器和Servlet引擎自身的一些环境和状态信息。
- Servlet程序的运行过程就是它与Servlet引擎的交互过程,Servlet程序只与Servlet引擎打交道,它并不与web服务器和客户端进行任何直接的交互。
- Servlet本身就是java语言的一个应用,具有Java语言的所有优势,能完成普通Java程序所能完成的所有功能。
- web服务器上可以布置多个功能各不相同的Servlet,每个Servlet都应宣称它可以处理何种样式的URL,当符合样式的URL请求到达时,Servlet引擎调用相应的Servlet进行处理。
Servlet程序查询数据库的工作过程
Servlet 的运行过程
1、Servlet引擎检查是否已经装载并创建了该Servlet的实例对象。如果是,则直接进行第4步,否则,执行第2步
2、装载并创建Servlet的一个实例对象
3、调用Servlet实例对象的init()方法
4、创建一个用于封装HTTP请求消息的HTTPServletRequest对象和一个代表HTTP响应消息的HTTPServletResponse对象,然后调用Servlet的service()方法并将请求和响应对象作为参数传递进去。
5、web应用程序被停止或重新启动之前,Servlet引擎将卸载Servlet,并在卸载之前调用Servlet的destroy()方法。
特殊说明
- 在元素中嵌套一个子元素,web应用程序在启动时就可以装载并创建Servlet的实例对象、以及调用Servlet实例对象的init()方法。
- 在Servlet的整个生命周期内,它的init方法只被调用一次,而对一个Servlet的访问请求都导致Servlet引擎调用一次servlet的service方法。对于每一次访问请求,Servlet引擎都会创建一个新的HttpServletRequest请求对象和一个新的HttpServletResponse响应对象,然后将这两个对象作为参数传递给它调用的Servlet的service()方法。
- Tomcat也提供了是否自动重新装载被修改的Servlet的配置选项。在Tomcat安装目录/conf/server.xml文件中,可以将元素的reloadable属性设置为true,Tomcat将监视该web应用程序的/WEB-INF/classes和/WEB-INF/lib目录下的类是否发生了变化,然后自动重新装载那些发生了改变的类。
<Context path="/test" docBase="d:myweb" debug="0" reloadable="true"/>
获取Tomcat管理员权限
修改H:\ruanjian\apache-tomcat-7.0.79\conf\tomcat-users.xml文件manager角色
输入用户名和密码xml文件中的
浏览器访问Servlet的过程示意图
Servlet、Servlet容器与Servlet API的关系
- 虽然Servlet源程序中引用的Servlet API,但Servlet运行时真正调用的对象是由Servlet容器中的实现类创建的,所以,将Servlet API的jar包增加到CLASSPATH环境变量中,只能保证程序可以编译成功,但不能让Servlet程序离开Servlet容器。
ServletConfig接口
- Servlet 在有些情况下可能需要访问Servlet容器或借助Servlet容器访问外部的资源,所以,Servlet引擎需要将表示Servlet容器的对象传递给Servlet。另外在web.xml文件中为某个Servlet设置的友好名称和初始化参数等信息也需要传递给该Servlet。
- Servlet引擎将代表Servlet容器的对象和Servlet的配置参数信息一并封装到一个称为ServletConfig的对象中,并在初始化Servlet实例对象时传递给该Servlet。ServletConfig接口则定义ServletConfig对象需要对外提供的方法,以便在Servlet程序中可以调用这些方法来获取有关信息。
- Servlet引擎调用Servlet的实例对象init (ServletConfig config)方法将ServletConfig对象传递给Servlet。Servlet.getServletConfig()方法必须返回init(ServletConfig config)方法传递进来的这个ServletConfig对象的引用。
ServletConfig接口的方法
GenericServlet类实现ServletConfig接口的目的
- Servlet接口中定义了一个getServletConfig方法,该方法必须返回Servlet容器调用Servlet.init(ServletConfig config)方法时传递的哪个ServletConfig对象的引用,GenericServlet类已经按此要求实现了getServletConfig方法。
- 在Servlet程序中如何调用ServletConfig对象的方法
String servletName=getServletConfig().getServletName();
- GenericServlet类如何实现ServletConfig接口中的方法
public String getServletName(){
return getServletConfig().getServletName();
}
- 在Servlet程序中调用ServletConfig对象的方法的简单方式
String servletName=getServletName();
ServletConfig对象应用实践
- 第一步、编写Servlet程序
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Enumeration;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
*
*/
/**
* @author zhang rui
* @version
* 创建时间:2019年2月22日 下午11:12:13
*/
public class ConfigTestServlet extends HttpServlet{
/* (non-Javadoc)
* @see javax.servlet.http.HttpServlet#service(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
*/
@Override
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 解决乱码问题
response.setContentType("text/html;charset=GBK");
PrintWriter out=response.getWriter();
out.println("<html>");
out.println("Servlet名称:"+getServletName()+"<br>");
Enumeration<String> e=getInitParameterNames();
out.println("下面是Servlet的初始化参数:");
while(e.hasMoreElements()){
String key=e.nextElement();
String value=getInitParameter(key);
out.println("<br>  "+key+"="+value+"<br>");
}
ServletContext context= getServletContext();
String path=context.getRealPath("/");
out.println("当前Servlet程序的本地目录为:"+path+"<br>");
out.println("</html>");
}
}
- 第二步、将编译好的ConfigTestServlet.class放置在H:\ruanjian\apache-tomcat-7.0.79\webapps\test\WEB-INF\classes文件中
- 第三步、编写web.xml文件,标签内的为初始化参数
- 第四步、启动tamcat,在浏览器中访问http://localhost:8080/test/show/config.html
设置tamcat自动重新加载
- 在H:\ruanjian\apache-tomcat-7.0.79\conf\server.xml中修改将reloadable设置为true