Servlet基础

Posted codeli

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Servlet基础相关的知识,希望对你有一定的参考价值。

Servlet

一、服务器端编程

简单的说编写运行服务器中的程序代码,在java中使用的就是Servlet技术。

1.1 软件架构模式

一个软件的形态问题,一个软件有展现给用户的一面,也有处理业务的一面,一般来说展现给用户的称为客户端,

处理业务逻辑的称为服务端。

  • 传统的软件: 采用 C/S架构 Client就是客户端 Server服务端,典型的比如:QQ(桌面应用) LOL(端游)
  • 目前流行方式: 采用B/S架构,Browser 浏览器(充当客户端) Server服务端 典型的 淘宝(网站) 贪玩蓝月(页游)

B/S 在于灵活,跨平台。

1.2 服务器

服务器 = 硬件(计算机) + 软件(web应用软件)

首先它是一台计算机(配置非常高),在它上面安装软件(Web服务器,web中间件),这个软件是用来执行后台代码的。

1.3 资源

服务器的作用是提供资源和计算(广义上数据处理),什么能够算资源? 比如图片,一个网页,登录服务,支付服务,下单服务。

  • 静态资源: 静态文件
  • 动态资源 : 系统提供的某些服务,后续学习Servlet 就是动态资源。
1.4 资源访问

使用URL 统一资源定位符。

协议 + IP + 端口 + 资源
https://media.bjnews.com.cn/image/2020/04/02/4909692635033185156.jpg

二、Web服务器

2.1 介绍
  • Tomcat 服务器,是javaWeb中使用的非常多的一款服务器软件,他是有apache软件开源基金会 提供的顶级开源项目。
官网: https://tomcat.apache.org/
2.2 安装
  • 解压即安装

  • 配置 JAVA_HOME 环境变量(tomcat运行依赖与jvm,需要指定jdk)

目录:

bin : 可执行文件目录,包含启动停止命令
conf: 配置文件目录,存放tomcat的配置文件
lib : 依赖和提供的类库jar包
logs: tomcat日志目录
temp: 临时目录,用于tomcat执行过程中临时文件存放。
webapps: 非常重要的目录,发布网站的文件夹。
work: 工作目录,将来jsp文件编译成servlet存放的目录
2.3 启动停止
bin/startup.bat  启动命令  不要重复启动,如果要启动先关闭已经启动的。
bin/shutdown.bat 停止命令

如果出现闪退:可能是你没有配置JAVA_HOME 环境变量

Neither the JAVA_HOME nor the JRE_HOME environment variable is defined
At least one of these environment variable is needed to run this program
2.4 测试访问
  • 先启动
  • 打开浏览器访问
http://localhost:8080

localhost 本机地址 8080 默认端口

2.5 配置
  • 端口配置 conf/server.xml
    <Connector port="8888" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" />

默认端口8080 可以改成其他如:8888

  • 启动日志乱码 conf/logging.properties
java.util.logging.ConsoleHandler.level = FINE
java.util.logging.ConsoleHandler.formatter = org.apache.juli.OneLineFormatter
java.util.logging.ConsoleHandler.encoding = gbk

windows 窗口默认编码为GBK,如果输出内容为UTF-8乱码。

2.6 发布静态网站

发布网站的本质就是把网站代码 拷贝到 服务器的webapps目录下。这样我么的网站就交个tomcat管理了。tomcat监听了一个端口,当我们使用浏览器 访问 IP+端口 找到了服务器,进而通过资源名称找到具体资源。

2.7 idea 整合Tomcat
1. Settings -> Run Configuration Templates for New Porject

2. TomcatServer -> Local

3. Application Server  点击  Configuration 找到tomcat安装位置

4. OK确认

【一定先把Tomcat整合好】后面创建项目就可以直接选了,如果没有整合,那么需要再创建项目时整合。

三、Servlet的入门

Servlet(Server Applet)是Java Servlet的简称,称为小服务程序或服务连接器,用Java编写的服务器端程序,具有独立于平台和协议的特性,主要功能在于交互式地浏览和生成数据,生成动态Web内容。

狭义的Servlet是指Java语言实现的一个接口,广义的Servlet是指任何实现了这个Servlet接口的类,一般情况下,人们将Servlet理解为后者。Servlet运行于支持Java的应用服务器中。从原理上讲,Servlet可以响应任何类型的请求,但绝大多数情况下Servlet只用来扩展基于HTTP协议的Web服务器。

