标签:
一个Servlet程序要按照以下的步骤进行开发:
* 创建一个Java类并继承HttpServlet类,重写其中的doGet等方法
* 配置web.xml文件,其配置代码如下:
<!--配置Servlet,tomcat服务器会读取其中的内容-->
<servlet>
<!--Servlet内部名称,可以自定义,但是最好不要乱写,尽量保证有意义-->
<servlet-name>写创建的类的名字</servlet-name>
<!--Servlet类全名,包名+简单类名-->
<servlet-class>写创建的类的全名(包名+简单类名)</servlet-class>
</servlet>
<!--Servlet映射配置-->
<servlet-mapping>
<!--Servlet内部名称,可以自定义,但是最好不要乱写,尽量保证有意义,一定要和上面的servlet-name保持一致-->
<servlet-name>写创建的类的名字</servlet-name>
<!--Servlet映射路径,也称为访问Servlet的名称-->
<url-pattern>访问该servlet程序时的URL(例如/first)</url-pattern>
</servlet-mapping>
Servlet的映射路径有servlet-mapping中的url-pattern(注意url-pattern要么要以/开头,要么要以*开头)决定,那么url-pattern究竟怎么写,怎么去匹配呢?有两种匹配方案:
精确匹配:/first(url-pattern) http://localhost:8080/Servlet工程名/first (浏览器中输入)
精确匹配的要点是:url-pattern以/开始,并且必须将url-pattern中的内容精确的写上。在精确匹配时要注意坚决不能漏掉/,否则会报错,一定要带有/
模糊匹配,下面三种方式,但是在一个url-pattern中不能组合下面的模糊匹配方式
如果在浏览器中输入的url有多个Servlet同时被匹配,也就是说模糊匹配和精确匹配都能找到对应的Servlet资源,精确匹配的优先级高(长得最像的优先被匹配),但是要尽量避免这种情况的发生。当以后缀名结尾的模糊匹配,优先级最低。
对于如下的一些映射关系:
问题:
我的理解:这个过程实际上是确实路由的路径,和Rails技术中的路由技术的原则是一样的。
解析URL的顺序:当输入一个URL时,首先会到web.xml文件中查找是否与偶匹配的url-pattern,如果能匹配到url-pattern,则处理,如果不能匹配到,则交给tomcat的default-servlet处理,也就是会去加载静态资源文件。
结论:先找动态资源,后找静态资源。
Servlet程序由tomcat服务器调用,所以有必要去知道究竟怎么去调用,Servlet生命周期就是要去搞明白Servlet对象什么时候去创建?调用什么方法?什么时候Servlet对象被销毁?销毁调用什么方法做了什么事情?Servlet程序的生命周期是由tomcat服务器去控制的。
构造方法:创建Servlet对象时调用,所谓的创建Servlet对象是指第一次访问Servlet的时候。Servlet在tomcat服务器中是单实例对象。
init:创建完Servlet对象时调用
service:每次发出请求时调用
destroy:销毁Servlet对象时调用。停止服务器或者重新部署web应用时调用销毁Servlet对象。
class clazz = class.forName("com.jpzhutech.servlet.firstServlet"); //根据得到的字节码文件得到字节码对象
Object obj = clazz.newInstance(); //调用firstServlet的无参构造函数
Method m = class.getDeclareMethod("init",ServletConfig.class)//创建一个ServletConfig对象
m.invoke(obj,config); //firstServlet的init方法被调用
Method m = clazz.getDeclareMethod("service",HttpServletRequest.class,HttpServletResponse.class);
m.invoke(obj,request,response); //service方法被调用
Method m = clazz.getDeclareMethod("destroy",null);
m.invoke(obj,null);//调用destroy方法
Servlet对象会在请求第一次加载时建立该类的对象,只要没有服务器的重新启动或者资源的重新加载,都不会再去创建新的Servlet对象,所以我们可以知道Servlet对象是单实例的,但是一个常识就是不止一个人会发出同样的URL请求,此时只有一个Servlet对象,怎么去做呢?实际上Servlet中有多线程处理逻辑,这些代码也是不需要我们去写的。
Servlet是单实例多线程的,所以我们应该把共享数据和代码块进行同步(使用synchronized关键字进行同步)。
建议在Servlet中尽量不要使用成员变量,如果确实要使用成员变量,必须要同步,而且要尽量缩小同步代码块的范围(因为同步会导致效率变得十分的低下),原则上哪里使用到了成员变量就同步哪里,以避免因为同步而导致的并发效率低下。
在Servlet接口以及其实现HttpServlet类中提供给了两个init方法,其函数原型分别如下:
init(ServletConfig config); // 系统调用
init(); //留给开发者使用,在其中写有关初始化的逻辑代码
实际上看查看Servlet的源代码,你会知道有参数的init方法会调用无参数的init方法,但是当我们重写(@Override)了有参数的init方法会导致tomcat服务器不调用无参数的init方法,实际上这个原理可以在Servlet编程中很方便的验证,因此我们的原则是在无参数的init方法中写我们的初始化逻辑。
在Http协议的讲解中已经学完。
在Http协议的讲解中已经学完。
总之,ServletConfig对象的作用就是去拿参数,和Properties配置文件的功能差不多。
<init-param></init-param>
,该参数就是初始化参数。创建时机:在创建完Servlet对象,在调用init方法之前,服务器会自动的创建。
得到对象:直接从有参数的init方法中得到,在代码中使用this.getServletconfig即可实现。一个wen应用中有多个Servletonfig对象,一个Servlet就对应一个ServletConfig对象
ServletContext对象被称为Servlet上下文对象,它表示一个当前的web应用环境,怎么理解呢?一个web应用中有且只有一个ServletContext对象。实际上ServletContext相当于该web应用中的web.xml。
创建时机:加载web应用时创建该对象。并且该对象的创建是早于ServletConfig对象的。
得到对象:从ServletConfig的getServletContext方法得到。
getContextPath() 得到当前web应用的路径,web应用路径说白了就是部署到tomcat服务器上运行的web应用的名称,通常用在请求重定向的资源名称中。
getInitParameter(String name) 得到web应用的初始化参数
<?xml version="1.0" encoding="UTF-8" ?>
<web-app>
在该子标签下,所有的servlet和servlet-mapping子标签之外,添加配置文件,因为该配置文件是全局的,所以随便写一个Servlet程序都能使用该配置。
<context-param>
<param-name>AAA</param-name>
<param-value>AAA‘s value</param-value>
</context-param>
<!--每个context-param参数其中只有一个param-name和param-value-->
<context-param>
<param-name>BBB</param-name>
<param-value>BBB‘s value</param-value>
</context-param>
</web-app>
上述两个方法的使用和ServletConfig中的该类方法使用是一样的。
下面的代码展示在一个Servlet应用中重要的文件,其他的文件请自行生成并使用,主要侧重于功能性测试。
package com.jpzhutech.servletcontext;
import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Servlet implementation class TestServletContext
*/
public class TestServletContext extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public TestServletContext() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
/***
//ServletContext servletContext = this.getServletConfig().getServletContext();
ServletContext servletContext = this.getServletContext();//此函数实际上是调用了上面的函数,看其源代码可以知道
String contextPath = servletContext.getContextPath();
System.out.println(contextPath);
案例: getContextPath()函数通常在重定向时用到,当我们请求动态资源失败时,经常需要将其定位到一个静态资源文件中,本示例定位到index.html
//response.sendRedirect("/servletcontext/index.html"); //当项目名称发生变化时,我们通常不希望去修改我们的源代码,使用getContextPath函数能够实现不修改源代码的效果
response.sendRedirect(contextPath+"/index.html");
*/
/**
* 获取全局ServletContext参数,所有的Servlet程序都能获得
String initParameter = servletContext.getInitParameter("AAA");
System.out.println(initParameter);
//使用迭代器获取初始化参数,这样我们能够获取到全部的Servlet参数
Enumeration<String> initParameterNames = servletContext.getInitParameterNames();
while (initParameterNames.hasMoreElements()) {
String nextElement = initParameterNames.nextElement();
String initParameter2 = servletContext.getInitParameter(nextElement);
System.out.println(initParameter2);
}
*/
/***
* 域对象相关方法,域对象的作用主要是为了保存数据,获取数据,可以在不同的动态资源之间共享数据
* 案例:比如现在有两个Servlet对象,在Servlet1中有name=eric,那么我们怎么将数据共享给Servlet2,
* 在全局配置文件中可以配置参数,这样所有的数据都能被任何的Servlet所共享
* 方案一:可以通过床底参数的形式传递参数,共享数据。局限:只能传递字符串类型
* 方案二:可以通过域对象共享数据,并且可以共享任何类型的数据。那么就在Servlet1中将共享的数据保存在域对象中,
* 然后再Servlet2中在域对象中取出共享的数据,ServletContext是我们接触到的第一个域对象
* 为什么能这么做?原因是在Servlet编程中,ServletContext在一个应用中有且仅有一个,所以不管存在哪里,只要
* 是同一个应用,都能被取到,ServletContext的作用域是整个web应用
* 所有的域对象:HttpServletRequest、ServletContext、HttpSession、PageContext ,这四个都是为了保存数据
* 共享数据,但是它们的作用域是不同的。
ServletContext servletContext = this.getServletContext();
servletContext.setAttribute("name", "eric"); //perfect的方案
System.out.println("保存成功");
Student student = new Student("xiaoming",23);
servletContext.setAttribute("student", student); //保存对象数据
*/
/***
* 转发函数的效果:效果上就是跳转页面,但是与重定向还是有区别的:
* 1. 地址栏:转发的地址栏不会发生变化,但是重定向的地址栏会变化
* 2. 转发只能转发到当前项目中的其它资源,但是重定向可以重定向到任意的资源没有任何的限制
* 3. 转发可以将数据存储到request中,但是如果使用重定向,那么将数据放置在request中是不行的
* 案例:实现从该Servlet跳转到index.html
RequestDispatcher requestDispatcher = this.getServletContext().getRequestDispatcher("/index.html");
//RequestDispatcher requestDispatcher = this.getServletContext().getRequestDispatcher("http://www.google.com"); //不能转发到该项目之外的资源中
requestDispatcher.forward(request, response); //但是该重定向操作,不会改变请求的URL,请求的URL仍然是原来的Servlet,这种重定向比较高端
*/
/***
* 得到指定资源的真实地址getRealPath()
String realPath = this.getServletContext().getRealPath("/index.html");
System.out.println(realPath);
*/
/***
* 将指定的资源作为流输出
InputStream resourceAsStream = this.getServletContext().getResourceAsStream("/index.html"); //该方法的作用是将指定的资源作为流输出
int length = 0 ;
byte[] buf = new byte[1024];
while((length=resourceAsStream.read(buf)) != -1){
String string = new String(buf,0,length);
System.out.println(string);
}
*/
}
}
class Student{
private String name;
int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + "]";
}
}
package com.jpzhutech.servletcontext;
import java.io.IOException;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Servlet implementation class TestServlet
*/
public class TestServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public TestServlet() {
super();
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
ServletContext servletContext = this.getServletContext();
String name = (String)servletContext.getAttribute("name"); //只有不删除,就能一直取到
System.out.println(name);
Student student = (Student)servletContext.getAttribute("student");
System.out.println(student);
}
}
<?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">
<context-param>
<param-name>AAA</param-name>
<param-value>AAA‘s value</param-value>
</context-param>
<context-param>
<param-name>BBB</param-name>
<param-value>BBB‘s value</param-value>
</context-param>
<servlet>
<description></description>
<display-name>TestServletContext</display-name>
<servlet-name>TestServletContext</servlet-name>
<servlet-class>com.jpzhutech.servletcontext.TestServletContext</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>TestServletContext</servlet-name>
<url-pattern>/TestServletContext</url-pattern>
</servlet-mapping>
<servlet>
<description></description>
<display-name>TestServlet</display-name>
<servlet-name>TestServlet</servlet-name>
<servlet-class>com.jpzhutech.servletcontext.TestServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>TestServlet</servlet-name>
<url-pattern>/TestServlet</url-pattern>
</servlet-mapping>
</web-app>
<!DOCTYPE html>
<html>
<head>
<title>index.html</title>
<meta name="keywords" content="keyword1,keyword2,keyword3">
<meta name="description" content="this is my page">
<meta name="content-type" content="text/html; charset=UTF-8">
<!--<link rel="stylesheet" type="text/css" href="./styles.css">-->
</head>
<body>
This is my HTML page. <br>
</body>
</html>
标签:
原文地址:http://blog.csdn.net/jpzhu16/article/details/51626495