Servlet 的 HelloWorld
1.创建一个 Servlet 接口的实现类.
public class HelloServlet implements Servlet{
}
2.在 web.xml 文件中配置和映射这个 Servlet
<!-- 配置和映射 Servlet -->
<servlet>
<!-- Servlet 注册的名字 -->
<servlet-name>helloServlet</servlet-name>
<!-- Servlet 的全类名 -->
<servlet-class>org.xst.servlet.HelloServlet</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 等的软件环境
Tomcat如何与Servlet协同工作
Servlet规范中的关键要求之一是,它们只能处理整个数据事务处理的某些部分。例如,servlet代码本身不会监听某个端口上的请求,也不会直接与客户端进行通信,也不负责管理其对资源的访问。相反,这些东西是由servlet容器Tomcat管理的。
如何工作
一个http请求到来,servlet容器(tomcat)将请求封装成servlet中的request对象,在requset中我们可以得到所有的http信息,然后可以对数据进行对应操作,最后再把数据封装成servlet的response对象,容器将response对象解析之后封装成一个http response.
什么是servlet
- servlet 是一个java接口.
- Servlet是J2EE 规范中的一种
- servlet就是一群人来指定java应用中使用web的各种规范.统一接口.
public interface Servlet {
/**
* Called by the servlet container to indicate to a servlet that the
* servlet is being placed into service.
*/
public void init(ServletConfig config) throws ServletException;
/**
* Returns a {@link ServletConfig} object, which contains
* initialization and startup parameters for this servlet.
* The <code>ServletConfig</code> object returned is the one
* passed to the <code>init</code> method.
*/
public ServletConfig getServletConfig();
/**
* Called by the servlet container to allow the servlet to respond to
* a request.
*
* <p>This method is only called after the servlet's <code>init()</code>
* method has completed successfully.
*/
public void service(ServletRequest req, ServletResponse res)throws ServletException, IOException;
/**
* Returns information about the servlet, such as author, version, and copyright.
*
* <p>The string that this method returns should
* be plain text and not markup of any kind (such as HTML, XML,etc.).
*/
public String getServletInfo();
/**
* Called by the servlet container to indicate to a servlet that the
* servlet is being taken out of service. This method is
* only called once all threads within the servlet's
* <code>service</code> method have exited or after a timeout
* period has passed. After the servlet container calls this
* method, it will not call the <code>service</code> method again
* on this servlet.
*
* <p>This method gives the servlet an opportunity
* to clean up any resources that are being held (for example, memory,
* file handles, threads) and make sure that any persistent state is
* synchronized with the servlet's current state in memory.
*/
public void destroy();
}
Servlet 生命周期的方法(以下方法都是由 Serlvet 容器负责调用.)
1. 构造器:
只被调用一次. 只有第一次请求 Servlet 时, 创建 Servlet 的实例. 调用构造器. 这说明 Serlvet 的单实例的!
2. init 方法:
只被调用一次. 在创建好实例后立即被调用. 用于初始化当前 Servlet.
3. service 方法:
被多次调用. 每次请求都会调用 service 方法. 实际用于响应请求的.
4. destroy 方法:
只被调用一次. 在当前 Servlet 所在的 WEB 应用被卸载前调用. 用于释放当前 Servlet 所占用的资源.
load-on-startup 参数:
1. 配置在 servlet 节点中:
<servlet>
<servlet-name>HelloServlet</servlet-name>
<servlet-class>org.xst.servlet.HelloServlet</servlet-class>
<!-- 可以指定 Servlet 被创建的时机 -->
<load-on-startup>1</load-on-startup>
</servlet>
2. load-on-startup: 可以指定 Serlvet 被创建的时机.
若为负数, 则在第一次请求时被创建.若为 0 或正数, 则在当前 WEB 应用被Serlvet 容器加载时创建实例, 且数组越小越早被创建.
关于 serlvet-mapping
- 同一个Servlet可以被映射到多个URL上,即多个 元素的子元素的设置值可以是同一个Servlet的注册名。
<servlet>
<servlet-name>HelloServlet</servlet-name>
<servlet-class>org.xst.servlet.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>HelloServlet</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>HelloServlet</servlet-name>
<url-pattern>/hello2</url-pattern>
</servlet-mapping>
- 在Servlet映射到的URL中也可以使用 * 通配符,但是只能有两种固定的格式:
一种格式是“.扩展名”,另一种格式是以正斜杠(/)开头并以“/”结尾。
<servlet>
<servlet-name>HelloServlet</servlet-name>
<servlet-class>org.xst.servlet.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>HelloServlet</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>HelloServlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
ServletConfig
/**
* A servlet configuration object used by a servlet container
* to pass information to a servlet during initialization.
*/
public interface ServletConfig {
/**
* Returns the name of this servlet instance.
* The name may be provided via server administration, assigned in the
* web application deployment descriptor, or for an unregistered (and thus
* unnamed) servlet instance it will be the servlet's class name.
*/
public String getServletName();
/**
* Returns a reference to the {@link ServletContext} in which the caller
* is executing.
*/
public ServletContext getServletContext();
/**
* Returns a <code>String</code> containing the value of the
* named initialization parameter, or <code>null</code> if
* the parameter does not exist.
*/
public String getInitParameter(String name);
/**
* Returns the names of the servlet's initialization parameters
* as an <code>Enumeration</code> of <code>String</code> objects,
* or an empty <code>Enumeration</code> if the servlet has
* no initialization parameters.
*/
public Enumeration getInitParameterNames();
}
封装了 Serlvet 的配置信息, 并且可以获取 ServletContext 对象
1. 配置 Serlvet 的初始化参数
<!--配置当前 WEB 应用的初始化参数-->
<context-param>
<param-name>cuser</param-name>
<param-value>croot</param-value>
</context-param>
<servlet>
<servlet-name>HelloServlet</servlet-name>
<servlet-class>org.xst.servlet.HelloServlet</servlet-class>
<!-- 配置 Serlvet 的初始化参数。 且节点必须在 load-on-startup 节点的前面 -->
<init-param>
<!-- 参数名 -->
<param-name>user</param-name>
<!-- 参数值 -->
<param-value>root</param-value>
</init-param>
<load-on-startup>0</load-on-startup>
</servlet>
2. 获取Servlet初始化参数
public class HelloServlet extends GenericServlet {
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
String user = getInitParameter("user"); //获取 servlet 的初始化参数
System.out.println(user); //root
String cuser = getServletContext().getInitParameter("cuser"); //获取 web 应用的初始化参数
System.out.println(cuser); //croot
}
}
ServletContext
/**
* <p>The <code>ServletContext</code> object is contained within
* the {@link ServletConfig} object, which the Web server provides the
* servlet when the servlet is initialized.
*/
public interface ServletContext {
/**
* Returns the context path of the web application.
*/
public String getContextPath();
/**
* Returns a <code>ServletContext</code> object that
* corresponds to a specified URL on the server.
*/
public ServletContext getContext(String uripath);
/**
* Returns the MIME type of the specified file, or <code>null</code> if
* the MIME type is not known. The MIME type is determined
* by the configuration of the servlet container, and may be specified
* in a web application deployment descriptor. Common MIME
* types are <code>"text/html"</code> and <code>"image/gif"</code>.
*/
public String getMimeType(String file);
/**
* Returns a URL to the resource that is mapped to a specified
* path. The path must begin with a "/" and is interpreted
* as relative to the current context root.
*/
public URL getResource(String path) throws MalformedURLException;
/**
* Returns the resource located at the named path as
* an <code>InputStream</code> object.
*
* <p>The data in the <code>InputStream</code> can be
* of any type or length. The path must be specified according
* to the rules given in <code>getResource</code>.
* This method returns <code>null</code> if no resource exists at
* the specified path.
*/
public InputStream getResourceAsStream(String path);
/**
* Returns a <code>String</code> containing the real path
* for a given virtual path. For example, the path "/index.html"
* returns the absolute file path on the server's filesystem would be
* served by a request for "http://host/contextPath/index.html",
* where contextPath is the context path of this ServletContext..
*
* <p>The real path returned will be in a form
* appropriate to the computer and operating system on
* which the servlet container is running, including the
* proper path separators. This method returns <code>null</code>
* if the servlet container cannot translate the virtual path
* to a real path for any reason (such as when the content is
* being made available from a <code>.war</code> archive).
*/
public String getRealPath(String path);
/**
* Returns the name and version of the servlet container on which
* the servlet is running.
*/
public String getServerInfo();
/**
* Returns a <code>String</code> containing the value of the named
* context-wide initialization parameter, or <code>null</code> if the
* parameter does not exist.
*
* <p>This method can make available configuration information useful
* to an entire "web application". For example, it can provide a
* webmaster's email address or the name of a system that holds
* critical data.
*/
public String getInitParameter(String name);
/**
* Returns the names of the context's initialization parameters as an
* <code>Enumeration</code> of <code>String</code> objects, or an
* empty <code>Enumeration</code> if the context has no initialization
* parameters.
*/
public Enumeration getInitParameterNames();
/**
* Returns the servlet container attribute with the given name,
* or <code>null</code> if there is no attribute by that name.
* An attribute allows a servlet container to give the
* servlet additional information not
* already provided by this interface. See your
* server documentation for information about its attributes.
* A list of supported attributes can be retrieved using
* <code>getAttributeNames</code>.
*
* <p>The attribute is returned as a <code>java.lang.Object</code>
* or some subclass.
* Attribute names should follow the same convention as package
* names. The Java Servlet API specification reserves names
* matching <code>java.*</code>, <code>javax.*</code>,
* and <code>sun.*</code>.
*/
public Object getAttribute(String name);
/**
* Returns an <code>Enumeration</code> containing the
* attribute names available
* within this servlet context. Use the
* {@link #getAttribute} method with an attribute name
* to get the value of an attribute.
*/
public Enumeration getAttributeNames();
/**
* Binds an object to a given attribute name in this servlet context. If
* the name specified is already used for an attribute, this
* method will replace the attribute with the new to the new attribute.
* <p>If listeners are configured on the <code>ServletContext</code> the
* container notifies them accordingly.
* <p>
* If a null value is passed, the effect is the same as calling
* <code>removeAttribute()</code>.
*
* <p>Attribute names should follow the same convention as package
* names. The Java Servlet API specification reserves names
* matching <code>java.*</code>, <code>javax.*</code>, and
* <code>sun.*</code>.
*/
public void setAttribute(String name, Object object);
/**
* Removes the attribute with the given name from
* the servlet context. After removal, subsequent calls to
* {@link #getAttribute} to retrieve the attribute's value
* will return <code>null</code>.
* <p>If listeners are configured on the <code>ServletContext</code> the
* container notifies them accordingly.
*/
public void removeAttribute(String name);
/**
* Returns the name of this web application corresponding to this ServletContext as specified in the deployment
* descriptor for this web application by the display-name element.
* @return The name of the web application or null if no name has been declared in the deployment descriptor.
*/
public String getServletContextName();
}
1.可以由 SerlvetConfig 获取
ServletContext servletContext = servletConfig.getServletContext()
2. 该对象代表当前 WEB 应用: 可以认为 SerlvetContext 是当前 WEB 应用的一个大管家. 可以从中获取到当前 WEB 应用的各个方面的信息.
GenericServlet
/**
* <p>To write a generic servlet, you need only
* override the abstract <code>service</code> method.
*/
public abstract class GenericServlet implements Servlet, ServletConfig, java.io.Serializable{
private static final String LSTRING_FILE = "javax.servlet.LocalStrings";
private static ResourceBundle lStrings =ResourceBundle.getBundle(LSTRING_FILE);
private transient ServletConfig config;
/**
*
* Does nothing. All of the servlet initialization
* is done by one of the <code>init</code> methods.
*
*/
public GenericServlet() { }
/**
* Called by the servlet container to indicate to a servlet that the
* servlet is being taken out of service. See {@link Servlet#destroy}.
*/
public void destroy() {
}
/**
* Returns a <code>String</code> containing the value of the named
* initialization parameter, or <code>null</code> if the parameter does
* not exist. See {@link ServletConfig#getInitParameter}.
*/
public String getInitParameter(String name) {
ServletConfig sc = getServletConfig();
if (sc == null) {
throw new IllegalStateException(
lStrings.getString("err.servlet_config_not_initialized"));
}
return sc.getInitParameter(name);
}
/**
* Returns the names of the servlet's initialization parameters
* as an <code>Enumeration</code> of <code>String</code> objects,
* or an empty <code>Enumeration</code> if the servlet has no
* initialization parameters. See {@link
* ServletConfig#getInitParameterNames}.
*/
public Enumeration getInitParameterNames() {
ServletConfig sc = getServletConfig();
if (sc == null) {
throw new IllegalStateException(
lStrings.getString("err.servlet_config_not_initialized"));
}
return sc.getInitParameterNames();
}
/**
* Returns this servlet's {@link ServletConfig} object.
*/
public ServletConfig getServletConfig() {
return config;
}
/**
* Returns a reference to the {@link ServletContext} in which this servlet
* is running. See {@link ServletConfig#getServletContext}.
*
* <p>This method is supplied for convenience. It gets the
* context from the servlet's <code>ServletConfig</code> object.
*/
public ServletContext getServletContext() {
ServletConfig sc = getServletConfig();
if (sc == null) {
throw new IllegalStateException(
lStrings.getString("err.servlet_config_not_initialized"));
}
return sc.getServletContext();
}
/**
* Returns information about the servlet, such as author, version, and copyright.
* By default, this method returns an empty string. Override this method
* to have it return a meaningful value. See {@link Servlet#getServletInfo}.
*/
public String getServletInfo() {
return "";
}
/**
* Called by the servlet container to indicate to a servlet that the
* servlet is being placed into service. See {@link Servlet#init}.
*
* <p>This implementation stores the {@link ServletConfig}
* object it receives from the servlet container for later use.
* When overriding this form of the method, call
* <code>super.init(config)</code>.
*/
public void init(ServletConfig config) throws ServletException {
this.config = config;
this.init();
}
/**
* A convenience method which can be overridden so that there's no need
* to call <code>super.init(config)</code>.
*
* <p>Instead of overriding {@link #init(ServletConfig)}, simply override
* this method and it will be called by
* <code>GenericServlet.init(ServletConfig config)</code>.
* The <code>ServletConfig</code> object can still be retrieved via {@link
* #getServletConfig}.
*/
public void init() throws ServletException {
}
/**
* Writes the specified message to a servlet log file, prepended by the
* servlet's name. See {@link ServletContext#log(String)}.
*/
public void log(String msg) {
getServletContext().log(getServletName() + ": "+ msg);
}
/**
* Writes an explanatory message and a stack trace
* for a given <code>Throwable</code> exception
* to the servlet log file, prepended by the servlet's name.
* See {@link ServletContext#log(String, Throwable)}.
*/
public void log(String message, Throwable t) {
getServletContext().log(getServletName() + ": " + message, t);
}
/**
* Called by the servlet container to allow the servlet to respond to
* a request. See {@link Servlet#service}.
*
* <p>This method is declared abstract so subclasses, such as
* <code>HttpServlet</code>, must override it.
*/
public abstract void service(ServletRequest req, ServletResponse res)throws ServletException, IOException;
/**
* Returns the name of this servlet instance.
* See {@link ServletConfig#getServletName}.
*/
public String getServletName() {
ServletConfig sc = getServletConfig();
if (sc == null) {
throw new IllegalStateException(
lStrings.getString("err.servlet_config_not_initialized"));
}
return sc.getServletName();
}
}
- 是一个 Serlvet. 是 Servlet 接口和 ServletConfig 接口的实现类. 但是一个抽象类. 其中的 service 方法为抽象方法
- 如果新建的 Servlet 程序直接继承 GenericSerlvet 会使开发更简洁.
- 具体实现:
①. 在 GenericServlet 中声明了一个 SerlvetConfig 类型的成员变量, 在 init(ServletConfig) 方法中对其进行了初始化
②. 利用 servletConfig 成员变量的方法实现了 ServletConfig 接口的方法
③. 还定义了一个 init() 方法, 在 init(SerlvetConfig) 方法中对其进行调用, 子类可以直接覆盖 init() 在其中实现对 Servlet 的初始化.
④. 不建议直接覆盖 init(ServletConfig), 因为如果忘记编写 super.init(config); 而还是用了 SerlvetConfig 接口的方法,则会出现空指针异常.
⑤. 新建的 init(){} 并非 Serlvet 的生命周期方法. 而 init(ServletConfig) 是生命周期相关的方法.
HttpServlet
- HttpServlet是一个 Servlet, 继承自 GenericServlet. 针对于 HTTP 协议所定制.
- 在 service() 方法中直接把 ServletReuqest 和 ServletResponse 转为HttpServletRequest 和 HttpServletResponse.并调用了重载的 service(HttpServletRequest, HttpServletResponse)
- 在 service(HttpServletRequest, HttpServletResponse) 获取了请求方式: request.getMethod(). 根据请求方式有创建了doXxx() 方法(xxx 为具体的请求方式, 比如 doGet, doPost)
@Override
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);
}
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
}
HttpServletRequest是 SerlvetRequest 的子接口. 针对于 HTTP 请求所定义. 里边包含了大量获取 HTTP 请求相关的方法.
ServletResponse: 封装了响应信息, 如果想给用户什么响应, 具体可以使用该接口的方法实现.
*getWriter(): 返回 PrintWriter 对象. 调用该对象的 print() 方法, 将把 print() 中的参数直接打印到客户的浏览器上.
设置响应的内容类型: response.setContentType(“application/msword”);
void sendRedirect(String location): 请求的重定向. (此方法为 HttpServletResponse 中定义.)
login应用
在 web.xml 文件中设置一个 WEB 应用的初始化参数user,和一个loginServlet的初始化参数 password.
定义一个 login.html, 里边定义两个请求字段: user, password. 发送请求到 loginServlet
在创建一个 LoginServlet, 在其中获取请求的 user, password. 比对其和 web.xml 文件中定义的请求参数是否一致
若一致, 响应 Hello:xxx, 若不一致, 响应 Sorry: xxx xxx 为 user.
<?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_2_5.xsd"
id="WebApp_ID" version="2.5">
<!-- 配置web 应用 的初始化参数-->
<context-param>
<param-name>cuser</param-name>
<param-value>root</param-value>
</context-param>
<servlet>
<servlet-name>LoginServlet</servlet-name>
<servlet-class>org.xst.servlet.LoginServlet</servlet-class>
<!-- 配置 Serlvet 的初始化参数。 且节点必须在 load-on-startup 节点的前面 -->
<init-param>
<param-name>ipassword</param-name>
<param-value>root</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>LoginServlet</servlet-name>
<url-pattern>/login</url-pattern>
</servlet-mapping>
</web-app>
public class LoginServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 获取xml 中loginServlet 的数据
String cuser = getServletContext().getInitParameter("cuser"); //获取web应用的初始化参数
String ipassword = getInitParameter("ipassword"); //获取servlet的初始化参数
// 获取页面的数据
String user = request.getParameter("user");
String password = request.getParameter("password");
if(cuser.equals(user) && ipassword.equals(password)){
System.out.println("hello:" + user);
}else{
System.out.println("sorry");
}
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>login</title>
</head>
<body>
<form action="/login" method="post">
user:<input type="text" name="user" value=""><br><br>
password:<input type="password" name="password" value=""><br><br>
<input type="submit" value="登陆">
</form>
</body>
</html>
http://localhost:8080/login.html
请求的转发和重定向区别
本质区别
请求的转发只发出了一次请求, 而重定向则发出了两次请求.
具体:
1. 地址栏
请求的转发: 地址栏是初次发出请求的地址.
请求的重定向: 地址栏不再是初次发出的请求地址. 地址栏为最后响应的那个地址
2. request对象
请求转发: 在最终的 Servlet 中, request 对象和中转的那个 request 是同一个对象.
请求的重定向: 在最终的 Servlet 中, request 对象和中转的那个 request 不是同一个对象.
3. 资源访问
请求的转发: 只能转发给当前 WEB 应用的的资源
请求的重定向: 可以重定向到任何资源.
4. /的意义
请求的转发: / 代表的是当前 WEB 应用的根目录
请求的重定向: / 代表的是当前 WEB 站点的根目录