最早支持Servlet标准的是JavaSoft的Java [Web Server](https://baike.baidu.com/item/Web Server/9306055),此后,一些其它的基于Java的Web服务器开始支持标准的Servlet。

3.1执行原理

1、当服务器接收到客户端浏览器的请求后会解析请求URL路径,获取访问Servelt的资源路径

2、查找web.xml文件,是否有对应的标签对应

3、如果有则找到对应文件的全限定类名

4、tomcat会将字节码文件加载进内存,并且创建对象

5、调用其他方法

3.2、Servlet的生命周期

1、被创建:执行init方法,而且值只执行一次

? servlet默认在第一次访问时被创建,

? 也可以在配置执行servlet

? 在标签下配置

? 的值为负数的时候表示第一次访问时创建,当值为0或者正数的时候 servlet在服务器启动的时候创建

? Servlet的init方法只执行一次说明Servlet在内存中只存在一个对象,Servlet是单例的,当多个用 户同时访问时,存在线程安全问题

? 解决方法是:尽量不要在Servelt中定义成员变量,即使定义了,也不要修改值

2、提供服务:执行Service方法执行多次,当每访问Servlet是,Servlet方法都会被调用一次

3、摧毁:执行destroy方法,只会执行一次,Servlet被摧毁时执行,服务器关闭,Servlet被摧毁,只有服务器正常执行时才会执行destroy方法

补充:

1.加载启动问题

<load-on-startup>1</load-on-startup>
或者注解
@WebServlet(value ="/xxx.do",loadOnStartup = 1)

启动服务器时就会创建和初始化Servlet

2 初始化参数问题

    <servlet>
        <servlet-name>LifeServlet</servlet-name>
        <servlet-class>com.qfedu.servlet.LifecycleServlet</servlet-class>
        <init-param>
            <param-name>gg</param-name>
            <param-value>郑宇</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
或者注解
@WebServlet(value = "/life.do",loadOnStartup = 1,
        initParams = { @WebInitParam(name = "gg",value = "kangkang")}   )
3.3Servlet的体系结构

HttpServelt抽象类继承GenericServlet抽象类,GenericServlet抽象类实现了HttpServlet接口

1、GenericServlet:将Servlet接口中的其他方法进行了默认空实现,只将Servlet方法作为抽象方法,将来定义Servelt类时,可以继承GenericServlet抽象类实现Service()方法即可

2、HttpServlet:对HttpServelt协议的一种封装简化

? a.定义类继承HttpServelt

? b.复写doGet和doPost方法

? doGet方法是以get方式提交的才执行

? doPost方法是以post方式提交的才执行

3.4 入门

1.创建一个JavaEE项目

2.定义一个类,实现Servlet或者继承HttpServlet抽象类

3.实现接口中的抽象方法

//使用注解开发
//@WebServlet(name = "/Servlet01")
public class ServletDemo01 extends HttpServlet{
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("test/html;charset=utf-8");
        resp.getWriter().println("你好servlet");

    }

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

        this.doGet(req,resp);
    }
}

4.配置Servlet的配置文件或者使用注解开发

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <!--配置servlet文件-->
    <servlet>
        <!--自定义选定class的servlet名称-->
        <servlet-name>ServletDemo01</servlet-name>
        <!--servlet全限定类名-->
        <servlet-class>servlet.ServletDemo01</servlet-class>
    </servlet>
    <!--配置servlet的映射-->
    <servlet-mapping>
        <!--引用servlet-->
        <servlet-name>ServletDemo01</servlet-name>
        <!--设置URL定位资源,将来通过该路径访问该servlet-->
        <url-pattern>/ServletDemo01</url-pattern>
    </servlet-mapping>
</web-app>
3.5 Servlet相关配置

1、urlpartten:Servlet访问路径

? 一个Servelt可以定义多个访问路径,如@WebServlet({"/demo001","/demo02","/demo03"})

2、路径定义规则

/xxx.:路径匹配

/xxx/xxx:多层路径目录结构

