JavaWeb核心技术(上)

目录

第一章 Servlet核心技术(上)(前端相关)

在这里插入图片描述

在这里插入图片描述

1.1 基本概念(常识)

1.1.1 C/S架构的概念

  • C/S架构(Client/Server,客户端/服务器模式),是一种比较早的软件体系结构,也是生活中很常见的结构。这种结构将需要处理的业务合理地分配到客户端和服务器端,客户端通常负责完成与用户的交互任务,服务器通常负责数据的管理。
  • C/S架构的主要优点如下:
    客户端的界面和功能可以很丰富。
    应用服务器的负荷较轻。
    响应速度较快。
  • C/S架构的主要缺点如下:
    适用面窄,用户群固定。
    维护和升级的成本高,所有的客户端都需要更新版本。

1.1.2 B/S架构的概念

  • B/S架构(Browser/Server,浏览器/服务器模式),是互联网兴起后的软件体系结构,该结构将
    系统功能实现的主要业务逻辑集中到服务器端,极少数业务逻辑在浏览器实现,浏览器通常负责完成与用户的交互任务服务器通常负责数据的管理
  • B/S架构的主要优点如下:
    无需安装客户端,只要有浏览器即可。
    适用面广,用户群不固定。
    通过权限控制实现多客户访问的目的,交互性较强。
    维护和升级的成本低,无需更新所有客户端版本。
  • B/S架构的主要缺点如下:
    应用服务器的负荷较重
    浏览器的界面和功能想要达到客户端的丰富程度需要花费大量的成本。
    在跨浏览器上不尽如人意,适配比较麻烦。

1.1.3 JavaWeb的概念

  • Web本意为网页的含义,这里表示互联网上供外界访问的资源。

  • 互联网上供外界访问的资源主要分为以下两种:
    1.静态资源:主要指Web页面中供人们浏览的数据始终是不变。
    2.动态资源:主要指Web页面中供人们浏览的数据由程序产生,不同时间点访问页面看到的内容各不相同。

  • JavaWeb主要指使用Java语言进行动态Web资源开发技术的统称,是解决相关Web互联网领域的技术总和。

  • 早期的B/S架构
    在这里插入图片描述

  • 后来的B/S架构
    在这里插入图片描述

使用Tomcat打开html使用的是http协议,双击直接打开html使用的是文件协议

1.2 HTTP协议(熟悉)

1.2.1 HTTP协议的概念

  • HTTP协议(HyperText Transfer Protocol,超文本传输协议)是由W3C(万维网联盟)组织制定的一种应用层协议,是用来规范浏览器与Web服务器之间如何通讯的数据格式,主要涉及浏览器的发请求格式和服务器的响应格式
  • HTTP协议通常承载于TCP协议之上,而承载于TLS或SSL协议层之上的协议就是常说的HTTPS协议。
  • HTTP默认的端口号为 80HTTPS默认的端口号为 443
    eg:http://www.baidu.com:80 中 80可以省略

在这里插入图片描述

1.2.2 HTTP请求格式

  • 客户端发送一个HTTP请求到服务器的请求消息主要包括:请求行、请求头、空白行和请求体。
请求行用来说明请求类型和要访问的资源以及所使用的HTTP版本,格式如下:
	请求类型 请求的路径 协议的版本(1.1)
请求头是紧接着请求行(即第一行)之后的部分,用来说明服务器要使用的附加信息(为服务器提供额外信息),格式
	(key:value)如下:
	主机 请求长度 请求的浏览器相关信息
空白行就是请求头部的空行,即使后面的请求数据为空则必须有空行。
	(最后一个请求头之后是一个空行,发送回车符和换行符,通知服务器以下不再有请求头;)

请求体也叫请求数据,可以添加任意的其他数据。

在这里插入图片描述

在这里插入图片描述

  • 举例常用如下:
POST /task01_demo01/demo1.html HTTP/1.1
Host: localhost:8088		主机
Content-Length: 21			包体长度
Cache-Control: max-age=0	缓存控制(有效期)
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64)	浏览器类别

name=scott&pwd=123456

1.2.3 HTTP响应格式

  • 通常情况下服务器接收并处理客户端发过来的请求后会返回一个HTTP的响应消息,主要包括:响应行、响应头、空白行和响应体。
响应行用来说明HTTP协议版本号和状态码以及状态消息,格式如下:
	协议的版本(1.0 1.1) 状态码 (200 成功 404 路径错误 500 服务错误) 状态信息
响应头用来说明客户端要使用的一些附加信息,格式(key:value)。
空白行就是响应头部的空行,即使后面的请求数据为空则必须有空行。

响应体用来服务器返回给客户端的文本信息。

在这里插入图片描述

  • 举例如下:
HTTP/1.1 200 OK
Content-Type: text/html		文本类型
Content-Length: 588			文本长度
Date: Thu, 08 Sep 2021 12:59:54 GMT		日期

<html><head><title>示例1</title></head>
<body><h1>这是一个HTML页面</h1></body>
</html>

1.3 Tomcat服务器(重点)

1.3.1 基本概念

  • Tomcat本意为公猫的含义,最初是由Sun公司的软件架构师詹姆斯·邓肯·戴维森开发的,后来他帮助将其变为开源项目并由Sun公司贡献给Apache软件基金会。
  • Tomcat 服务器是一个开源的轻量级Web应用服务器,在中小型系统和并发量小的场合下被普遍使用,是开发和调试Servlet、JSP 程序的首选。

1.3.2 安装方式

  • 下载地址:http://tomcat.apache.org/
    在这里插入图片描述

1.3.3 目录结构

bin 主要存放二进制可执行文件和脚本。
conf 主要存放各种配置文件。
lib 主要用来存放Tomcat运行需要加载的jar包。
logs 主要存放Tomcat在运行过程中产生的日志文件。
temp 主要存放Tomcat在运行过程中产生的临时文件。
webapps 主要存放应用程序,当Tomcat启动时会去加载该目录下的应用程序。
work 主要存放tomcat在运行时的编译后文件,例如JSP编译后的文件。

1.3.4 启动和关闭

  • 启动方式
    使用bin目录下的批处理文件startup.bat来启动Tomcat服务器,若出现一个毫秒数说明启动成功。
  • 关闭方式
    使用bin目录下的批处理文件shutdown.bat来关闭Tomcat服务器。
  • 注意事项
    启动之前首先安装JDK并配置环境变量JAVA_HOME。若希望Tomcat服务器可以在任意路径启动,则需要配置环境变量CATALINA_HOME(tomcat的目录)。
    关于环境变量(其实就是配置了Path后,如果当前目录下找不到相应的指令,就到Path中去找,)
  • 启动信息乱码的处理方式(主要是编码与解码不一致,dos窗口是GBK):logging.properties文件修改为
    java.util.logging.ConsoleHandler.encoding = GBK

在这里插入图片描述

1.3.5 配置文件

  • server.xml文件是服务器的主配置文件,可以设置端口号、设置域名或IP、默认加载的项目、请求编码等。
<Connector port="8888" protocol="HTTP/1.1"
			connectionTimeout="20000"
			redirectPort="8443" />
  • tomcat-users.xml文件用来配置管理Tomcat服务器的用户与权限 。
<role rolename="manager-gui"/>
<user username="admin" password="123456" roles="manager-gui"/>

1.4 Servlet的概念和使用(重点)

idea创建web项目

在这里插入图片描述

在这里插入图片描述

idea中Tomcat服务器的相关配置
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

1.4.1 基本概念

  • Servlet(Server Applet)是Java Servlet的简称,称为小服务程序或服务连接器,是Java语言编写 的服务器端程序,换句话说,Servlet就是运行在服务器上的Java类
  • Servlet用来完成B/S架构下客户端请求响应处理,也就是交互式地浏览和生成数据,生成动态Web内容。
  • 用于处理客户端的请求

1.4.2 Servlet的编程步骤

  1. 建立一个Java Web Application项目并配置Tomcat服务器。
  2. 自定义类实现Servlet接口或继承 HttpServlet类(推荐) 并重写service方法。
  3. 将自定义类的信息配置到 web.xml文件并启动项目,配置方式如下:

在这里插入图片描述

<!-- 配置Servlet -->
<servlet>
	<!-- 起别名   HelloServlet是Servlet类的别名 -->
	<servlet-name> HelloServlet </servlet-name>
	<!-- 别名对应的Servlet类    com.lagou.task01.HelloServlet是包含路径的真实的Servlet类名 -->
	<servlet-class> com.lagou.task01.HelloServlet </servlet-class>
