Servlet技术及应用

Servlet技术及应用

实验预习内容

  1. Web页面中都可以使用哪些方式来发送HTTP请求?
    答:Web应用中可以使用GET,POST,HEAD,PUT,DELETE,CONNECT,OPTIONS,TRACE八种请求方式来发送HTTP请求。

  2. GET与POST两种请求方式有什么区别?分别适用于什么情况?
    答:(1)GET与POST两种请求方式的区别:

    (2)GET与POST两种请求方式所适用的情况:1) 在做数据查询时,建议用GET方式;而在做数据添加、修改或删除时,建议用POST方式。2) GET方式的安全性较POST方式要差些,包含机密信息时,建议用POST方式。如果仅考虑时间因素的话,GET方式的时间效率是要优于POST方式的。

  3. HTTP响应内容的类型都有哪些?如何设置HTTP响应内容的类型?
    答:(1)HTTP响应内容的类型一共分为五大类:
    在这里插入图片描述
    (2)通过设置响应头来设置HTTP响应内容的类型。

  4. 什么是ServletContext对象,它的生存周期如何?
    答:(1)ServletContext对象:ServletContext代表是一个Web应用的环境对象,内部封装了web应用的信息,一个web应用只有一个ServletContext对象,但是有多个Servlet对象。(2)ServletContext对象的生命周期:创建:服务器启动(该web应用加载到服务器中) 销毁:服务器关闭(web应用被卸载)

  5. ServletContext与ServletRequest的getRequestDispatcher()方法有什么区别?、
    答:ServletContext对象是应用级对象(application级),而ServletRequest是request级对象。(1)如果使用绝对路径(”/index.jsp”),那他们没有区别。(2)如果使用相对路径,则只有ServletRequest.getRequestDispatcher()方法可用,因为request对象本身包含当前请求的path。

实验内容与步骤

1.简单的综合应用,掌握Servlet将请求转发给另一个Servlet的方法。
【步骤1】创建一个名为input.html的HTML页面,其中包括一个表单,表单中包含两个文本域,分别供用户输入学号和姓名,该页面也包含提交和重置按钮。
【步骤2】 定义一个名为com.demo.Student类,其中包括学号sno和姓名name两个private的成员变量,定义访问和修改sno和name的方法。
【步骤3】编写名为FirstServlet的Servlet,要求当用户在input.html中输入信息后点击“提交”按钮,请求FirstServlet对其处理。在FirstServlet中使用表单提交的请求参数(学号和姓名)创建一个Student对象并将其作为属性存储在请求作用域中,然后通过请求对象的getRequestDispatcher()方法获得RequestDispatcher()对象,将请求转发到SecondServlet。
【步骤4】在SecondServlet中取出请求作用域中存储的Student对象,并显示输出该学生的学号和姓名,5秒钟之后,自动返回input.html页面。

在这里插入图片描述

  • input.html
<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>输入学生信息</title>
</head>
<body>
<form action="FirstServlet" method="post">
    学号<input type="text" name="sno" size="15" /><br>
    姓名<input type="text" name="sname" size="15"/><br>
    <input type="submit" value="登录" />
    <input type="reset" value="取消" />
</form>
</body>

</html>
  • Student
package com.demo;

public class Student {
    private String sno;
    private String name;
    public Student(String sno, String name) {
        // TODO Auto-generated constructor stub
        this.sno=sno;
        this.name=name;
    }
    public String getSno() {
        return sno;
    }
    public void setSno(String sno) {
        this.sno = sno;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }

}
  • FirstServlet
package com.demo;

import java.io.IOException;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/FirstServlet")
public class FirstServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request,
                          HttpServletResponse response)
            throws ServletException, IOException {
        String sno = request.getParameter("sno");
        String name = request.getParameter("sname");
        Student student = new Student(sno,name);
        request.setAttribute("student", student);
        RequestDispatcher rd = request.getRequestDispatcher("/SecondServlet");
        rd.forward(request, response);
    }
}
  • SecondServlet
package com.demo;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/SecondServlet")
public class SecondServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request,
                          HttpServletResponse response)
            throws ServletException, IOException {
        Student student= (Student)request.getAttribute("student");
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();
        out.println("<title>学生信息</title>");
        out.println("学号:"+student.getSno()+"<br>");
        out.println("姓名:"+new String(
                student.getName().getBytes("iso-8859-1"),"UTF-8")+"<br>");
        //out.println("<a href='input.html'>返回输入页面</a>");
        response.setHeader("Refresh","5;url=input.html");
    }
}

运行结果:
在这里插入图片描述
2.编写一个Servlet,显示所有请求头信息:
【步骤1】在exp01项目下编写一个名为ShowHeadersServlet.java的Servlet程序,使其能够检索所有的请求头,并且能够以表格的形式将请求头的参数名和参数值显示出来。
【步骤2】在浏览器地址栏中输入正确的URL,访问并测试该Servlet。

  • ShowHeadersServlet
package com.demo;