/*.demo:扩展名匹配

3.2关于IDEA的一些操作

1、快速创建一个Servlet

技术图片

2、关于服务器tomcat的设置

进入修改

技术图片

技术图片

技术图片

四、HTTP协议

4.1概念

HTTP(HyperText Transfer Protocol,超文本传输协议)是一个简单的请求-响应协议,他通常运行在TCP之上。他指定了客户端可能发送给服务器什么样的消息以及得到什么样的响应。请求和响应消息的头以ASCLL码形式给出,而消息内容则有一个类似MIME的格式

整个web开发都是围绕着这个Http协议展开的,所以有的web技术都是协议范畴下的技术,如果不搞清楚这个协议,那么,多理解整个web开发是有影响的。

理解

超文本?不限于文本(各种文档类型)。

传输协议? 网络模型OSI七层网络通信模型中的传输层协议

HTTP 是控制文档或数据传输的一种协议,这种协议建立在TCP上(java中TCP的实现是Scoket),我们知道TCP是长连接,但是Http是无连接。

42.HTTP的特点

1、是基于TCP/IP的高级协议

2、默认端口号是80

3、基于请求/响应模式的:一次请求一次响应

4、无状态的:每次请求之间相互独立,不能交互数据,服务端不需要维护客户的状态信息,提高处理效率

5、支持 B/S 软件模型。

6、http传输协议,不管你传输的内容,但是内容的类型是需要说明的

7、无连接 TCP面向长连接的 Http 短连接(客户端发送消息,服务端响应,就断开连接),不用维护连接,提高效率。

HTTP的历史版本

1.0版本:每次请求都会创建新的连接

1.1版本:会复用连接

4.3 Http请求消息

请求服务需要发送数据,那么这些数据有一定的格式,所谓的格式就是协议,协议的目的是为了通信双方更好理解。

方法  URL  版本  [回车换行]   --- 请求行 
key : value  [回车换行]      --- 请求头
....

请求正文

请求消息数据格式
1、请求行
	请求URL  请求方式   请求协议版本
	请求方式:
	共有7种,常用的是2种get 和 post
GET /sport/test HTTP/1.1   
Host: localhost:8080
Connection: keep-alive  // Http1.1新增特性 一个页面中的资源请求可以不用断开连接,在一个连接中完成。
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
//这是浏览器的相关信息
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.122 Safari/537.36 Edg/81.0.416.64
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
Cookie: JSESSIONID=690FC52F422D58F0B54ACA4FEBD218F3
4.4 请求方法

请求方法
Http1.0
GET(获取), POST(新增) HEAD

? Http1.1
? DELETE(删除资源) PUT(修改) OPTIONS PATCH TRACE CONNECT

Get 和 Post 区别

1. 从使用场景上看: get 表示获取服务器上的资源。  post 表客户端提交资源。
2. 从表现上看, get 浏览器地址栏可见(数据走url)   post 地址栏不可见(安全性高,数据走请求正文)
3. 从数据量看, get 有数据量的限制, post 理论上没有明确限制(上传大文件)。
4.5 HTTP响应消息

1、响应消息:服务器发送给客户端的数据

2、结构

? 1、响应行:

? 协议版本 响应状态码 状态码描述

? 2、响应头:

? 格式:头名2称:值

? 常见的响应头:

? 1、Context-Type:服务器告诉客户端本次响应体数据格式以及编码格式

? 2、Context-disposition:服务器告诉客户端以什么格式响应体数据值 值:in-line:默认值,在当前页面打开 attachment filename:xxx 以附件形式打开响应体
3、响应空行

4、响应体:传输的数据

4.6 状态码

用一个数字表示服务器响应某种现象(响应状态)

50X 服务器错误  500 后台代码出现了异常Exception
40X 资源找不到  404请求的资源找不到(1.根本就没这个资源,2url写错了)
30X 资源重定向或者权限问题
20X 请求成功    200 成功
4.7 文档类型

计算机世界中 使用的是MIME 标准的扩展名协议。

html = text/html

css = text/css

text = text/plain

json = application/json

在http协议中指定一个文档的类型使用的就是 MIME类型 这个类型在http中其实称为Content-Type

五、Servlet 深入

5.1 Servlet 创建方式
1. 实现 Servlet 接口 [了解]
2. 继承 GenericServlet[了解]
3. 继承 HttpServlet【掌握】

Servlet Servlet 标准接口(与协议无关)

GenericServlet 通用的Servlet为了简化Servlet开发的过渡过渡接口(抽象类)

HttpServlet 完全支持Http协议的Servlet,很好的实现HTTP协议规范。

代码:

package com.qfedu.servlet;

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

//创建Servlet :
//方式1:
//public class MyServlet implements Servlet {
//    @Override
//    public void init(ServletConfig servletConfig) throws ServletException {
//
//    }
//
//    @Override
//    public ServletConfig getServletConfig() {
//        return null;
//    }
//
//    @Override
//    public void service(ServletRequest req, ServletResponse resp) throws ServletException, IOException {
//            resp.getWriter().println("implements Servlet");
//    }
//
//    @Override
//    public String getServletInfo() {
//        return null;
//    }
//
//    @Override
//    public void destroy() {
//
//    }
//}
// 需要是很多方法




// 方式二:
// extends GenericServlet  简化Servlet
/*
public class MyServlet extends GenericServlet{
    @Override
    public void service(ServletRequest servletRequest, ServletResponse resp) throws ServletException, IOException {

        resp.getWriter().println("extends GenericServlet");
    }
}*/
// 需要实现 一个方法



