Servlet

Servlet   

什么是servlet

  Servlet 是Java Server Applet的简称,称为小服务器程序,用Java编写的服务器端程序,主要功能交互式地浏览和修改数据,生成动态Web内容。
  Servlet运行于支持Java的应用服务器中。从实现上讲,Servlet可以响应任何类型的请求,但绝大多数情况下Servlet只用来扩展基于HTTP协议的Web服务器。

创建servlet常见的错误

  (1)HTTP Status 404 资源找不到
  解决方法:查看Tomcat的webapps目录下找到当前项目在WEB-INF下的classes内能否找到刚刚的class文件
  如果有,重新启动Tomcat
  如果没有,在Eclipse中选择Project–>clean让Eclipse清空缓存并重新构建项目,再次运行
  idea中,把out目录的内容删除,然后重新运行。
  (2)serlvet地址配置重复
  (3)serlvet地址配置错误,比如没有写/ Invalid url-pattern

Servlet核心接口和类

Servlet接口
  在ServletAPI中最重要的是Servlet接口,所有Servlet都会直接或间接的与该接口发生联系,或是直接实现该接口,或间接继承自实现了该接口的类。
该接口包括以下五个方法:
  init(ServletConfig config)
  ServletConfig getServletConfig()
  service(ServletRequest req,ServletResponse res)
  String getServletInfo()
  destroy( )

处理方式:
  (1)第一次访问Servlet时,服务器会创建Servlet对象,并调用init方法,再调用service方法
  (2)第二次再访问时,Servlet对象已经存在,不再创建,执行service方法
  (3)当服务器停止,会释放Servlet,调用destroy方法。

例:

@WebServlet(name = "MyServler4",value = "/myservlet4")
public class MyServlet4 implements Servlet {
    //初始化servlet
    @Override
    public void init(ServletConfig servletConfig) throws ServletException {
        System.out.println("初始化servlet-----------init------"+this.hashCode());
    }

    //获取Servlet配置
    @Override
    public ServletConfig getServletConfig() {
        System.out.println("获取Servlet配置------------getServletConfig----"+this.hashCode());
        return null;
    }

    //服务
    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        System.out.println("服务方法---------------service--------"+this.hashCode());
    }

    //获取servlet基本信息
    @Override
    public String getServletInfo() {
        System.out.println("获取servlet基本信息----------------getServletInfo");
        return null;
    }

    //销毁
    @Override
    public void destroy() {
        System.out.println("------销毁----------destroy---------"+this.hashCode());
    }
}

GenericServlet抽象类
  GenericServlet 使编写 servlet 变得更容易。它提供生命周期方法 init 和 destroy 的简单实现,要编写一般的 servlet,只需重写抽象 service 方法即可

HttpServlet类
  是继承GenericServlet的基础上进一步的扩展。
  提供将要被子类化以创建适用于 Web 站点的 HTTP servlet 的抽象类。HttpServlet 的子类至少必须重写一个方法,该方法通常是以下这些方法之一:
  doGet,如果 servlet 支持 HTTP GET 请求
  doPost,用于 HTTP POST 请求
  doPut,用于 HTTP PUT 请求
  doDelete,用于 HTTP DELETE 请求
  init 和 destroy,用于管理 servlet 的生命周期内保存的资源
  getServletInfo,servlet 使用它提供有关其自身的信息

Servlet的两种创建方式

第一种方式:继承HttpServlet

/**
 * Servlet implementation class HelloServlet
 * 演示Servlet的第一种创建方式,继承HttpServlet.也是开发中推荐的
 * 
 */
@WebServlet("/hs1")
public class HelloServlet 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 {
		
		response.getWriter().print("我是Servlet创建的第一种方式");
	}
	/**
	 * @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);
	}
}

创建的第二种方式:实现接口Servlet

/**
 * Servlet创建的第二种方式:实现接口Servlet
 * */
@WebServlet("/hs2")
public class HelloServlet2 implements Servlet{

	@Override
	public void destroy() {
		// TODO Auto-generated method stub
	}

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

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

	@Override
	public void init(ServletConfig arg0) throws ServletException {
		// TODO Auto-generated method stub	
	}
	@Override
	public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		System.out.println("OK");
		response.setContentType("text/html;charset=UTF-8");
		response.getWriter().println("我是第二种创建方式");
	}
}
Servlet的两种配置方式

第一种注解式配置 Servlet3.0及以后 :

@WebServlet(name = "haha", value = "/myservlet", loadOnStartup = 0, initParams = {@WebInitParam(name = "houhou", value = "666"),@WebInitParam(name = "heihei", value = "888")})
public class MyServlet extends HttpServlet {

    @Override
    public void init() throws ServletException {
        super.init();
        System.out.println("myservlet初始化了");
        ServletConfig servletConfig = getServletConfig();
        String name = servletConfig.getInitParameter("houhou");
        String value = servletConfig.getInitParameter("heihei");
        System.out.println(name + value);
    }

