Web 开发和部署一个 Servlet 基本流程




Servlet 的开发步骤:

开发一个类,继承 HttpServlet, 重写 doGet 方法
在 web.xml中,去配置这个 Servlet
部署到 Tomcat 容器中
启动 Tomcat
打开浏览器,发送请求,查看响应




整个工程结构如下:


web-servlet-01-hello
├── pom.xml
└── src
    ├── main
    │   ├── java
    │   │   └── com
    │   │       └── guyu
    │   │           └── servlet01
    │   │               └── servlet
    │   │                   └── HelloServlet.java
    │   ├── resources
    │   └── webapp
    │       ├── WEB-INF
    │       │   └── web.xml
    │       └── index.jsp
	└── test
		 └──  java
		 

  • 项目工程模板 【mavenWebProject】链接:

    链接:https://pan.baidu.com/s/12YVZQr0pH-gi-mVI35c9Dg
    提取码:58b1


各目录的作用:

	pom.xml:用于管理源代码、配置文件、项目授权、项目的依赖关系等等
	src:主要用来存放我们的 Java 代码
	webapp:主要用来存放需要发布的应用文件,包括页面,配置文件等
	WEB-INF:存放一些管理类,配置文件等
	web.xml: 项目的配置文件
	index.jsp: 默认的首页面
	test: 测试类代码



利用 tomcat7-maven-plugin 插件运行如下图所示:

故屿





在浏览器输入 http://localhost:10086/hs 如下图所示:

故屿

浏览器输入 http://localhost:10086/hs/hello 如下图所示:

故屿



就这样,Web 开发和部署一个 Servlet 实例是不是很简单呀,源代码如下:





pom.xml 代码如下:


<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.guyu</groupId>
    <artifactId>Servlet-01</artifactId>
    <packaging>war</packaging>
    <version>1.0-SNAPSHOT</version>

    <name>Maven Web Project and Servlet-01</name>
    <url>https://www.cnblogs.com/guyu-</url>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>

    <dependencies>
        <!--provided-->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>javax.servlet.jsp</groupId>
            <artifactId>jsp-api</artifactId>
            <version>2.2</version>
            <scope>provided</scope>
        </dependency>
        
        <!--runtime-->
        <dependency>
            <groupId>jstl</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
            <scope>runtime</scope>
        </dependency>
        
        <!--test-->
		<dependency>
		    <groupId>junit</groupId>
		    <artifactId>junit</artifactId>
		    <version>4.12</version>
		    <scope>test</scope>
		</dependency>

    </dependencies>

    <build>        
        <plugins>
            <plugin>
                <groupId>org.apache.tomcat.maven</groupId>
                <artifactId>tomcat7-maven-plugin</artifactId>
                <version>2.2</version>
                <configuration>
                    <!-- 内置Tomcat插件端口,只适合开发环境,不适合产品环境 -->
                    <port>10086</port>
                    <!-- 应用名 -->
                    <path>/hs</path>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-dependency-plugin</artifactId>
                <version>2.10</version>
            </plugin>
        </plugins>
    </build>
</project>

					注:内置 tomcat 端口号 10086 和 应用名 /hs 可自行更改配置.本实例都以此配置



webapp/index.jsp 代码如下:


<%@ page pageEncoding="UTF-8" contentType="text/html;charset=UTF-8" %>
<html>
<body>
<h2 align="center">你好 maven web 项目!</h2>
</body>
</html>




webapp/WEB-INF/web.xml 代码如下:


<?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_3_0.xsd" id="WebApp_ID" version="3.0">

    <!-- listener -->

    <!-- filter -->

    <!-- servlet -->

	 <!-- 基于xml配置,八行代码-->
    <servlet>
        <!--自定义,一般为类名-->
        <servlet-name>helloservlet</servlet-name>
        <!--一定是package + .类名-->
        <servlet-class>com.guyu.servlet01.servlet.HelloServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <!--给Servlet提供(映射)一个可供客户端访问的URL-->
        <servlet-name>helloservlet</servlet-name>
        <!-- servlet的映射路径 -->
        <url-pattern>/hello</url-pattern>
    </servlet-mapping>
</web-app>




servlet01\servlet\HelloServlet.javal 代码如下:


package com.guyu.servlet01.servlet;

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

/**
 * @Author: Fred
 * @Date: 2020/10/13 11:23
 * @description 第一个 Servlet 实例
 */
public class HelloServlet extends HttpServlet {

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //0. 设置响应头
        resp.setContentType("text/html;charset=utf-8");
        //1. 通过response对象来获取对浏览器端的输出流
        PrintWriter pw = resp.getWriter();
        //2. 调用方法输出
        pw.println("<html>");
        pw.println("<head>");
        pw.println("<title>hello,servlet</title>");
        pw.println("</head>");
        pw.println("<body>");
       pw.println("<h2 align=\"center\">你好,故屿!</h2>");
        pw.println("<p align=\"center\">当前系统时间:"+new Date()+"</p>");
        pw.println("</body>");
        //3.释放资源
        pw.close();
    }
}