</servlet>
<!-- 映射Servlet(配置访问浏览器方式) -->
<servlet-mapping>
	<!-- HelloServlet是Servlet类的别名,与上述名称必须相同 -->
	<servlet-name> HelloServlet </servlet-name>
	<!-- /hello是供浏览器使用的地址  (配置访问浏览器访问地址) -->
	<url-pattern> /hello </url-pattern>
</servlet-mapping>
在浏览器上访问的方式为:
http://localhost:8080/工程路径/url-pattern的内容

1.4.3 Servlet接口

( 1 )基本概念
javax.servlet.Servlet接口用于定义所有servlet必须实现的方法。

在这里插入图片描述
在这里插入图片描述

( 2 )常用的方法
方法声明功能介绍
void init(ServletConfig config)由servlet容器调用,以向servlet指示servlet正在 被放入服务中
void service(ServletRequest req, ServletResponse res)由servlet容器调用,以允许servlet响应请求
ServletConfig getServletConfig()返回ServletConfig对象,该对象包含此servlet的初 始化和启动参数
String getServletInfo()返回有关servlet的信息,如作者、版本和版权
void destroy()由servlet容器调用,以向servlet指示该servlet正 在退出服务

1.4.5 GenericServlet类

( 1 )基本概念
  • javax.servlet.GenericServlet类主要用于定义一个通用的、与协议无关的servlet,该类实现了Servlet接口
  • 若编写通用servlet,只需重写service抽象方法即可。
    在这里插入图片描述
    在这里插入图片描述
( 2 )常用的方法
方法声明功能介绍
abstract void service(ServletRequest req, ServletResponse res)由servlet容器调用允许servlet响应 请求

1.4.6 HttpServlet类

( 1 )基本概念
  • javax.servlet.http.HttpServlet类是个抽象类继承了GenericServlet类
  • 用于创建适用于网站的HTTP Servlet,该类的子类必须至少重写一个方法。

在这里插入图片描述
在这里插入图片描述

  • 第一次访问
    在这里插入图片描述
  • 再次访问
    在这里插入图片描述
  • 关闭Tomcat
    在这里插入图片描述
( 2 )常用的方法
方法声明功能介绍
void doGet(HttpServletRequest req, HttpServletResponse resp)处理客户端的GET请求
void doPost(HttpServletRequest req, HttpServletResponse resp)处理客户端的POST请求
void init()进行初始化操作
void service(HttpServletRequest req, HttpServletResponse resp)根据请求决定调用doGet还是doPost方法
void destroy()删除实例时释放资源

在这里插入图片描述

( 3 )简化写法
@WebServlet(name = "HelloServlet4", urlPatterns = "/hello4")
public class HelloServlet4 extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("Post请求方式...");
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("Get请求方式...");
        this.doPost(request, response);
    }
}

1.4.7 Servlet 的生命周期

在这里插入图片描述

  • 构造方法只被调用一次,当第一次请求Servlet时调用构造方法来创建Servlet的实例。
  • init方法只被调用一次,当创建好Servlet实例后立即调用该方法实现Servlet的初始化。
  • service方法被多次调用,每当有请求时都会调用service方法用于请求的响应
  • destroy方法只被调用一次,当该Servlet实例所在的Web应用被卸载前调用该方法来释放当前占用
    的资源。

1.5 POST和GET请求(重点)

1.5.1 GET请求

* 发出GET请求的主要方式:
	(1)在浏览器输入`URL按回车`
	(2)点击`<a>超链接`
	(3)点击submit按钮,提交 <form method=“get”>表单
* GET请求特点:
	会将请求数据添加到`请求URL地址的后面`,只能提交少量的数据、不安全

1.5.2 POST请求

* 发出POST请求的方法如下:
		点击submit按钮,提交 <form method=“post”>表单
* POST请求的特点:
	`请求数据`添加到`HTTP协议体中`,可提交`大量数据、安全性好`

代码演示到1.5.6

一:前端准备 parameter.html
<form action="parameter" method="post">
    姓名:<input type="text" name="name"/><br/>
    年龄:<input type="text" name="age"/><br/>
    爱好:<input type="checkbox" name="hobby" value="java"/>java
          <input type="checkbox" name="hobby" value="c"/>c
          <input type="checkbox" name="hobby" value="c++"/>c++
          <br/>
    <input type="submit" value="提交">
</form>

在这里插入图片描述

1.5.3 ServletRequest接口

( 1 )基本概念
  • javax.servlet.ServletRequest接口主要用于向servlet 提供 客户端请求信息,可以从中获取到任何请求信息
  • Servlet容器创建一个ServletRequest对象,并将其作为参数传递给Servlet的service方法。
( 2 )常用的方法
方法声明功能介绍
String getParameter(String name)以字符串形式返回请求参数的值,如果该参数不存在,则返回空 值
String[] getParameterValues( String name)返回一个字符串对象数组,其中包含给定请求参数所具有的所有 值,如果该参数不存在,则返回空值 ( 返回该请求参数的所有值 )
Enumeration getParameterNames()返回包含此请求中包含的参数名称的字符串对象的枚举。如果请 求没有参数,则方法返回空枚举( 返回所有请求参数 )
Map<String, String[]> getParameterMap()返回请求参数的键值对,一个键可以对应多个值
String getRemoteAddr()返回发送请求的客户端或最后一个代理的IP地址
int getRemotePort()返回发送请求的客户端或最后一个代理的端口号
  • 编写ParameterServlet
  • 配置web.xml
    <servlet>
        <servlet-name>parameterServlet</servlet-name>
        <servlet-class>com.lagou.demo02.ParameterServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>parameterServlet</servlet-name>
        <url-pattern>/parameter</url-pattern>
    </servlet-mapping>

public class ParameterServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //Servlet接收中文乱码,设置请求信息中的编码方式为utf-8来解决乱码问题
        request.setCharacterEncoding("utf-8");

        System.out.println("-----------------------ServletRequest 接口方法-------------------------------------");
        // 1.获取指定参数名称对应的参数值并打印
        String name = request.getParameter("name");
        System.out.println("获取到的姓名:" + name);

        String[] hobbies = request.getParameterValues("hobby");
        System.out.print("获取的爱好:");
        for(String hobby : hobbies){
            System.out.print(hobby + " ");
        }
        System.out.println();

        System.out.println("-----------------------2.获取所有参数的名称-------------------------------------");
        Enumeration<String> parameterNames = request.getParameterNames();
        System.out.print("获取所有参数的名字:");
        while(parameterNames.hasMoreElements()){
            System.out.print(parameterNames.nextElement() + " ");
        }
        System.out.println();

        System.out.println("-----------------------3.获取请求参数名和对应值的第二种方式-------------------------------------");
        Map<String, String[]> parameterMap = request.getParameterMap();
        // 使用Map集合中所有的键值对组成Set集合
        Set<Map.Entry<String, String[]>> entries = parameterMap.entrySet();
        // 遍历Set集合
        for (Map.Entry<String, String[]> me : entries) {
            System.out.print(me.getKey() + "对应的数值有:");
            for (String ts : me.getValue()) {
                System.out.print(ts + " ");
            }
            System.out.println();
        }
}

在这里插入图片描述

1.5.4 HttpServletRequest接口

( 1 )基本概念
  • javax.servlet.http.HttpServletRequest接口是ServletRequest接口的子接口,主要用于提供HTTP请求信息的功能。
  • 不同于表单数据,在发送HTTP请求时,HTTP请求头直接由浏览器设置。
    可直接通过HttpServletRequest对象提供的一系列get方法获取请求头数据。
( 2 )常用的方法
方法声明功能介绍
String getRequestURI()返回此请求的资源路径信息 ( /task01_demo02/hello )
StringBuffer getRequestURL()返回此请求的完整路径信息
String getMethod()返回发出此请求的HTTP方法的名称,例如GET、POST
String getQueryString()返回路径后面请求中附带的参数
String getServletPath()返回此请求中调用servlet的路径部分( /hello )
  • 在doPost中添加代码
		System.out.println("-----------------------获取客户端请求的其它信息 HttpServletRequest-------------------------------------");
        //0:0:0:0:0:0:0:1是ipv6的表现形式,对应ipv4来说相当于127.0.0.1,也就是本机
        System.out.println("发送请求的客户端IP地址为:" + request.getRemoteAddr());
        System.out.println("发送请求的客户端端口号为:" + request.getRemotePort());
        System.out.println("请求资源的路径为:" + request.getRequestURI());  ///u01_d02_servletInstantiation/parameter
        System.out.println("请求资源的完整路径为:" + request.getRequestURL());
        System.out.println("请求方式为:" + request.getMethod());
        System.out.println("请求的附带参数为:" + request.getQueryString());
        System.out.println("请求的Servlet路径为:" + request.getServletPath());    ///parameter

