Servlet学习笔记
一 、使用 JavaEE 版的 Eclipse 开发动态的 WEB 工程(JavaWEB 项目)
- 把开发选项切换到 JavaEE
- 可以在 Window -> Show View 中找到 Package Explorer, 并把其拖拽到开发区的左边
- 在 Servers 面板中新建 Tomcat 服务器. 一定要关联到 Tomcat 安装的根目录
- 新建一个 Dynamic Web Project. 其中 Target Runtime 需选择 Tomcat6.0
- 开发 Java WEB 应用
- 可以通过 run on server 来运行 WEB 项目.
二、 Servlet 的 HelloWorld
创建一个 Servlet 接口的实现类.
public class HelloServlet implements Servlet{}
在 web.xml 文件中配置和映射这个 Servlet
<!-- 配置和映射 Servlet --> <servlet> <!-- Servlet 注册的名字 --> <servlet-name>helloServlet</servlet-name> <!-- Servlet 的全类名 --> <servletclass> </servlet-class> </servlet> <servlet-mapping> <!-- 和某一个 servlet 节点的 serlvet-name 子节点的文本节点一致 --> <servlet-name>helloServlet</servlet-name> <!-- 映射具体的访问路径: / 代表当前 WEB 应用的根目录. --> <url-pattern>/hello</url-pattern> </servlet-mapping>
三、Servlet 容器: 运行 Servlet、JSP、Filter 等的软件环境.
可以来创建 Servlet, 并调用 Servlet 的相关生命周期方法.
JSP, Filter, Listener, Tag …
四、Servlet 生命周期的方法: 以下方法都由 Serlvet 容器负责调用.
- 构造器: 只被调用一次. 只有第一次请求 Servlet 时, 创建 Servlet 的实例. 调用构造器. (这说明 Serlvet 的单实例的!)
- init 方法: 只被调用一次. 在创建好实例后立即被调用. 用于初始化当前 Servlet.
- service: 被多次调用. 每次请求都会调用 service 方法. 实际用于响应请求的.
- destroy: 只被调用一次. 在当前 Servlet 所在的 WEB 应用被卸载前调用. 用于释放当前 Servlet 所占用的资源.
五、load-on-startup 参数:
配置在 servlet 节点中:
<servlet>
<!-- Servlet 注册的名字 -->
<servlet-name>secondServlet</servlet-name>
<!-- Servlet 的全类名 -->
<servletclass>
</servlet-class>
<!-- 可以指定 Servlet 被创建的时机 -->
<load-on-startup>2</load-on-startup>
</servlet>
load-on-startup: 可以指定 Serlvet 被创建的时机. 若为负数, 则在第一次请求时被创建.若为 0 或正数, 则在当前 WEB 应用被Serlvet 容器加载时创建实例, 且数组越小越早被创建.
六、关于 serlvet-mapping:
同一个Servlet可以被映射到多个URL上,即多个
<servlet-mapping>
元素的<servlet-name>
子元素的设置值可以是同一个Servlet的注册名。在Servlet映射到的URL中也可以使用 * 通配符,但是只能有两种固定的格式:
一种格式是“*
.扩展名”,另一种格式是以正斜杠(/)开头并以“/*
”结尾。<servlet-mapping> <servlet-name>secondServlet</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping>
OR
<servlet-mapping> <servlet-name>secondServlet</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping>
注意: 以下的既带 / 又带扩展名的不合法.
<servlet-mapping> <servlet-name>secondServlet</servlet-name> <url-pattern>/*.action</url-pattern> </servlet-mapping>
七、ServletConfig: 封装了 Serlvet 的配置信息, 并且可以获取 ServletContext 对象
ServletConfig代表当前Servlet在web.xml中的配置信息。
在Servlet接口中init方法参数就是ServletConfig,在Servlet创建出来时,init方法立即被容器调用,由容器传入ServletConfig对象。
在GenericServlet中,实现了这个方法,将ServletConfig设置成了类的成员变量,并提供了getServletConfig方法,获取该对象。
我们的Servlet都间接继承子GenericServlet,所以可以在自己的Servlet中直接调用getServletConfig方法获取这个对象。
在web.xml中的标签中可以配置零个或多个标签,用来为当前Servlet配置一些自定义的参数–称为Serlvet的初始化参数。
ServletConfig接口中定义了以下方法:
◆ getInitParameter(String name):根据给定的初始化参数,返回匹配的初始化参数值。
◆ getInitParameterNames():返回一个Enumeration对象,该对象包含了所有存放在web.xml中元素子元素中的所有的初始化参数名。
◆ getServletContext():返回一个servletContext()对象,
◆ getServltName():返回servlet的名字,即web.xml中的相对应的servlet的子元素的值。如果没有配置这个子元素,则返回servlet类的全局限定名。
Example:
actionServlet
org.apache.struts.action.ActionServlet
first
netfish
last
blog
actionServlet
*.do
如上,红色标记处为初始化参数,相当于servlet共享参数。
在servlet中:
public class BlogServlet extends HttpServlet {
String first = this.getInitParameter(“first”);
String last = this.getInitParameter(“last”);
System.out.println(“第一个参数:” + first + “第二个参数:” + last);
}
注:HttpServlet类继承了GenericServlet类,而GenericServlet类实现了ServletConfig接口,因此在HttpServlet类和GenericServlet类及子类中都可以直接调用ServletConfig接口中的方法。
八、 ServletContext
ServletContext是servlet与servlet容器之间的直接通信的接口。Servlet容器在启动一个Webapp时,会为它创建一个ServletContext对象,即servlet上下文环境。每个webapp都有唯一的ServletContext对象。同一个webapp的所有servlet对象共享一个ServeltContext,servlet对象可以通过ServletContext来访问容器中的各种资源。
ServletContext接口提供的方法分为以下几种类型:
用于在Webapp范围内存取共享数据的方法。
注:webapp范围具有以下两层含义:
(1) 表示有webapp的生命周期构成的时间段。
(2) 表示在webapp的生命周期内所有web组件的集合。
◆ setAttribute(String name, java.lang.Object object):以键值对的形式,把一个java对象和一个属性名绑定,并存放到ServletContext中,参数name指定属性名,参数Object表示共享数据。
◆ getAttribute(String name):根据参数给定的属性名,返回一个Object类型的对象。
◆ getAttributeNames():返回一个Enumeration对象,该对象包含了所有存放在ServletContext中的属性名。
◆ removeAttribute(String name):根据参数指定的属性名,从servletContext对象中删除匹配的属性。
访问当前Webapp的资源
◆ getContextpath():返回当前webapp的URL入口。
◆ getInitParameter(String name):返回webapp配置文件中匹配的初始化参数值。在web.xml中元素中子元素表示Webapp应用范围内的初始参数。
◆ getInitParameterNames():返回一个Enumeration对象,该对象包含了所有存放在web.xml中元素中子元素的初始化参数名。
◆ getServletContextName():返回webapp名称。即元素中子元素的值。
◆ getRequestDispatcher(String path):返回一个用于向其他web组件转发请求的RequestDispatcher对象。
访问servlet容器的相关信息
◆ getContext(String uripath):根据参数指定的url,返回当前servlet容器中其他web应用的servletContext()对象。
访问web容器的相关信息
◆ getMajorVersion():返回servlet容器支持的java servlet API 的主版本号。
◆ getMinorVersion():返回servlet容器支持的java Servlet API的次版本号。
◆ getServerInfo():返回servlet容器的名字和版本。
访问服务器端的文件系统资源
◆ getRealPath(String path):根据参数指定的虚拟路径,返回文件系统中的一个真实的路径。
◆ getResource(String path):返回一个映射到参数指定的路径的url。
◆ getResourceAsStream(String path):返回一个用于读取参数指定的文件的输入流。(把文件读到输入流中去)
◆ getMimeType(String file):返回参数指定的文件的MIME类型。
输出日志
◆ log(String msg):向servlet的日志文件中写日志。
◆ log(String message, java.lang.Throwable throwable):向servlet的日志文件中写错误日志,以及异常的堆栈信息。
ServletContext对象获得几种方式:
javax.servlet.http.HttpSession.getServletContext()
javax.servlet.jsp.PageContext.getServletContext()
javax.servlet.ServletConfig.getServletContext()
以上是servlet2.5版本及以前的获取方法。
servlet3.0中新增方法:
javax.servlet.ServletRequest.getServletContext()
ServletContext和ServletConfig二者区别
从作用范围来说,ServletConfig作用于某个特定的Servlet,即从该Servlet实例化,那么就开始有效,但是该Servlet之外的其他Servlet不能访问;ServletContext作用于某个webapp,即在一个webapp中相当于一个全局对象,在Servlet容器启动时就已经加载,对于不同的webapp,有不同的ServletContext。
其次,来看一下二者参数的使用。如果一个参数为整个webapp所用,那么就配置为ServletContext参数,如下所示:
ContextParam
hello, this is ServletContext param.
如果一个参数仅为一个Servlet所用,那么就应该配置为ServletConfig参数,如下所示:
servlet名称
servlet全局限定名
ServletParam
hello, this is ServletConfig param.
最后,说明一下参数的获取。访问ServletConfig参数,取得ServletConfig对象后,调用getInitParameter()方法;访问ServletContext对象,只要调用现有的ServletConfig对象的getServletContext()即可,然后同样调用getInitParamter()方法就能获取参数。例如对于上面的参数,可以通过如下方法获取各自参数。
public class GetParam extends HttpServlet {
ServletConfig config;
public void init(ServletConfig config) {
this.config=config;
}
public void doGet(HttpServletRequest request,HttpServletResponse response) throws ServletException,IOException {
String servletparam=(String)config.getInitParameter(“ServletParam”);
System.out.println(servletparam);
String contextparam = (String)config.getServletContext().getInitParameter(“ContextParam”);
System.out.println(contextparam);
}
public void destroy() {
}
}
九、GET 请求和 POST 请求:
使用GET方式传递参数:
①.在浏览器地址栏中输入某个URL地址或单击网页上的一个超链接时,浏览器发出的HTTP请求消息的请求方式为GET。
②. 如果网页中的<form>
表单元素的 method 属性被设置为了“GET”,浏览器提交这个FORM表单时生成的HTTP请求消息的请求方式也为GET。
③. 使用GET请求方式给WEB服务器传递参数的格式:http://localhost:8080/counter.jsp?name=lc&password=123
④. 使用GET方式传送的数据量一般限制在 1KB 以下。
使用 POST 方式传递参数:
①. POST 请求方式主要用于向 WEB 服务器端程序提交 FORM 表单中的数据: form 表单的 method 置为 POST
②. POST 方式将各个表单字段元素及其数据作为 HTTP 消息的实体内容发送给 WEB 服务器,传送的数据量要比使用GET方式传送的数据量大得多。POST /counter.jsp HTTP/1.1 referer: http://localhost:8080/Register.html content-type: application/x-www-form-urlencoded host: localhost:8080 content-length: 43
?name=zhangsan&password=123 –请求体中传递参数.
十、如何在 Serlvet 中获取请求信息:
Servlet 的 service() 方法用于应答请求: 因为每次请求都会调用 service() 方法
public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException
- ServletRequest: 封装了请求信息. 可以从中获取到任何的请求信息.
- ServletResponse: 封装了响应信息, 如果想给用户什么响应, 具体可以使用该接口的方法实现.
这两个接口的实现类都由服务器实现, 并在服务器调用 service 方法时自动传入参数.
ServletRequest: 封装了请求信息. 可以从中获取到任何的请求信息.
①. 获取请求参数:
- String getParameter(String name): 根据请求参数的名字, 返回参数值. 若请求参数有多个值(例如 checkbox), 该方法只能获取到第一个提交的值.
- String[] getParameterValues(String name): 根据请求参数的名字, 返回请求参数对应的字符串数组.
- Enumeration getParameterNames(): 返回一个Enumeration对象, 类似于ServletConfig(或ServletContext) 的getInitParameterNames() 方法.
- Map getParameterMap(): 返回请求参数的键值对: key: 参数名, value: 参数值, String 数组类型.
②. 获取请求的 URI:
HttpServletRequest hr = (HttpServletRequest) request; String requestURI = hr.getRequestURI(); System.out.println(requestURI); // /day_29/loginServlet
③. 获取请求方式:
String method = hr.getMethod(); System.out.println(method); //GET
④. 若是一个 GET 请求, 获取请求参数对应的那个字符串, 即 ? 后的那个字符串.
String queryString = hr.getQueryString(); System.out.println(queryString); //user=atguigu&password=123456&interesting=game&interesting=party&interesting=shopping
⑤. 获取请求的 Serlvet 的映射路径
String servletPath = hr.getServletPath(); System.out.println(servletPath); // /loginServlet
⑥. 和 attribute 相关的几个方法: 见JSP学习章节
HttpServletRequest: 是 SerlvetRequest 的子接口. 针对于 HTTP 请求所定义. 里边包含了大量获取 HTTP 请求相关的方法.
ServletResponse: 封装了响应信息, 如果想给用户什么响应, 具体可以使用该接口的方法实现.
①getWriter(): 返回 PrintWriter 对象. 调用该对象的 print() 方法, 将把 print() 中的参数直接打印
到客户的浏览器上.②设置响应的内容类型:
response.setContentType("application/msword");
③void sendRedirect(String location): 请求的重定向. (此方法为 HttpServletResponse 中定义.)
十一、GenericServlet
- 是一个 Serlvet. 是 Servlet 接口和 ServletConfig 接口的实现类. 但是一个抽象类. 其中的 service 方法为抽象方法
- 如果新建的 Servlet 程序直接继承 GenericSerlvet 会使开发更简洁.
具体实现:
① 在 GenericServlet 中声明了一个 SerlvetConfig 类型的成员变量, 在 init(ServletConfig) 方法中对其进行了初始化
② 利用 servletConfig 成员变量的方法实现了 ServletConfig 接口的方法
③ 还定义了一个 init() 方法, 在 init(SerlvetConfig) 方法中对其进行调用, 子类可以直接覆盖 init() 在其中实现对 Servlet 的初始化.
④ 不建议直接覆盖 init(ServletConfig config), 因为如果忘记编写 super.init(config); 而还是用了 SerlvetConfig 接口的方法,则会出现空指针异常.
⑤新建的 init(){} 并非 Serlvet 的生命周期方法. 而 init(ServletConfig) 是生命周期相关的方法.public abstract class GenericServlet implements Servlet, ServletConfig { /** 以下方法为 Servlet 接口的方法 **/ @Override public void destroy() {} @Override public ServletConfig getServletConfig() { return servletConfig; } @Override public String getServletInfo() { return null; } private ServletConfig servletConfig; @Override public void init(ServletConfig arg0) throws ServletException { this.servletConfig = arg0; init(); } public void init() throws ServletException{} @Override public abstract void service(ServletRequest arg0, ServletResponse arg1) throws ServletException, IOException; /** 以下方法为 ServletConfig 接口的方法 **/ @Override public String getInitParameter(String arg0) { return servletConfig.getInitParameter(arg0); } @Override public Enumeration getInitParameterNames() { return servletConfig.getInitParameterNames(); } @Override public ServletContext getServletContext() { return servletConfig.getServletContext(); } @Override public String getServletName() { return servletConfig.getServletName(); } }
十二、HttpServlet:
是一个 Servlet, 继承自 GenericServlet. 针对于 HTTP 协议所定制.
在 service() 方法中直接把 ServletReuqest 和 ServletResponse 转为 HttpServletRequest 和 HttpServletResponse.
并调用了重载的 service(HttpServletRequest, HttpServletResponse)在 service(HttpServletRequest, HttpServletResponse) 获取了请求方式: request.getMethod(). 根据请求方式有创建了
doXxx() 方法(xxx 为具体的请求方式, 比如 doGet, doPost)public void service(ServletRequest req, ServletResponse res)throws ServletException, IOException { HttpServletRequest request; HttpServletResponse response; try { request = (HttpServletRequest) req; response = (HttpServletResponse) res; } catch (ClassCastException e) { throw new ServletException("non-HTTP request or response"); } service(request, response); } @Override public void service(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException { //1. 获取请求方式. String method = request.getMethod(); //2. 根据请求方式再调用对应的处理方法 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{ // TODO Auto-generated method stub } public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub }
实际开发中, 直接继承 HttpServlet, 并根据请求方式复写 doXxx() 方法即可.
好处: 直接由针对性的覆盖 doXxx() 方法; 直接使用 HttpServletRequest 和 HttpServletResponse, 不再需要强转.
*作业1
在 web.xml 文件中设置两个 WEB 应用的初始化参数, user, password.
定义一个 login.html, 里边定义两个请求字段: user, password. 发送请求到 loginServlet
在创建一个 LoginServlet, 在其中获取请求的 user, password. 比对其和 web.xml 文件中定义的请求参数是否一致
若一致, 响应 Hello:xxx, 若不一致, 响应 Sorry: xxx xxx 为 user.
*作业2
在 MySQL 数据库中创建一个 test_users 数据表, 添加 3 个字段: id, user, password. 并录入几条记录.
定义一个 login.html, 里边定义两个请求字段: user, password. 发送请求到 loginServlet
在创建一个 LoginServlet(需要继承自 HttpServlet, 并重写其 doPost 方法),
在其中获取请求的 user, password.
利用 JDBC 从 test_users 中查询有没有和页面输入的 user, password 对应的记录
SELECT count(id) FROM test_users WHERE user = ? AND password = ?
若有, 响应 Hello:xxx, 若没有, 响应 Sorry: xxx xxx 为 user.