一、什么是servlet? 能做什么?
sun公司制订的一种用于扩展web服务器功能的组件规范。
扩展:
web服务器本身没有计算能力,也就是说,不能处理动态资源的请求。servlet可以处理动态资源的请求。组件:
组件是符合规范,完成一定功能,并可以单独部署的软件模块。组件一般不能独立运行,需要依赖容器才能运行。容器:
在是一种程序,提供组件的运行环境,并且管理组件的生命周期。servlet容器:
提供servlet运行的环境,并且管理servlet的生命周期。一般常见的web服务器,比如tomcat, 除了是一个servlet容器以外,同时,也是一个web服务器,就是说已经集成了Servlet容器。
能做什么?
servlet只能够采用java语言来开发,servlet可以做java类能做的所有的事情。
二、如何开发一个servlet?
step1 写一个java类,实现Servlet接口或者继承HttpServlet类。
step2 编译 (依赖servlet api–[servlet-api.jar])
javac -cp servlet-api.jar -d . HelloWorld.java
step3 打包(定义一个特定的目录结构,将相应的字节码,配置文件,相关的jar文件放到对应的
录结构里)
appname(名称任意,一般称为应用名)
WEB-INF(必须这样写)
classes(放.class文件)
lib(可选,放.jar文件)
web.xml(部署描述文件)
html/jsp
step4 部署(将step3中的结果放到服务器特定的目录,对于tomcat,是webapps)
step5 启动服务器
JAVA_HOME:c:\jdk1.6
path:%JAVA_HOME%\bin
classpath:.;c:\jdk1.6\lib
startup.bat
系统变量中:JAVA_HOME:jdk的路径
startup.sh
启动成功:http://localhost:8080
关闭服务器
shutdown.bat
shutdown.sh
step6 访问servlet
http://localhost:8080/appname/url-pattern
三、servlet是如何运行的?
假如在浏览器地址栏输入了如下地址:
http://ip:port/helloworld/hello
1)浏览器依据ip,port连接服务器。
2)浏览器将请求数据按http协议打成一个http请求数据包(包含了 helloworld/hello)
3)服务器当中的一个负责通讯的模块(一般称为servlet引擎)会创建HttpServletRequest的一个实例(HttpServletRequest实际上是一个接口,由服务器提供者来实现),该实例包含了请求数据包中的数据。另外,还创建了一个HttpServletResponse的一个实例,包含了响应数据包中的数据
4)服务器依据helloworld/hello找到web.xml,依据web.xml中的信息找到对应的Servlet类名。会查看该Servlet有没有对应的实例,如果没有,则创建实例,有的话,就不创建,使用现成的实例。接下来,调用service()方法。service方法里面的代码可以通过HttpServletRequest提供的方法来获得请求中的数据,并且,也可以将处理之后的结果通过HttpServletResponse提供的方法设置返回的结果。
5)Servlet引擎从HttpServletResponse获取数据,生成http响应数据包,发送给浏览器。
四、Servlet生命周期方法
以下方法都是由Servlet容器负责调用:
1>构造器:只被调用一次,只有第一次请求Servlet时,创建Servlet的实例,调用构造器
这说明Servlet是单实例的!
2>init 方法:只被调用一次,在创建好实例后立即被调用,用于初始化Servlet
如果想定义自己的初始化过程,可以override init()方法。
方式一: override init(ServletConfig config);
方式二: override init()
一般最好使用方式二
3>service:被多次调用。每次请求都会调用service方法。实际用于响应请求的。
4>destroy:只被调用一次。在当前Servlet所在的WEB应用被卸载前调用。用于释放当前Servlet所占用资源,将Servlet引用的对象置为空。
五、load-on-startup参数:
1>配置在Servlet节点中
<servlet>
<!--Servlet 注册的名字-->
<servlet-name>helloServlet</servlet-name>
<!--Servlet 的全类名-->
<servlet-class>com.javaweb.HelloServlet</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
2>load-on-startup:可以在指定Servlet被创建的时机。
若为负数,则在第一次请求时被创建,
若为0或正数,则在当前Web应用Servlet容器加载时创建实例,且数值越小越早被创建。
六、ServletConfig
ServletConfig:封装了Servlet的配置信息,并且可以获取ServletContext对象
1>配置Servlet初始化参数
<servlet>
<!--Servlet 注册的名字-->
<servlet-name>helloServlet</servlet-name>
<!--Servlet 的全类名-->
<servlet-class>com.javaweb.HelloServlet</servlet-class>
<!--配置Servlet初始化参数-->
<init-param>
<param-name>user</param-name>
<param-value>root</param-value>
<init-param>
<init-param>
<param-name>password</param-name>
<param-value>1230</param-value>
<init-param>
<!--注意!!! 必须将初始化参数放在前面-->
<load-on-startup>2</load-on-startup>
</servlet>
2>获取初始化参数:
-getInitParameter(String name):获取指定参数名的初始化参数
-getInitParameterNames():获取【参数名】组成的Enumeration
public void init(ServletConfig servletConfig)thows ServletException{
String user = servletConfig.getInitParameter("user");
System.out.println("user: "+user);
Enumeration<String> names = serveltConfig.getInitParameterNames();
while(names.hasMoreElements()){
String name = names.nextElement();
String value = servletConfig.getInitParameter(name);
System.out.println("--"+ name +": "+ value);
}
}
七、ServletContext
1>可以由ServletConfig获取
ServletContext servletContext = servletConfig.getServletContext();
2>该对象代表当前WEB应用:可以认为ServletContext是当前WEB应用的一个大管家,可以从中获取当前WEB应用的各方面信息。
①获取当前WEB应用的初始化参数【可以被所有的Servlet所获取,而Servlet的初始化参数只可以被自己所使用】
<context-param>
<param-name>driver</param-name>
<param-value>cn.edu.computer.HellowServlet</param-value>
</context-param>
<context-param>
<param-name>jdbcUr1</param-name>
<param-value>
jdbc:mysql://127.0.0.1:3306/java
</param-value>
</context-param>
方法:
ServletContext.getInitParameter();
ServletContext.getInitParameterNames();
②获取当前WEB应用的某一个文件在服务器上的绝对路径,而【不是部署前】的
getRealPath()
③获取当前WEB应用的名称:
getContextPath()
代码:
String contextPath = servletContext.getContextPath();
System.out.println(contextPath);
④获取当前WEB应用的某一个文件对应的输入流:
getResourceAsStream(String path)-path的/为当前WEB应用的根目录
代码:
ClassLoader classLoader = getClass().getClassLoader();
InputStream is = classLoader.getResourceAsStream("jdbc.properties");
System.out.println("1 "+is );
InputStream is1 = servletContext.getResourceAsStream("WEB-INF/classes/jdbc.properties");
System.out.println("2 "+is1);
⑤和attribute相关的几个方法
八、如何在Servlet中获取请求信息:
1>Servlet的service()方法用于应答请求。每次请求都会调用该方法。
public void service(ServletRequest request, ServletResponse response)
throws ServletException, IOException {
ServletRequest:封装了请求信息,可以从中获取到任何请求信息
ServletResponse:封装了响应信息,如果想给用户什么响应,具体可以使用该接口方法实现
这两个接口的实现类都是服务器给予实现的,并在服务器调用service()方法时代入
2>ServletRequest
①获取请求参数
String getParameter(String name):根据请求参数名字,返回参数值。
若请求参数有多个值(例如:checkbox)该方法只能获取到第一个提交的值,这时 需使用getParameterValues():
String[] getParameterValues(String name):根据请求参数名字,返回请求参数返回对应参数数组
Enumeration getParameterNames():返回参数名对应的Enumeration对象
类似于ServletConfig(或ServletContext())的getInitParameterNames()方法
Map getParameterMap():返回请求参数的键值对-key:参数名,value:参数值,String数组类型
②获取请求的URL:
HttpServletRequest httpServletRequest = (HttpServletRequest)request;
String requestURI = httpServletRequest.getRequestURI();
URI:/day29/loginServlet
③获取请求方式:
String method = httpServletRequest.getMethod(); //GET
④若是GET请求,获取请求参数对应的那个字符串,即?后面的字符串
String queryString = httpServletRequest.getQueryString(); //user=dd&password=123456&interesting=game…
⑤获取请求的Servlet的映射路径
String servletPath = httpServletRequest.getServletPath();
// /loginServlet
⑥和attribute相关的几个方法
3>HttpServletRequest:是ServletRequest的子接口。针对于HTTP请求所定义,里面包含了大量获取HTTP请求相关的方法。
4>ServletResponse:封装了响应信息,如果想给用户什么响应,具体可以使用该接口的方法实现。
①getWriter():返回PrintWriter对象。调用该对象的print()方法,将把print()中的参数直接打印到浏览器。
②设置相应的内容类型:response.setContentType(“application/msword”); //将在响应以Word文件方式发送
③void sendRedirect(String location): 请求的重定向。(此方法为HttpServletRespnse中定义)
九、GenericServlet:
1>是一个Servlet.是Servlet接口和ServletConfig接口的实现类,是一个【抽象类】。其中的service方法为抽象方法。
2>如果新建的Servlet程序直接继承GenericSerlvet会使开发更简洁。
3>具体实现:
①在GenericServlet中声明了一个ServletConfig类型的成员变量,在init(ServletConfig)方法中对其进行了初始化
②利用servletConfig成员变量的方法实现了ServletConfig接口的方法
③还定义了一个init()方法,在init(ServletConfig)方法中对其进行调用,子类可以直接覆盖init()在其中实现对Servlet的初始化
④不建议直接覆盖init(ServletConfig),因为如果忘记编写super.init(ServletConfig),而还使用了ServletConfig接口的方法,则
会出现空指针异常。
⑤新建的init(){}并非Servlet的生命周期方法,而init(ServletConfig name)是。
public abstract class MyGenericServlet implements Servlet,ServletConfig{}
十、HttpServlet:
1>是一个Servlet,继承自GenericServlet,针对HTTP协议所定制。
2>在service()方法中直接把ServletRequest和ServletResponse转化为HttpServletRequest和HttpServletResponse并调用了重载的service(HttpServletRequest,HttpServletResponse)
在service(HttpServletRequest,HttpServletResponse)获取请求方式:request.getMethod()
根据请求方式又创建了doXxx() 方法(如:doGet()和 doPost()
3>实际开发中,直接继承HttpServlet,并且根据请求方式复写doXxx()方法接口
4>优点:直接针对性的覆盖doXxx()方法;
直接使用HttpServletRequest 和 HttpServletResponse,就不再需要强制转换。
public class MyHttpServlet extends MyGenericServlet {
@Override
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException {
if (req instanceof HttpServletRequest) {
HttpServletRequest request = (HttpServletRequest) req;
if (res instanceof HttpServletResponse) {
HttpServletResponse response = (HttpServletResponse) res;
service(request, response);
}
}
}
public void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException{
String method = request.getMethod();
if("GET".equalsIgnoreCase(method)){
doGet(request,response);
}else if("POST".equalsIgnoreCase(method)){
doPost(request, response);
}
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException{
}
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException{
}
}
最后附上核心类与接口联系图: