Servlet

概述:

Java Servlet 是运行在 Web 服务器或应用服务器上的程序,它是作为来自 Web 浏览器或其他 HTTP 客户端的请求和 HTTP 服务器上的数据库或应用程序之间的中间层。

使用 Servlet,您可以收集来自网页表单的用户输入,呈现来自数据库或者其他源的记录,还可以动态创建网页。

(Servlet可以理解为是实现了Servlet接口的类)

Servlet 在 Web 应用程序中的位置:

Servlet的任务:

  • 读取客户端(浏览器)发送的显式的数据。这包括网页上的 HTML 表单,或者也可以是来自 applet 或自定义的 HTTP 客户端程序的表单。
  • 读取客户端(浏览器)发送的隐式的 HTTP 请求数据。这包括 cookies、媒体类型和浏览器能理解的压缩格式等等。
  • 处理数据并生成结果。这个过程可能需要访问数据库,执行 RMI 或 CORBA 调用,调用 Web 服务,或者直接计算得出对应的响应。
  • 发送显式的数据(即文档)到客户端(浏览器)。该文档的格式可以是多种多样的,包括文本文件(HTML 或 XML)、二进制文件(GIF 图像)、Excel 等。
  • 发送隐式的 HTTP 响应到客户端(浏览器)。这包括告诉浏览器或其他客户端被返回的文档类型(例如 HTML),设置 cookies 和缓存参数,以及其他类似的任务。

Servlet的生命周期:

  • Servlet调用init()进行初始化;
  • Servlet调用service()处理客户端的请求(doGet()、doPost());
  • Servlet调用destroy()销毁;
  • 被JVM的垃圾回收器回收;

服务器会在启动时(load-on-startup为1)或第一次请求Servlet时(load-on-startup为0)初始化一个Servlet对象,然后这个Servlet对象会去处理所有客户端请求。服务器关闭才会销毁Servlet对象。无论请求多少次Servlet,只有一个Servlet实例。多个客户端并发请求时,服务器会启动多个线程分别执行该Servlet的service()。

一个简单的Servlet实例:

Servlet类:

package com.answer.vo;

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

public class HelloWorld extends HttpServlet {
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
        response.setCharacterEncoding("utf-8");
        response.setContentType("text/html");
        PrintWriter out=response.getWriter();
        out.print("<h1>666</h1>");
        out.flush();
        out.close();
    }
    public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {
        this.doGet(request, response);
    }
}

web.xml:

<servlet>
        <servlet-name>HelloWorld</servlet-name>
        <servlet-class>com.answer.vo.HelloWorld</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>HelloWorld</servlet-name>
        <url-pattern>/HelloWorld</url-pattern>
    </servlet-mapping>

以上也可一采用注解:

@WebServlet(name = "HelloWorld",urlPatterns = "/HelloWorld")

结果:

Servlet客户端Http请求:

客户端浏览器发出的请求被封装成一个HttpServletRequest对象。所有的信息包括请求的地址,请求的参数,提交的数据,上传的文件,客户端的IP地址都包含在这个对象中。

浏览器的头信息;

读取Http头的方法:

可通过HttpServletRequest对象;