import java.io.PrintWriter;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;

@WebServlet(name = "ShowHeadersServlet", value = "/ShowHeadersServlet")
public class ShowHeadersServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html;charset=gb2312");
        PrintWriter out = response.getWriter();

        out.println("<html>");
        out.println("<head><title>All Headers</title>");
        out.println("</head>");
        out.println("<body bgcolor=\"#fdf5e6\">");
        out.println("<h1 align=\"center\">All Request Headers</h1>");
        out.println("<table border=1 align=\"center\">\n"+"<tr bgcolor=\"#ffad00\">\n"+"<th>Header Name<th>Header Value");
        Enumeration headerNames = request.getHeaderNames();
        while(headerNames.hasMoreElements()){
            String headerName = (String)headerNames.nextElement();
            out.println("<tr><td>"+headerName);
            out.println("<td>"+request.getHeader(headerName));
        }
        out.println("</table>\n</body></html>");
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request,response);
    }
}

在这里插入图片描述
3.编写一个名为ExcelServlet的Servlet程序,通过设置响应内容类型和输出流,向客户端浏览器响应一个带数据的Excel电子表格,程序的运行结果要求如下图所示。
在这里插入图片描述

  • ExcelServlet
package com.demo;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;
import java.io.PrintWriter;

@WebServlet(name = "ExcelServlet", value = "/ExcelServlet")
public class ExcelServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setHeader("Cache-Control","no-cache");
        response.setContentType("application/vnd.ms-excel;charset=utf-8");
        PrintWriter out = response.getWriter();
        out.println("<h3>Student information</h3>");
        out.println("学号\t姓名\t性别\t年龄\t所在系");
        out.println("95001\t李勇\t男\t20\t信息");
        out.println("95002\t刘晨\t女\t19\t数学");
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    }
}

4.使用ServletConfig检索Servlet的初始化参数。
【步骤1】编写ConfigDemoServlet程序,通过注释为其添加初始化参数email、telephone,在Servlet中读取该servlet的名称和初始化参数email、telephone,并将这两个参数的值在响应的HTML文本中输出。
【步骤3】在浏览器的地址栏中输入下面URL请求该Servlet:
http://localhost:8080/ exp01/configDemo.do
要求程序的运行结果如下图所示:
在这里插入图片描述

  • ConfigDemoServlet
package com.demo;
import java.io.*;
import javax.servlet.*;
import javax.servlet.annotation.*;
import javax.servlet.http.*;

@WebServlet(name="ConfigDemoServlet",
        urlPatterns = {"/configDemo.do"},
        initParams = {
                @WebInitParam(name = "email", value = "hacker@163.com"),
                @WebInitParam(name = "telephone", value = "8899123")
        })
public class ConfigDemoServlet extends HttpServlet{
    String servletName = null;
    ServletConfig config = null;
    String email = null;
    String telephone = null;
    private ServletContext servletContext;

    public void init(ServletConfig config) {
        this.config = config;
        servletName = config.getServletName();
        email = config.getInitParameter("email");
        telephone = config.getInitParameter("telephone");
    }
    public void doGet(HttpServletRequest request,
                      HttpServletResponse response)
            throws ServletException,IOException{
        response.setContentType("text/html;charset=UTF-8");

        //写入日志文件
        this.servletContext=config.getServletContext();
        String admin_email = servletContext.getInitParameter("admin-email");//利用名字获取值
        String admin_tel = servletContext.getInitParameter("admin-tel");//利用名字获取值
        servletContext.log(admin_email);
        servletContext.log(admin_tel);

        PrintWriter out = response.getWriter();
        out.println("<html><body>");
        out.println("<head><title>配置对象</title></head>");
        out.println("Servlet名称:"+servletName+"<br>");
        out.println("Email地址:"+email+"<br>");
        out.println("电话:"+telephone);
        out.println("</body></html>");

        out.println("<br><br>");
        out.println("web.xml文件中的初始化参数值admin-email: " + admin_email);
        out.println("<br>");
        out.println("web.xml文件中的初始化参数值admin-tel: " + admin_tel);
    }
}

运行截图:
在这里插入图片描述
5. 为ServletContext配置初始化参数并进行访问。
在web.xml文件中为当前web应用添加两个名为admin-email和admin-tel的ServletContext初始化参数,在ConfigDemoServlet中获取这两个参数的参数值,使用ServletContext对象将admin-email和admin-tel的参数值写入日志文件中,并查看日志文件。

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">

    <!-- 配置整个web应用的初始化参数 -->
    <context-param>
        <param-name>admin-email</param-name>
        <param-value>123456@qq.com</param-value>
    </context-param>

    <context-param>
        <param-name>admin-tel</param-name>
        <param-value>1234567890</param-value>
    </context-param>

</web-app>

运行截图:
在这里插入图片描述
6. 编写一个名为CountServlet的Servlet程序:
1)使用成员变量保存该Servlet被访问的次数,试打开多个浏览器窗口模拟多个用户同时访问该Servlet,观察该Servlet被访问次数的变化。
2)修改该Servlet,通过ServletContext属性保存被多用户同时访问的次数,体会用ServletContext在应用作用域共享数据的方法。