在这里插入图片描述

1.5.5 ServletResponse接口

( 1 )基本概念
  • javax.servlet.ServletResponse接口用于定义一个对象来帮助Servlet向客户端发送响应
  • Servlet容器创建ServletResponse对象,并将其作为参数传递给servlet的service方法。
( 2 )常用方法
方法声明功能介绍
PrintWriter getWriter()返回可向客户端发送字符文本的PrintWriter对象
String getCharacterEncoding()获取服务器响应内容的默认编码方式
void setCharacterEncoding(String charset)指定响应的编码集(MIME字符集),例如UTF-8
void setContentType(String type)如果尚未提交响应,则设置发送到客户端响应的内容类型。内容类型 可以包括字符编码规范,例如text/html;charset=UTF-8
  • 在doPost中继续添加代码
        System.out.println("-----------------------5.向浏览器发出响应数据-------------------------------------");
        //获取响应数据的默认编码方式
        System.out.println("服务器响应数据的默认编码方式为:" + response.getCharacterEncoding()); //ISO-8859-1

        // 设置服务器和浏览器的 编码方式以及文本类型( 响应的内容类型 )
        response.setContentType("text/html;charset=UTF-8");
        System.out.println("修改后的编码方式: " + response.getCharacterEncoding());
        PrintWriter writer = response.getWriter();
        //writer.write("I Received!");
        //writer.write("我接收到了!");
        Random random = new Random();
        int num = random.nextInt(100) + 1;
        writer.write("<h1>" + num + "</h1>");
        System.out.println("服务器发送数据成功!!!");
        writer.close();

在这里插入图片描述

1.5.6 HttpServletResponse接口

( 1 )基本概念
  • javax.servlet.http.HttpServletResponse接口继承ServletResponse接口,以便在发送响应时提供特定于HTTP的功能。
( 2 )常用的方法
方法声明功能介绍
void sendRedirect(String location)使用指定的重定向位置URL向客户端发送临时重定向响应

1.5.7 使用示例

// 继承HttpServlet
public class HelloWorld extends HttpServlet {
	// 重写HttpServlet中的doGet方法
	protected void doGet(HttpServletRequest request, HttpServletResponse response)throws IOException, ServletException {
		// 设置响应输出编码,避免中文乱码
		response.setContentType(“text/html;charset=utf-8);
		// 获取响应输出流
		PrintWriter out= response.getWriter();
		// 利用输出流输出信息
		out.println(<html><body> Hello world!</body></html>);
		//关闭流
		out.close();
	}
}
案例题目
使用Servlet获取在服务器获取一个1~100之间的随机数并发送给客户端进行显示。

1.6 Servlet接收中文乱码(重点)

1.6.1 接收乱码原因

  • 浏览器在提交表单时,会对中文参数值进行自动编码。当Tomcat服务器接收到浏览器请求后自动解码,当编码与解码方式不一致时,就会导致乱码。

1.6.2 解决POST接收乱码

设置请求信息中的编码方式为utf-8来解决乱码问题
接收之前设置编码方式:
		request.setCharacterEncoding("utf-8");
提示:
		必须在调用	request.getParameter(“name”)之前设置

1.6.3 解决GET接收乱码

将接收到的中文乱码重新编码:
	// 接收到get请求的中文字符串
	String name = request.getParameter("name");
	// 将中文字符重新编码,默认编码为ISO-8859-1(用对应的方式转成原始的字节数组,再重新用utf-8进行解码)
	String userName = new String(name.getBytes(“ISO-8859-1),“utf-8");

1.7 ServletConfig接口(熟悉)

( 1 )基本概念
  • javax.servlet.ServletConfig接口用于描述Servlet本身的相关配置信息在初始化期间用于将信息传递给Servlet配置对象
( 2 )配置方式
<!-- 在web.xml中配置ServletConfig初始化参数 -->
<servlet>
	<servlet-name>actionservlet</servlet-name>
	<servlet-class>com.lagou.demo01.ActionServlet</servlet-class>
	<!-- 配置 Serlvet 的初始化参数 -->
	<init-param>
		<!-- 参数名 -->
		<param-name>config</param-name>
		<!-- 参数值 -->
		<param-value>struts.xml</param-value>
	</init-param>
</servlet>
( 3 )常用的方法
方法声明功能介绍
String getServletName()返回Servlet的别名
String getInitParameter(String name)返回包含初始化参数值的字符串,如果该参数不存在,则返回null
Enumeration getInitParameterNames()将servlet的初始化参数的名称作为字符串对象的枚举返回,如果 servlet没有初始化参数,则返回空枚举
ServletContext getServletContext()返回对调用方正在其中执行的ServletContext的引用
<!--    ServletConfig-->
    <servlet>
        <servlet-name>ConfigServlet</servlet-name>
        <servlet-class>com.lagou.demo02.ConfigServlet</servlet-class>
        <!-- 实现初始化参数的配置 -->
        <init-param>
            <param-name>userName</param-name>
            <param-value>admin</param-value>
        </init-param>
        <init-param>
            <param-name>password</param-name>
            <param-value>123456</param-value>
        </init-param>
    </servlet>
    
    <servlet-mapping>
        <servlet-name>ConfigServlet</servlet-name>
        <url-pattern>/config</url-pattern>
    </servlet-mapping>

  • 使用实现servlet,重写init方法(ServletConfig作为形参)
public class ConfigServlet implements Servlet {

    @Override
    public void init(ServletConfig servletConfig) throws ServletException {
        System.out.println("初始化操作执行了...");
        System.out.println("Servlet的别名是:" + servletConfig.getServletName()); // ConfigServlet

        System.out.println("-----------------------------------------------");
        // 获取配置文件中的初始化参数信息
        String userName = servletConfig.getInitParameter("userName");
        System.out.println("获取到的初始化用户名为:" + userName);
        // 获取所有配置参数的名称
        Enumeration<String> initParameterNames = servletConfig.getInitParameterNames();
        while (initParameterNames.hasMoreElements()) {
            System.out.println("初始化参数名为:" + initParameterNames.nextElement());
        }

        System.out.println("-----------------------------------------------");
        // 获取ServletContext接口的引用
        ServletContext servletContext = servletConfig.getServletContext();
        System.out.println("获取到的ServletContext引用为:" + servletContext);

    }
   
   ......
}

在这里插入图片描述

1.8 ServletContext接口(熟悉)

( 1 )基本概念
  • javax.servlet.ServletContext接口主要用于定义一组方法,Servlet使用这些方法与它的Servlet容器通信。
  • 服务器容器在启动时会为每个项目创建唯一的一个ServletContext对象用于实现多个Servlet之间的信息共享和通信
    在Servlet中通过this.getServletContext()方法可以获得ServletContext对象。
( 2 )配置方式
<!--在web.xml中配置ServletContext初始化参数 -->
<context-param>
	<!--参数名 -->
	<param-name>username</param-name>
	<!--参数值 -->
	<param-value>scott</param-value>
<context-param>

<context-param>
	<param-name>password</param-name>
	<param-value>tiger</param-value>
<context-param>
( 3 )常用的方法
方法声明功能介绍
String getInitParameter(String name)返回包含初始化参数值的字符串,如果该参数不存在,则返回 null
Enumeration getInitParameterNames()将servlet的初始化参数的名称作为字符串对象的枚举返回,如 果servlet没有初始化参数,则返回空枚举
String getRealPath(String path)返回包含给定虚拟路径的实际路径的字符串
String getContextPath()返回与此上下文关联的主路径
InputStream getResourceAsStream(String path)将位于指定路径的资源作为InputStream对象返回
void setAttribute(String name, Object object)将指定的属性名和属性值绑定到当前对象
Object getAttribute(String name)根据执行的属性名获取属性值
void removeAttribute(String name)删除指定的属性名信息
  • 编写一个servlet,ConfigServlet
    <!-- 对于ServletContext对象的参数进行配置 -->
    <context-param>
        <param-name>param1</param-name>
        <param-value>value1</param-value>
    </context-param>
    <context-param>
        <param-name>param2</param-name>
        <param-value>value2</param-value>
    </context-param>

    <servlet>
        <servlet-name>ContextServlet</servlet-name>
        <servlet-class>com.lagou.demo02.ContextServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>ContextServlet</servlet-name>
        <url-pattern>/context</url-pattern>
    </servlet-mapping>
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //获取ServletConfig对象
        ServletContext servletContext = getServletConfig().getServletContext();
        //方式二
//        ServletContext servletContext1 = getServletContext();

        Enumeration<String> initParameterNames = servletContext.getInitParameterNames();
        while (initParameterNames.hasMoreElements()) {
            String s = initParameterNames.nextElement();
            System.out.println( s + "对应的值为:" + servletContext.getInitParameter(s));
        }



        System.out.println("---------------------2.相关路径的获取-------------------------------------");
        // 本质上就是获取工程路径    /工程名 即 /u01_d02_servletInstantiation
        System.out.println("获取上下文关联的路径信息为:" + servletContext.getContextPath());

        /*
        *   斜杠/ 在服务器上解析为 https://ip地址:端口号/工程名   获取实际路径信息
        *   获取到的是部署工程路径信息   对应  当前工程中的web目录
        * */
        System.out.println("获取到的实际路径信息为: " + servletContext.getRealPath("/"));



        System.out.println("---------------------3.设置和获取属性信息-------------------------------------");
        servletContext.setAttribute("key1","value1");
        System.out.println("根据参数指定的属性名获取到的属性值为:" + servletContext.getAttribute("key1"));
        System.out.println("根据参数指定的属性名获取初始话的属性值为:" + servletContext.getAttribute("param1"));  //servletContext.getInitParameter("param1")
        servletContext.removeAttribute("key1");
        System.out.println("根据参数指定的属性名获取到的属性值为:" + servletContext.getAttribute("key1"));
    }

