servlet高级编程

Servlet 高级编程

Servlet 是运行在 Web 服务器或应用服务器上的程序,它是作为来自 Web 浏览器或其他 HTTP 客户端的请求和 HTTP 服务器上的数据库或应用程序之间的中间层。

1、Servlet概述

1.1 什么是Servlet?

Servlet是JavaWeb的三(Servlet、Filter、Listener)大组件之一,它属于动态资源。Servlet的作用是处理请求,服务器会把接收到的请求交给Servlet来处理,在Servlet中通常需要:
① 接收请求数据;
② 处理请求;
③ 完成响应。

例如客户端发出登录请求,或者输出注册请求,这些请求都应该由Servlet来完成处理!Servlet需要我们自己来编写,每个Servlet必须实现javax.servlet.Servlet接口。

图示:

servlet高级编程_第1张图片

1.2 实现Servlet有三种方式

① 实现javax.servlet.Servlet接口;
② 继承javax.servlet.GenericServlet类;
③ 继承javax.servlet.http.HttpServlet类;

通常我们会去继承HttpServlet类来完成我们的Servlet,但学习Servlet还要从javax.servlet.Servlet接口开始学习。

问题:有人就要问了,为什么开发Servlet有三种方法?
回答:应为Servlet这个技术不是一开始出现就那么成熟,他经历一个发展的阶段。
Servlet --> GenericServlet --> HttpServlet

1.3 Servlet体系结构的介绍

servlet高级编程_第2张图片

1.4 了解C/S、B/S的区别

① C/S图示:

servlet高级编程_第3张图片

② B/S图示:
servlet高级编程_第4张图片

总结
B/S的优势:

a.开发成本低
b.管理维护简单
c.产品升级便利
d.对用户培训费用低
e.用户使用方便,出现错误的概率低。

B/S的不足:

a.安全性不足
b.客户端不能随心变化,受浏览器的限制

③ 什么是B/S技术
servlet高级编程_第5张图片

④ 1.4B/S技术的工作原理
servlet高级编程_第6张图片

2 、Servlet接口

2.1 编程helloServlet

我们开始第一个Servlet应用吧!首先在webapps目录下创建helloservlet目录,它就是我们的应用目录了,然后在helloservlet目录中创建准备JavaWeb应用所需内容:
① 创建/helloservlet/WEB-INF目录;
② 创建/helloservlet/WEB-INF/classes目录;
③ 创建/helloservlet/WEB-INF/lib目录;
④ 创建/helloservlet/WEB-INF/web.xml文件;

Eclipse创建项目:(实战)
避免出现乱码:

1、整个web项目编码utf-8;
2、创建数据库utf-8;
3、Servlet设置字符编码;
4、Jsp页面设置utf-8;
5、Tomcat配置utf-8;(URIEncoding="UTF-8")

接下来我们开始准备完成Servlet,完成Servlet需要分为两步:
⑤ 编写Servlet类;
⑥ 在web.xml文件中配置Servlet;

案列:01_Servlet1(实现Servlet接口)
用接口Servlet来编写一个Servlet(介绍Servlet的生命周期,该Servlet完成一个简单的功能,想浏览器相应一条信息“hello world”)

	eclipse创建动态项目
	创建Hello类实现implements Servlet

Servlet类文件:

package com.hqyj.servlet.test;

import java.io.IOException;

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

public class Servlet1 implements Servlet {
	// 销毁Servlet实例,释放内存。
	// 什么时候调用三种情况
	// 1、reload 该servlet(webApps)
	// 2、关闭tomcat
	// 3、关闭电脑
	@Override
	public void destroy() {
		System.out.println("----destroy------");
	}
	
	// 得到Servlet配置文件
	@Override
	public ServletConfig getServletConfig() {
		System.out.println("----getServletConfig------");
		return null;
	}
	
	// 得到Servlet信息
	@Override
	public String getServletInfo() {
		System.out.println("----getServletInfo------");
		return null;
	}
	
	// 该函数用于初始化Servlet,类似于类的构造函数。
	// 该 只会被调用一次,当用户第一次访问该Servlet时被调用。
	@Override
	public void init(ServletConfig config) throws ServletException {
		System.out.println("----init-----");
	}
	