package com.demo;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Servlet implementation class countServlet1
 */
@WebServlet("/CountServlet")
public class CountServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    public CountServlet() {
        super();
        // TODO Auto-generated constructor stub
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //设置字符编码
        request.setCharacterEncoding("utf-8");
        response.setCharacterEncoding("utf-8");
        response.setContentType("text/html; charset=utf-8");


        //获取全局的共享数据
        ServletContext servletContext = this.getServletContext();

        //获取计数器count
        Integer count = (Integer) servletContext.getAttribute("count");

        //如果获取的计算器对象为空 ,说明是第一次访问,并将count,放入servletCount
        if( servletContext.getAttribute("count") == null) {
            count = 1;
            servletContext.setAttribute("count", count);
        }else {
            //否则就不是第一次访问,将登陆的计数器进行加1的数据更新
            servletContext.setAttribute("count", count+1);
        }

        //将登陆的次数显示在页面上
        PrintWriter out =response.getWriter();
        out.print("<!DOCTYPE html>\r\n" +
                "<html>\r\n" +
                "<head>\r\n" +
                "<meta charset=\"UTF-8\">\r\n" +
                "<title>登陆网页次数统计</title>\r\n" +
                "</head>\r\n" +
                "<body>");
        out.print("<h1>");
        out.print("count="+ servletContext.getAttribute("count"));
        out.print("<h1>");
        out.print("</body>\r\n" +
                "</html>");
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        doGet(request, response);
    }

}

运行截图:
在这里插入图片描述

思考题

  1. 请求中的参数如果是中文,如何正常显示中文参数值?
    答:对中文参数进行两次URLEncode,由于服务器会自动进行一次URLDecode,所以我们在服务端编程再进行一次URLDecode。
  2. 使用RequestDispatcher的forward()方法转发请求和使用HttpServletResponse的sendRedirect()方法重定向请求有什么区别?
    答:(1)RequestDispatcher.forward 方法只能将请求转发给同一个WEB应用中的组件;而HttpServletResponse.sendRedirect 方法不仅可以重定向到当前应用程序中的其他资源,还可以重定向到同一个站点上的其他应用程序中的资源,甚至是使用绝对URL重定向到其他站点的资源。(2)调用HttpServletResponse.sendRedirect 方法重定向的访问过程结束后,浏览器地址栏中显示的URL会发生改变,由初始的URL地址变成重定向的目标URL;而调用 RequestDispatcher.forward 方法的请求转发过程结束后,浏览器地址栏保持初始的URL地址不变。(3)HttpServletResponse.sendRedirect 方法对浏览器的请求直接作出响应,响应的结果就是告诉浏览器去重新发出对另外一个URL的访问请求。(4)RequestDispatcher.forward 方法的调用者与被调用者之间共享相同的request 对象和response 对象,它们属于同一个访问请求和响应过程;而HttpServletResponse.sendRedirect 方法调用者与被调用者使用各自的request 对象和response 对象,它们属于两个独立的访问请求和响应过程。(5)无论是RequestDispatcher.forward 方法,还是HttpServletResponse.sendRedirect 方法,在调用它们之前,都不能有内容已经被实际输出到了客户端。如果缓冲区中已经有了一些内容,这些内容将被从缓冲区中清除。
  3. 什么是Web归档文件?如何为一个Web应用创建一个WAR文件?如何发布WAR文件?
    答:(1)相当于 windows 下保存网页为 web档案(.mht)的功能,即把页面上所有元素(文字、格式、图片等)都保存在硬盘上的一个特殊文件里边方便离线查看和使用。(2)可以在命令行中运用jar命令。或者直接利用IDE工具进行打包。(3)方法一:直接将应用目录复制到%tomcat_home%\webapps目录下。方法二:在%tomcat_home%\conf下的server.xml的下增加<Context path=”/news”docBase=”C:\News”reloadable=”true”/>。方法三:在%tomcat_home%\conf\catalina\localhost\下创建news.xml,内容同上,文件名必须与path路径一致。方法四:在Tomcat Manager中发布:
    Context Path=/news
    xml configuration file URL:\conf\catalina\localhost
    WAR or Directory URL:C:\News
  4. 如何编写线程安全的Servlet?
    答:(1)变量的线程安全:这里的变量指字段和共享数据(如表单参数值)。(2)属性的线程安全。(3)使用同步的集合类。(4)不要在Servlet中创建自己的线程来完成某个功能。(5)在多个servlet中对外部对象(比方文件)进行修改操作一定要加锁,做到互斥的访问。(6)javax.servlet.SingleThreadModel接口是一个标识接口,如果一个Servlet实现了这个接口,那Servlet容器将保证在一个时刻仅有一个线程可以在给定的servlet实例的service方法中执行。将其他所有请求进行排队。
  • 6
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值