注:
此实例只对初学者,上述代码可通过在 HelloServlet.java 类中加 @WebServlet(urlPatterns = “/hello”) 注解代替 web.xml 八行代码。
另外可使用 JSP 指令、标签和 HTML 的综合体开发更简便。
针对 Servlet 配置的初始化参数,支持xml和注解两种配置。







以下加强实例 [8]







Servlet 从创建到销毁的过程

  • init()
    Servlet 通过调用 init () 方法进行初始化
  • service()
    Servlet 调用 service() 方法来处理客户端的请求
  • destroy()
    Servlet 通过调用 destroy() 方法终止(结束)

最后,Servlet 是由 JVM 的垃圾回收器进行垃圾回收的。



如下代码:


package com.guyu.servlet01.servlet;

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

/**
 * @Author: Fred
 * @Date: 2020/10/13 16:03
 */

//若使用了 load-on-startup 则根据 load-on-startup=1 的值来先后创建这些 Servlet,并直接调用它们的init方法,发送请求后才会调用service()方法
@WebServlet(urlPatterns = "/life")
//@WebServlet(urlPatterns = "/life",loadOnStartup = 1)
public class LifeCycleServlet extends HttpServlet {

    private int count = 0;

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp)
                                            throws ServletException, IOException {
        resp.setContentType("text/html;charset=utf-8");
        PrintWriter pw = resp.getWriter();
        //
        count++;
        //
        pw.println("<h2 align=\"center\">每次请求都会调用1次service方法,共计:"+count+"次</h2>");
        System.out.println("--- LifeCycleServlet的service()方法被调用了 --> "+count+"次");
        //
        pw.close();
    }

    /*********************
     * 此方法也只会执行1次,它的执行时机:
     *  当此Servlet被摧毁卸载时或应用被容器给停掉[undeploy] 或 容器 shutdown 时
     *  需 startup 启动 Tomcat,发送localhost:9090 登录容器选择 undeploy 即可响应
     */
    @Override
    public void destroy() {
        System.out.println("-- LifeCycleServlet的destroy()方法被调用了...");
    }

    /*********************
     * 此方法是在容器创建完Servlet实例后,就被调用,只调用1次。
     * @throws ServletException
     */
    @Override
    public void init() throws ServletException {
        System.out.println("--- LifeCycleServlet的init()方法被调用了....");
        System.out.println("--- 请等待五秒....");
        //模拟这个过程需5秒....
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}









此实例演示初始化参数: 向浏览器端发送请求,响应信息实时地写入到创建本地文件中


  • servlet02\servlet\InitParamServlet .javal 代码如下:

package com.guyu.servlet02.servlet;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebInitParam;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;

/**
 * @Author: Fred
 *  * @Date: 2020/10/14 15:12
 */
@WebServlet(urlPatterns = {"/init/param"},
        initParams = {
            @WebInitParam(name="flag",value = "true"),
            @WebInitParam(name="dir", value = "D:\\temp\\count.txt")
        })
public class InitParamServlet extends HttpServlet {

    private int count = 0;

    @Override
    public void doGet(HttpServletRequest req, HttpServletResponse resp)
                                        throws ServletException, IOException {
        //获取当前servlet初始化参数
        ServletConfig servletConfig = getServletConfig();
        String flag = servletConfig.getInitParameter("flag");
        String dir = servletConfig.getInitParameter("dir");
        //获取全局初始化参数
        String global = getServletContext().getInitParameter("global");

        //
        count++;
        //
        if(Boolean.parseBoolean(flag)) {
            //把这个计数器中的值实时地写入到文件中
            File file = new File(dir);
            if(!file.exists()) {
                file.createNewFile();
            }
            //输入
            PrintWriter out = new PrintWriter(new FileWriter(file,true), true);
            out.println("当前访问的次数:"+count+"\n"+new Date());
            //关闭
            out.close();

            //再往浏览器端写信息
            resp.setContentType("text/html;charset=utf-8");
            PrintWriter pw = resp.getWriter();
            pw.println("<h2 align=\"center\">访问次数:"+count+"</h2>");
            pw.println("<h3 align=\"center\">"+global+"</h3>");
            pw.close();
        }
    }
}



  • webapp/WEB-INF/web.xml 代码中 全局初始化参数配置 如下:

<?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_3_0.xsd" id="WebApp_ID" version="3.0">

    <!-- listener -->

    <!-- filter -->

    <!-- servlet -->

    <!-- 全局初始化参数-->
    <context-param>
        <param-name>global</param-name>
        <param-value>hello,context param  and guyu</param-value>
    </context-param>
    
    <!-- 第一个 servlet 实例-->
    <servlet>
        <!--自定义,一般为类名-->
        <servlet-name>helloservlet</servlet-name>
        <!--一定是package + .类名-->
        <servlet-class>com.guyu.servlet01.servlet.HelloServlet</servlet-class>