在这里插入图片描述

在这里插入图片描述

第二章 Servlet核心技术(下)(后端相关)

在这里插入图片描述

2.1 Servlet+JDBC应用(重点)

  • 在Servlet中可以使用JDBC技术访问数据库,常见功能如下:

    • 1.查询DB数据,然后生成显示页面,例如:列表显示功能。
    • 2.接收请求参数,然后对DB操作,例如:注册、登录、修改密码等功能。
  • 为了方便重用和便于维护等目的,经常会采用DAO(Data Access Object)模式对数据库操作进行
    独立封装。
    在这里插入图片描述

  • DAO工厂(工厂模式)
    工厂类:封装了对象的创建细节,为调用者提供符合要求的对象。

注册案例

在这里插入图片描述

1.准备
1.1 创建数据库

在这里插入图片描述

1.2 添加lib的方式
  • 方式一
    在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

  • 检查是否添加成功
    在这里插入图片描述

  • 方式二
    在这里插入图片描述

3.前端页面
  • 注册页面 register.html
    <form action="RegisterServlet">
        用户名:<input type="text" name="userName"/><br/>&nbsp;&nbsp;&nbsp;&nbsp;码:<input type="text" name="password"/><br/>
        <input type="submit" value="提交"/>
    </form>

在这里插入图片描述

4.数据库连接工具
4.1 DBUtil
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;

public class DBUtil {
    private static String jdbcName;   // 用于描述驱动信息
    private static String dbUrl;      // 用于描述URL信息
    private static String dbUserName; // 用户描述用户名信息
    private static String dbPassword; // 用户描述密码信息

    static {
        jdbcName = "com.mysql.jdbc.Driver";
        dbUrl = "jdbc:mysql://localhost:3306/lagou_db_web";
        dbUserName = "root";
        dbPassword = "root";
        try {
            //加载数据库驱动
            Class.forName(jdbcName);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取连接
     * @return
     * @throws SQLException
     */
    public static Connection getConnection() throws SQLException {
        Connection connection = DriverManager.getConnection(dbUrl, dbUserName, dbPassword);
        return connection;
    }

    /**
     * 关闭连接
     * @param conn
     * @throws SQLException
     */
    public static void closeConnection(Connection conn, PreparedStatement psts) throws SQLException {
        if (null != conn){
            conn.close();
        }
        if (null != psts){
            psts.close();
        }
    }
}
4.1 DBUtilTest
public class DBUtilTest {
    public static void main(String[] args) {
        Connection connection = null;


        try {
            connection = DBUtil.getConnection();
            System.out.println("数据库连接成功!!!");
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            /*try {
                DbUtil.closeConnection(connection);
            } catch (SQLException e) {
                e.printStackTrace();
            }*/
        }
    }
}

在这里插入图片描述

5. 实体类
public class User {
	private int id;
    private String userName;
    private String password;

    public User() {
    }

    public User(String userName, String password) {
        this.userName = userName;
        this.password = password;
    }
	
	......
}
6. UserDao
public class UserDao {
    
    //注册功能
    public int createUser(User user){
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        try {
            //1.获取连接
            connection = DBUtil.getConnection();
            //2.准备sql语句
            String sql = "insert into t_user values(null, ?, ?)";
            //3.获取PrepareStatement类型的引用
            preparedStatement = connection.prepareStatement(sql);
            // 4.向问号所占的位置设置数据
            preparedStatement.setString(1,user.getUserName());
            preparedStatement.setString(2,user.getPassword());
            // 5.执行sql语句
            int row = preparedStatement.executeUpdate();
            return row; //执行成功
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            //关闭资源
            try {
                DBUtil.closeConnection(connection,preparedStatement);
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        return 0;   //执行失败
    }
}

在这里插入图片描述

7. RegisterServlet
public class RegisterServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 1.获取请求对象中保存的用户名和密码信息
        String userName = request.getParameter("userName");
        System.out.println("获取到的用户名为:" + userName);
        String password = request.getParameter("password");
        System.out.println("获取到的密码为:" + password);

        // 2.将接受到的用户名和密码信息打包成用户对象交给DAO层进行处理
        User user = new User(userName, password);
        UserDao userDao = new UserDao();
        int res = userDao.createUser(user);

        // 3.将处理结果响应到浏览器
        response.setContentType("text/html;charset=utf-8");
        PrintWriter writer = response.getWriter();
        if (1 == res) {
            System.out.println("注册成功!");
            writer.write("<h1>注册成功!</h1>");
        } else {
            writer.write("<h1>注册失败!</h1>");
        }
        writer.close();
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }
}
  • web.xml
    <servlet>
        <servlet-name>RegisterServlet</servlet-name>
        <servlet-class>com.lagou.demo01.servlet.RegisterServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>RegisterServlet</servlet-name>
        <url-pattern>/register</url-pattern>
    </servlet-mapping>

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

2.2 重定向和转发(重点)

在这里插入图片描述

2.2.1 重定向的概述

( 1 )重定向的概念

(重新指定方向)
1.首先客户浏览器发送http请求,当web服务器接受后发送 302 状态码响应及对应新的location给客户浏览器。
2.客户浏览器发现是 302 响应,则自动再发送一个新的http请求,请求url是新的location地址,服务器根据此请求寻找资源并发送给客户。

( 2 )重定向的实现

实现重定向需要借助javax.servlet.http.HttpServletResponse接口中的以下方法:

方法声明功能介绍
void sendRedirect(String location)使用指定的重定向位置URL向客户端发送临时重定向响 应
( 3 )重定向的原理

在这里插入图片描述

( 4 )重定向的特点
  • 重定向之后,浏览器地址栏的URL会发生改变

  • 重定向过程中会将前面Request对象销毁,然后创建一个新的Request对象

  • 重定向的URL可以是其它项目工程(跳转到百度)。

代码示例
  • 重定向前端页面
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>重定向</title>
</head>
<body>

    <form action="RS" method="post">
        <input type="submit" value="重定向">
    </form>

</body>
</html>
  • 重定向后的页面
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>目标页面</title>
</head>
<body>

    <h1>重定向后的页面: 服务器重新指定位置后的页面</h1>

</body>
</html>
  • RedirectServlet
public class RedirectServlet extends HttpServlet{
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doPost(req, resp);
    }

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

        System.out.println("收到浏览器请求!!!");
        //重定向: 给浏览器发送一个新的位置
        resp.sendRedirect("target.html");
        //重定向到其它工程
        //resp.sendRedirect("https://www.baidu.com/?tn=88093251_38_hao_pg");
    }
}
  • web.xml
    <servlet>
        <servlet-name>RedirectServlet</servlet-name>
        <servlet-class>com.lagou.demo02.servlet.RedirectServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>RedirectServlet</servlet-name>
        <url-pattern>/RS</url-pattern>
    </servlet-mapping>

在这里插入图片描述

  • 重定向后:注意观察 地址栏、状态码
    在这里插入图片描述

2.2.2 转发的概述

( 1 )转发的概念
  • 一个Web组件(Servlet/JSP)将未完成的处理通过容器转交给另外一个Web组件继续处理,转发的各个组件会共享Request和Response对象
( 2 )转发的实现
  • 绑定数据到Request对象
方法声明功能介绍
Object getAttribute(String name)将指定属性值作为对象返回,若给定名称属性不存 在,则返回空值
void setAttribute(String name,Object o)在此请求中存储属性值
  • 获取转发器对象
方法声明功能介绍
RequestDispatcher getRequestDispatcher(String path)返回一个RequestDispatcher对象,该对象充当位 于给定路径上的资源的包装器(请求调度器)
  • 转发操作
方法声明功能介绍
void forward(ServletRequest request, ServletResponse response)将请求从一个servlet转发到服务器上的另一个资 源(Servlet、JSP文件或HTML文件)
( 3 )转发的特点
  • 转发之后浏览器地址栏的URL不会发生改变。
  • 转发过程中共享Request对象。
  • 转发的URL不可以是其它项目工程(在当前项目下找)
    在这里插入图片描述
代码示例
  • forword
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>转发测试</title>
</head>
<body>

    <form action="forwardServlet" method="post">
        <input type="submit" value="转发"/>
    </form>

</body>
</html>
  • ForwardServlet
public class ForwardServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("接收到了浏览器的请求");
        //向request中设置信息
        req.setAttribute("key1", "value1");

        //转发  也就是让web组件将任务转交给另外一个web组件
        RequestDispatcher requestDispatcher = req.getRequestDispatcher("/targetServlet");
        //RequestDispatcher requestDispatcher = request.getRequestDispatcher("https://www.baidu.com/");
        requestDispatcher.forward(req, resp);
    }
  • TargetServlet
public class TargetServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("接收到转发过来的信息");
        System.out.println("获取到的值为:" + req.getAttribute("key1"));

        resp.setContentType("text/html;charset=utf-8");
        resp.getWriter().write("<h1>接收到了转发信息</h1>");
    }
}
    <servlet>
        <servlet-name>ForwardServlet</servlet-name>
        <servlet-class>com.lagou.demo02.servlet.ForwardServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>ForwardServlet</servlet-name>
        <url-pattern>/forwardServlet</url-pattern>
    </servlet-mapping>

    <servlet>
        <servlet-name>TargetServlet</servlet-name>
        <servlet-class>com.lagou.demo02.servlet.TargetServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>TargetServlet</servlet-name>
        <url-pattern>/targetServlet</url-pattern>
    </servlet-mapping>

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

( 4 ) 重定向和转发的比较

在这里插入图片描述

2.3 Servlet线程安全(重点)

  • 服务器在收到请求之后,会启动一个线程来进行相应的请求处理。

  • 默认情况下,服务器为每个Servlet 只创建一个对象实例。当多个请求访问同一个Servlet时,会有多个线程访问同一个Servlet对象,此时就可能发生线程安全问题。

  • 多线程并发逻辑,需要使用synchronized对代码加锁处理,但尽量避免使用。

代码示例

  • thread.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Servlet线程安全测试</title>
</head>
<body>

    <iframe width="600px" height="100px" src="threadServlet?name=zhangfei1"></iframe><br/>
    <iframe width="600px" height="100px" src="threadServlet?name=lisi2"></iframe><br/>
    <iframe width="600px" height="100px" src="threadServlet?name=wangwu3"></iframe><br/>
    <iframe width="600px" height="100px" src="threadServlet?name=zhaoliu4"></iframe><br/>

</body>
</html>
  • ThreadServlet

/**
 * 进行线程安全测试
 */
@WebServlet(name = "ThreadServlet", urlPatterns = "/threadServlet")
public class ThreadServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doPost(req, resp);
    }

    //准备一个成员变量,作为共享数据
    private String name;

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //通过锁的方式来防止输出
        synchronized (this) {
            /*
            * 如果不通过锁的方式来进行处理,那么就不设置成员变量,而是每次请求是进行重新创建
            * name = req.getParameter("name");  //获取request对象中获取名字为name的测试数值并赋值给成员变量name
            * */
            String name = req.getParameter("name");
            System.out.println("获取到的name: " + name);

            //2.睡眠5秒
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            //3.使用打印流将成员变量name的数值发送给浏览器
            PrintWriter writer = resp.getWriter();
            writer.write("<h1>" + name + "</h1>");
            writer.close();
        }
    }
}

在这里插入图片描述

  • 使用成员变量,共享数据时
  • 5s后几乎一起显示出来
    在这里插入图片描述
  • 不使用成员变量时,或上锁时
  • 5s显示一个
    在这里插入图片描述
    在这里插入图片描述

2.4 状态管理(重点)

  • Web程序基于HTTP协议通信,而HTTP协议是”无状态”的协议,一旦服务器响应完客户的请求之后,就断开连接,而同一个客户的下一次请求又会重新建立网络连接。
  • 服务器程序有时是需要判断是否为同一个客户发出的请求,比如客户的多次选购商品。因此,有必要跟踪同一个客户发出的一系列请求。
  • 把浏览器与服务器之间多次交互作为一个整体,将多次交互所涉及的数据保存下来,即状态管理
  • 多次交互的数据状态可以在客户端保存,也可以在服务器端保存。状态管理主要分为以下两类:
    • 客户端管理:将状态 保存客户端。基于Cookie技术实现。
    • 服务器管理:将状态保存在服务器端。基于Session技术实现。
      在这里插入图片描述

2.5 Cookie技术(重点)

在这里插入图片描述

2.5.1 基本概念

  • Cookie本意为”饼干“的含义,在这里表示客户端以“名-值”形式进行保存的一种技术。
  • 浏览器向服务器发送请求时,服务器将数据以Set-Cookie (消息头)的方式响应给浏览器,然后浏览器会将这些数据文本文件的方式保存起来。
  • 当浏览器再次访问服务器时,会将这些数据以Cookie消息头的方式发送给服务器。
    在这里插入图片描述

2.5.2 相关的方法

  • 使用javax.servlet.http.Cookie类的构造方法实现Cookie的创建。
方法声明功能介绍
Cookie(String name, String value)根据参数指定数值构造对象 new
示例1:添加cookie
@WebServlet(name = "CookieServlet",urlPatterns = "/cookieServlet")
public class CookieServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //1.测试浏览器的请求是否到达
        System.out.println("看看是否被执行");

        //2.创建Cookie对象并且添加到响应信息中
        Cookie cookie=new Cookie("name","zhangfei");
        //发送到浏览器中
        resp.addCookie(cookie);

        System.out.println("添加cookie成功");
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doPost(req, resp);
    }
}
  • 第一次访问
    在这里插入图片描述

  • 第二次访问
    在这里插入图片描述

  • 使用javax.servlet.http.HttpServletResponse接口的成员方法实现Cookie的添加

方法声明功能介绍
void addCookie(Cookie cookie)添加参数指定的对象到响应
示例2 获取cookie
@WebServlet(name ="CookieServlet2", urlPatterns = "/cookieServlet2")
public class CookieServlet2 extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        //获取客户端发来的Cookie信息并且打印出来
        Cookie[] cookies = req.getCookies();

        System.out.println("获取到的Cookie:");
        for (Cookie cookie : cookies) {
            System.out.println(cookie.getName() + " 对应值: " + cookie.getValue());
            System.out.println("获取到cookie的时间:" + cookie.getMaxAge());
        }
    }

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

在这里插入图片描述

  • 使用javax.servlet.http.HttpServletRequest接口的成员方法实现Cookie对象的获取。
方法声明功能介绍
Cookie[] getCookies()返回此请求中包含的所有Cookie对象
  • 使用javax.servlet.http.Cookie类的构造方法实现Cookie对象中属性的获取和修改。
方法声明功能介绍
String getName()返回此Cookie对象中的名字
String getValue()返回此Cookie对象的数值
void setValue(String newValue)设置Cookie的数值
代码示例
示例3 设置cookie
  • 不能直接设置中文
String   str   =   java.net.URLEncoder.encode("中文""UTF-8");            //编码
String   str   =   java.net.URLDecoder.decode("编码后的字符串","UTF-8");   // 解码
@WebServlet(name ="CookieServlet3", urlPatterns = "/cookieServlet3")
public class CookieServlet3 extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 1.获取客户端发来的Cookie信息并打印出来
        Cookie[] cookies = req.getCookies();
        for (Cookie tc : cookies) {
            // 2.当获取到的Cookie对象的名字为name时,将对应的数值修改为guanyu并添加到响应信息中
            if ("name".equalsIgnoreCase(tc.getName())) {
                tc.setValue("guanyu");
                resp.addCookie(tc);
                break;
            }
        }
        System.out.println("修改Cookie信息成功!");
    }

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