//方式三:
//常用的方法(掌握)
//重写两个方法(为了应对前端请求的方式)
public class MyServlet  extends HttpServlet {

    // 专门对付 以get 方式发送的请求
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {

    }

    // 专门对付 以post 方式发送的请求
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {

    }
}

到底执行哪一个,有前端提交的方式决定。

5.2 配置方式
  1. xml 配置
<!-- 注册Servlet -->
<servlet>
    <servlet-name>My</servlet-name>
    <servlet-class>com.qfedu.servlet.MyServlet</servlet-class>
</servlet>
<!-- 映射Servlet -->
<servlet-mapping>
    <servlet-name>My</servlet-name>
    <url-pattern>/my</url-pattern>
</servlet-mapping>

url 前一定加 / 否则启动不了 多个Servlet 名字和url不能相同。

  1. 注解配置
@WebServlet("/java")
public class MyServlet  extends HttpServlet {

    // 专门对付 以get 方式发送的请求
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        resp.getWriter().println("hehe");

    }

    // 专门对付 以post 方式发送的请求
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {

    }
}
@WebServlet(urlPatterns = "/java")
@WebServlet("/java")
@WebServlet(urlPatterns = {"/java","/test"}  )

1 使用这个注解就注册了Servlet 2. urlPatterns就是访问路径

5.3 Servlet 接受参数

Servlet 的作用是接受用户的请求,那么它必须可以获得用户提交的数据,请求一定走http协议。

5.3.1 准备一个前端注册界面

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>表单标签</title>
	</head>
	<body>
        <!--
        、 action : 提交的后台地址(Servlet地址)
           method  : 提交方式 post 或者 get 提交方式不同,后台执行的方法不同。
        、-->
		<form action="/user/reg.do"  method="post"  >
			<input name="username" type="text"   placeholder="输入账号" />
			<br />
		    <input name="password" type="password" placeholder="输入密码" />

			<br />
			性别:<input name="sex" type="radio" value="man"  />男 <input name="sex" type="radio" value="woman" checked="checked" />女

			<br />
			爱好: <input name="hobby" type="checkbox" value="Live" /> 直播
			<input name="hobby" type="checkbox" value="Game" checked="checked"/> 游戏
			<input name="hobby" type="checkbox" value="girl" checked="checked"/> 美女
			<br />
			学历:
			<select name="edu" style="width: 120px;">
				<option value="xx">小学</option>
				<option value="cz" selected="selected"  >初中</option>
				<option value="gz">高中</option>
				<option value="dx" >大学</option>
			</select>
			<br />
			自我介绍:
			<textarea name="info" rows="10" cols="60"></textarea>
			<br />
			<input type="submit" value="注册" />
	
		</form>    
	</body>
</html>

5.3.2 后台Servlet

package com.qfedu.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.util.Arrays;

//这是一个注册的Servlet 接受用户的请求数据
@WebServlet("/user/reg.do")
public class RegisterServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
       //HttpServletRequest req  请求对象:封装请求数据
       //HttpServletResponse resp 响应对象: 封装响应数据

       //取数据
       //为了防止乱码,获得数据前设置req 的编码格式 ios885
       req.setCharacterEncoding("UTF-8");
       String name=  req.getParameter( "username" );
       String pwd=  req.getParameter( "password" );
       String sex = req.getParameter("sex");
       String[] hobbys = req.getParameterValues("hobby");
       String edu = req.getParameter("edu");
       String info = req.getParameter("info");
       //测试
        System.out.println(name);
        System.out.println(pwd);
        System.out.println(sex);
        System.out.println(Arrays.toString(hobbys));
        System.out.println(edu);
        System.out.println(info);
        // 如果在这里连接数据库? 是不是可以真正实现注册?
    }
}

req.setCharacterEncoding("UTF-8"); 解决从请求对象中获得数据乱码

String getParameter( String name ); 获取前端参数,参数name 一定要和前端的 标签name一致。