<!--        <load-on-startup>1</load-on-startup>-->

<!--        基于xml配置,为了简单快捷推荐使用基于注解的配置-->
<!--        <init-param>-->
<!--            <param-name>path</param-name>-->
<!--            <param-value>d:/temp</param-value>-->
<!--        </init-param>-->
<!--        <init-param>-->
<!--            <param-name>name</param-name>-->
<!--            <param-value>故屿</param-value>-->
<!--        </init-param>-->

    </servlet>
    <servlet-mapping>
        <!--给Servlet提供(映射)一个可供客户端访问的URL-->
        <servlet-name>helloservlet</servlet-name>
        <!-- servlet的映射路径 -->
        <url-pattern>/hello</url-pattern>
    </servlet-mapping>

    <!-- 第二个 servlet 实例-->
    <servlet>
        <servlet-name>showservlet</servlet-name>
        <servlet-class>com.guyu.servlet01.servlet.ShowServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>showservlet</servlet-name>
        <url-pattern>/show</url-pattern>
    </servlet-mapping>

</web-app>



  • 运行后在浏览器输入 http://localhost:10086/hs/init/param 刷新三次如下图所示:

故屿



  • 在本地 D:\temp\count.txt 文件中看查看响应信息

故屿






此实例演示有关Servlet 的 url-pattern 的模糊匹配模式


  • servlet02\servlet\UrlPatternServlet.javal 代码如下:

package com.guyu.servlet02.servlet;


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

/**
 * @Author: Fred
 * @Date: 2020/10/14 16:12
 *
 *  此案例演示 url-pattern的模糊匹配
 */
//@WebServlet(urlPatterns = "/demo/*")
    @WebServlet(urlPatterns = "*.haha")
public class UrlPatternServlet extends HttpServlet {

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp)
                                            throws ServletException, IOException {
        //通过以下几个方法,让大家理解url的涵义
        //http://host:port/appName/resource?queryString
        //http://192.168.0.34:9090/crm/user/query?id=1

        String host = req.getRemoteHost();

        int port = req.getServerPort();

        //获取应用名
        String appName = req.getContextPath();

        //获取servlet的url-pattern
        String servletPath = req.getServletPath();

        //获取除 servlet path以外的其它路径中的信息
        String pathInfo = req.getPathInfo();

        //获取queryString
        String queryString = req.getQueryString();

        //输出以上信息
        resp.setContentType("text/html;charset=utf-8");
        PrintWriter pw = resp.getWriter();
        //
        pw.print("<p align=\"center\">主机名:"+host+"</p>");
        pw.print("<p align=\"center\">服务端口:"+port+"</p>");
        pw.print("<p align=\"center\">应用名:"+appName+"</p>");
        pw.print("<p align=\"center\">servlet-path:"+servletPath+"</p>");
        pw.print("<p align=\"center\">pathInfo:"+pathInfo+"</p>");
        pw.print("<p align=\"center\">queryString:"+queryString+"</p>");
        pw.close();
    }
}



  • 运行后在浏览器输入 http://127.0.0.1:10086/hs/demo/update?guyu 如下图所示:

故屿

	注意:以上使用注解@WebServlet(urlPatterns = "/demo/*")
		  以下使用注解@WebServlet(urlPatterns = "*.haha")

  • 运行后在浏览器输入http://127.0.0.1:10086/hs/demo/update.haha?guyu 如下图所示:

故屿



以上关于模糊匹配 这个*号对应的路径,可以通过 getPathInfo 来获取,从而判断具本的请求操作






此实例演示表单如何获取请求参数


  • servlet02\servlet\FormParameterServlet.javal 代码如下:

package com.guyu.servlet02.servlet;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Arrays;

/**
 * @Author: Fred
 * @Date: 2020-10-15 10:19:00
 *
 *  此案例演示如何获取请求参数
 */
@WebServlet(urlPatterns = "/param/form", name = "formServlet")
public class FormParameterServlet extends HttpServlet {

    @Override
    public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //设置请求体部和响应体部的编码,需为 post 请求【不是头部】
        req.setCharacterEncoding("utf-8");
        resp.setCharacterEncoding("utf-8");

        //获取请求参数,通过 getParameter 和 getParameterValues 方法
        String username = req.getParameter("username");
        String pwd = req.getParameter("pwd");
        String pwd2 = req.getParameter("pwd2");
        String age = req.getParameter("age");
        String sex = req.getParameter("sex");
        String email = req.getParameter("email");
        String birth = req.getParameter("birth");
        //针对复选框,调用多个值的方法
        String[] hobbies = req.getParameterValues("hobby");
        //获取文件
        String icon = req.getParameter("icon");
        //获取隐藏域
        String special = req.getParameter("special");
        //获取多行文本框
        String intro = req.getParameter("intro");
        //获取单选下拉框的值
        String degree = req.getParameter("degree");