2.5.3 Cookie的生命周期

默认情况下,浏览器会将Cookie信息保存在内存中,只要浏览器关闭,Cookie信息就会消失

方法声明功能介绍
int getMaxAge()返回cookie的最长使用期限(以秒为单位)
void setMaxAge(int expiry)设置cookie的最长保留时间(秒)
@WebServlet(name = "CookieServlet4",urlPatterns ="/cookieServlet4")
public class CookieServlet4 extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //1.创建Cookie信息
        Cookie cookie = new Cookie("name2", "liubei");

        //2.获取Cookie信息的默认使用期限
        System.out.println("该Cookie的使用期限为: " + cookie.getMaxAge());

        //3.修改Cookie信息的使用期限,正数表示在指定的秒数后失效 负数表示浏览器关闭后失效 0表示马上失效
        cookie.setMaxAge(20);

        //4.添加到响应信息中
        resp.addCookie(cookie);

        System.out.println("设置cookie生命周期成功!!!");
    }

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

2.5.4 Cookie的路径问题

  • 浏览器在访问服务器时,会比较Cookie的路径与请求路径是否匹配,只有匹配的Cookie才会发送给服务器。
  • Cookie的默认路径等于添加这个Cookie信息时的组件路径,例如:/项目名/目录/add.do请求添加了一个Cookie信息,则该Cookie的路径是 /项目名/目录。
  • 访问的请求地址必须符合Cookie的路径或者其子路径时,浏览器才会发送Cookie信息
方法声明功能介绍
void setPath(String uri)设置cookie的路径信息

@WebServlet(name = "CookieServlet5", urlPatterns ="/cookieServlet5")
public class CookieServlet5 extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //1.创建Cookie对象并指定数值
        Cookie cookie = new Cookie("name5", "zhangfei1");

        //3.修改Cookie的路径信息
//        cookie.setPath(req.getContextPath() + "/hello");

        //2.添加响应信息中
        resp.addCookie(cookie);

        System.out.println("设置路径成功!!!");
    }

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

在这里插入图片描述

  • 设置路径

@WebServlet(name = "CookieServlet5", urlPatterns ="/cookieServlet5")
public class CookieServlet5 extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //1.创建Cookie对象并指定数值
//        Cookie cookie = new Cookie("name5", "zhangfei1");
        Cookie cookie = new Cookie("name5", "guanyu2");

        //3.修改Cookie的路径信息
        cookie.setPath(req.getContextPath() + "/hello");

        //2.添加响应信息中
        resp.addCookie(cookie);

        System.out.println("设置路径成功!!!");
    }

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

在这里插入图片描述

  • 子路径请求头上面有2个cookie
    在这里插入图片描述
  • 非子路径在这里插入图片描述

2.5.5 Cookie的特点

Cookie技术不适合存储所有数据,程序员只用于存储少量、非敏感信息,原因如下:

  • 将状态数据保存在浏览器端,不安全。
  • 保存数据量有限制,大约4KB左右。
  • 只能保存字符串信息。
  • 可以通过浏览器设置为禁止使用。

2.6 Session技术(重点)

2.6.1 基本概念

  • Session本意为"会话"的含义,是用来维护一个客户端和服务器关联的一种技术。
  • 浏览器访问服务器时,服务器会为每一个浏览器都在服务器端的内存中分配一个空间,用于创建一个Session对象,该对象有一个id属性且该值唯一,我们称为SessionId,并且服务器会将这个SessionId 以Cookie方式发 送给浏览器存储
  • 浏览器再次访问服务器时将SessionId发送给服务器服务器可以依据SessionId 查找相对应的Session对象

在这里插入图片描述

2.6.2 相关的方法

  • 使用javax.servlet.http.HttpServletRequest接口的成员方法实现Session的获取。
方法声明功能介绍
HttpSession getSession()返回此请求关联的当前Session,若此请求没有 则创建一个
  • 使用javax.servlet.http.HttpSession接口的成员方法实现判断和获取。
方法声明功能介绍
boolean isNew()判断是否为新创建的Session
String getId()获取Session的编号
示例代码1 session获取
@WebServlet(name = "SessionServlet", urlPatterns = "/sessionServlet")
public class SessionServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //1.调用getSession方法获取或者创建Session
        HttpSession session = req.getSession();

        //2.判断该Session对象是否为新建对象
        System.out.println(session.isNew() ? "新创建的session对象" : "已有的session对象");

        //3.获取编号并打印
        System.out.println("获取的sessionId: " + session.getId());
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doPost(req, resp);
    }
}
  • 第一次请求
    在这里插入图片描述

  • 第二次请求
    在这里插入图片描述

  • 使用javax.servlet.http.HttpSession接口的成员方法实现属性的管理。

方法声明功能介绍
Object getAttribute(String name)返回在此会话中用指定名称绑定的对象,如果没有对象在 该名称下绑定,则返回空值
void setAttribute(String name, Object value)使用指定的名称将对象绑定到此会话
void removeAttribute(String name)从此会话中删除与指定名称绑定的对象
@WebServlet(name = "SessionServlet2", urlPatterns = "/sessionServlet2")
public class SessionServlet2 extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //1.获取session
        HttpSession session = req.getSession();
        //2.获取指定属性名对应的属性值
        session.setAttribute("name", "machao");
        System.out.println("获取的属性值:" + session.getAttribute("name"));

        //3.删除指定的属性名
        session.removeAttribute("name");
        System.out.println("获取的属性值:" + session.getAttribute("name"));
    }

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

在这里插入图片描述

2.6.3 Session的生命周期

  • 为了节省服务器内存空间资源,服务器会将空闲时间过长的Session对象自动清除掉,服务器默认的超时限制一般是 30 分钟
  • 使用javax.servlet.http.HttpSession接口的成员方法实现失效实现的获取和设置。
方法声明功能介绍
int getMaxInactiveInterval()获取失效时间
void setMaxInactiveInterval(int interval)设置失效时间
@WebServlet(name = "SessionServlet3", urlPatterns = "/sessionServlet3")
public class SessionServlet3 extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
        HttpSession session = req.getSession();
        System.out.println("获取到的默认失效时间为:" + session.getMaxInactiveInterval());

        //修改失效时间后重新获取并且打印   秒为单位
        session.setMaxInactiveInterval(600);
        System.out.println("获取到失效时间为:" + session.getMaxInactiveInterval());
    }

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

在这里插入图片描述

  • 可以配置web.xml文件修改失效时间(单位分钟)
<session-config>
	<session-timeout> 30 </session-timeout>
</session-config>

2.6.4 Session的特点

  • 数据比较安全。
  • 能够保存的数据类型丰富,而Cookie只能保存字符串。
  • 能够保存更多的数据,而Cookie大约保存4KB。
  • 数据保存在服务器端会占用服务器的内存空间,如果存储信息过多、用户量过大,会严重影响服务器的性能。

第三章 JSP核心技术

3.1 JSP的概述(熟悉)

在这里插入图片描述

3.1.1 JSP的概念

  • JSP是Java Server Pages的简称,跟Servlet一样可以动态生成HTML响应, JSP文件命名为xxx.jsp。
  • 与Servlet不同,JSP文件以HTML标记为主,然后内嵌Java代码段,用于处理动态内容。

3.1.2 JSP的示例

	<%@ page import="java.util.Date" %>
	<%@ page contentType="text/html;charset=UTF-8" language="java" %>
	<html>
		<head>
			<title>Hello Time</title>
		</head>
		<body>
			现在的时间是:<%= new Date()%>
		</body>
	</html>

3.1.3 JSP与Servlet的关系

在这里插入图片描述

3.2 JSP的语法(熟悉)

3.2.1 JSP语法结构

  • 声明区

  • 程序代码区

  • 表达式

  • 注释

  • 指令和动作

  • 内置对象

3.2.2 声明区

  • 基本语法:
    <%! %>

  • 说明:可以定义全局变量、方法、类。

<%!
	int i;
	public void setName(){… …}
%>

3.2.3 程序代码区

  • 基本语法:
    <%程序代码区%>
  • 说明:可以定义局部变量以及放入任何的Java程序代码。
<%
	int j;
	for (int k=0; k<10; k++) {
		… …
	}
%>

