Java Servlet是和平台无关的服务器端组件,功能是实现对客户端请求的响应。
Servlet组件运行在Servlet容器中,我们通常说的Servlet容器一般就指Tomcat服务器。
Servlet容器负责Servlet和客户的通信,以及调用Servlet的方法,Servlet和客户采用“请求/响应”的模式。
客户<---(请求/响应)--->Servlet容器<----(ServletRequest/ServletResponse)---->Servlet组件
Servlet可完成如下功能:
1.创建并返回基于客户请求的动态HTML页面
2.创建可嵌入到现有HTML页面中的部分HTML页面(Html片断)
3.与其他服务器资源进行通信,如数据库,基于Java的应用程序
Servlet其实就是一组Java程序,最顶层是接口Interface Servlet,Servlet组件实现该接口定义的方法,javax.servlet.Servlet接口
在Eclipse中创建一个Dynamic Web Project,并且配置Tomcat服务器,选择next,最后可勾选web.xml的自动生成。
在src下创建package,并且创建HelloWorld类,实现Servlet接口,并且实现Servlet接口定义的方法,无参构造函数
public class HelloWorld implements Servlet{ @Override public void destroy() { System.out.println("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 arg0) throws ServletException { System.out.println("init"); } @Override public void service(ServletRequest arg0, ServletResponse arg1) throws ServletException, IOException { System.out.println("service"); } public HelloWorld() { System.out.println("HelloWorld constructor ..."); } }配置web.xml文件,在WebContent/WEB-INF下,配置HelloWorld类的Servlet和映射
<?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_3_0.xsd" id="WebApp_ID" version="3.0"> <display-name>ServletTest2</display-name> <servlet> <servlet-name>HelloWorld</servlet-name> <servlet-class>com.cqupt.java.servlet.HelloWorld</servlet-class> </servlet> <servlet-mapping> <servlet-name>HelloWorld</servlet-name> <url-pattern>/hello</url-pattern> </servlet-mapping> </web-app>
配置两个元素:servlet和servlet-mapping
url-pattern元素中的/hello,其中"/"代表web应用的根目录,也就是http://localhost:8080/项目名/
右键项目,运行在服务器上,在Eclipse或系统的浏览器上,输入网址http://localhost:8080/项目名/配置的url-pattern
在这里是http://localhost:8080/ServletTest/hello,Eclipes显示的结果为:
HelloWorld constructor ...
init
service
无限制刷新网页时,每次只显示service
关闭服务器,显示destroy
这说明了Servlet的生命周期。
web.xml文件中servlet的配置和映射,如果只配置servlet,不配置映射servlet-mapping,并且设置为Tomcat启动时加载,会显示:
<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_3_0.xsd" id="WebApp_ID" version="3.0"> <display-name>ServletTest2</display-name> <servlet> <servlet-name>HelloWorld</servlet-name> <servlet-class>com.cqupt.java.servlet.HelloWorld</servlet-class> <load-on-startup>1</load-on-startup> </servlet> </web-app>
HelloWorld constructor ...
init
但不会显示service
注意:Servlet程序必须存储在"web应用程序目录\WEB-INF\classes\"目录中
使用Servlet时,我们不需要手动new类的实例,也不用手动调用方法,这一切都是Servlet容器帮我们完成的操作。
Servlet容器:运行Servlet、Jsp、Filter等的软件环境,可以来创建Servlet,并调用Servlet的相关生命周期方法。
由上节的HelloWorld可以看出,Servlet的生命周期:
1.构造方法:只被调用一次,只有在第一次请求Servlet时,才创建对应的Servlet实例,调用构造器。说明Servlet是单实例的!(单实例,就会存在线程安全问题,不推荐使用全局变量)
2.init方法:只被调用一次,在创建好实例后,立即被调用,用于初始化当前Servlet,init方法的形参有特殊的作用(ServletConfig类型的形参)。
3.service方法:被多次调用,每次请求都会调用service方法,实际用于响应请求的方法。
4.destroy方法:只被调用一次,在当前servlet所在的web应用被卸载前调用,用于当前Servlet所占用的资源。
这些方法都是Servlet容器负责调用。
在servlet元素配置中,加入load-on-startup的配置标签,是为了,不需要请求,在Tomcat服务器启动时就加载该Servlet。
数值为负数,在请求时加载;数值为0和整数,在服务器启动时加载,并init初始化,并且,数值越小,越早被加载创建
<servlet> <servlet-name>HelloWorld</servlet-name> <servlet-class>com.cqupt.java.servlet.HelloWorld</servlet-class> <load-on-startup>0</load-on-startup> </servlet> <servlet> <servlet-name>Second</servlet-name> <servlet-class>com.cqupt.java.servlet.SecondServlet</servlet-class> <load-on-startup>3</load-on-startup> </servlet> <servlet> <servlet-name>Third</servlet-name> <servlet-class>com.cqupt.java.servlet.ThirdServlet</servlet-class> <load-on-startup>5</load-on-startup> </servlet>先创建加载HelloWorld,然后是Second,最后是Third
有关servlet-mapping的配置需注意两点
1.一个Servlet可以配置多个servlet-mapping,这样可以通过不同的url地址访问Servlet实例
2.url-pattern配置中使用通配符*只有两种合法的形式:
一种是 *.扩展名 的方法,例如 *.html,那么在访问web应用主目录 或者 aa.html 、.html时都可以请求到该Servlet
<servlet> <servlet-name>Third</servlet-name> <servlet-class>com.cqupt.java.servlet.ThirdServlet</servlet-class> <load-on-startup>5</load-on-startup> </servlet> <servlet-mapping> <servlet-name>Third</servlet-name> <url-pattern>*.html</url-pattern> </servlet-mapping>访问 :
web主目录:http://localhost:8080/ServletTest/
http://localhost:8080/ServletTest/.html
http://localhost:8080/ServletTest/aa.html都可以得到Servlet 的响应。
第二种是以正斜杠/开头,并以 /* 结尾
<servlet> <servlet-name>Third</servlet-name> <servlet-class>com.cqupt.java.servlet.ThirdServlet</servlet-class> <load-on-startup>5</load-on-startup> </servlet> <servlet-mapping> <servlet-name>Third</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping>其他例如 /*.action 都不合法。
Servlet配置时,可以给需要的Servlet配置初始化参数,配置方法:在servlet标签下使用init-param标签
<servlet> <servlet-name>HelloWorld</servlet-name> <servlet-class>com.cqupt.java.servlet.HelloWorld</servlet-class> <!-- init-param 标签必须放在load-on-startup标签之前 ,否则有错--> <init-param> <!-- 参数名 --> <param-name>user</param-name> <!-- 参数值 --> <param-value>root</param-value> </init-param> <init-param> <param-name>password</param-name> <param-value>1234</param-value> </init-param> <load-on-startup>0</load-on-startup> </servlet> <servlet-mapping> <servlet-name>HelloWorld</servlet-name> <url-pattern>/hello</url-pattern> </servlet-mapping>注意:init-param 标签必须放在load-on-startup标签之前 ,否则有错
那么如何在Servlet类中获取呢,关键在ServletConfig类,Servlet的init方法的形参就是ServletConfig类型
可以通过Servlet的init方法获取配置的初始化参数:
1.使用ServletConfig的getInitParameter(参数名)获取
@Override public void init(ServletConfig config) throws ServletException { System.out.println("init get init-param"); String user = config.getInitParameter("user"); System.out.println("user:"+user); String password = config.getInitParameter("password"); System.out.println("password:"+password); }
2.使用ServletConfig类的getInitParameterNames()获取所有参数名的Enumeration集合对象,再根据参数名获取参数值
@Override public void init(ServletConfig config) throws ServletException { System.out.println("init get init-param"); Enumeration<String> names = config.getInitParameterNames(); while(names.hasMoreElements()){ String name = names.nextElement(); System.out.println(name+":"+config.getInitParameter(name)); } }也可以使用getServletName()获取Servlet的名字
System.out.println(config.getServletName());
还可以使用getServletContext获取ServletContext对象,经常使用。
ServletContext servletContext = config.getServletContext();
ServletContex同ServletConfig类一样,是Servlet中经常使用且很重要的类。
ServletContext对象代表当前Web应用:可以认为ServletContext是当前web应用的大管家,可以从中获取关于Web应用的各种信息。
1.设置当前Web应用的初始化参数,直接在web-app标签下配置context-param标签即可
<!-- 配置当前web应用的初始化参数 --> <context-param> <param-name>driver</param-name> <param-value>com.mysql.jdbc.Driver</param-value> </context-param> <context-param> <param-name>jdbcUrl</param-name> <param-value>jdbc:mysql:///test</param-value> </context-param>
通过getInitParameter(参数名)和getInitParameterNames()获取
@Override public void init(ServletConfig config) throws ServletException { System.out.println("init ..."); ServletContext servletContext = config.getServletContext(); String driver = servletContext.getInitParameter("driver"); System.out.println(driver); Enumeration<String> names = servletContext.getInitParameterNames(); while(names.hasMoreElements()){ String name = names.nextElement(); String value = servletContext.getInitParameter(name); System.out.println(value); } }
2.获取当前Web应用的某一个文件在服务器上的绝对路径,而不是部署前的路径。
使用getRealPath(String path),path是根目录下的路径文件,以/开始
//note.txt在WebContent/下,获取的不是部署前的路径 String realPath = servletContext.getRealPath("/note.txt"); System.out.println(realPath); //D:\java\.metadata\.plugins\org.eclipse.wst.server.core\tmp1\wtpwebapps\ServletTest\note.txt
String webName = servletContext.getContextPath(); System.out.println(webName); //输出:/ServletTest输出Web应用的名称,不是项目的名称,默认的Web名称是项目的名称,但是后期在配置服务器发布web应用时,经常会改变,通过这个方法可以动态获取到Web应用的名称。
4.获取文件输入流,getResourceAsStream(String path),其中path是当前Web应用的根目录开始的:"/"
try{ ClassLoader classLoader = getClass().getClassLoader(); InputStream prop = classLoader.getResourceAsStream("jdbc.properties"); System.out.println(prop); }catch(Exception e) { e.printStackTrace(); } try{ //使用Servlet获取文件输入流,文件路径必须是从web应用开始 //而在项目src下的所有文件都部署在web应用的/WEB-INF/classes/目录下 // InputStream in = servletContext.getResourceAsStream("jdbc.properties");//null获取不到 InputStream in = servletContext.getResourceAsStream("/WEB-INF/classes/jdbc.properties"); System.out.println(in); }catch(Exception e) { e.printStackTrace(); }
HTTP协议是超文本传输协议,是TCP/IP协议族的应用层协议,负责浏览器与服务器之间数据交换的过程,以及数据本身的格式。
HTTP协议是无状态的,每次网页的请求,都必须建立连接----发送请求-----返回数据-----断开连接,之所以服务器可以跟踪客户的网页访问,是Session起的作用(后续)
每次连接只处理一个请求和响应。
请求消息的结构:一个请求行,若干消息头,以及实体内容,消息头和实体内容之间要用空行隔开
响应消息的结构:一个状态行,若干消息头,以及实体内容,同样,消息头和实体内容之间要用空行隔开
请求方式有两种:GET请求和POST请求
GET请求,将参数附加在URL后,以键值对的方式,传送的数据是有限制的,一般在1kb以下
http://localhost:8080/ServletTest/loginServlet?user=bbb&password=123&submit=submit
POST请求,把参数插入在请求体里,传送的数据量比GET请求传送的多。
1.在浏览器中输入URl地址或者单击网上的一个超链接时,浏览器发出的HTTP请求方法就是GET
2.如果网页的form表单指定了请求方法为GET,浏览器提交这个表单时,生成的HTTP请求消息的请求方式也是GET
3.使用GET请求为WEB服务器传参数格式:url?参数名1=参数1&参数名2&参数2
http://localhost:8080/ServletTest/loginServlet?user=bbb&password=123
4.使用GET请求传递的数据在1k以下,传递参数一般够用。
1.网页表单form指定的请求方式为post,生成的HTTP请求使用POST方法
2.POST请求将form表单提交的数据作为HTTP消息的请求实体发送给WEB服务器,传递的数据比GET方法要大得多。
提交文件时,必须使用POST请求