    //get请求
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("....................");
        doPost(req, resp);
        System.out.println("我的MyServlet执行Get请求");
    }

    //post请求
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("我的MyServlet执行Post请求");
    }

}

使用注解方式:
  注解类 WebServlet
  name:serlvet名字 (可选)
  value: 配置url路径
  urlPatterns:配置url路径 ,和value作用一样,不能同时使用
  loadOnStartup:配置Servlet的创建的时机, 如果是0或者正数 启动程序时创建,如果是负数,则访问时创建。数子越小优先级越高。
  initParams:配置Servlet的初始化参数

第二种web.xml配置 Servlet所有版本都支持:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">

    <!--使用xml文件配置servlet-->
    <!--添加servlet节点-->
    <servlet>
        <!--名称-->
        <servlet-name>MyServlet3</servlet-name>
        <!--servlet的全称类名(包名.类名)-->
        <servlet-class>servlet.MyServlet3</servlet-class>


        <!--配置参数-->
        <init-param>
            <param-name>email</param-name>
            <param-value>xxx@qq.com</param-value>
        </init-param>
        <init-param>
            <param-name>address</param-name>
            <param-value>北京</param-value>
        </init-param>


        <!--配置启动时机,数字越小优先级越高-->
        <load-on-startup>1</load-on-startup>
    </servlet>

    <!--
    通过名字取映射地址
    <servlet>
        <servlet-name></servlet-name>
        定义启动的参数个数,可以定义多个
        <init-param>
            <param-name></param-name>
            <param-value></param-value>
        </init-param>
        <init-param>
            <param-name></param-name>
            <param-value></param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name></servlet-name>
        <url-pattern></url-pattern>
    </servlet-mapping>
    -->


    <!--添加servlet-mapping节点(映射设置)【别忘了映射】-->
    <servlet-mapping>
        <!--名称-->
        <servlet-name>MyServlet3</servlet-name>
        <!--资源的匹配规则:精准匹配-->
        <url-pattern>/myservlet3</url-pattern>
    </servlet-mapping>
</web-app>

容器在进行url-pattern配置的时候是遵循一定的匹配原则的
url-pattern定义匹配规则,取值说明:
  精确匹配 /具体的名称 只有url路径是具体的名称的时候才会触发Servlet
  后缀匹配 .xxx 只要是以xxx结尾的就匹配触发Servlet
  通配符匹配 /
匹配所有请求,包含服务器的所有资源
  通配符匹配 / 匹配所有请求,包含服务器的所有资源,不包括.jsp

load-on-startup
  1元素标记容器是否应该在web应用程序启动的时候就加载这个servlet。
  2它的值必须是一个整数,表示servlet被加载的先后顺序。
  3如果该元素的值为负数或者没有设置,则容器会当Servlet被请求时再加载。
  4如果值为正整数或者0时,表示容器在应用启动时就加载并初始化这个servlet,值越小,servlet的优先级越高,就越先被加载。值相同时,容器就会自己选择顺序来加载。

<init-param>
      <param-name>name</param-name>
      <param-value>张三</param-value>
</init-param>

  1 init-param元素用来定义Servlet启动的参数,可以定义多个
  2 param-name表示参数名称
  3 param-value表示参数值

Servlet的生命周期

阶段一、实例化(调用构造方法)
  实例化阶段是Servlet生命周期中的第一步,由Servlet容器调用Servlet的构造器创建一个具体的Servlet对象的过程。而这个创建的时机可以是在容器收到针对这个组件的请求之后,即用了才创建;也可以在容器启动之后立刻创建实例,而不管此时Servlet是否使用的上。使用如下代码可以设置Servlet是否在服务器启动时就执行创建

<load-on-startup>1</load-on-startup> 

阶段二、初始化(init方法)
  Servlet在被加载实例化之后,必须要初始化它。在初始化阶段,init()方法会被调用。这个方法在javax.servlet.Servlet接口中定义。其中,方法以一个ServletConfig类型的对象作为参数。ServletConfig对象由Servlet引擎负责创建,从中可以读取到事先在web.xml文件中通过节点配置的多个name-value名值对。ServletConfig对象还可以让Servlet接受一个ServletContext对象。
一般情况下,init方法不需要编写,因GenericServlet已经提供了init方法的实现,并且提供了getServletConfig方法来获得ServletConfig对象。
注:init方法只被执行一次

阶段三、就绪/服务
  Servlet被初始化以后就处于能够响应请求的就绪状态。每个对Servlet的请求由一个ServletRequest对象代表,Servlet给客户端的响应由一个ServletResponse对象代表。当客户端有一个请求时,容器就会将请求与响应对象转给Servlet,以参数的形式传给service方法。service方法由javax.servlet.Servlet定义,由具体的Servlet实现