3.2.4 表达式(输出)

  • 基本语法:
    <%=... ...%>

  • 说明:可以输出一个变量或一个具体内容,但=后面必须是字符串变量或者可以被转换成字符串的

  • 注意:不需要以 ; 结束,只有一行

	<%=“hello world”%>
	<%=i+1%>
  • 示例 declare.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>测试声明区、打印</title>
    <%!
        int ia; //全局变量

        public void show(){
            System.out.println("这是全局方法");
        }

        public class MyClass{
            {
                System.out.println("这是全局方法");
            }
        }
    %>

    <%
        int ib = 20;    //局部变量

        for(int i = 0; i < 3; i++){
            System.out.println("随便写点java代码");
        }
    %>
</head>
<body>

    <%= ia + 1 %>   <%-- 1 --%>
    <%= ib %>       <%-- 20 --%>
    <%= "暂时写点" %>

</body>
</html>

在这里插入图片描述

在这里插入图片描述

  • 案例题目
使用for循环输出一个html语言的表格,具体表头如下:
id name age salary
1 	1 	1 	1
2 	2 	2 	2
...
5 	5 	5 	5
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>实现表格的绘制</title>
</head>
<body>

    <table>
        <tr>
            <td>id</td>
            <td>name</td>
            <td>age</td>
            <td>salary</td>
        </tr>

        <%
            for(int i = 1; i < 6; i++){
        %>
        <tr>
            <th><%= i %></th>
            <th><%= i %></th>
            <th><%= i %></th>
            <th><%= i %></th>
        </tr>
        <%
            }
        %>
    </table>

</body>
</html>

在这里插入图片描述

3.2.5 注释

格式:
<!--… …--> 		HTML文件的注释,浏览器可以查看到(查看源代码)

<%--… …--%> 	JSP文件的注释,浏览器看不到

<%//… …%> 		Java语言中的单行注释,浏览器看不到

<%/*… …*/%> 	Java语言中的多行注释,浏览器看不到

注释的内容不会被执行
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>注释的测试</title>
</head>
<body>
<!-- 这是HTML文件中的注释方式,浏览器是可以看到的 -->
<%-- 这是JSP文件中的注释方式,该方式浏览器是看不到的 --%>
<%
    // Java语言中的单行注释   浏览器看不到哦
    /* Java语言中的多行注释   浏览器看不到哦! */
%>
</body>
</html>

3.2.6 指令和动作

  • 指令格式:
    <%@指令 属性=“属性值”%>

  • 指令的属性可以设定多个。

  • JSP常用指令有:page、taglib、include。

( 1 )page指令
  • page指令用于导包和设置一些页面属性,常用属性如下:
import 			导入相应的包,惟一允许在同一文档中多次出现的属性
contentType 	设置Content-Type响应报头,标明即将发送到浏览器的文档类型
pageEncoding 	设置页面的编码
language 		指定页面使用的语言
session 		控制页面是否参与HTTP会话
errorPage 		处理当前页面中抛出但未被捕获的任何异常
isErrorPage 	当前页是否可以作为其他页面的错误处理页面

在这里插入图片描述

( 2 )taglib指令
  • taglib指令用来扩展JSP程序的标签元素,引入其他功能的标签库文件
<!-- prefix属性用于指定库前缀 -->
<!-- uri属性用于指定库的标识 -->
<%@taglib uri=“tagLibary” prefix=“prefix”%>
( 3 )include指令 ( 静态包含 )
  • include指令用于引入另一个JSP程序HTML文件等,格式如下:
<%@include file=“被包含的文件地址%>
  • JSP引擎会在JSP文件的转换时期先把file属性设定的文件包含进来,然后开始执行转换及编译的工作。

在这里插入图片描述
在这里插入图片描述

  • head.html
    在这里插入图片描述

在这里插入图片描述

( 4 )jsp:include/jsp:param ( 动态包含 )
  • jsp:include动作用于引入另一个JSP程序或HTML文件等。
  • 执行到include时,被include的文件才会被编译。
  • 如果include的是jsp文件,那它不会被转换成Servlet文件。
<jsp:include page=“URLSpec” flush=“true”/>
<jsp:include page=“URLSpec” flush=“true”>
	<jsp:param name=“key” value=“value”/>
</jsp:include>
( 5 )include指令和include动作的区别
  • include指令是在JSP程序的转换时期就将file属性所指定的程序内容嵌入再编译执行(静态包含)。
  • include动作在转换时期是不会被编译的,只有在客户端请求时期被执行到才会被动态的编译载入(动态包含,推荐)。
( 6 )jsp:forward/jsp:param
  • forward动作用于在JSP中实现转发,将请求转发到另一个指定的JSP程序或者Servlet中处理。
<jsp:forward page=“urlSpec” flush=“true”/>

<jsp:forward page=“urlSpec”>
	<!-- 用于指定参数和其对应的值 -->
	<jsp:param name=“key” value=“value”/>
</jsp:forward>
  • forward.jsp
    在这里插入图片描述

  • tagert.jsp
    在这里插入图片描述

在这里插入图片描述

3.3 JSP内置对象(重点)

3.3.1 基本概念

  • 在JSP程序中有 9 个内置对象由容器为用户进行实例化,程序员可以不用定义就直接使用这些变量。

  • JSP转换成Servlet后会自动追加这些变量的定义,使用内置对象可以简化JSP的开发。

3.3.2 对象名称

对象变量对象类型作用
outJSPWriter输出流
requestHttpServletRequest请求信息
responseHttpServletResponse响应信息
sessionHttpSession会话
applicationServletContext全局的上下文对象
pageContextPageContextJSP页面上下文
pageObjectJSP页面本身
configServletConfigServlet配置对象
exceptionThrowable捕获网页异常

3.3.3 out内置对象

  • out内置对象是一个缓冲的输出流,用来给客户端输出信息
  • 常用方法如下:
方法声明功能介绍
void println(String x)向客户端输出各种类型数据
void newLine()输出一个换行符
void close()关闭输出流
int getBufferSize()返回缓冲区的大小
int getRemaining()返回缓冲区中未使用的字节数
void flush()输出缓冲区里的数据
注意下面2个方法清除缓存后客户端不会有任何内容,flush()放clearBuffer()输出内容,放claer()则报错
void clearBuffer()清除缓冲区里的数据,同时把数据输出到客户端
void clear()清除缓冲区里的数据,但不把数据输出到客户端
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>out内置对象的使用</title>
</head>
<body>

    <%
        out.print("<h1>");
        out.print("HelloWorld ! ! !");
        out.print("</h1>");
//        out.close();

        int bufferSize = out.getBufferSize();
        System.out.println("缓冲区总大小" + bufferSize);

        int remaining = out.getRemaining();
        System.out.println("缓冲区剩余大小" + remaining);

        System.out.println("已经使用字节数" + (bufferSize - remaining) );
        
        //清除缓冲区 并输出到客户端
        out.flush();        //放在clearBuffer前面会输出内容,放在clear前面会报错
        out.clearBuffer();  //如果不加out.flush();不会输出任何内容
        System.out.println("清除的缓冲区" + out.getRemaining());
    %>

</body>
</html>

在这里插入图片描述

在这里插入图片描述

3.3.4 request内置对象

  • request对象封装的是调用JSP页面的请求信息,它是HttpServletRequest接口的一个实例。
  • 对象的属性值 只在一个请求中保存。
  • 常用方法如下:
方法声明功能介绍
String getMethod()返回客户端向服务器端传送数据的方式
String getParameter(String name)返回客户端向服务器端传送的参数值
String[] getParameterValues( String name)获得指定参数的所有值
String getRequestURI()获得请求地址
String getRemoteAddr()返回发送请求的客户端或最后一个代理的IP地址
int getRemotePort()返回发送请求的客户端或最后一个代理的端口号
String getServerName()获取服务器的名字
int getServerPort()获取服务器端的端口
void setAttribute(String name,Object o)在此请求中存储属性。属性在请求之间重置
Object getAttribute(String name)将指定属性的值作为对象返回,若不存在则返回空 值
  • request.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>request内置对象的使用</title>
</head>
<body>

    <%
        System.out.println("获取到的服务器名称为:" + request.getServerName());    /* localhost */
        System.out.println("获取服务器端的端口" + request.getServerPort());          /* 8080 */
        request.setAttribute("name", "zhangfei");
    %>

    <%--实现转发效果,也就是服务器跳转--%>
    <jsp:forward page="requestTarget.jsp"></jsp:forward>
</body>
</html>
  • requestTarget.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>获取requerst对象中的值</title>
</head>
<body>

    <%= "获取的属性值为:" + request.getAttribute("name") %>

</body>
</html>

在这里插入图片描述