	// 用于处于业务逻辑
	// 程序员应该把业务逻辑代码写在这里
	// 当用于每访问该类的时候,都会被调用
	// request 用于获得客户端的信息(浏览器)
	// response 用于向客户端返回(服务器)
	@Override
	public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {
		System.out.println("----service------");
	}
}

配置Web.xml文件



	
	Servlet1
	
	com.hqyj.servlet.test.Servlet1


	
	Servlet1
	
	/servlet1

总结
Servlet中的方法大多数不是由我没来调用,而是由Tomcat来调用,并且Servlet对象也不是由我们来创建的,而是由Tomcat来创建,并由服务器来调用相应的方法。
 单列,一个类只有一个对象;一个应用中当然可以存在多个Servlet类。
 线程不安全,但它的效率是最高的。

2.2 Servlet的生命周期

Servlet部署在容器里(应用服务器Tomcat,其他应用服务器,比如jboss,weblogic…),它的生命周期由容器来管理。
Servlet的生命周期分为以下几个阶段:(重点)

1.装载Servlet,由相应的容器来完成
2.创建一个Servlet实例
3.调用Servlet的init()方法,该方法只会在第一次访问Servlet时被调用一次
4.服务:调用Servlet的service()方法,一般业务逻辑在这里处理,该方法在访问该Servlet时,会被调用
5.销毁:调用Servlet的destroy()方法,销毁该Servlet实例,该方法在以下情况被调用:
    a.tomcat重新启动
    b.reload该webapps
    c.重新启动电脑

图1:

servlet高级编程_第7张图片

图2:

servlet高级编程_第8张图片

2.3 Servlet接口相关的类型

① ServletConfig
ServletConfig对象对应web.xml文件中的元素。例如你想获取当前Servlet在web.xml文件中的配置名,那么可以使用servletConfig.getServletName()方法获取!
图示:
servlet高级编程_第9张图片

ServletConfig对象是由服务器创建的,然后传递给Servlet的init()方法,你可以在init()方法中使用它!
 String getServletName():获取Servlet在web.xml文件中的配置名称,即指定的名称;
 ServletContext getServletContext():用来获取ServletContext对象,ServletContext会在后面讲解;
 String getInitParameter(String name):用来获取在web.xml中配置的初始化参数,通过参数名来获取参数值;
 Enumeration getInitParameterNames():用来获取在web.xml中配置的所有初始化参数名称;

案列:02_Servlet2
用接口Servlet来编写一个Servlet(介绍Servlet的生命周期,该Servlet完成一个简单的功能,想浏览器相应一条信息“hello world”)
 eclipse创建动态项目
 创建Hello类实现implements Servlet

Servlet类文件:

// 该函数用于初始化Servlet,类似于类的构造函数。
// 该 只会被调用一次,当用户第一次访问该Servlet时被调用。
@Override
public void init(ServletConfig config) throws ServletException {
	System.out.println("----init-----");

	// 获取初始化参数
	System.out.println(config.getInitParameter("m1"));
	System.out.println(config.getInitParameter("m2"));

	// 获取所有初始化参数名称
	Enumeration e = config.getInitParameterNames();
	while (e.hasMoreElements()) {
		System.out.println(e.nextElement());
	}
}

配置Web.xml文件



	Servlet1
	com.hqyj.servlet.test.Servlet2
	
		m1
		v1
	
	
		m2
		v2
	


	Servlet1
	/servlet1

3 、继承GenericServlet

3.1 编程GenericServlet

案列:03_Servlet3通过继承GenericServlet开发servlet)
通过GenericServlet去开发servlet,只需要重写service方法,相对来说要简单一些。
Servlet类文件:

package com.hqyj.servlet.test;

import java.io.IOException;

import javax.servlet.GenericServlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

public class Servlet3 extends GenericServlet {
	@Override
	public void init() throws ServletException {
		System.out.println("------初始化------");
	}

	@Override
	public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {
		System.out.println("------service-------");
	}

	@Override
	public void destroy() {
		System.out.println("------destroy------");
	}
}

配置Web.xml文件



	Servlet1
	com.hqyj.servlet.test.Servlet3


	Servlet1
	/servlet3

