j2ee中的Servlet类

今天主要来说一下servlet
servlet其实就是一个java类,是用来处理客户端请求的类,servlet被装载在servlet容器中,servlet容器一般寄存在服务器端。
1.我们如何创建一个servlet类呢?
1)创建servlet类就是创建一个实现Servlet接口的类

2.servlet的生命周期:servlet类实例在第一次被请求时被创建,在服务器关闭时被销毁。其实就是所谓的单例。

servlet实例是个单例。那么既然是单例那么就会出现一个问题,那么就是线程不安全的。比如说:

package com.yd.servlet;

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

import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

import org.omg.CORBA.SystemException;

//创建一个servlet类
public class HelloWord implements Servlet {
	private int ticket=4;
	public HelloWord() {
		System.out.println("constructor");
	}
	@Override
	public void destroy() {
		System.out.println("我是servlet类被destroy的方法");
	}

	@Override
	public ServletConfig getServletConfig() {
		return null;
	}
	@Override
	public String getServletInfo() {
			return null;
	}
	@Override
	public void init(ServletConfig servletConfig) throws ServletException {
	}
	@Override
	public void service(ServletRequest arg0, ServletResponse arg1) throws ServletException, IOException {
               if(ticket>0){
			System.out.println("你买到"+ticket+"张票了");
			try {
				Thread.sleep(10*1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			ticket--;
		}else{
			System.out.println("对不起没有票了");
		}
				System.out.println("客户端请求servlet类时调用的service方法");
	}
}
如上的代码,如果同一时间我有多个客户端请求我的HelloWord这个Servlet类时我的全局变量ticket不能正确的被访问。
那么这里我总结了两点避免出现以上的线程不安全问题

①如果一个变量需要被所有的客户端访问,那么在访问该变量的时候加上同步机制即可

synchronized(对象){

  //在此访问共享变量

}

实现如下即可,至于synchronized可以参考我的另一个博客:http://blog.csdn.net/nihaowoshiyudong/article/details/53389543

synchronized (this) {
		   if(ticket>0){
				System.out.println("你买到"+ticket+"张票了");
				try {
					Thread.sleep(10*1000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				ticket--;
			}else{
				System.out.println("对不起没有票了");
			}
		}

②如果变量不需要被所有的客户端访问,那么只要在方法中声明即可。

3.servlet类中包含四大方法
1)constructor构造器,在客户端第一次请求servlet类时servlet容器创建servlet类是调用,并且只有在第一次调用时被创建
接下来再次请求该servlet类时,servlet容器会先看一下有没有该servlet类的实例,如果有直接拿过来使用,如果没有就创建
总的来说servlet实例是一个单例。
2)init方法和constructor一样只有在第一次请求servlet类时被调用
3)service方法是每次请求都会执行的方法,她带有两个参数一个是HttpServletRequest(请求对象),
一个是HttpServletResponse(响应对象)。

4)最后一个就是destroy方法了,只有在服务器关闭时,实例才会调用该方法,销毁自己。用于释放当前servlet所占用的资源

package com.yd.servlet;

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

import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

import org.omg.CORBA.SystemException;

//创建一个servlet类
public class HelloWord implements Servlet {
	public HelloWord() {
		System.out.println("constructor");
	}
	@Override
	public void destroy() {
		System.out.println("我是servlet类被destroy的方法");
	}

	@Override
	public ServletConfig getServletConfig() {
		System.out.println("getServletConfig()");
		return null;
	}

	@Override
	public String getServletInfo() {
		System.out.println("getServletInfo()");
		return null;
	}