HttpServlet将service方法拆分了。doGet和doPost

阶段四、销毁
  Servlet容器在销毁Servlet对象时会调用destroy方法来释放资源。通常情况下Servlet容器停止或者重新启动都会引起销毁Servlet对象的动作,但除此之外,Servlet容器也有自身管理Servlet对象的准则,整个生命周期并不需要人为进行干预

获取请求参数

html页面:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title>欢迎页面</title>
	</head>
	<body>
		<h1>欢迎你</h1>
		<div>
			<form action="HelloServlet", method="post">
				<label>姓名:</label><input name="name"><br/>
				<label>年龄:</label><input  name="age"><br/>
				<input type="submit" value="提交">
			</form>
		</div>
	</body>
</html>

Servlet代码:

/**
 * Servlet implementation class HelloServlet
 * 演示Servlet的获取请求参数
 * 
 */
@WebServlet("/HelloServlet")
public class HelloServlet 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 {
		//获取表单提交的姓名
		String name=request.getParameter("name");
		//获取年龄
		String age=request.getParameter("age");
		//服务端输出打印
		System.out.println(request.getRemoteAddr()+"发来信息:姓名:"+name+"---->年龄:"+age);
	}

	/**
	 * @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);
	}
}
请求方式
GET【默认】

  GET提交的数据会放在URL之后,以?分割URL和传输数据,参数之间以&相连
  GET提交的数据大小有限制(因为浏览器对URL的长度有限制)
  GET方式提交数据,会带来安全问题
  效率高
对应的Servlet的方法时doGet

POST

  POST方法是把提交的数据放在HTTP包的Body中
  POST方法提交的数据没有限制
  POST提交的数据相对安全
  效率相对没有GET高
对应的Servlet的方法时doPost

乱码问题

原因:
  产生乱码,就是因为服务器和客户端沟通的编码不一致造成的,因此解决的办法是:在客户端和服务器之间设置一个统一的编码,之后就按照此编码进行数据的传输和接收

GET乱码

在Tomcat7及以下
  客户端以UTF-8的编码传输数据到服务器端,而服务器端的request对象使用的是ISO8859-1这个字符编码来接收数据,服务器和客户端沟通的编码不一致因此才会产生中文乱码的。解决办法:在接收到数据后,先获取request对象以ISO8859-1字符编码接收到的原始数据的字节数组,然后通过字节数组以指定的编码构建字符串,解决乱码问题。

Tomcat8的版本
  GET基本就不会乱码了,因为服务器对url的编码格式可以进行自动转换

解决

/**
 * Servlet implementation class HelloServlet
 * 演示Servlet的GET请求,中文乱码的问题
 * 
 */
@WebServlet("/GETServlet")
public class GetServlet 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 {
		//获取表单提交的姓名
		String name=request.getParameter("name");
		name=new String(name.getBytes("ISO8859-1"),"UTF-8");
		//获取年龄
		String age=request.getParameter("age");
		//服务端输出打印
		System.out.println(request.getRemoteAddr()+"发来信息:姓名:"+name+"---->年龄:"+age);
	}
	/**
	 * @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);
	}
}
POST乱码

原因:
  由于客户端是以UTF-8字符编码将表单数据传输到服务器端的,因此服务器也需要设置以UTF-8字符编码进行接收,要想完成此操作,服务器可以直接使用从ServletRequest接口继承而来的"setCharacterEncoding(charset)"方法进行统一的编码设置。

/**
 * Servlet implementation class HelloServlet
 * 演示Servlet的GET请求,中文乱码的问题
 * 
 */
@WebServlet("/GETServlet")
public class GetServlet 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 {
		}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		//设置请求参数的编码格式--对GET无效
        request.setCharacterEncoding("UTF-8");
		//获取表单提交的信息
		String name=request.getParameter("msg");
		//服务端输出打印
		System.out.println(request.getRemoteAddr()+"发来信息:"+msg);
	}
}
Servlet中输入中文
页面返回乱码

  浏览器识别不到返回的中文是什么编码格式,就会默认使用GB2312,如果返回的是UTF-8格式的那么在浏览器上就会显示乱码的问题

解决:

response.setContentType("text/html;charset=UTF-8");
Servlet线程安全问题

  因为每次请求都会创建一个线程,如果多人同时请求,那么就会存在多个线程操作同一个Servlet对象,那么如果在对应的方法中操作了成员变量,就有可能产生线程安全的问题。

解决:
  1、synchronized
    将存在线程安全问题的代码放到同步代码块中
  2、实现SingleThreadModel接口
    servlet实现SingleThreadModel接口后,每个线程都会创建servlet实例,这样每个客户端请求就不存在共享资源的问题,但是servlet响应客户端请求的效率太低,所以已经淘汰。
  3、尽可能只使用局部变量

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值