4 、继承HttpServlet

4.1 编程HttpServlet

图1:
servlet高级编程_第10张图片

图2:
servlet高级编程_第11张图片

案列:04_Servlet4(通过继承HttpServlet)
通过HttpServlet去开发servlet,需要重写doGet、doPost方法,这是目前用的最多的一种方法。
表单提交数据get请求和post请求的区别:

1.从安全性看getpost。get请求服务器立即处理请求,而post请求可能形成一个队列请求

 eclipse创建动态项目
 创建Hello类实现implements Servlet

Servlet类文件:

package com.hqyj.servlet.test;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class Servlet4 extends HttpServlet {

	@Override
	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		System.out.println("-------doGet--------");
	}

	@Override
	protected void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		System.out.println("-------doPost--------");
	}

}

配置Web.xml文件



	Servlet4
	com.hqyj.servlet.test.Servlet4


	Servlet4
	/servlet4

优化:

package com.hqyj.servlet.test;

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;

public class Servlet4 extends HttpServlet {

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		System.out.println("-------doGet--------");
		// 业务逻辑
		PrintWriter printWriter = resp.getWriter();
		printWriter.println("hello world! HelloHttpServer");
	}

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		System.out.println("-------doPost--------");
		this.doGet(req, resp);
	}

}

4.2 一个简单的用户登录系统

案列:05_UserSystem(通过HttpServlet去开发Servlet)
现在我们已经初步了解了Servlet的基本原理和机制做一个:用户登录网站
功能:

1.进行简单的用户验证
2.如何使用Servlet开发动态网页
3.如何从一个页面跳转到另一个页面上

图:
servlet高级编程_第12张图片

login.jsp文件:

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>




Insert title here


	

首页


用户名:
密码:

Servlet类文件:

package com.hqyj.servlet.test;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class Servlet4 extends HttpServlet {
	@Override
	public void init() throws ServletException {
		System.out.println("---init()---");
	}

	@Override
	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		// 1、接收数据
		String userName = request.getParameter("userName");
		String password = request.getParameter("password");
		System.out.println("---------" + userName);
		System.out.println("=========" + password);
		if (userName.equals("admin")) {
			// 正确
			// 3、跳转页面
			response.sendRedirect("view/mian.jsp");
		} else {
			// 错误
			// 3、跳转页面
			response.sendRedirect("login.jsp");
		}
		// 2、调用业务
		// ?
	}

	@Override
	protected void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		System.out.println("--------doPost-----------");
		this.doGet(request, response);
	}

}

Web.xml文件:



	04_j1809_servlet

	
	
		servlet4
		com.hqyj.servlet.test.Servlet4
		0
	
	
		servlet4
		/servlet4
		/ssss4
	


	
		login.jsp
	

5 、Servlet细节

5.1 Servlet与线程安全

因为一个类型的Servlet只有一个实例对象,那么就有可能会现时出一个Servlet同时处理多个请求,那么Servlet是否为线程安全的呢?
答案是:“不是线程安全的”。这说明Servlet的工作效率很高,但也存在线程安全问题!
所以我们不应该在Servlet中创建成员变量,因为可能会存在一个线程对这个成员变量进行写操作,另一个线程对这个成员变量进行读操作。

public class Servlet4 extends HttpServlet {
	// 成员变量
	private String name = "zhangsan";

	@Override
	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		// 成员变量
		private String name = "zhangsan";
		// 1、接收数据
		String userName = request.getParameter("userName");
		String password = request.getParameter("password");

5.2 让服务器在启动时就创建Servlet

默认情况下,服务器会在某个Servlet第一次收到请求时创建它。也可以在web.xml中对Servlet进行配置,使服务器启动时就创建Servlet。
图:



	servlet4
	com.hqyj.servlet.test.Servlet4
	0


	servlet4
	/servlet4

在元素中配置元素可以让服务器在启动时就创建该Servlet,其中元素的值必须是大于等于的整数,它的使用是服务器启动时创建Servlet的顺序。上例中,根据的值可以得知服务器创建Servlet的顺序为Hello1Servlet、Hello2Servlet、Hello3Servlet。

Servlet类文件:

package com.hqyj.servlet.test;

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;

public class Servlet4 extends HttpServlet {
	@Override
	public void init() throws ServletException {
		System.out.println("---init()---");
	}

	@Override
	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		// 1、接收数据
		String userName = request.getParameter("userName");
		String password = request.getParameter("password");
		System.out.println("---------" + userName);
		System.out.println("=========" + password);
		if (userName.equals("admin")) {
			// 正确
			// 3、跳转页面
			response.sendRedirect("view/mian.jsp");
		} else {
			// 错误
			// 3、跳转页面
			response.sendRedirect("login.jsp");
		}
		// 2、调用业务
		// ?
	}

	@Override
	protected void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		System.out.println("--------doPost-----------");
		this.doGet(request, response);
	}

}

结果:控制台打印

十月 29, 2018 10:33:05 下午 org.apache.catalina.loader.WebappClassLoader validateJarFile
信息: validateJarFile(D:\Java_XG\Environment\TOMCAT8.0\wtpwebapps\04_j1809_servlet\WEB-INF\lib\servlet-api.jar) - jar not loaded. See Servlet Spec 2.3, section 9.7.2. Offending class: javax/servlet/Servlet.class
十月 29, 2018 10:33:06 下午 org.apache.catalina.util.SessionIdGenerator createSecureRandom
信息: Creation of SecureRandom instance for session ID generation using [SHA1PRNG] took [410] milliseconds.
---init()---
十月 29, 2018 10:33:06 下午 org.apache.catalina.startup.HostConfig deployDirectory
信息: Deploying web application directory D:\Java_XG\Environment\TOMCAT8.0\webapps\docs
十月 29, 2018 10:33:06 下午 org.apache.catalina.startup.HostConfig deployDirectory
信息: Deploying web application directory D:\Java_XG\Environment\TOMCAT8.0\webapps\manager
十月 29, 2018 10:33:06 下午 org.apache.catalina.startup.HostConfig deployDirectory
信息: Deploying web application directory D:\Java_XG\Environment\TOMCAT8.0\webapps\ROOT
十月 29, 2018 10:33:07 下午 org.apache.coyote.AbstractProtocol start
信息: Starting ProtocolHandler ["http-nio-8080"]
十月 29, 2018 10:33:07 下午 org.apache.coyote.AbstractProtocol start
信息: Starting ProtocolHandler ["ajp-nio-8009"]
十月 29, 2018 10:33:07 下午 org.apache.catalina.startup.Catalina start
信息: Server startup in 2025 ms

5.3

是的子元素,用来指定Servlet的访问路径,即URL。它必须是以“/”开头!

  1. 可以在中给出多个,
    例如:


	Servlet4
	com.hqyj.servlet.test.Servlet4


	Servlet4
	/servlet4
	/ssss

那么这说明一个Servlet绑定了两个URL,无论访问/servlet4还是/ssss,访问的都是servlet4。

2)还可以在中使用通配符,所谓通配符就是星号“”,星号可以匹配任何URL前缀或后缀,使用通配符可以命名一个Servlet绑定一组URL,例如:
 /servlet/