	@Override
	public void init(ServletConfig servletConfig) throws ServletException {
		System.out.println("init");
		//获得servletconfig中的servlet类的初始化参数
		//获得当servlet类的注册名
		/*String instance=servletConfig.getServletName();
		System.out.println("我是servlet类的注册名:"+instance);
		//获得servlet类的初始化参数名
		Enumeration<String> initnames= servletConfig.getInitParameterNames();
		while(initnames.hasMoreElements()){
			//获得初始化的参数名
			String name=initnames.nextElement();
			//通过参数名获得参数值
			String value=servletConfig.getInitParameter(name);
			System.out.println("name:"+name+"\tvalue:"+value);
		}*/
		//获得servletContext
		ServletContext servletContext=servletConfig.getServletContext();
		//通过servletcontext获得web应用的初始化参数  
		Enumeration<String> names=servletContext.getInitParameterNames();
		while(names.hasMoreElements()){
			String name=names.nextElement();
			String value=servletContext.getInitParameter(name);
			System.out.println("name:"+name+"\tvalue:"+value);
		}
		//获得文件在服务器中的位置
		String path=servletContext.getRealPath("/business/a.txt");
		System.out.println(path); 
		//结果如下:C:\Users\WenQu\workspace\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps\J2EE_Test01\business\a.txt
		//以流的形式获得当前web工程下文件
		InputStream is=servletContext.getResourceAsStream("/business/a.txt");
		byte[] bs=new byte[1024];
		int n=0;
		try {
			while((n=is.read(bs))!=-1){
				String str=new String(bs, 0, n, "utf-8");
				System.out.println(str);
			}
		} catch (IOException e) {
			e.printStackTrace();
		}finally {
			try {
				is.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		System.out.println(is);
	}

	@Override
	public void service(ServletRequest arg0, ServletResponse arg1) throws ServletException, IOException {
		System.out.println("客户端请求servlet类时调用的service方法");
	}

}
3.创建好servlet需要在服务器端配置该servlet类,这样客户端请求该servlet类时才能快速准确到找到处理请求的servlet类。
配置servlet类有两种方法

1)通过配置文件web.xml来配置servlet

<servlet>  //这是配置一个servlet
    <servlet-name>response</servlet-name>   //servlet的名字
    <servlet-class>com.yc.servlet.TestServlet</servlet-class>  //servlet的处理类
    <init-param> 
      <param-name>unicode</param-name>   //servlet的初始化参数名
      <param-value>utf-8</param-value>  //与servlet初始化参数名对应的参数值
    </init-param>
	<!--配置servlet被创建的时机 -->
	<load-on-startup>数值<load-on-startup>  //如果数值为负数那么当前servlet将在第一次被请求时创建  
	//如果是0或整数则会在当前应用被servlet容器加载时创建当前servlet类  且数值越小越先被创建
</servlet>
<servlet-mapping>   //配置servlet的映射关系的
   <servlet-name>response</servlet-name>  //上面配置的servlet名字
   <url-pattern>/yd</url-pattern>   //请求地址
</servlet-mapping>
上面的配置文件的意义:当请求地址为项目名称/yd时,服务器就找到配置的servlet-mapping中的url-pattern中
与之对应的地址,然后根据servlet-name找到servlet-class中的处理类来处理客户端的请求。
2).第二种配置servlet的方法很简单就是我们的注解方式配置servlet。
语法为:@WebServlet("请求地址"),意思同上当客户端地址栏的地址为请求地址时,
则服务器就会把该请求交给对应的servlet处理类来处理。
4.关于servlet-mapping
1)同一个servlet类可以被映射到多个url上,也就是多个servlet-mapping下的servlet-name可以是同一个servlet类的注册名
2)servlet-mapping下的url-pattern中可以使用*通配符,通配符的使用可以是网站开发的拓展性更好,但是只有两种格式:

一种格式是*.拓展名   另一种是以/开头..../*结尾

关于浏览器端发送的url请求,web服务器在把url映射到servlet处理类时有通配符时是按照一定原则来匹配的。

 ①精确路径匹配。例子:比如servletAurl-pattern/testservletBurl-pattern/* ,这个时候,如果我访问的urlhttp://localhost/test,这个时候容器就会先进行精确路径匹配,发现/test正好被servletA精确匹配,那么就去调用servletA,也不会去理会其他的servlet了。

②最长路径匹配。例子:servletAurl-pattern/test/*,而servletBurl-pattern/test/a/*,此时访问http://localhost/test/a时,容器会选择路径最长的servlet来匹配,也就是这里的servletB这也是精确匹配的一种。

*.拓展名的匹配度最低。 

5.关于配置Servlet类时有时加上<load-up-startup>那么这个节点是用来设置什么的呢?

<servlet>  //这是配置一个servlet
    <servlet-name>response</servlet-name>   //servlet的名字
    <servlet-class>com.yc.servlet.TestServlet</servlet-class>  //servlet的处理类
    <init-param> 
      <param-name>unicode</param-name>   //servlet的初始化参数名
      <param-value>utf-8</param-value>  //与servlet初始化参数名对应的参数值
    </init-param>
	<!--配置servlet被创建的时机 -->
	<load-on-startup>数值<load-on-startup>  //如果数值为负数那么当前servlet将在第一次被请求时创建  
	//如果是0或整数则会在当前应用被servlet容器加载时创建当前servlet类  且数值越小越先被创建
</servlet>
其中的数值指的的其在web服务器启动时被web服务器创建的顺序。服务器启动时就会创建servlet类的实例并且调用其init方法。其最重要的用途就是为整个web项目做初始化准备,例如为站点准备数据或者启动线程等。

6.关于inti方法中参数ServletConfig是包装servlet类的配置信息的,并且可以获得ServletContext
1)如何配置servlet的信息呢?
  <servlet>
  	<servlet-name>hello</servlet-name>
  	<servlet-class>com.yd.servlet.HelloWord</servlet-class>
  	<init-param>
  		<param-name>user</param-name>
  		<param-value>master</param-value>
  	</init-param>
  	<init-param>
  		<param-name>password</param-name>
  		<param-value>a</param-value>
  	</init-param>
  </servlet>
  如下在servlet节点中添加init-param节点并且设置param-name和param-value的值即可。一个servlet类可以设置多个init-param参数节点
2)那么如何来获得在web.xml中给servlet类配置的init-param呢?
就是通过我们的ServletConfig来获得,具体实现如下代码:
public void init(ServletConfig servletConfig) throws ServletException {
		System.out.println("init");
		//获得servletconfig中的servlet类的初始化参数
		//获得当servlet类的注册名
		String instance=servletConfig.getServletName();
		System.out.println("我是servlet类的注册名:"+instance);
		//获得servlet类的初始化参数名
		Enumeration<String> initnames= servletConfig.getInitParameterNames();
		while(initnames.hasMoreElements()){
			//获得初始化的参数名
			String name=initnames.nextElement();
			//通过参数名获得参数值
			String value=servletConfig.getInitParameter(name);
			System.out.println("name:"+name+"\tvalue:"+value);
		}
}
7.通过servletConfig可以获得ServletContext对象,那么servletContext是什么呢?
API中是这样解释的:Defines a set of methods that a servlet uses to communicate with its servlet container
也就是定义一个方法的集合用来和他的servlet容器交流的一个servlet特殊类。通俗的说ServeltContext对象就是用来管理当前的web项目的,负责当前的web工程和servlet容器做交流的特殊的servlet类。从servletcontext可以获得当前web项目下的一些资源的信息,可以被当前web项目下的所有servlet类访问
1)那么如何给ServletContext设置参数呢?
在web工程下的web.xml中配置如下:
<context-param> //通过context-param设置的参数可以被所有的servlet类使用
    <param-name>参数名</param-name>
    <param-value>参数值</param-value>
<context-param>
2)其重要的方法有一下几个:
getInitParameter(java.lang.String name):通过参数名获得servletcontext的初始化参数
getInitParameterNames():获得初始化所有参数的名字
getRealPath(java.lang.String path) :获得一个文件在服务器中的位置
getResourceAsStream(java.lang.String path):获得一个资源以流的形式
还有一些获得上下文属性的一些方法也很重要。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值