String getParameterValues(String name); 和getParameter 作用一致,用于获得多值的情况比如 复选框。

5.4 乱码问题

请求乱码解决

req.setCharacterEncoding("utf-8");//设置请求的编码方式为utf-8

响应乱码

resp.setCharacterEncoding("utf-8")//设置数据流的编码方式为utf-8

resp.setContextType("text/html;charSet=utf-8);//告诉前端浏览器要把这个响应内容解析为网页,且用utf-8解析

5.5 超链接传参

这种提交方式属于 get方式

< a  href=‘serlvet地址?name=value&name=value‘ >   超链接文本   </a>

?后面的内容是一个或者多个 名值 多个用 &连接。

后台的处理和表单提交数据处理没有区别,后端依然通过name 获得value

5.6 整合jdbc
  1. 引入jar 且 as Libary

  2. 拷贝 工具类 和 配置文件

  3. 编写实体类

  4. 编写Servlet

  5. 三层架构编程

控制器:

package com.qfedu.servlet;

import com.qfedu.entity.Book;
import com.qfedu.service.BookService;
import com.qfedu.service.impl.BookServiceImpl;

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.List;

/**
 * 处理 查询全部图书信息的Servlet
 * Servlet的职责是
 *   1. 接受请求
 *   2. 获取数据
 *   3. 处理( 调用业务层处理  )
 *   3. 响应
 */
@WebServlet("/books.do")
public class BookListServlet extends HttpServlet {


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

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

        //完成处理( 自己搞不定需要找对应的服务层对象 )
        BookService bookService = new BookServiceImpl();

        //调用查询业务方法
        List<Book> bookList=  bookService.findAll();

        //把数据响应给客户端
        resp.setCharacterEncoding("utf-8");
        resp.setContentType("text/html;charset=utf-8");

        // 思路: 把集合中的数据 编织到 table表格中, 动态的输出一段html代码(动态资源的核心)
        PrintWriter ps = resp.getWriter();

        ps.println("<html>");
        ps.println("<head>");
        ps.println("<link href=‘/css/table.css‘ rel=‘stylesheet‘  />");
        ps.println("</head>");
        ps.print("<body>");
            ps.println("<table border=1>");
            ps.println("<tr>
" +
                    "				<td>编号</td>
" +
                    "				<td>名字</td>
" +
                    "				<td>价格</td>
" +
                    "				<td>作者</td>
" +
                    "				<td>时间</td>
" +
                    "			</tr>");
            for (Book b:bookList){
                ps.println( "<tr>"   );
                ps.println("<td> "+ b.getId()  +"  </td>");
                ps.println("<td> "+ b.getBookName()  +"  </td>");
                ps.println("<td> "+ b.getPrice()  +"  </td>");
                ps.println("<td> "+ b.getAuthor() +"  </td>");
                ps.println("<td> "+ b.getPublish()+"  </td>");
                ps.println("</tr>");
            }
            ps.println("</table>");
        ps.println("</body>");
        ps.println("</html>");
    }
}

业务层

package com.qfedu.service.impl;

import com.qfedu.dao.BookDao;
import com.qfedu.dao.impl.BookDaoImpl;
import com.qfedu.entity.Book;
import com.qfedu.service.BookService;

import java.util.List;

//业务实现层
public class BookServiceImpl implements BookService {

    BookDao bookDao = new BookDaoImpl();

    @Override
    public List<Book> findAll() {
        return bookDao.findAll();
    }
}

持久层

package com.qfedu.dao.impl;

import com.qfedu.common.util.DataSourceUtil;
import com.qfedu.dao.BookDao;
import com.qfedu.entity.Book;
import jdk.nashorn.internal.runtime.ECMAException;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanListHandler;

import java.sql.SQLException;
import java.util.List;

//持久层实现
public class BookDaoImpl implements BookDao {

