1.Servlet简介
(1)Java Servlet是和平台无关的服务器端组件,它运行在Servlet容器中。Servlet容器负责Servlet和 客户的通信以及调用Servlet的方法,Servlet和客户的通信采用“请求/响应”的模式。
(2)Servlet可完成如下功能:创建并返回基于客户请求的动态HTML页面;创建可嵌入到现有HTML 页面中的部分HTML 页面(HTML 片段);与其它服务器资源(如数据库或基于Java的应用程序)进行通信。
2.Servlet的helloworld实现
首先,需要创建一个实现Servlet接口的实现类:public class HelloWorld implements Servlet
package com.zhaoliang.javaweb; import java.io.IOException; import javax.servlet.Servlet; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; /* * 如何创建Servlet? */ public class HelloServlet implements Servlet{ @Override public void destroy() { System.out.println("destroy"); } @Override public ServletConfig getServletConfig() { System.out.println("servlet config"); return null; } @Override public String getServletInfo() { System.out.println("servlet info"); 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 HelloServlet(){ System.out.println("HelloServlet's constructor"); } }
<pre name="code" class="html"><?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"> <!-- 配置Servlet --> <servlet> <!-- Servlet的注册名 --> <servlet-name>helloServlet</servlet-name> <!-- Servlet的全类名 --> <servlet-class>com.zhaoliang.javaweb.HelloServlet</servlet-class> </servlet> <!-- 映射Servlet --> <servlet-mapping> <!-- 与某一个Servlet的注册名一致 --> <servlet-name>helloServlet</servlet-name> <!-- 映射具体的访问路径:/代表当前项目的根目录 --> <url-pattern>/hello</url-pattern> </servlet-mapping> </web-app>这样我们就可以在服务上运行Servlet了。
注:
1.Servlet容器:运行Servlet,JSP,Filter等软件环境
1)可以用来创建Servlet,并调用Servlet相关生命周期方法
2)JSP,Filter,Listener,Tag......
2.Servlet的生命周期方法:以下方法都是由Servlet容器进行调用
1)构造器(constructor):只被调用一次。只有第一次请求Servlet时,创建Servlet实例,调用构造器。这说明Servlet是单实例的(存在线程安全问题,不应创建全局变量)
2)init:只被调用一次。创建好实例后立即被调用,用于初始化Servlet。
3)service:被多次调用。每次请求都会调用service方法。实际用于响应请求。
4)destroy:只被调用一次。当前Servlet所在的WEB应用被卸载前调用,用于释放当前Servlet所占用的资源。
5)Servlet方法调用的过程:
(1)Servlet引擎检查是否已经装载并创建了该Servlet的实例对象。如果是,则直接执行第④步,否则,执行第②步。
(2)装载并创建该Servlet的一个实例对象:调用该 Servlet 的构造器
(3)调用Servlet实例对象的init()方法。
(4)创建一个用于封装请求的ServletRequest对象和一个代表响应消息的ServletResponse对象,然后调用Servlet的service()方法并将请求和响应对象作为参数传递进去。
(5)WEB应用程序被停止或重新启动之前,Servlet引擎将卸载Servlet,并在卸载之前调用Servlet的destroy()方法。
3.load-on-startup参数
1)配置在<Servlet></Servlet>节点中
<servlet> <!-- Servlet的注册名 --> <servlet-name>helloServlet</servlet-name> <!-- Servlet的全类名 --> <servlet-class>com.zhaoliang.javaweb.HelloServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet>
4.<servlet-mapping></servlet-mapping>
1)同一个Servlet可以被映射到多个URL上,即多个<servlet-mapping>元素的<servlet-name>子元素的设置值可以是同一个Servlet的注册名。
2)在Servlet映射到的URL中也可以使用 * 通配符,但是只能有两种固定的格式:一种格式是“*.扩展名”,另一种格式是以正斜杠(/)开头并以“/*”结尾。
<!-- 映射Servlet --> <servlet-mapping> <!-- 与某一个Servlet的注册名一致 --> <servlet-name>helloServlet</servlet-name> <!-- 映射具体的访问路径:/代表当前项目的根目录 --> <url-pattern>/*</url-pattern> </servlet-mapping>或者
<!-- 映射Servlet --> <servlet-mapping> <!-- 与某一个Servlet的注册名一致 --> <servlet-name>helloServlet</servlet-name> <!-- 映射具体的访问路径:/代表当前项目的根目录 --> <url-pattern>*.html</url-pattern> </servlet-mapping>
1)配置Servlet初始化参数
<!-- 配置Servlet --> <servlet> <!-- Servlet的注册名 --> <servlet-name>helloServlet</servlet-name> <!-- Servlet的全类名 --> <servlet-class>com.zhaoliang.javaweb.HelloServlet</servlet-class> <!-- 配置Servlet初始化参数,该节点必须放在loa-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>1230</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet>
>getInitParameter(String name):返回String,获取指定参数名的初始化参数
>getInitParameterNames():返回
Enumeration
,返回参数名。
@Override public void init(ServletConfig arg0) throws ServletException { System.out.println("init"); String user = arg0.getInitParameter("user"); System.out.println("user:" + user); System.out.println("========"); Enumeration names = arg0.getInitParameterNames(); while(names.hasMoreElements()){ String name = (String) names.nextElement(); System.out.println("name:" + name); } String servletName = arg0.getServletName(); System.out.println("========"); System.out.println("servletname : " + servletName); }
3)ServletContext对象
(1)可以有 ServletConfig 的 getServletContext 方法获得
(2)该对象代表当前WEB应用,可以认为ServletContext是WEB应用的一个大管家,可以获取当前WEB应用的各个信息。
①获取当前WEB应用的初始化参数
首先,需要设置WEB应用的初始化参数(注意:<context-param>与<init-param>的区别:<context-param>是全局的初始化参数,所有的Servlet都可以访问获取,而<init-param>是局部的初始化参数,只有特定的(HelloServlet)可以获取
<!-- 配置当前WEB应用初始化参数(全局的,所有的Servlet都可以获取 --> <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///zhaoliang</param-value> </context-param>
>getInitParameter(String name):返回String,获取指定参数名的初始化参数
>getInitParameterNames():返回
Enumeration
,返回参数名。
@Override public void init(ServletConfig arg0) throws ServletException { System.out.println("init"); ServletContext servletContext = arg0.getServletContext(); String driver = servletContext.getInitParameter("driver"); System.out.println("driver : " + driver); System.out.println("============="); Enumeration<String> names = servletContext.getInitParameterNames(); while(names.hasMoreElements()){ String name = names.nextElement(); String value = servletContext.getInitParameter(name); System.out.println("name :" + name + "--> value : " + value); } }
②获取当前 WEB 应用的某一个文件在服务器上的绝对路径(必须是在webContent文件夹下),而不是部署前的路径
getRealPath(String path)
③获取当前 WEB 应用的名称
getContentPath()
getResourceAsStream(String path) : path / 相对于当前应用的根目录
⑤和Attribute相关的四个方法
getAttribute(String name) ,getAttributeNames(),removeAttribute(String name),setAttribute(String name,Object object)
@Override public void init(ServletConfig arg0) throws ServletException { System.out.println("init"); ServletContext servletContext = arg0.getServletContext(); String realPath = servletContext.getRealPath("hello.jsp"); System.out.println("realPath :" + realPath); String contextPath = servletContext.getContextPath(); System.out.println("contextPath :" + contextPath); InputStream is = servletContext.getResourceAsStream("/hello.jsp"); System.out.println("stream :" + is); }
3.GET 和POST
1.使用 GET 方式传递参数
1)在浏览器地址栏中输入某个URL地址或单击网页上的一个超链接时,浏览器发出的HTTP请求消息的请求方式为GET。
2)如果网页中的<form>表单元素的method属性被设置为了“GET”,浏览器提交这个FORM表单时生成的HTTP请求消息的请求方式也为GET。
3)使用GET请求方式给WEB服务器传递参数的格式:
http://www.lampbrother.net/counter.jsp?name=lc&password=123
4)使用GET方式传送的数据量一般限制在1KB以下。
2.使用 POST 方式传递参数
1)POST请求方式主要用于向WEB服务器端程序提交FORM表单中的数据。 form 表单的 method 设置为 POST
2)POST方式将各个表单字段元素及其数据作为HTTP消息的实体内容发送给WEB服务器,传送的数据量要比使用GET方式传送的数据量大得多。
3)POST请求消息的格式:
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
3.如何在Servlet中获取请求参数
1)Servlet的 service() 用于应答请求,每次请求都会调用 service() 方法
public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException
>ServletRequest:封装了请求信息,从中可以获取任何请求信息
>ServletResponse:封装了响应信息,如果想给用户什么响应,可以通过ServletResponse的相关方法实现。
这两个接口的实现类都是服务器给予实现的,并在服务器调用 service 方法时传入
2)ServletRequest:封装了请求信息,从中可以获取任何请求信息
(1)获取请求参数
>String getParameter(String name):根据请求参数的名字,返回参数值
>String[] getParameterValues(String name):根据请求参数名字,返回一组参数值(多选checkbox)
>Enumeration getParameterNames():类似于ServletConfig(ServletContext)的 getInitParameterNames()
>Map getParameterMap():返回请求参数的键/值对,键-->参数名 值-->String数组类型
页面信息(login.html)
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Insert title here</title> </head> <body> <form action="LoginServlet" method="post"> user:<input type="text" name="user"/> password:<input type="password" name="password"/> <br><br> interesting: <input type="checkbox" name="interesting" value="reading"/>reading <input type="checkbox" name="interesting" value="watchingTV"/>watchingTV <input type="checkbox" name="interesting" value="sport"/>sport <input type="checkbox" name="interesting" value="game"/>game <br><br> <input type="submit" value="submit"/> </form> </body> </html>Servlet信息(LoginServlet)
import java.io.IOException; import java.util.Arrays; import java.util.Enumeration; import java.util.Map; import java.util.Map.Entry; import javax.servlet.Servlet; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; public class LoginServlet implements Servlet { @Override public void destroy() { // TODO Auto-generated method stub } @Override public ServletConfig getServletConfig() { // TODO Auto-generated method stub return null; } @Override public String getServletInfo() { // TODO Auto-generated method stub return null; } @Override public void init(ServletConfig arg0) throws ServletException { // TODO Auto-generated method stub } @Override public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub System.out.println("请求来了..."); System.out.println(); String user = request.getParameter("user"); String password = request.getParameter("password"); System.out.println("!!!" + user + "," + password); System.out.println(); String[] interestings = request.getParameterValues("interesting"); for(String interest:interestings){ System.out.println("@@@" + interest); } System.out.println(); Enumeration<String> names = request.getParameterNames(); while(names.hasMoreElements()){ String name = names.nextElement(); String value = request.getParameter(name); System.out.println("###" + name + "," + value); } System.out.println(); Map<String,String[]> paraMap = request.getParameterMap(); for(Map.Entry<String, String[]> entry :paraMap.entrySet()){ System.out.println("$$$" + entry.getKey() + ":" + Arrays.asList(entry.getValue())); } } }
(2)HttpServletRequest:是ServletRequest的子接口,针对HTTP所定义,里面包含了大量获取HTTP请求信息的相关方法。
> HttpServletRequest httpServletRequest = (HttpServletRequest) request;
> getRequestURI():获取请求URL
> getMethod():获取请求方法
>getQueryString():获取GET请求 ? 后的字符串
>getServletPath():获取Servlet的映射路径
>和Attribute相关的方法:
3)ServletResponse:封装了响应信息,如果想给用户什么响应,可以通过ServletResponse的相关方法实现
(1)getWriter():返回 PrintWriter 对象,调用该对象的 print() 方法,将print()中的内容直接打印到客户的浏览器上。
(2)getContentType(String contentTypeNmae):设置响应内容类型
(3)getOutputStream():返回OutputStream对象,下载图片,word文档时可以用到
(4)void sendRedirect(String location):请求重定向。此方法为HttpServletResponse中定义(HttpServletResponse httpServletResponse = (HttpServletResponse) response;
综合练习:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Insert title here</title> </head> <body> <!-- 在web.xml文件中设置两个WEB应用初始化参数:user,password。 定义一个login.html,里边定义两个请求字段:user,password,发送请求到loginServlet 创建LoginServlet,在其中获取请求参数user,password,对比web.xml中的参数是否一致 若一致,输出hello XXX;若不一致,输出 sorry XXX --> <form action="loginServlet" method="post"> user:<input type="text" name="user"/> password:<input type="password" name="password"/> <input type="submit" value="submit"/> </form> </body> </html>
<?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"> <display-name>day_02</display-name> <context-param> <param-name>user</param-name> <param-value>Tom</param-value> </context-param> <context-param> <param-name>password</param-name> <param-value>123456</param-value> </context-param> <servlet> <servlet-name>loginServlet</servlet-name> <servlet-class>com.zhaoliang.servlet.LoginServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>loginServlet</servlet-name> <url-pattern>/loginServlet</url-pattern> </servlet-mapping> </web-app>
import java.io.IOException; import java.io.PrintWriter; import javax.servlet.Servlet; import javax.servlet.ServletConfig; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; public class LoginServlet implements Servlet { private ServletContext servletContext = null; @Override public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException { String userClient = request.getParameter("user"); String passwordClient = request.getParameter("password"); String userService = null; String passwordService = null; if(servletContext != null){ userService = servletContext.getInitParameter("user"); passwordService = servletContext.getInitParameter("password"); } PrintWriter printWriter = response.getWriter(); if(userService.equals(userClient) && passwordService.equals(passwordClient)){ printWriter.println("hello: " + userService); }else{ printWriter.println("sory: " + userClient); } } @Override public void destroy() { } @Override public ServletConfig getServletConfig() { return null; } @Override public String getServletInfo() { return null; } @Override public void init(ServletConfig servletConfig) throws ServletException { servletContext = servletConfig.getServletContext(); } }
4.GenericServlet
1)是一个Servlet,是Servlet接口和ServletConfig接口的实现类,但是一个抽象类,其中service方法为抽象方法
2)如果新建的Servlet程序直接继承GenericServlet,会使开发变得很简洁
3)具体实现
(1)在 GenericServlet 中,定义一个ServletConfig类型的对象,并在init(ServletConfig arg0)中为其初始化
(2)利用ServletConfig 成员变量的方法实现了ServletConfig接口的方法
(3)还定义了一个init()方法,在init(ServletConfig)方法中对其进行调用,子类可以直接覆盖init()方法,在其中实现对Servlet的初始化
(4)不建议直接覆盖init(ServletConfig),如果忘记编写super(ServletConfig),而且还用了ServletConfig接口方法,会出现空指针异常。
(5)init()不是Servlet的生命周期方法,而init(ServletConfig)才是生命周期方法
import java.io.IOException; import java.util.Enumeration; import javax.servlet.Servlet; import javax.servlet.ServletConfig; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; public abstract class MyGenericServlet 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(); } }
1)是一个Servlet,继承自GenericServlet,针对于HTTP协议定制
2)在service方法中直接把ServletRequest和ServletResponse转为HttpServletRequest和HttpServletResponse,并调用了重载的service(HttpServletRequest,HttpServletResponse)。在service(HttpServletRequest,HttpServletResponse)中获取了请求方式 request.getMethod(),根据请求方式创建了doXXX(xxx为具体的请求方式,比如GET,POST)方法。
3)实际开发中,直接继承HttpServlet,根据请求方式调用doXXX方法
4)直接有针性的覆盖doXXX方法,直接使用HttpServletRequest和HttpServletResponse对象不需要强转。
5)Servlet的关系图
import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import sun.awt.HToolkit; public class MyHttpServlet extends MyGenericServlet { @Override public void service(ServletRequest arg0, ServletResponse arg1) throws ServletException, IOException { HttpServletRequest request; HttpServletResponse response; try { request = (HttpServletRequest) arg0; response = (HttpServletResponse) arg1; } 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); } 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{ } }
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Insert title here</title> </head> <body> <!-- 在web.xml文件中设置两个WEB应用初始化参数:user,password。 定义一个login.html,里边定义两个请求字段:user,password,发送请求到loginServlet 创建LoginServlet,在其中获取请求参数user,password,对比web.xml中的参数是否一致 若一致,输出hello XXX;若不一致,输出 sorry XXX --> <form action="loginServlet" method="post"> user:<input type="text" name="user"/> password:<input type="password" name="password"/> <input type="submit" value="submit"/> </form> </body> </html>
<?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"> <display-name>day_02</display-name> <servlet> <servlet-name>loginServlet</servlet-name> <servlet-class>com.zhaoliang.servlet.LoginServlet3</servlet-class> </servlet> <servlet-mapping> <servlet-name>loginServlet</servlet-name> <url-pattern>/loginServlet</url-pattern> </servlet-mapping> </web-app>
import java.io.IOException; import java.io.PrintWriter; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.text.Format; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.xml.ws.Response; public class LoginServlet3 extends HttpServlet { /** * */ private static final long serialVersionUID = 1L; @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String username = req.getParameter("user"); String password = req.getParameter("password"); Connection connection = null; PreparedStatement ps = null; ResultSet rs = null; try { String sql = "select count(id) from test_users where name = ?" + "and password = ?"; Class.forName("com.mysql.jdbc.Driver"); String url = "jdbc:mysql:///zhaoliang"; String user = "root"; String password2 = "123456"; connection = DriverManager.getConnection(url, user, password2); ps = connection.prepareStatement(sql); ps.setString(1, username); ps.setString(2, password); rs = ps.executeQuery(); PrintWriter pWriter = resp.getWriter(); if(rs.next()){ int count = rs.getInt(1); pWriter.println(count); if(count > 0){ pWriter.println("hello : " + username); }else{ pWriter.println("sorry : " + username); } } } catch (Exception e) { e.printStackTrace(); }finally{ if(rs != null){ try { rs.close(); } catch (SQLException e) { e.printStackTrace(); } } if(ps != null){ try { ps.close(); } catch (SQLException e) { e.printStackTrace(); } } if(connection != null){ try { connection.close(); } catch (SQLException e) { e.printStackTrace(); } } } } }