3.3.5 response内置对象

  • response对象用于给客户端相应输出处理结果,它是HttpServletResponse接口的一个实例。
  • 经常用于设置HTTP标题,添加cookie、设置响应内容的类型和状态、发送HTTP重定向和编码URL。
  • 常用方法如下:
方法声明功能介绍
void addCookie(Cookie cookie)添加一个Cookie对象,用于在客户端保存特定的信 息
void addHeader(String name, String value)添加HTTP头信息,该Header信息将发送到客户端
boolean containsHeader(String name)判断指定名字的HTTP文件头是否存在( 是否存在该HTTP头 )
void sendRedirect(String location)重定向JSP文件
void setContentType(String type)设置类型与编码方式
<%@ page import="java.util.Date" %>
<%@ page import="java.text.SimpleDateFormat" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>reponse内置对象的使用</title>
</head>
<body>

    <%
        //表示每隔1秒进行刷新
        response.setHeader("refresh", "1");

        //获取到当前系统时间
        Date date = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yy-MM-dd HH:mm:ss");
        String format = sdf.format(date);
    %>

    <%= "当前时间:" + format %>
</body>
</html>

在这里插入图片描述

3.3.6 session内置对象

  • session对象表示浏览器和服务器之间的一次会话,一次会话可以包含多次请求(区别request),在多次请求之间可以借助session对象存储信息,它是HttpSession类型的一个实例。
  • 该对象的属性值在一次会话范围中保存,保存在服务器端,只要不关闭浏览器默认半个小时内都可以访问。
  • 常用方法如下:
方法声明功能介绍
void setAttribute(String name, Object value)使用指定的名称将对象绑定到此会话
Object getAttribute(String name)返回在此会话中用指定名称绑定的对象,如果没有对象在该 名称下绑定则返回空值
  • session.jsp
    在这里插入图片描述
  • sessionTarget.jsp
    在这里插入图片描述
  • 先访问session.jsp

在这里插入图片描述
换一个浏览器直接访问
在这里插入图片描述

3.3.7 application内置对象

  • application对象是一个web程序的全局变量,它是ServletContext类型的一个实例。
  • 在整个服务器上保存数据,所有用户共享
  • 常用方法如下:
方法声明功能介绍
void setAttribute(String name, Object object)将对象绑定到此servlet上下文中的给定属性名
Object getAttribute(String name)返回给定名称的servlet容器属性,若没有该名称的属 性返回null
  • application.jsp
    在这里插入图片描述
  • applicationTarget.jsp
    在这里插入图片描述
  • 全局对象
    在这里插入图片描述
    在这里插入图片描述

3.3.8 pageContext内置对象

  • pageContext对象是PageContext类型的对象,可以使用这个对象来管理其他的隐含对象
  • 只在一个页面中保存数据。
方法声明功能介绍
void setAttribute(String name, Object value, int scope)使用适当的作用域设置指定的名称和值
Object getAttribute(String name, int scope)返回指定作用域中名称关联的对象,若找不到 则返回null
ServletRequest getRequest()获取请求对象
ServletResponse getResponse()获取响应对象
HttpSession getSession()获取会话对象
ServletConfig getServletConfig()获取配置对象
JspWriter getOut()获取输出对象
Object getPage()获取页面对象
Exception getException()获取异常对象
  • pageContext.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>pageContext内置对象的使用</title>
</head>
<body>

    <%
        pageContext.setAttribute("name", "liubei");
    %>

    <%= "获取到的pageContext内置对象中的属性值为:" + pageContext.getAttribute("name") %>

</body>
</html>
  • pageContextTarget.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>pageContext内置对象属性的获取</title>
</head>
<body>

    <%= "获取到的pageContext内置对象中的属性值为" + pageContext.getAttribute("name") %>   <%-- null --%>

</body>
</html>
  • 只能在同一个页面中获取到
    在这里插入图片描述
    在这里插入图片描述

3.3.9 exception内置对象

  • exception 对象是Throwable的实例,表示的是JSP的异常信息

  • 如果要使用它,必须将对应页面page指令的isErrorPage属性设置成true。(没有设置 就不会提示exception内置对象)

  • 单个页面的处理方式( 出现错误跳转到error.jsp )

<%@page errorPage="error.jsp" %>
  • 该页面出错
    在这里插入图片描述

  • 出错处理页面
    在这里插入图片描述
    在这里插入图片描述

  • 在web.xml中配置统一的异常处理页面。(修改配置文件,要重启服务器)

<error-page>
	<exception-type>java.lang.Throwable</exception-type>
	<location>/error.jsp</location>
</error-page>

3.4 JavaBean组件(熟悉)

( 1 )基本概念
  • JavaBean 是使用 Java 语言开发的一个可重用的组件,在 JSP 开发中可以使用 JavaBean 减少重复代码,使整个 JSP 代码的开发更加简洁。
  • JavaBean本质上就是Java类,通常要求如下:
    • 属性:全部私有化,通过get和set方法进行访问。
    • 方法:必须是public关键字修饰。
    • 构造器 :必须有无参构造方法。
( 2 )使用方式
  • 使用jsp:useBean的方式创建javaBean实例
<jsp:useBean id=“对象名” scope=“保存范围 class=“包名.类名” />
保存范围有:page|request|sessin|application,默认为page范围。
  • 使用jsp:setProperty的方式设置javaBean的属性值
<jsp:setProperty name="对象名" property="属性名" value="属性值" 或者 param="表单提交的参数名"/>
  • 使用jsp:getProperty的方式获取javaBean的属性值
<jsp:getProperty name="对象名" property="属性名"/>
示例代码1 创建对象、设置属性、获取属性值
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>JavaBean组件的使用</title>
</head>
<body>

    <%
        // 创建Student类型的对象并设置成员变量的数值
        // Student student = new Student();
        // student.setId(1001);
        // student.setName("zhangfei");
    %>

    <%-- 表示创建Student类型的对象由student引用变量负责记录  有效范围是当前页面 --%>
    <jsp:useBean id="student" scope="page" class="com.lagou.demo02.Student"/>   <%--Student student = new Student();--%>
    
    <%-- 表示将student对象中名字为id的属性值设置为1002 --%>
    <jsp:setProperty name="student" property="id" value="1002"/>                <%-- student.setId(1002); --%>
    <jsp:setProperty name="student" property="name" value="guanyu"/>

    <%-- 获取属性值 --%>
    <%= student.getId() %>
    <%= student.getName() %><br/>

    <jsp:getProperty name="student" property="id"/>
    <jsp:getProperty name="student" property="name"/>

</body>
</html>

在这里插入图片描述

示例代码2
  • beanparam.html
    <form action="bean2.jsp" method="post">
        学号: <input type="text" name="id1"/>      <br/>
        姓名: <input type="text" name="name1"/>    <br/>
              <input type="submit" value="向JavaBean组件传参"/>
    </form>
  • bean2.jsp 使用参数param设置属性值,并设置作用域为session
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>实现前端页面传入过来参数的接收和设置</title>
</head>
<body>

    <jsp:useBean id="student" class="com.lagou.demo02.Student" scope="session"/>

    <%--获取表单提交的参数--%>
    <jsp:setProperty name="student" property="name" param="name1"/>
    <jsp:setProperty name="student" property="id" param="id1"/>

</body>
</html>
  • 获取session中的数据
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>实现JavaBean组件中对象属性值的打印</title>
</head>
<body>

    <jsp:useBean id="student" scope="session" class="com.lagou.demo02.Student"/>

    经过参数赋值后获取到的学号是:<jsp:getProperty name="student" property="id"/><br/>
    经过参数赋值后获取到的姓名是:<jsp:getProperty name="student" property="name"/><br/>

</body>
</html>

在这里插入图片描述
在这里插入图片描述

( 3 )保存范围
  • JavaBean的保存范围有page、request、session以及application,默认是page范围
( 4 )删除方式
<%
	内置对象.removeAttribute(JavaBean的名字”);
%>
  • 示例代码
        <%
            session.removeAttribute("student");
        %>

3.5 MVC设计模式(重点)

3.5.1 基本概念

  • MVC是模型(Model)和视图(View)以及控制器(Controller)的简写,是一种将数据、界面显示和业务逻辑进行分离的组织方式,这样在改进界面及用户交互时,不需要重新编写业务逻辑,从而提高了代码的可维护性。

  • M:主要用于封装业务数据的JavaBean(Bean) 和 业务逻辑的JavaBean(Service)及访问数据库的DAO对象。

  • V:主要负责数据收集 和 数据展现,通常由JSP文件完成。

  • C:主要负责流程控制 和 页面跳转,通常由Servlet完成。

3.5.2 基本模型

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值