    @Override
    public List<Book> findAll() {
        QueryRunner runner = new QueryRunner(DataSourceUtil.getDataSource());
        String sql = "select * from tb_books";
        try {
            return runner.query(sql,new BeanListHandler<>( Book.class ) );
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }
}

六、Servlet的两大组件(request和response)

6.1 HttpRequest
6.1.1 HttpRequest概述

1、request和response对象是由服务器创建

2、request是来获取请求消息,response是用来处理响应信息

6.2 request的功能
6.2.1 获取请求行数据

如:GET/day14/demo01?name=zhangsan HTTP/1.1

1、获取请求方式:GET

String getMethod( )

2、获取虚拟路径:/day14

String getContextPath( )

3、获取Servlet路径:/demo01

String getServletPath( )

4、获取get方式请求的参数:name=zhangsan

String getQueryString( )

5、获取请求URI:/day14/demo01

String getRequestURI( )

6、获取请求的URL

StringBUffer getRequest( ):http://localhost/day14/demo01

注:URL:统一资源定位符:如http://localhost:8080/day14/demo01

? URI:统一资源标识符:如:/day14/demo01


//1、获取请求方式:String getMethod()
String method = req.getMethod();
System.out.println(method);
//2、获取虚拟目录路径 String getContextPath()
String contextPath = req.getContextPath();
System.out.println(contextPath);
//3、获取Servlet路径 string getServletPath()
String servletPath = req.getServletPath();
System.out.println(servletPath);
//4、获取get方式请求参数:String getQueryString()
String queryString = req.getQueryString();
System.out.println(queryString);
//5、获取请求URI:String getRequestURI()
//   获取请求URL:StringBuffer getRequestURL()
String requestURI = req.getRequestURI();
System.out.println(requestURI);
StringBuffer requestURL = req.getRequestURL();
System.out.println(requestURL);
//6、获取协议及版本: String getProtocol()
String protocol = req.getProtocol();
System.out.println(protocol);
//7、获取客户机的IP地址: String getRemoteAddr()
String remoteAddr = req.getRemoteAddr();
System.out.println(remoteAddr);
6.2.2 获取请求头数据

1、String getHeader(String name):通过请求头的名称获取请求头的值

2、Enumeration getHeaderNames( ) :获取所有的请求头名称

protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String header = req.getHeader("user-Agent");//获取浏览器信息
        if(header.contains("Chrome")){
            System.out.println("使用的是谷歌浏览器......");
        }else if(header.contains("Firefox")){
            System.out.println("使用的是火狐浏览器......");
        }
    }
6.2.3 获取请求体数据

只有post方式提交的数据才有请求体

步骤:

1、获取流对象
BufferedReader getReader( ):获取字符输入流,只能操作字符数据

ServletInputStream getInputSream( ):获取字节输入流

2、设置响应文本格式格式

Response.setContextType("text/html;charset=utf-8") 告诉客户端使用使用html的格式打开响应

6.2.4 获取请求参数
  • 获取请求参数通用方式,不管是get方式提交的还是post方式提交都可以使用下列方法来获取请求参数

String getParameter(String name) 根据参数名称获取参数值

String[ ] getParameterValues(String name) 根据参数名称获取参数值的数组 常用于获取复选框

Enumeration getParameterNames( ) 获取所有请求的参数名称

Map<String,String[]> getParameterMap( ) 获取所有参数的Map集合

6.2.4 跳转

跳转是指一种在服务器内部的资源跳转方式

步骤:

? 1、通过Request对象获取请求转发器对象:

? requestDisPatcher getRequestDispatcher(String path)// path 转发URL

? 2、使用RequestDisPatchar对象来进行转发

? forword(Servlet servlet,Response response)

? 特点:

  • 浏览器地址栏不发生改变

  • 只能转发到当前服务器内部资源中

  • 转发是一次请求

6.2.5 共享数据

? 1、域对象:一个有作用范围的对象,可以在范围内共享数据

? 2、request域:代表依次请求的范围,一般适用于请求转发多个资源中共享数据

? 3、方法

? void setAttribute(String name,Object obj) 以键值对的形式存储数据

? Object getAttribute(String name) 通过键获取数据

? void removeAttribute(String name) 通过键移除键值对数据

? 4、获取ServletContext:

? ServletContext getServletContext( )

//将数据存储到request数据域中 void setAttribute(String name,Object obj):存储数据
        req.setAttribute("value1","1");
 //通过键获取request数据域的数据
        Object value1 = req.getAttribute("value1");
6.3 HttpResponse
6.3.1 概述

? HttpResponse使用来处理响应信息的

6.3.2 功能

? 1、设置响应行

? 格式:HTTP/1.1 200 ok

? 设置状态码:setStatus(int sc)

? 2、设置响应头:

? setHeander(String name,String value)

? 3、设置响应体:

? 步骤

? a、获取输出流

? printWriter getWriter( ) 字符输出流

? ServletOutputStream getOutputStream( ) 获取字节输出流

? b、使用输出流将数据输出到客户端

6.3.3 重定向

重定向的两种方式