:/servlet/a、/servlet/b,都匹配/servlet/;(路径匹配)
.do:/abc/def/ghi.do、/a.do,都匹配*.do;(后缀名匹配)
 /*:匹配所有URL;(什么都匹配)

请注意,通配符要么为前缀,要么为后缀,不能出现在URL中间位置,也不能只有通配符。例如:/.do就是错误的,因为星号出现在URL的中间位置上了。.*也是不对的,因为一个URL中最多只能出现一个通配符。

注意,通配符是一种模糊匹配URL的方式,如果存在更具体的,那么访问路径会去匹配具体的。例如:



	Servlet4
	com.hqyj.servlet.test.Servlet4


	Servlet4
	/servlet4/mm



	Servlet5
	com.hqyj.servlet.test.Servlet5


	Servlet5
	/servlet4/*


	login.jsp

当访问路径为http://localhost:8080/hello/servlet/hello1时,因为访问路径即匹配hello1的,又匹配hello2的,但因为hello1的中没有通配符,所以优先匹配,即设置hello1。

6 、ServletContext(重要)

6.1 ServletContext概述

服务器会为每个应用创建一个ServletContext对象:
 ServletContext对象的创建是在服务器启动时完成的;
 ServletContext对象的销毁是在服务器关闭时完成的。

ServletContext对象的作用是在整个Web应用的动态资源之间共享数据!例如在AServlet中向ServletContext对象中保存一个值,然后在BServlet中就可以获取这个值,这就是共享数据了。

6.2 获取ServletContext

在Servlet中获取ServletContext对象:
 在void init(ServletConfig config)中:ServletContext context = config.getServletContext();
ServletConfig类的getServletContext()方法可以用来获取ServletContext对象;
在GenericeServlet或HttpServlet中获取ServletContext对象:
 GenericServlet类有getServletContext()方法,所以可以直接使用this.getServletContext()来获取;

public class MyServlet implements Servlet {
public void init(ServletConfig config) {
    ServletContext context = config.getServletContext();
}
…
}

public class MyServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response) {
    ServletContext context = this.getServletContext();
}
}

6.3 域对象的功能

ServletContext是JavaWeb四大域对象之一:
 PageContext;
 ServletRequest;
 HttpSession;
 ServletContext;

(注:作用域从小到大为:PageContext(jsp页面),ServletRequest(一次请求),HttpSession(一次会话),ServletContext(整个web应用))
所有域对象都有存取数据的功能,因为域对象内部有一个Map,用来存储数据,下面是ServletContext对象用来操作数据的方法:

 1)void setAttribute(String name, Object value):用来存储一个对象,也可以称之为存储一个域属性,例如:servletContext.setAttribute(“xxx”, “xxx”),在ServletContext中保存了一个域属性,域属性名称为xxx,域属性的值为XXX。请注意,如果多次调用该方法,并且使用相同的name,那么会覆盖上一次的值,这一特性与Map相同;
 2)Object getAttribute(String name):用来获取ServletContext中的数据,当前在获取之前需要先去存储才行,例如:String value = (String)servletContext.getAttribute(“xxx”);,获取名为xxx的域属性; 
 3)void removeAttribute(String name):用来移除ServletContext中的域属性,如果参数name指定的域属性不存在,那么本方法什么都不做;
 4)Enumeration getAttributeNames():获取所有域属性的名称;

案例:
AServlet 类文件:

package com.hqyj.servlet.test;

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;

public class AServlet extends HttpServlet {

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		// 1、获取ServletContext对象
		// 2、调用其setAttribute()方法完成保存数据
		ServletContext application = this.getServletContext();
		application.setAttribute("name", "翠花");
	}

}

BServlet 类文件:

package com.hqyj.servlet.test;

import java.io.IOException;
import java.io.PrintWriter;

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 BServlet extends HttpServlet {

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		// 1、获取ServletContext对象
		// 2、调用其getAttribute()方法完成获取数据
		ServletContext application = this.getServletContext();
		String name = (String) application.getAttribute("name");
		System.out.println("------------" + name);
	}

}

Web.xml文件



	aServlet
	com.hqyj.servlet.test.AServlet


	aServlet
	/aServlet



	bServlet
	com.hqyj.servlet.test.BServlet


	bServlet
	/bServlet

6.4 访问量统计

相信各位一定见过很多访问量统计的网站,即“本页面被访问过XXX次”。因为无论是哪个用户访问指定页面,都会累计访问量,所以这个访问量统计应该是整个项目共享的!很明显,这需要使用ServletContext来保存访问量。
AServlet 类文件:

package com.hqyj.servlet.test;

import java.io.IOException;
import java.io.PrintWriter;

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 AServlet extends HttpServlet {

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		// 1、获取ServletContext对象
		// 2、从ServletContext对象中获取名为count的属性
		// 3、如果存在,访问量+1,然后再保存回去
		// 4、如果不存在,表明第一次访问,向ServletContext中保存名为count的属性,值为1
		ServletContext application = this.getServletContext();
		Integer count = (Integer) application.getAttribute("count");
		if (count == null) {
			application.setAttribute("count", 1);
		} else {
			application.setAttribute("count", count + 1);
		}
		// 向浏览器输出
		PrintWriter printWriter = resp.getWriter();
		printWriter.print(count);
	}

}

你可能感兴趣的:(前端,服务器相关)