        //输出以上信息
        resp.setContentType("text/html;charset=utf-8");
        PrintWriter pw = resp.getWriter();

        pw.print("<h2 align=\"center\">请求的数据已全部收到,请查看后台控制台</h2>");
        pw.close();

        //下面,在控制台中输出以上的变量
        System.out.printf("UserName: %s\n",username);
        System.out.printf("Pwd: %s \n", pwd);
        System.out.printf("Pwd2: %s \n", pwd2);
        System.out.printf("Age: %s \n", age);
        System.out.printf("Sex: %s \n", sex);
        System.out.printf("Email: %s \n", email);
        System.out.printf("Birth: %s \n", birth);
        //复选框:
        if(hobbies != null) {
            System.out.printf("爱好:%s\n", Arrays.toString(hobbies));
        }
        //
        System.out.printf("Icon: %s \n", icon);
        System.out.printf("Special: %s \n", special);
        System.out.printf("Intro: %s \n", intro);
        System.out.printf("Degree: %s \n", degree);
    }

    @Override
    public void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        //ctrl+o 重写doPost方法,返回doGet
        doGet(req, resp);
    }
}



  • webapp/html/form.html 代码中 表单元素 如下:

<!DOCTYPE html>
<html>
<head>
	<title>表单案例</title>
	<meta charset="utf-8">
</head>
<body>
<h2 align="center">表单元素</h2>
<hr size="10" noshade="noshade">
<h3 align="center">以下是一个多种不同类型的表单域</h3>

<!-- post请求,提交表单数据响应控制台返回值全为 null -->
<form action="/hs/param/form" name="xxForm" method="post"
	  enctype="multipart/form-data">

<!-- 提交表单数据响应控制台返回数据值,该 enctype 为默认值可不写,这种情况下,method 可以是 get或post,注未配置get编码 -->
<!--<form action="/hs/param/form" name="xxForm" method="post">-->
<!--			enctype="application/x-www-form-urlencoded">-->

	<br>

    <p align="center"><input type="text" name="username" placeholder="用户名"></p>
    <p align="center"><input type="password" name="pwd" placeholder="密码"></p>
    <p align="center"><input type="password" name="pwd2" placeholder="请确认密码"></p>
    <p align="center"><input type="number" name="age" placeholder="你的年龄">
	
    <p align="center">
    <input type="radio" name="sex" value="1" checked><input type="radio" name="sex" value="0"></p>

    <p align="center"><input type="email" name="email" placeholder="你的邮箱"></p>
    <p align="center"><input type="date" name="birth" placeholder="你的生日"></p>

    <p align="center">
    <input type="checkbox" name="hobby" value="编程">编程
	<input type="checkbox" name="hobby" value="电影">电影
	<input type="checkbox" name="hobby" value="小说">小说
	<input type="checkbox" name="hobby" value="游戏">游戏
	</p>

    <p align="center">请选择头像:<input type="file" name="icon" accept="image/png"></p>
	<!-- 表单的隐藏域,在页面上是不显示的 -->
    <input type="hidden" name="special" value="100">
	
	<!-- 多行文本框 -->
	<p align="center">
	<textarea cols="13" cols="37" name="intro" placeholder="自我介绍"></textarea>
	</p>

	<!-- 下拉选择框 -->
    <p align="center">
    <select name="degree">
    	<option value="novalue" selected>=请选择=</option>
		<option value="本科">本科</option>
		<option value="专科">专科</option>
		<option value="硕士">硕士</option>
		<option value="博士">博士</option>
		<option value="高中">高中</option>
		<option value="中专">中专</option>
		<option value="其它">其它</option>
	</select>
	</p>

    <p align="center">
    <input type="button" value="普通按钮">
	<input type="submit" value="提交表单">
	<input type="reset" value="重置表单"> 
	</p>

</form>

<!-- 待上面的HTML文档加载完成后,再来导入js -->
<script type="text/javascript" src="js/form_demo.js"></script>
</body>
</html>




  • 以 enctype 属性是 “multipart/form-data”

运行后在浏览器先输入 http://localhost:10086/hs/html/form.html 如下图所示:

故屿

  • 输入填写表单数据后 提交表单 此时已自动跳转 http://localhost:10086/hs/param/form 如下图所示:

故屿



  • 在控制台中输出的数据变量 如下图所示:

故屿







  • 以 enctype 属性是 “application/x-www-form-urlencoded”

      	运行后在浏览器先输入 http://localhost:10086/hs/html/form.html 
      	输入填写表单数据后 提交表单 此时已自动跳转 http://localhost:10086/hs/param/form 
    


  • 在控制台中输出的数据变量 如下图所示:

故屿





获取请求参数时需要注意的事项:

	不同的表单类型,在后台需要使用不同的方法来获取表单数据
	
	其中,如果<form> 的enctype属性是:

		enctype="multipart/form-data" 时,method必需是 post,  则后台需要通过 
					request.getPart() 或 request.getParts()   来获取表单数据。
	
		enctype="application/x-www-form-urlencoded" 这个值是默认值,这种情况下,method可以是 get或post, 后台则通过 
					request.getParameter() 或 request.getParameterValues() 来获取表单数据。	
					
	注:只要不做文件上传,则enctype就使用默认值。





此实例演示 Servlet 每隔 1 秒显示当前系统时间


  • servlet02\servlet\RefreshServlet .javal 代码如下:

package com.guyu.servlet02.servlet;

import java.io.IOException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

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

/**
 * @Author: Fred
 * @Date: 2020/10/15 17:24
 *
 *  扩展 HttpServlet 类,刷新自动加载时间设置显示
 */

@WebServlet(urlPatterns = "/Refresh")
public class RefreshServlet extends HttpServlet {

    // 处理 GET 方法请求的方法
    public void doGet(HttpServletRequest request,
                      HttpServletResponse response)
            throws ServletException, IOException
    {
        // 设置刷新自动加载时间为 1 秒
        response.setIntHeader("Refresh", 1);
        // 设置响应内容类型
        response.setContentType("text/html;charset=UTF-8");

        //使用默认时区和语言环境获得一个日历
        Calendar cale = Calendar.getInstance();
        //将Calendar类型转换成Date类型
        Date tasktime=cale.getTime();
        //设置日期输出的格式
        SimpleDateFormat df=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss E a");
        //格式化输出
        String nowTime = df.format(tasktime);
        PrintWriter out = response.getWriter();
        String title = "自动刷新 Header 设置 - 1秒一次";
        String docType =
                "<!DOCTYPE html>\n";
        out.println(docType +
                "<html>\n" +
                "<head><title>" + title + "</title></head>\n"+
                "<body bgcolor=\"#BFEFFF\">\n" +
                "<h1 align=\"center\">" + title + "</h1>\n" + "<br>" +
                "<font color=\"#FF0000\">\n" +
                "<h4 align=\"center\" >当前时间是:" + nowTime + "</p>\n");
    }
    // 处理 POST 方法请求的方法
    public void doPost(HttpServletRequest request,
                       HttpServletResponse response)
            throws ServletException, IOException {
        doGet(request, response);
    }
}


  • 运行后在浏览器输入 http://localhost:10086/hs/Refresh 如下图所示:

故屿






本案例演示请求的跳转


  • servlet02\servlet\JumpServlet.javal 代码如下:

package com.guyu.servlet02.servlet;

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;
import java.io.IOException;

/**
 * @Author: Fred
 * @Date: 2020/10/16 10:19
 *
 * 本案例演示请求的跳转
 */
@WebServlet(urlPatterns = "/jump/*",name = "jumpServlet")
public class JumpServlet extends HttpServlet {

    @Override
    public void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        String pathinfo = req.getPathInfo();
        if(pathinfo != null) {
            //进一步判断这个值
            if(pathinfo.equals("/one")) {
                //执行 one 操作
                System.out.println("即将跳转到 /init/param中...");
                //浏览器请求跳转到 /init/param 后,控制台响应显示输出信息
                jump("/init/param",req, resp);
                //可写可不写
                return ;
            } else if(pathinfo.equals("/two")) {
                //执行 two 操作时 请求http://localhost:10086/hs/jump/two
                // 直接把 one 修改 two 时为出现后台无响应信息,需路径整串重新请求
                System.out.println("即将跳转到 /html/form.html中...");

//                System.out.println("即将跳转到 /WEB-INF/jsp/hello.jsp...");


                //跳转静态资源
                jump("/html/form.html",req, resp);

                //跳转 webapp/WEB-INF 被容器给保护的资源
                //jump("/WEB-INF/jsp/hello.jsp", req, resp);

                //可写可不写
                return ;
            } else {
                //说明用户写的资源,我们没有 此访问 http://localhost:10086/hs/jump/*
                resp.sendError(HttpServletResponse.SC_NOT_ACCEPTABLE, "406... 不接受此请求,请重新输入指定 /* 的值!");
                //执行 /* 操作
                //System.out.println("请重新输入指定 /* 的值!");
                //return ;
            }
        }
    }

    /*****
     * 跳转方法
     * @param target
     * @param req
     * @param resp
     */
    private void jump(String target, HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        //1.获取 RequestDispatcher对象
//        RequestDispatcher dispatcher = req.getRequestDispatcher(target);
        RequestDispatcher dispatcher = getServletContext().getRequestDispatcher(target);
        //2. 直接转发
        dispatcher.forward(req, resp);
    }
}


  • webapp/WEB-INF/jsp/hello.jsp 此目录下代码必需要通过 Servlet 跳转如下:
<%--
  Created by IntelliJ IDEA.
  User: Administrator
  Date: 2020/10/16
  Time: 10:28
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>jsp</title>
</head>
<body>
    <h1 align="center">恭喜你,跳进来了  故屿!</h1>
</body>
</html>



  • 运行后在浏览器请求输入 http://localhost:10086/hs/jump/one 如下图所示:

故屿



  • 在浏览器请求输入 http://localhost:10086/hs/jump/two 如下图所示

故屿



  • 在浏览器请求输入 http://localhost:10086/hs/jump/* 如下图所示

故屿



  • 在控制台中响应输出的数据 如下图所示:

故屿



	注意在 web 开发中,服务端资源分成两大类时:

		这些资源如果是放在项目的webapp目录下,我们通过浏览器是可以直接访问的。
		如果这些资源是放在项目的webapp/WEB-INF 目录下,则这些资源就被容器给保护起来了,通过
		浏览器是不能直接访问,必需要通过Servlet跳转。


  • 此时 servlet02\servlet\JumpServlet.javal 代码如下注释修改:

故屿



  • 在浏览器请求输入 http://localhost:10086/hs/jump/two 如下图(注意通过Servlet跳转后的页面路径不会改变)

故屿

就这样通过浏览器请求访问服务端动、静态资源的跳转就完成啦~






本案例演示转发和重定向


  • servlet03\servlet\ForwardOrRedirectServlet.javal 代码如下:

package com.guyu.servlet03.servlet;

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;
import javax.servlet.http.HttpSession;
import java.io.IOException;

/********
 * 此案例演示 转发和重定向
 */
@WebServlet(urlPatterns = "/frdemo/*",name = "frServlet")
public class ForwardOrRedirectServlet extends HttpServlet {

    @Override
    public void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

//        HttpSession session = req.getSession();
//        ServletContext application = getServletContext();
        //
        String pathinfo = req.getPathInfo();
        if(pathinfo != null) {
            if (pathinfo.equals("/forward")) {
                //绑定数据
                req.setAttribute("DEMO_KEY", "这是放在 request 范围中的数据");
//                session.setAttribute("SES_DEMO_KEY","这是放在 session 范围中的数据");
//                application.setAttribute("APP_DEMO_KEY", "这是放在 application 范围中的数据");

                //转发
                req.getRequestDispatcher("/show_result").forward(req, resp);

            } else if (pathinfo.equals("/redirect")) {
                //绑定数据
                req.setAttribute("DEMO_KEY", "这是放在 request 范围中的数据");
//                session.setAttribute("SES_DEMO_KEY","这是放在 session 范围中的数据");
//                application.setAttribute("APP_DEMO_KEY", "这是放在 application 范围中的数据");

                //重定向: 注 location 前面要带上应用名 /hs
                String appName = req.getContextPath();
                resp.sendRedirect(appName+"/show_result");
//                resp.sendRedirect("/show_result");


            } else {
                //不支持
                resp.sendError(HttpServletResponse.SC_NOT_ACCEPTABLE, "不支持此请求");
            }
        } else {
            resp.sendError(404, "页面不存在");
        }
    }
}



  • servlet03\servlet\ShowResultServlet .javal 代码如下:

package com.guyu.servlet03.servlet;

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

@WebServlet(urlPatterns = "/show_result")
public class ShowResultServlet extends HttpServlet {

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        resp.setContentType("text/html;charset=utf-8");
        PrintWriter pw = resp.getWriter();

        //直接从请求范围取出之前绑定的值
        String demo_key = (String) req.getAttribute("DEMO_KEY");

//        String ses_demo_key = (String) req.getSession().getAttribute("SES_DEMO_KEY");
//        String app_demo_key = (String) getServletContext().getAttribute("APP_DEMO_KEY");

        //
        if(demo_key != null) {
//            pw.println("<h2 align=\"center\">DEMO_KEY: "+demo_key+"</h2>");
            pw.println("<h2 align=\"center\">"+demo_key+"</h2>");

        } else {
            pw.println("<h2 align=\"center\">从request范围取不到DEMO_KEY</h2>");
        }

//        pw.println("<h2>SES_DEMO_KEY: "+ses_demo_key+"</h2>");
//        pw.println("<h2>APP_DEMO_KEY: "+app_demo_key+"</h2>");

        //
        pw.close();
    }
}



  • 运行后在浏览器请求输入 http://localhost:10086/hs/frdemo/forward 如下图所示:

故屿

  • 此时如上图 需注意 请求转发【forward】 时,地址栏中的地址是不变化的,因为请求是同一个;


  • 在浏览器请求输入 http://localhost:10086/hs/frdemo/redirect 时地址变化 如下图所示:

故屿

  • 重定向【redirect】 时,地址栏中的地址是变化的,因为请求是新的请求!


  • 而在浏览器请求输入 http://localhost:10086/hs/frdemo 时,如下图所示:

      	frdemo 末尾不带 / ,则为 404 页面不存在!
      	frdemo 末尾带 / ,则为 406 不支持此请求!
    

故屿

故屿

转发和重定向的区别:

    请求转发时,地址栏中的地址是不变化的,因为请求是同一个;
    重定向时,地址栏中的地址是变化的,因为请求是新的请求。
    
    请求转发时,可以从 request 中取出之前绑定的 key 值;
    重定向时,不能从 request 中取出之前绑定的 key 值。





本案例演示 请求头和响应头的头信息


  • servlet03\servlet\HeaderServlet .javal 代码如下:
package com.guyu.servlet03.servlet;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Enumeration;

/**
 * 本案例演示 请求头和响应头的信息
 */
@WebServlet(urlPatterns = "/header")
public class HeaderServlet extends HttpServlet {

    @Override
    public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        //演示浏览器请求后在控制台响应一些头信息
        Enumeration<String> headerNames = req.getHeaderNames();
        while (headerNames.hasMoreElements()) {
            String name = headerNames.nextElement();
            String value = req.getHeader(name);
            System.out.printf("%s: %s\n", name, value);
        }

        //响应头类型编码
        resp.setContentType("text/html;charset=utf-8");
        PrintWriter pw = resp.getWriter();

        //输出一个页面,可使用Sublime 快速替换编辑
        pw.println("<!DOCTYPE html>");
        pw.println("<html>");
        pw.println("<head>");
        pw.println("	<title>header demo</title>");
        pw.println("	<meta charset='utf-8'>");
        pw.println("</head>");
        pw.println("<body>");
        pw.println("<div id='container'>");
        pw.println("	<h2 align=\"center\">用户登录</h2>");
        pw.println("	<form name='loginForm' action='"+req.getContextPath()+"/header' method='post'>");
        pw.println("		<p align=\"center\"><input type='text' name='user' placeholder='用户名'></p>");
        pw.println("		<p align=\"center\"><input type='password' name='pwd' placeholder='密 码'></p>");
        pw.println("		<p align=\"center\">");
        pw.println("			<input type='submit' value='登录'>");
        pw.println("			<input type='reset' value='重置'>");
        pw.println("		</p>");
        pw.println("	</form>");
        pw.println("</div>");
        pw.println("</body>");
        pw.println("</html>");
        //关闭
        pw.close();
    }

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

}




  • 运行后在浏览器请求输入 http://127.0.0.1:10086/hs/header 如下图所示:

故屿



  • 在控制台中响应输出的数据 如下图所示 请求头信息:

故屿

  • 继续填写登录

package com.guyu.servlet03.servlet;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Enumeration;

/**
 * 本案例演示 请求头和响应头的信息
 */
@WebServlet(urlPatterns = "/header")
public class HeaderServlet extends HttpServlet {

    @Override
    public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        //演示浏览器请求后在控制台响应一些头信息
//        Enumeration<String> headerNames = req.getHeaderNames();
//        while (headerNames.hasMoreElements()) {
//            String name = headerNames.nextElement();
//            String value = req.getHeader(name);
//            System.out.printf("%s: %s\n", name, value);
//        }

        //把上面封装起来
        printRequestHeader(req);

        //响应头类型编码
        resp.setContentType("text/html;charset=utf-8");
        PrintWriter pw = resp.getWriter();

        //输出一个页面,可使用Sublime 快速替换编辑
        pw.println("<!DOCTYPE html>");
        pw.println("<html>");
        pw.println("<head>");
        pw.println("	<title>header demo</title>");
        pw.println("	<meta charset='utf-8'>");
        pw.println("</head>");
        pw.println("<body>");
        pw.println("<div id='container'>");
        pw.println("	<h2 align=\"center\">用户登录</h2>");
        pw.println("	<form name='loginForm' action='"+req.getContextPath()+"/header' method='post'>");
        pw.println("		<p align=\"center\"><input type='text' name='user' placeholder='用户名'></p>");
        pw.println("		<p align=\"center\"><input type='password' name='pwd' placeholder='密 码'></p>");
        pw.println("		<p align=\"center\">");
        pw.println("			<input type='submit' value='登录'>");
        pw.println("			<input type='reset' value='重置'>");
        pw.println("		</p>");
        pw.println("	</form>");
        pw.println("</div>");
        pw.println("</body>");
        pw.println("</html>");
        //关闭
        pw.close();
    }


    @Override
    public void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        req.setCharacterEncoding("utf-8");
        resp.setCharacterEncoding("utf-8");

        //获取请求参数
        String user = req.getParameter("user");
        String pwd = req.getParameter("pwd");

        //输出 这两个量变 以及请求头
        resp.setContentType("text/html;charset=utf-8");
        PrintWriter pw = resp.getWriter();

        pw.println("<h2 align=\"center\">你的登录名:"+user+"</h2>");
        pw.println("<h2 align=\"center\">登录密码:"+pwd+"</h2>");

        //在后台输出请求头
        printRequestHeader(req);
    }

    private void printRequestHeader(HttpServletRequest req) {

        System.out.println("--- 华丽丽地分割线 ---");

        Enumeration<String> headerNames = req.getHeaderNames();
        while (headerNames.hasMoreElements()) {
            String name = headerNames.nextElement();
            String value = req.getHeader(name);
            System.out.printf("%s: %s\n", name, value);
        }
    }

}



  • 运行后在浏览器请求输入 http://127.0.0.1:10086/hs/header 后与填写登录提交 如下图所示:

故屿



  • 此时在控制台中响应输出的数据,两次分割线信息 如下图所示 :

故屿

对上述在浏览器中按 F12 也可查看相关信息:

故屿






本案例演示 Cookie 的添加和获取


此实例详情请见 Web 开发 Servlet 进阶之 Cookie、Session、Filter、Listener

  • servlet03\servlet\CookieServlet.javal 代码如下:

package com.guyu.servlet03.servlet;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

/**
 * 本案例演示 cookie的添加和获取
 */
@WebServlet(urlPatterns = "/cookie")
public class CookieServlet extends HttpServlet {

    @Override
    public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        resp.setContentType("text/html;charset=UTF-8");
        PrintWriter pw = resp.getWriter();

        //0. 先判断是否有cookie
        Cookie[] cookies = req.getCookies();
        if(cookies != null && cookies.length > 0) {
            //说明已经存在 cookie, 迭代
            for(Cookie c : cookies) {
                pw.println("<h2 align=\"center\">以下是cookie的值</h2>");
                pw.println("<div style='border:1px solid red;margin-left:750px;margin-right:750px'>");
                pw.println("    <p align=\"center\">Cookie名: "+c.getName()+"</p>");
                pw.println("    <p align=\"center\">Cookie值: "+c.getValue()+"</p>");
                pw.println("    <p align=\"center\">Cookie Domain: "+c.getDomain()+"</p>");
                pw.println("    <p align=\"center\">Cookie Path: "+c.getPath()+"</p>");
                pw.println("    <p align=\"center\">Cookie Max-Age: "+c.getMaxAge()+"</p>");
                pw.println("</div>");
            }
        } else {
            //说明没有cookie  需要清除浏览数据 ctrl+shift+delete
            //1.负责向客户端写 cookie
            //创建两个Cookie
            Cookie c1 = new Cookie("_user","guyu");
            
            //c1.setDomain("127.0.0.1");
            //c1.setPath("/cookie");

            //设置 Cookie 有效期其时长为 一分钟
            //当第一次访问 http://127.0.0.1:10086/hs/cookie 时,等待60s后再点击查看 cookie 时
            //此时 cookie 过期,request 会请求不到,反之60s内请求可查看其 cookie
            c1.setMaxAge(60);

            Cookie c2 = new Cookie("_pwd", "root");

            //psd 密码有效期时长 30s
            c2.setMaxAge(30);

            //2.把这两个cookie写到客户端,添加到响应
            resp.addCookie(c1);
            resp.addCookie(c2);
            //3.输出一个超链接,让用户查看cookie
            pw.println("<h2 align=\"center\"><a href='"+
                        req.getContextPath()+"/cookie'>查看cookie</a></h2>");
        }
        //关闭
        pw.close();
    }

    @Override
    public void doPost(HttpServletRequest req, HttpServletResponse resp)
                            throws ServletException, IOException {
        doGet(req, resp);
    }
}


  • 运行后在浏览器输入 http://127.0.0.1:10086/hs/cookie 时,响应头内会显示设置其 cookie 的所有数据如下图所示:

故屿

  • 在其 30s 内点击查看 cookie 时 ,请求头内会显示其 cookie 的所有数据:

故屿

  • 重运行后若在其 30s 后点击查看 cookie 时 ,请求头内只会显示其 第一个 cookie 的数据值,因为第二个 cookie 的数据值有效期为 30s:

故屿


重运行后反之若在其 60s 后点击查看 cookie 时 ,此时数据值都已失效。

注:
	当客户端第一次请求来到服务端时,服务端会通过响应头把一小段信息写给客户端,
	客户端以cookie的方式来存储这段信息。




回到顶部















Note:
欢迎点赞,留言,转载请在文章页面明显位置给出原文链接
知者,感谢您在茫茫人海中阅读了我的文章
没有个性 哪来的签名!
详情请关注点我
持续更新中

扫一扫 有惊喜!
© 2020 10 - Guyu.com | 【版权所有 侵权必究】
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值