一、设置状态码,Response.SetStatus("302"),表示跳转使用Response.SetHeander("地址","跳转资源");

//设置状态码为302(重定向)
        response.setStatus(302);
        //设置响应头location为重定向资源"/responseDemo02"
            //注:localhost:表示客户端吧应当去哪里提取文档
        response.setHeader("location","/day09/responseDemo02");

二、简单的重定向方式

Request.sendRedirect("资源路径");

 //简单的重定向的方法
 response.sendRedirect("/day09/responseDemo01");
6.3.4转发和重定向的区别

重定向的特点:redirect
1、地址栏不改变

? 2、重定向可以访问其他站点

? 3、重定向是两次请求,不能使用request对象来共享数据

转发特点:forward

? 1、转发是一次请求

? 2、转发只能访问服务器下的资源

? 3、转发只是一次请求,可以使用request对象来共享数据

七、会话管理

会话是指一个终端用户与交互系统进行通讯的过程,比如从输入账户密码进入操作系统到退出操作系统就是一个会话过程。

这种在多次HTTP连接间维护用户与同一用户发出的不同请求之间关联的情况称为维护一个会话(session)。

简单的说: 让服务器记住客户端。

7.1 会话

1、会话:一次会话中包含多次请求和响应

? 一次会话:浏览器第一次给服务器资源发送请求,直至一方断开
2、功能:再一次会话内共享资源

3、方式:

? 客户端会话技术:Cookie

? 服务器端会话技术:Session

7.2.1 概述

Cookie 是存储在客户端的一种简单文本格式的数据,这中数据以name-value形式存在。它的作用帮助服务端存储一些数据到客户端中,比如用户上网的一些行为,浏览记录,记住账号密码。

javaweb中Cookie的类型为javax.servlet.http.Cookie

7.2.2 快速入门

? 步骤:

? 1、创建Cookie对象

Cookie cookie = new Cookie(String name,String value);

? 2、发送Cookie对象

response.addCookie(Cookie cooke)

? 3、获取Cookie对象 拿到数据

Cookie[] cookies = request.getCookies(String);
7.2.3 实现原理

是基于响应头set-cookie和请求头cookie实现的

//设置有效时间
ck.setMaxAge(300);//单位秒
//响应的时候,通过响应头写回到客户端
resp.addCookie(ck);
resp.getWriter().println("<h1>ok</h1>");
7.2.4 cookie的 细节

1、一次会话cookie可以发送多个cookie,可以创建多个Cookie对象 request使用addCookie方法发送即可

2、默认情况下当浏览器关闭后,Cookie数据被销毁

? 持久化存储:

//设置 有效期
ck.setMaxAge(int secondes);//单位秒

有效期为

? 负数(默认): 不存储,关闭浏览器就无效了,(浏览器使用期间有效)

? 正数: 指定的时间后过期

? 零 : 删除(立即删除)

?

//删除的原理: 重复发送一个同名的cooke客户端去,同时设置这个cooke过期时间为0
Cookie cookie = new Cookie("hobby","");
cookie.setMaxAge(0);
resp.addCookie(cookie);

3、在tomcat8之前,cookie不能直接存储中文数据(可以使用URL转码和解码)

? 在tomcat8之后,cookie支持中文数据,但是特殊字符让然不支持,所以建议使用URL编码存储和解析

4、cookie共享问题:

1、假设在一个tomcat服务器中部署多个web项目,name在这些web项目中Cookie能不能共享?

? 默认情况下不能共享,可以设置Cookie.setPath(String path) 设置当前的虚拟目录,如果要共享可以将path设置为“/”

2、不同Tomcat服务器间cookie共享问题:

setDoamin(String path):如果设置一级域名相同,那么多个服务器之间Cookie可以共享

? 如:cookie.setDomain("baidu.com")那么tieba.baidu.com和new.baidu.com中cookie可以共享

5、不建议使用Cookie存储敏感信息

7.2.5 案例
/**
 * 上次访问时间案例
 在服务器中的Servlet判断是否有一个名为lastTime的cookie
 1. 有:不是第一次访问
 1. 响应数据:欢迎回来,您上次访问时间为:2018年6月10日11:50:20
 2. 写回Cookie:lastTime=2018年6月10日11:50:01
 2. 没有:是第一次访问
 1. 响应数据:您好,欢迎您首次访问
 2. 写回Cookie:lastTime=2018年6月10日11:50:01
 */