序号方法 & 描述
1Cookie[] getCookies()
返回一个数组,包含客户端发送该请求的所有的 Cookie 对象。
2Enumeration getAttributeNames()
返回一个枚举,包含提供给该请求可用的属性名称。
3Enumeration getHeaderNames()
返回一个枚举,包含在该请求中包含的所有的头名。
4Enumeration getParameterNames()
返回一个 String 对象的枚举,包含在该请求中包含的参数的名称。
5HttpSession getSession()
返回与该请求关联的当前 session 会话,或者如果请求没有 session 会话,则创建一个。
6HttpSession getSession(boolean create)
返回与该请求关联的当前 HttpSession,或者如果没有当前会话,且创建是真的,则返回一个新的 session 会话。
7Locale getLocale()
基于 Accept-Language 头,返回客户端接受内容的首选的区域设置。
8Object getAttribute(String name)
以对象形式返回已命名属性的值,如果没有给定名称的属性存在,则返回 null。
9ServletInputStream getInputStream()
使用 ServletInputStream,以二进制数据形式检索请求的主体。
10String getAuthType()
返回用于保护 Servlet 的身份验证方案的名称,例如,"BASIC" 或 "SSL",如果JSP没有受到保护则返回 null。
11String getCharacterEncoding()
返回请求主体中使用的字符编码的名称。
12String getContentType()
返回请求主体的 MIME 类型,如果不知道类型则返回 null。
13String getContextPath()
返回指示请求上下文的请求 URI 部分。
14String getHeader(String name)
以字符串形式返回指定的请求头的值。
15String getMethod()
返回请求的 HTTP 方法的名称,例如,GET、POST 或 PUT。
16String getParameter(String name)
以字符串形式返回请求参数的值,或者如果参数不存在则返回 null。
17String getPathInfo()
当请求发出时,返回与客户端发送的 URL 相关的任何额外的路径信息。
18String getProtocol()
返回请求协议的名称和版本。
19String getQueryString()
返回包含在路径后的请求 URL 中的查询字符串。
20String getRemoteAddr()
返回发送请求的客户端的互联网协议(IP)地址。
21String getRemoteHost()
返回发送请求的客户端的完全限定名称。
22String getRemoteUser()
如果用户已通过身份验证,则返回发出请求的登录用户,或者如果用户未通过身份验证,则返回 null。
23String getRequestURI()
从协议名称直到 HTTP 请求的第一行的查询字符串中,返回该请求的 URL 的一部分。
24String getRequestedSessionId()
返回由客户端指定的 session 会话 ID。
25String getServletPath()
返回调用 JSP 的请求的 URL 的一部分。
26String[] getParameterValues(String name)
返回一个字符串对象的数组,包含所有给定的请求参数的值,如果参数不存在则返回 null。
27boolean isSecure()
返回一个布尔值,指示请求是否使用安全通道,如 HTTPS。
28int getContentLength()
以字节为单位返回请求主体的长度,并提供输入流,或者如果长度未知则返回 -1。
29int getIntHeader(String name)
返回指定的请求头的值为一个 int 值。
30int getServerPort()
返回接收到这个请求的端口号。

请求实例:

public class RequestServlet extends HttpServlet {
    private static final long serialVersionUID = -7936817351382556277L;

    /**
     * @param accept
     * @return 客户端浏览器接受的文件类型
     */
    private String getAccept(String accept){
        StringBuffer buffer = new StringBuffer();
        if(accept.contains("image/gif"))	buffer.append("GIF 文件, ");
        if(accept.contains("image/x-xbitmap"))	buffer.append("BMP 文件, ");
        if(accept.contains("image/jpeg"))	buffer.append("JPG 文件, ");
        if(accept.contains("application/vnd.ms-excel"))	buffer.append("Excel 文件, ");
        if(accept.contains("application/vnd.ms-powerpoint"))	buffer.append("PPT 文件, ");
        if(accept.contains("application/msword"))	buffer.append("Word 文件, ");
        return buffer.toString().replaceAll(", $", "");
    }
    /**
     * @param locale
     * @return 语言环境名称
     */
    private String getLocale(Locale locale) {
        if(Locale.SIMPLIFIED_CHINESE.equals(locale))	return "简体中文";
        if(Locale.TRADITIONAL_CHINESE.equals(locale))	return "繁体中文";
        if(Locale.ENGLISH.equals(locale))				return "英文";
        if(Locale.JAPANESE.equals(locale))				return "日文";
        return "未知语言环境";
    }


    /**
     * @param userAgent
     * @return 客户端浏览器信息
     */
    private String getNavigator(String userAgent) {
        if(userAgent.indexOf("TencentTraveler") > 0)	return "腾讯浏览器";
        if(userAgent.indexOf("Maxthon") > 0)	return "Maxthon浏览器";
        if(userAgent.indexOf("MyIE2") > 0)	return "MyIE2浏览器";
        if(userAgent.indexOf("Firefox") > 0)	return "Firefox浏览器";
        if(userAgent.indexOf("MSIE") > 0)	return "IE 浏览器";
        return "未知浏览器";
    }

    /**
     * @param userAgent
     * @return 客户端操作系统
     */
    private String getOS(String userAgent) {
        if(userAgent.indexOf("Windows NT 5.1") > 0)	return "Windows XP";
        if(userAgent.indexOf("Windows 98") > 0)	return "Windows 98";
        if(userAgent.indexOf("Windows NT 5.0") > 0)	return "Windows 2000";
        if(userAgent.indexOf("Linux") > 0)	return "Linux";
        if(userAgent.indexOf("Unix") > 0)	return "Unix";
        return "未知";
    }
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        request.setCharacterEncoding("UTF-8");
        response.setCharacterEncoding("UTF-8");

        response.setContentType("text/html");

        String authType = request.getAuthType();
        String localAddr = request.getLocalAddr();
        Locale locale = request.getLocale();
        String localName = request.getLocalName();
        String contextPath = request.getContextPath();
        int localPort = request.getLocalPort();
        String method = request.getMethod();
        String pathInfo = request.getPathInfo();
        String pathTranslated = request.getPathTranslated();
        String protocol = request.getProtocol();
        String queryString = request.getQueryString();
        String remoteAddr = request.getRemoteAddr();
        int port = request.getRemotePort();
        String remoteUser = request.getRemoteUser();
        String requestedSessionId = request.getRequestedSessionId();
        String requestURI = request.getRequestURI();
        StringBuffer requestURL = request.getRequestURL();
        String scheme = request.getScheme();
        String serverName = request.getServerName();
        int serverPort = request.getServerPort();
        String servletPath = request.getServletPath();
        Principal userPrincipal = request.getUserPrincipal();

        String accept = request.getHeader("accept");
        String referer = request.getHeader("referer");
        String userAgent = request.getHeader("user-agent");

        String serverInfo = this.getServletContext().getServerInfo();

        PrintWriter out = response.getWriter();
        out.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">");
        out.println("<HTML>");

        // 这里<title></title>之间的信息在浏览器中显示为标题
        out.println("  <HEAD><TITLE>Request Servlet</TITLE></HEAD>");
        out.println("  <style>body, font, td, div {font-size:12px; line-height:18px; }</style>");
        out.println("  <BODY>");

        out.println("<b>您的IP为</b> " + remoteAddr + "<b>,位于</b> " + "xxxx" + "<b>;您使用</b> " + getOS(userAgent) + " <b>操作系统</b>," + getNavigator(userAgent) + " <b>。您使用</b> " + getLocale(locale) + "。<br/>");
        out.println("<b>服务器IP为</b> " + localAddr + "<b>,位于</b> " + "xxxx" + "<b>;服务器使用</b> " + serverPort + " <b>端口,您的浏览器使用了</b> " + port + " <b>端口访问本网页。</b><br/>");
        out.println("<b>服务器软件为</b>:" + serverInfo + "。<b>服务器名称为</b> " + localName + "。<br/>");
        out.println("<b>您的浏览器接受</b> " + getAccept(accept) + "。<br/>");
        out.println("<b>您从</b> " + referer + " <b>访问到该页面。</b><br/>");
        out.println("<b>使用的协议为</b> " + protocol + "。<b>URL协议头</b> " + scheme + ",<b>服务器名称</b> " + serverName + ",<b>您访问的URI为</b> " + requestURI + "。<br/>" );
        out.println("<b>该 Servlet 路径为</b> " + servletPath + ",<b>该 Servlet 类名为</b> " + this.getClass().getName() + "。<br/>");
        out.println("<b>本应用程序在硬盘的根目录为</b> " + this.getServletContext().getRealPath("") + ",<b>网络相对路径为</b> " + contextPath + "。 <br/>");

        out.println("<br/>");

        out.println("<br/><br/><a href=" + requestURI + "> 点击刷新本页面 </a>");

        out.println("  </BODY>");
        out.println("</HTML>");
        out.flush();
        out.close();
    }
}

Servlet客户端Http响应:

服务器对客户端浏览器做出的响应被封装成一个HttpServletResponse对象,通过HttpServletResponse.getWriter()获得一个PrintWriter对象,可使用该对象输出信息。

从 Web 服务器端返回到浏览器的HTTP 1.1 响应报头;

设置Http响应报头的方法:

序号方法 & 描述
1String encodeRedirectURL(String url)
为 sendRedirect 方法中使用的指定的 URL 进行编码,或者如果编码不是必需的,则返回 URL 未改变。
2String encodeURL(String url)
对包含 session 会话 ID 的指定 URL 进行编码,或者如果编码不是必需的,则返回 URL 未改变。
3boolean containsHeader(String name)
返回一个布尔值,指示是否已经设置已命名的响应报头。
4boolean isCommitted()
返回一个布尔值,指示响应是否已经提交。
5void addCookie(Cookie cookie)
把指定的 cookie 添加到响应。
6void addDateHeader(String name, long date)
添加一个带有给定的名称和日期值的响应报头。
7void addHeader(String name, String value)
添加一个带有给定的名称和值的响应报头。
8void addIntHeader(String name, int value)
添加一个带有给定的名称和整数值的响应报头。
9void flushBuffer()
强制任何在缓冲区中的内容被写入到客户端。
10void reset()
清除缓冲区中存在的任何数据,包括状态码和头。
11void resetBuffer()
清除响应中基础缓冲区的内容,不清除状态码和头。
12void sendError(int sc)
使用指定的状态码发送错误响应到客户端,并清除缓冲区。
13void sendError(int sc, String msg)
使用指定的状态发送错误响应到客户端。
14void sendRedirect(String location)
使用指定的重定向位置 URL 发送临时重定向响应到客户端。
15void setBufferSize(int size)
为响应主体设置首选的缓冲区大小。
16void setCharacterEncoding(String charset)
设置被发送到客户端的响应的字符编码(MIME 字符集)例如,UTF-8。
17void setContentLength(int len)
设置在 HTTP Servlet 响应中的内容主体的长度,该方法设置 HTTP Content-Length 头。
18void setContentType(String type)
如果响应还未被提交,设置被发送到客户端的响应的内容类型。
19void setDateHeader(String name, long date)
设置一个带有给定的名称和日期值的响应报头。
20void setHeader(String name, String value)
设置一个带有给定的名称和值的响应报头。
21void setIntHeader(String name, int value)
设置一个带有给定的名称和整数值的响应报头。
22void setLocale(Locale loc)
如果响应还未被提交,设置响应的区域。
23void setStatus(int sc)
为该响应设置状态码。

响应实例:

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;

import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGImageEncoder;

public class IdentityServlet extends HttpServlet {
    private static final long serialVersionUID = -479885884254942306L;

    public static final char[] CHARS = { '2', '3', '4', '5', '6', '7', '8',
            '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M',
            'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' };

    public static Random random = new Random();

    public static String getRandomString() {
        StringBuffer buffer = new StringBuffer();
        for (int i = 0; i < 6; i++) {
            buffer.append(CHARS[random.nextInt(CHARS.length)]);
        }
        return buffer.toString();
    }

    public static Color getRandomColor() {
        return new Color(random.nextInt(255), random.nextInt(255), random
                .nextInt(255));
    }

    public static Color getReverseColor(Color c) {
        return new Color(255 - c.getRed(), 255 - c.getGreen(), 255 - c
                .getBlue());
    }

    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        response.setContentType("image/jpeg");

        String randomString = getRandomString();
        request.getSession(true).setAttribute("randomString", randomString);

        int width = 100;
        int height = 30;

        Color color = getRandomColor();
        Color reverse = getReverseColor(color);

        BufferedImage bi = new BufferedImage(width, height,
                BufferedImage.TYPE_INT_RGB);
        Graphics2D g = bi.createGraphics();
        g.setFont(new Font(Font.SANS_SERIF, Font.BOLD, 16));
        g.setColor(color);
        g.fillRect(0, 0, width, height);
        g.setColor(reverse);
        g.drawString(randomString, 18, 20);
        for (int i = 0, n = random.nextInt(100); i < n; i++) {
            g.drawRect(random.nextInt(width), random.nextInt(height), 1, 1);
        }

        // 转成JPEG格式
        ServletOutputStream out = response.getOutputStream();
        JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
        encoder.encode(bi);
        out.flush();
    }

    public static void main(String[] args) {
        System.out.println(getRandomString());
    }
}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script>
        function reloadImage() {
            document.getElementById("btn").disabled=true;
            document.getElementById("identity").src="/IdentityServlet?ts"
            +new Date().getTime();
        }
    </script>
</head>
<body>
    <img src="/IdentityServlet" id="identity" onload="btn.disabled=false"/>
    <input type="button" onclick="reloadImage()" value="换个图片" id="btn">
</body>
</html>

ServletContext对象:

  ServletContext是一个全局的储存信息的空间,服务器开始就存在,服务器关闭才释放。WEB容器在启动时,它会为每个Web应用程序都创建一个对应的ServletContext,它代表当前Web应用,并且它被所有客户端共享。由于一个WEB应用中的所有Servlet共享同一个ServletContext对象,因此Servlet对象之间可以通过ServletContext对象来实现通讯。ServletContext对象通常也被称之为context域对象。公共聊天室就会用到它。当web应用关闭、Tomcat关闭或者Web应用reload的时候,ServletContext对象会被销毁。

其ServletContext对象具有的属性:

添加属性:setAttribute(String name, Object obj);

得到值:getAttribute(String name),这个方法返回Object

删除属性:removeAttribute(String name)

ServletContext中的属性的生命周期从创建开始,到服务器关闭结束。

实例:

public class ServletContext1 extends HttpServlet {
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
        response.setContentType("text/html");
        response.setCharacterEncoding("utf-8");
        PrintWriter out=response.getWriter();
        ServletContext servletContext=this.getServletContext();
        servletContext.setAttribute("name","ans");
        out.println("将 name=小明  写入了ServletContext");
    }
}
public class ServletContext2 extends HttpServlet {
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
        response.setContentType("text/html");
        response.setCharacterEncoding("utf-8");
        PrintWriter out=response.getWriter();
        ServletContext servletContext=this.getServletContext();
        String name=(String) servletContext.getAttribute("name");
        out.println("name:"+name);
    }
}

粗看之下,这个运行结果和Session,Cookie的应用似乎没什么区别,但事实上则完全不一样的。只要不关闭Tomcat或者reload该应用,当我们关闭当前的浏览器,或者是换一个浏览器,比如从360浏览器换到了IE浏览器再次访问Servlet2,我们依然可以看到这个结果!这就是和Session,Cookie最大的不同了。之所以会造成这种不同,是因为ServletContext存在于服务器内存中的一个公共空间,它可以供所有的用户客户端访问。

Servlet之间的跳转:

转向(Forward):

转向是通过RequestDispatcher对象的forward(HttpServletRequest request, HttpServletResponse response)方法实现的。RequestDispatcher可以通过getRequestDispatcher()方法来获得。其主要是把请求转发到服务器上的另一个资源。

@WebServlet(name = "ForwardServlet",urlPatterns = "/ForwardServlet")
public class ForwardServlet extends HttpServlet {
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        String destination = request.getParameter("destination");
        // 跳转到 /WEB-INF/web.xml。通过地址栏输入网址是不能访问到该文件的,但是 forward 可以
        if("file".equals(destination)){
            RequestDispatcher dispatcher = request.getRequestDispatcher("/WEB-INF/web.xml");
            dispatcher.forward(request, response);
        }
        // 跳转到 /forward.jsp
        else if("jsp".equals(destination)){
            // 通过 setAttribute 方法传递一个 Date 对象给 JSP 页面
            Date date = new Date();
            request.setAttribute("date", date);
            RequestDispatcher dispatcher = request.getRequestDispatcher("/forward.jsp");
            dispatcher.forward(request, response);
        }
        // 跳转到另一个 Servlet
        else if("servlet".equals(destination)){
            RequestDispatcher dispatcher = request.getRequestDispatcher("/DatabaseAccess");
            dispatcher.forward(request, response);
        }
        else{
            response.setCharacterEncoding("UTF-8");
            response.setContentType("text/html; charset=UTF-8");
            response.getWriter().println("缺少参数。用法:" + request.getRequestURL() + "?destination=jsp 或者 file 或者 servlet ");
        }

    }
    public void doPut(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        this.doGet(request, response);
    }
}

重定向(Redirect):

重定向是利用服务器的返回的状态码来实现的。重定向请求到另一个网页的最简单的方式是使用 response 对象的 sendRedirect() 方法。

response.sendRedirect("https://www.baidu.com");

该方法把响应连同状态码和新的网页位置发送回浏览器。也可以通过把 setStatus() 和 setHeader() 方法一起使用来达到同样的效果:

String site = "http://www.baidu.com" ;
response.setStatus(response.SC_MOVED_TEMPORARILY);
response.setHeader("Location", site); 

 

Servlet数据库访问(MySQL):

public class DatabaseAccess extends HttpServlet {
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
        response.setContentType("text/html");
        response.setCharacterEncoding("utf-8");
        PrintWriter out = response.getWriter();
        String title = "数据库结果";
        out.println("<html>\n" +
                "<head><title>" + title + "</title></head>\n" +
                "<body bgcolor=\"#f0f0f0\">\n" +
                "<h1 align=\"center\">" + title + "</h1>\n");
        try{
            Class.forName("com.mysql.jdbc.Driver");
            Connection connection= DriverManager.getConnection("jdbc:mysql://localhost:3306/bz?useUnicode=true&characterEncoding=utf-8",
                    "root","root");
            String sql="select * from user1";
            PreparedStatement ppst=connection.prepareStatement(sql);
            ResultSet rst=ppst.executeQuery();
            while(rst.next()){
                int id  = rst.getInt("id");
                String name = rst.getString("name");
                String pwd = rst.getString("password");


                // 输出数据
                out.println("ID: " + id + "<br>");
                out.println("Name: " + name + "<br>");
                out.println("Password: " + pwd + "<br>");
                out.println("</body></html>");

            }
            rst.close();
            ppst.close();
            connection.close();
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Dream答案

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值