@WebServlet("/cookieTest02")
public class CookieTest02 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //设置响应的消息体的数据格式以及编码
        response.setContentType("text/html;charset=utf-8");
        //1.获取所有Cookie
        Cookie[] cookies = request.getCookies();
        boolean flag = false;//没有cookie为lastTime
        //2.遍历cookie数组
        if(cookies != null && cookies.length > 0){
            for (Cookie cookie : cookies) {
                //3.获取cookie的名称
                String name = cookie.getName();
                //4.判断名称是否是:lastTime
                if("lastTime".equals(name)){
                    //有该Cookie,不是第一次访问
                    flag = true;//有lastTime的cookie
                    //设置Cookie的value
                    //获取当前时间的字符串,重新设置Cookie的值,重新发送cookie
                    Date date  = new Date();
                    SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
                    String str_date = sdf.format(date);
                    System.out.println("编码前:"+str_date);
                    //URL编码
                    str_date = URLEncoder.encode(str_date,"utf-8");
                    System.out.println("编码后:"+str_date);
                    cookie.setValue(str_date);
                    //设置cookie的存活时间
                    cookie.setMaxAge(60 * 60 * 24 * 30);//一个月
                    response.addCookie(cookie);

                    //响应数据
                    //获取Cookie的value,时间
                    String value = cookie.getValue();
                    System.out.println("解码前:"+value);
                    //URL解码:
                    value = URLDecoder.decode(value,"utf-8");
                    System.out.println("解码后:"+value);
                    response.getWriter().write("<h1>欢迎回来,您上次访问时间为:"+value+"</h1>");


                    break;

                }
            }
        }
        if(cookies == null || cookies.length == 0 || flag == false){
            //没有,第一次访问
            //设置Cookie的value
            //获取当前时间的字符串,重新设置Cookie的值,重新发送cookie
            Date date  = new Date();
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
            String str_date = sdf.format(date);
            System.out.println("编码前:"+str_date);
            //URL编码
            str_date = URLEncoder.encode(str_date,"utf-8");
            System.out.println("编码后:"+str_date);

            Cookie cookie = new Cookie("lastTime",str_date);
            //设置cookie的存活时间
            cookie.setMaxAge(60 * 60 * 24 * 30);//一个月
            response.addCookie(cookie);

            response.getWriter().write("<h1>您好,欢迎您首次访问</h1>");
        }
    }
7.3 Session
7.3.1 概念

? 服务器端会话技术,在一次会话的多次请求间共享数据,将数据保存在服务端的对象中 javaweb中的session是HTTPSession

? Session域: Session 域,服务器为每个浏览器开辟的独立的一块空间,每个浏览器独立的空间,用户保存该客户端的一些信息 是以键值的形式存储的

7.3.2 快速入门
//获取session
HttpSession session = request.getSession();
//存储数据
session.setAttribute("username","zhangsan");//可以存储对象
session.removeAttribute("username");
7.3.3 原理

session的实现是依赖cookie的

7.3.4 细节

1、客户端关闭后,服务器不关闭,两次获取的session是否为同一个?

? 默认情况下不是,若需要可以创建Cookie键为JESSIONID,让cookie持久化存储

Cookie cookie = new Cookie("JSESSIONID",session.getID());
//设置时间
cookie.setMaxAge(60*60);
response.addCookie(c);

2、客户端不关闭,服务器关闭后,两次获取的Session是同一个吗?

? 不是同一个,但是要确保数据不丢失可以让Session存储在磁盘上

Session的钝化:
在服务器关闭之前将Session对象序列化到硬盘上

Session的活化:

? 在服务器启动之后,将Session转化到Session对象即可

Session的失效时间:

? 1、服务器自动关闭

? 2、自毁 session.invaliadate( )

? 3、session默认失效时间是30分钟

? 可以进行配置

<session-config>
    <session-time>30</session-time>
    </session>
7.3.5 特点

1、session用于存储一次会话的多次请求的数据,存储在服务器上

2、session可以存储任意类型、大小的数据

7.3.6 Session 和Cookie的区别

1、session存储在服务器端,cookie存储在客户端

2、session没有数据大小限制,cookie有大小限制

3、session数据安全 cookie相对不安全

?

以上是关于Servlet基础的主要内容,如果未能解决你的问题,请参考以下文章

jsp基础语言-jsp代码段

JSP基础--JSP入门

[vscode]--HTML代码片段(基础版,reactvuejquery)

Servlet基础下

filter与servlet

java基础 第十四章(Servlet声明周期Servlet向jsp中提供数据Servlet跳转jspjsp中书写java代码)