javaweb

1.xml(了解)

1.1 配置文件

1.1.1 配置文件的作用

配置文件是用于给应用程序提供参数配置以及初始化设置的一些特殊格式的文件。
补充:也作为异步系统之间进行数据传输的媒介(现已被jason代替)

1.1.2 常见的配置文件类型
  1. properties(属性)文件,例如druid连接池就是使用properties文件作为配置文件。
  2. XML文件:例如Tomcat就是用XML文件作为配置文件。
  3. YAML文件:例如SpringBoot就是用TAML文件作为配置文件。
  4. jason文件:通常用于文件传输,也可以用来做前端或者移动端的配置文件。

1.2 properties文件(不讲太深)

atguigu.jdbc.url=jdbc:mysql://192.168.198.100:3306/bj1026
atguigu.jdbc.driver=com.mysql.cj.jdbc.Driver
atguigu.jdbc.username=root
atguigu.jdbc.password=root

1.3 XML文件

1.3.1 文件事例
<?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">

    <!-- 配置SpringMVC前端控制器 -->
    <servlet>
        <servlet-name>dispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

        <!-- 在初始化参数中指定SpringMVC配置文件位置 -->
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:spring-mvc.xml</param-value>
        </init-param>

        <!-- 设置当前Servlet创建对象的时机是在Web应用启动时 -->
        <load-on-startup>1</load-on-startup>

    </servlet>
    <servlet-mapping>
        <servlet-name>dispatcherServlet</servlet-name>

        <!-- url-pattern配置斜杠表示匹配所有请求 -->
        <!-- 两种可选的配置方式:
                1、斜杠开头:/
                2、包含星号:*.atguigu
             不允许的配置方式:前面有斜杠,中间有星号
                /*.app
         -->
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>
1.3.2 概念介绍

XML是eXtensible Markup Language的缩写,翻译过来就是可扩展标记语言,基本语法是标签。
可扩展
可扩展表示XML允许自定义格式。但是不代表你可以随意写,由专人来写。
image.png
约束
在XML基本语法规范的基础上,我们使用的第三方应用程序、框架会通过设计XML约束的方式强制规定配置文件可以写什么和怎么写,规定之外的都不可以写。
XML基本语法的定位是:我们不需要从零开始一行一行的编写XML代码,而是在第三方程序、框架已提供的配置文件的基础上更改,改成什么样取决于你的需求,而怎么改取决于XML的基本语法和具体的XML约束。

1.3.3 XML的基本语法
  • XML声明文档

这部分是固定形式,但需要注意XML需要在第一行开始写。

<?xml version="1.0" encoding="UTF-8"?>
  • 根标签

根标签有且只能有一个。

  • 标签关闭
    • 双标签:开始标签和结束标签必须成对出现。
    • 单标签:单标签在标签内关闭。
  • 标签嵌套
    • 可以嵌套,但是不能交叉嵌套。
  • 注释不能嵌套
  • 标签名、属性名建议使用小写字母
  • 属性
    • 属性必须有值
    • 属性值必须加引号,单双都行

补充:XML + HTML约束 = HTNL
了解到这即可,深究以后再学。

2.Tomcat

2.1 Web服务器

  • Web服务器通常由硬件和软件共同构成。
    • 硬件:电脑,提供服务供其它客户电脑访问

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-p9Aj2tgn-1692627788023)(images/1561995738943.png#id=yRpMM&originalType=binary&ratio=1&rotation=0&showTitle=false&status=done&style=none&title=)] image.png

  • 软件:电脑上安装的服务器软件,安装后能提供服务给网络中的其他计算机,将本地文件映射成一个虚拟的url地址供网络中的其他人访问。
  • web服务器常用来接收客户端发送的请求和响应客户端的请求。
  • 常见的javaweb服务器:Tomcat(Apache):当前应用最广的JavaWeb服务器等。

客户端:用户使用的那一端。
服务器端:为客户端提供服务器的那一端。

2.2 Tomcat的使用(简单了解)

2.2.1 tomcat的目录结构
  • bin:命令文件存放的目录
  • conf:配置文件存放的目录(xml文件)
  • lib:tomcat运行需要的jar包
  • logs:日志文件的存放目录
  • temp:临时文件
  • webapps:web项目部署的目录(war包 jar ---->Java项目的压缩包、war ----->web项目编译后的压缩包)
  • work:工作的目录

**tomcat的使用前提:**需要正确配置JAVA_HOME的环境变量(因为需要java的运行环境)

2.2.2 启动/暂停服务器

双击startup.bat
双击shutdown.bat

3.HTTP协议简介

3.1HTTP 超文本传输协议

规定了浏览器和万维网服务器之间互相通信的规则。
规定了传输数据的格式。
客户端与服务器端通信时传输的内容我们称之为报文。HTTP协议就算规定报文的格式。

3.2 报文

3.1.1 报文格式

  • 报文
    • 请求报文:客户端向服务器发送数据
    • 响应报文:服务器往客户端发送数据
3.1.2 请求报文
① 报文格式
  • 请求首行(请求行)
  • 请求头信息(请求头)
  • 空行
  • 请求体
GET /05_web_tomcat/login_success.html?username=admin&password=123213 HTTP/1.1
请求方式 	访问的服务器中的资源路径      ?get请求参数	                 协议版本
POST /05_web_tomcat/login_success.html HTTP/1.1


Host: localhost:9999
Connection: keep-alive
Cache-Control: max-age=0
sec-ch-ua: " Not A;Brand";v="99", "Chromium";v="98", "Google Chrome";v="98"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.102 Safari/537.36
客户端的产品信息
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,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
Referer: http://localhost:9999/day05_http_servlet_war_exploded/admin.html
请求的来源:防盗链
Accept-Language: zh-CN,zh;q=0.9
Cookie: Idea-5083c5c3=66e5f757-3f90-4449-b1ab-0b5a62d33e8f
If-None-Match: W/"156-1646441736888"
If-Modified-Since: Sat, 05 Mar 2022 00:55:36 GMT

空行:在请求头末尾和请求体开始之间。用来区分请求体和请求头。帮助服务器正确解析HTTP请求报文。
请求体:分为俩种情况:

② get请求
  • 请求参数在请求首行中,所以没有请求体,也没有请求空行。
  • 请求参数拼接在url地址中,地址可见url?name1=value1&name2=value2,不安全
  • 参数在地址栏中携带,大小有一定的限制,并且只能携带纯文本
  • 请求方式:
    • get方式提交时HTTP中没有消息体
    • 超链接
    • form中method为空或get时(默认为get)
  • 没有请求体,所以封装和解析快,效率高
③ post请求
  • post请求有请求体。
  • post请求数据在请求体中携带,请求体数据大小没有显示,可以用来上传所有内容(文件、文本),且只有post请求可以上传文件。
  • 地址栏参数不可见,相对安全。
  • post的效率比get低。
  • 请求方式:
    • form中method属性为post
  • 请求体:客户端向服务器端传输的数据。
3.1.3 响应报文
① 报文格式
  • 响应首行(响应行)
  • 响应头信息(响应头)
  • 空行
  • 响应体
②具体情况
HTTP/1.1 200 OK
协议 版本 响应状态码
说明:响应协议为HTTP1.1,响应状态码为200,表示请求成功; 
Accept-Ranges: bytes
ETag: W/"149-1646442372967"
Last-Modified: Sat, 05 Mar 2022 01:06:12 GMT
Content-Type: text/html
响应的类型
Content-Length: 149
Date: Sat, 05 Mar 2022 01:19:59 GMT

空行

<!--需要浏览器解析使用的内容[如果响应的是html页面,最终响应体内容会被浏览器显示到页面中]-->

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title>Insert title here</title>
	</head>
	<body>
		恭喜你,登录成功了...
	</body>
</html>
③ 响应码
  • 200:请求成功。
  • 404:请求的资源没有找到。说明客户端错误的请求了不存在的资源。
  • 500:请求资源找到了,但是服务器内部出现了错误。一般为代码问题。
  • 302:重定向,当响应码为302时,表示服务器要求浏览器重新再发一个请求,服务器会发送一个响应头Location,它指定了新请求的URL地址;
2xx - 成功。表示服务器成功地接受了客户端请求。 
3xx - 重定向。表示要完成请求,需要进一步操作。客户端浏览器必须采取更多操作来实现请求。例如,浏览器可能不得不请求服务器上的不同的页面,或通过代理服务器重复该请求。 
4xx - 请求错误。这些状态代码表示请求可能出错,妨碍了服务器的处理。 
5xx - 服务器错误。表示服务器在尝试处理请求时发生内部错误。 这些错误可能是服务器本身的错误,而不是请求出错。

4.Servlet

4.1 什么是Servlet

Servlet(Server Applet):服务器端的一个小程序。
Servlet是包含与web应用相关的一系列接口。
如果把Web比作一个餐厅,Servlet就是餐厅的服务员,负责接待顾客、上菜、结账。与客户端进行交互,处理请求和响应。

4.2 web应用的运行方式

image.png

4.3 如何使用Servlet

  • 创建一个类
  • 让这个类实现Servlet接口
  • 实现接口中所有的抽象方法
  • 为该类设置访问路径
    • 在web.xml中设置访问路径
  • 将设置的访问路径设置给超链接或其他地方。
<servlet>
    <!--为Servlet起个名字-->
    <servlet-name>abc</servlet-name>
    <!--Servlet的全类名-->
    <servlet-class>com.atguigu.servlet.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
    <!--要和servlet中servlet-name的名字一致-->
    <servlet-name>abc</servlet-name>
    <!--设置访问路径:注意 必须以/开头-->
    <url-pattern>/hello</url-pattern>
</servlet-mapping>
 <a href="hello">访问HelloServlet</a>

注意:

  • 网页必须放在web下(但不能放在WEB-INF下)
  • url-pattern必须以“/”开头
  • 网页的请求路径,不能以/开头

4.4 Servlet的生命周期

① Servlet对象的创建:构造器

默认情况下,Servlet容器第一次收到Http请求时创建Servlet对象。

② Servlet对象的初始化:init()

Servlet容器创建Servlet对象后,会调用init方法执行一些初始化操作。例如,读取一些资源文件,配置文件或建立某周连接(数据库连接)。
init只在创建对象的时候执行一次。

③ 处理请求:service()

Servlet接口中定义了service方法处理HTTP请求。
在每一次接到请求后都会执行。在第二次及以后的每一次请求都会直接执行service方法。
Servlet的作用一般在该方法中体现。
此方法要求将ServletRequest对象和ServletResponse对象传入。

④ Servlet对象的销毁:destroy()

服务器重启、服务器停止执行或者web应用卸载会销毁Servlet对象。会调用 destroy()方法。

public class Test implements Servlet {
    @Override
    public void init(ServletConfig servletConfig) throws ServletException {
        
    }

    @Override
    public ServletConfig getServletConfig() {
        return null;
    }

    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {

    }

    @Override
    public String getServletInfo() {
        return null;
    }

    @Override
    public void destroy() {

    }
}
补充:load-on-startup(用的很少,了解一下)

在xml的Servlet标签内设置-------->设置自启动。

  • 一个xml文件可以有多个Servlet,可以用设置Servlet的执行顺序,数值越小越先启动。
  • 当值为0或者大于0时,表示容器在应用启动时就加载这个servlet
  • load-on-startup放在的最后一行
<servlet>
      <!--为Servlet起个名字-->
      <servlet-name>Hello</servlet-name>
      <!--Servlet的全类名-->
      <servlet-class>com.atguigu.servlet.HelloServlet</servlet-class>
      <!--设置当前Servelt的初始化参数-->
      <init-param>
          <param-name>path</param-name>
          <param-value>classpath:springmvc.xml</param-value>
      </init-param>
      <!--设置自启动-->
      <load-on-startup>1</load-on-startup>
  </servlet>

4.5 Sevlet的俩个接口

① ServletConfig接口
  • Servlet配置接口,封装了Servlet配置信息。Config---->配置
  • 每一个Servlet都有唯一一个相对应的ServletConfig对象
  • ServletConfig对象由Servlet容器创建,在Servlet进行初始化的时候传递给init方法
public void init(ServletConfig servletConfig) throws ServletException
  • 功能
    1. 获取servlet的名称(web.xml中配置servlet-name的值)
    2. 获取全局上下文ServletContext对象:getServletContext()
    3. 获取Servlet初始化参数getInitParameter(String) / getInitParameterNames()。
<servlet>
  <servlet-name>aaa</servlet-name>
  <servlet-class>Test1.TestServlet</servlet-class>

  <init-param>
      <param-name>path</param-name>
      <param-value>classpath:springmvc.xml</param-value>
  </init-param>
</servlet>
<servlet-mapping>
  <servlet-name>aaa</servlet-name>
  <url-pattern>/a</url-pattern>
</servlet-mapping>
public void init(ServletConfig servletConfig) throws ServletException {
    System.out.println("servletConfig = " + servletConfig);
    String servletName = servletConfig.getServletName();
    System.out.println("servletName = " + servletName);
    String initParameter = servletConfig.getInitParameter("path");
    System.out.println("initParameter = " + initParameter);
    Enumeration<String> initParameterNames = servletConfig.getInitParameterNames();
    System.out.println("initParameterNames = " + initParameterNames);
    ServletContext servletContext = servletConfig.getServletContext();
    System.out.println("servletContext = " + servletContext);
}
输出结果:
servletConfig = org.apache.catalina.core.StandardWrapperFacade@75cb26f1
servletName = aaa
initParameter = classpath:springmvc.xml
initParameterNames = java.util.Collections$3@7b0cd638
servletContext = org.apache.catalina.core.ApplicationContextFacade@7f334d81

② ServeltContext接口
  • Web容器在启动时,每个Web应用程序都创建唯一个对应的ServletContext对象,代表Web应用。所有的Servlet共享一个ServletContext对象,所以ServletContext对象也被称为 application 对象
  • ServletContext对象是由服务器启动的时候,tomcat创建的。
  • 功能:
    1. 获得获取项目的上下文路径(带/的项目名):getContextPath()
    2. 获取虚拟路径所映射的真实路径:getRealPath(String path)
    • 虚拟路径:浏览器访问web应用中资源所使用的路径
    • 本地路径:资源在文件系统中的实际保存路径
    1. 获取web应用程序的全局初始化参数:getInitParameter()
    2. 作为域对象共享数据
      • 域对象:在一定作用域范围内共享数据的对象。
      • ServletContext所用域的对象是整个web项目。

注意:servletContext.getRealPath(“/upload”); 后期上传下载会用到。后期再说,本文不多介绍

<!--设置全局初始化参数-->
<!--    <context-param>-->
<!--        <param-name>servletCntextInitParamKey</param-name>-->
<!--        <param-value>servletCntextInitParamValue</param-value>-->
<!--    </context-param>-->
<context-param>
    <param-name>ccc</param-name>
    <param-value>bbb</param-value>
</context-param>
public class TestServlet implements Servlet {
    @Override
    public void init(ServletConfig servletConfig) throws ServletException {
        ServletContext servletContext = servletConfig.getServletContext();
        String contextPath = servletContext.getContextPath();
        System.out.println("contextPath = " + contextPath);
        String initParameter = servletContext.getInitParameter("ccc");
        System.out.println("initParameter = " + initParameter);
        servletContext.setAttribute("key","value");
        Object key = servletContext.getAttribute("key");
        System.out.println("key = " + key);
    }
}
输出结果:
contextPath = /yue
initParameter = bbb
key = value

4.6 Servlet的技术体系

① 创建Servlet的方式
  • 实现Servlet接口,实现5个方法
② 创建GenericServlet的方式
  • 创建一个类
  • 继承一个抽象类(GenericServlet)
  • 实现抽象类中的抽象方法
  • 配置Servlet的访问路径

GenericServlet的主要功能是将service以外的其他方法做了实现,我们只需要实现service方法即可

③ 创建HttpServlet的方式(常用)
  • 创建一个类
  • 继承一个抽象类(HttpServlet)
  • 重写俩个方法doGet和doPost
  • 配置Servet的访问路径
public class TestServlet extends HttpServlet{
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
       
    }
}
  • HttpServlet是专门用来处理Http请求的Servlet。
  • HttpServlet是对GenericServlet进行进一步的封装和扩展。
  • 在service(ServletRequest req, ServletResponse res)方法中,将ServletRequest和ServletResponse转换为HttpServletRequest和HttpServletResponse,根据不同HTTP请求类型调用专门的方法进行处理。
    • get请求doGet
    • post请求doPost
补充:为什么doGet请求和doPost请求可以嵌套使用
  • 第一点:因为doPost和doGet的代码基本一致。
  • 第二点:因为我们的请求不是get就是post,嵌套使用不论是哪个请求,对应的方法都能调用。

4.7 处理请求和响应的接口

4.7.1 HttpServletRequest
  • 该接口是ServletRequest接口的子接口,封装了HTTP请求的相关信息

接口功能如下:

① 获得请求头信息:
  • request.getHeader(String key);
② 获得url的路径信息:
  • request.getContextPath();//获得上下文路径 ★
  • request.getServerName();
  • request.getServerPort();

补充:获取上下文参数的方法:

  1. 通过servletContext获得
  2. 通过HttpServletRequest获得
③ 获得请求方式:
  • request.getMethod();
④ 获得请求参数:
  • String request.getParameter(String key); 根据key值返回一个value
  • String[] request.getParameterValues(String key); 根据key值返回多个value
  • Map<String,String[]> request.getParameterMap(); 将整个表单的所有数据都放在map集合内
⑤ 转发
  • 作用:转发到其他的Servlet/转发到网页
  • 使用:
    1. 获得转发器对象:RequestDispatcher requestDispatcher = request.getRequestDispatcher(目标路径);
    2. 进行转发操作:requestDispatcher.forward(request,response);
    3. 合成代码:request.getRequestDispatcher(“root.html”).forward(request,response);
  • 原理:
    • request作为作用域对象共享数据。作用的范围是本次请求,响应结束,请求结束。在进行转发的时候将request和response作为参数传递了。所以被传递的对象也获得了请求参数和响应参数
⑥ 向请求域中保存(获取)数据
  • request.setAttribute/ request.getAttribute
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    //获取请求头信息
    String connection = req.getHeader("Connection");
    System.out.println("connection = " + connection);
    //获取上下文参数
        //req获得上下文参数
    String contextPath = req.getContextPath();
    System.out.println("contextPath = " + contextPath);
        //servletContext获得上下文参数
    ServletContext servletContext = this.getServletContext();
    String contextPath1 = servletContext.getContextPath();
    System.out.println("contextPath1 = " + contextPath1);
    //获取请求方式
    String method = req.getMethod();
    System.out.println("method = " + method);
    //获取请求参数
    String username = req.getParameter("username");
    System.out.println("username = " + username);
    req.setAttribute("gpy","niubi");
    Object gpy = req.getAttribute("gpy");
    System.out.println("gpy = " + gpy);
    //转发操作
    req.getRequestDispatcher("Second.html").forward(req, resp);
    }
输出结果:
connection = keep-alive
contextPath = /yue
contextPath1 = /yue
method = POST
username = dasdasdas
gpy = niubi
4.7.2 HttpServletResponse
  • 该接口是ServletResponse接口的子接口,封装了服务器针对于HTTP响应的相关信息。

功能如下

① 通过输出流将响应数据输出给客户端
  • PrintWriter writer = response.getWriter(); writer.write(“

    success

    ”);
  • image.png
  • 响应的数据可以在response中看到
② 设置响应乱码(添加响应头的方式) 不学了用不上了以后用别的框架
③ 重定向(页面跳转)
  • 重定向到另一个Servlet response.sendRedirect(“second”);
  • 重定向至页面 response.sendRedirect(“admin.html”);
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    PrintWriter writer = resp.getWriter();
    writer.write("<h1>Welcome to my website!</h1>");
    resp.sendRedirect("Second.html");
}

4.8 转发和重定向

image.png
转发 重定向
浏览器的感知 感知不到 感知到
网址栏的网址 不变 会改变
请求的次数 一次请求 两次请求
请求域的共享数据 可以 不可以
发起者 request response
WEB-INF 可以访问的 不可以访问的
补充:
WEB-INF的资源有一个特性:外部不可访问。即客户端无法访问,服务器可以访问(Tomcat)
web项目应用程序的代码通常是在服务器上运行的(Tomcat)。转发是在服务器内部进行的,所以可以说是服务器在请求资源,WEB-INF可以被服务器访问,所有转发可以访问WEB-INF资源。

4.9 应用域和请求域

① 应用域(ServletContext)
  • 数据共享的范围是整个web应用
② 请求域(HttpServletRequest)
  • 数据共享的范围是本次请求
  • 可以向请求域添加属性
    • 添加属性:setAttribute(String key,Object value);
    • 获取属性:getAttribute(String key)
    • 移除属性:removeAttribute(String key)

4.10 web项目路径问题(url)

url:(从整个网络环境中找一个资源
uniform Resource Locater : 统一资源定位符
完整的url如下图::
image.png

  • 相对路径:如果路径不以"/"开始就是相对路径。根据当前资源所在的路径为基准。
  • 绝对路径:如果路径一"/" 开始就是绝对路径。(建议使用)
  • http://localhost:9999/day06_servlet_war_exploded/login.html
    • ① 服务器端:
      • 最开始的“/”表示当前Web应用的根目录。
      • 只要是服务端解析的绝对路径,都是以web根目录为起始的。
      • http://localhost:9999/day06_servlet_war_exploded
    • ② 浏览器端
      • 最开始的“/”表示当前主机地址。
      • http://localhost:9999

补充:

  • 标签(HTML)
  • 位置:加在head标签内
  • 功能:为当前网页内所有的路径添加前缀
  • 代码:
  • 注意:
    • base标签需要在所有路径的上方
    • 一旦页面内的路径想使用base标签,路径前不能以/开头

5.三层架构及持久层的操作

三层架构图解.png

5.1 三层架构的划分

  • 控制层:负责处理浏览器请求、返回反应,页面调度
  • 业务层:负责处理业务逻辑,根据业务逻辑从数据库查询出来的数据进行运算、组装,封装好后返回给表述层等调用持久话层的操作。
  • 持久层:根据上一层的调用对数据库的数据执行增删改查的操作。

5.2 持久层的操作(除了加密其他用mybatis即可)

  • 数据库的建立
  • 导入jar包
  • 创建外部属性文件(知道就行)
xxxxxxxxxx driverClassName=com.mysql.jdbc.Driverurl=jdbc:mysql://localhost:3306/bookstoreusername=rootpassword=rootinitialSize=10maxActive=20maxWait=10000
加密操作

a. 加密方式介绍

  • 对称加密:加密和解密使用的相同的密钥,常见的对称加密算法有:DES、3DES
  • 非对称加密:加密和解密使用的密钥不同,常见的非对称加密算法有:RSA
    • 加密:使用私钥加密
    • 解密:使用公钥解密
  • 消息摘要:  消息摘要算法的主要特征是加密过程不需要密钥,并且经过加密的数据无法被解密,只有相同的原文经过消息摘要算法之后,才能得到相同的密文,所以消息摘要通常用来校验原文的真伪。常用的消息摘要算法有:MD5、SHA、MAC

我们在书城项目中采用MD5算法对密码进行加密
b. 封装执行加密的工具类(直接复制过去)

public class MD5Util {

    /**
     * 针对明文字符串执行MD5加密
     * @param source
     * @return
     */
    public static String encode(String source) {

        // 1.判断明文字符串是否有效
        if (source == null || "".equals(source)) {
            throw new RuntimeException("用于加密的明文不可为空");
        }

        // 2.声明算法名称
        String algorithm = "md5";

        // 3.获取MessageDigest对象
        MessageDigest messageDigest = null;
        try {
            messageDigest = MessageDigest.getInstance(algorithm);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }

        // 4.获取明文字符串对应的字节数组
        byte[] input = source.getBytes();

        // 5.执行加密
        byte[] output = messageDigest.digest(input);

        // 6.创建BigInteger对象
        int signum = 1;
        BigInteger bigInteger = new BigInteger(signum, output);

        // 7.按照16进制将bigInteger的值转换为字符串
        int radix = 16;
        String encoded = bigInteger.toString(radix).toUpperCase();

        return encoded;
    }
}

创建数据库的工具类

package com.atguigu.util;

import com.alibaba.druid.pool.DruidDataSourceFactory;

import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.util.Properties;

public class JDBCUtils {
    private static DataSource dataSource =null;
    private static ThreadLocal<Connection> threadLocal = new ThreadLocal<>();
    //创建连接池
    static{
        //读取属性文件
        Properties prop = new Properties();
        //System.out.println("prop1:"+prop);
        InputStream is = JDBCUtils.class.getClassLoader().getResourceAsStream("db.properties");
        try {
            prop.load(is);
            //System.out.println("prop2:"+prop);
            //根据属性文件创建连接池
            dataSource = DruidDataSourceFactory.createDataSource(prop);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //获取数据库连接
    public static Connection getConnection(){
        //先从ThreadLocal中获取
        Connection conn = threadLocal.get();
        //如果没有连接,说明是该线程中第一次访问,
        if(conn ==null ){
            try {
                //从连接池中获取一个连接
                conn = dataSource.getConnection();
                //放入到threadLocal中
                threadLocal.set(conn);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        //返回连接
        return conn;
    }
    //关闭数据库连接(如果采用了连接池,就是归还连接)
    public static void releaseConnection(){
        //从threadLocal中获取
        Connection conn = threadLocal.get();
        try {
            if(conn !=null){
                conn.close(); //不是物理关闭,而是放入到连接池中,置为空闲状态
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            //这个语句不要少
            //threadLocal.set(null);//连接已经放回连接池,不使用了。ThreadLocal也不需要再保存了
            threadLocal.remove();
        }
    }
}

创建BaseDao

package com.atguigu.dao;

import com.atguigu.util.JDBCUtils;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.dbutils.handlers.ScalarHandler;

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

/**
 * 功能:对数据库的任意表格进行增删改查
 *      ① 增删改
 *      ② 三个查询
 */
public class BaseDao<T> {
    //2. 创建QueryRunner对象
    private QueryRunner runner=new QueryRunner();
    /**
     * 功能:对数据库进行增删改的操作
     * @param sql
     * @param params
     * @return
     */
    public boolean update(String sql,Object...params){
        //1. 获得数据库连接
        Connection connection = JDBCUtils.getConnection();
        //3. 执行
        try {
            int update = runner.update(connection, sql, params);
            if(update>0)
                return true;
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            //4. 释放资源
            JDBCUtils.releaseConnection();
        }
        return false;
    }

    /**
     * 功能:查询多条数据
     * @param type
     * @param sql
     * @param params
     * @return
     */
    public List<T> getBeanList(Class type,String sql,Object...params){
        //1. 获得数据库连接
        Connection connection = JDBCUtils.getConnection();
        //3. 执行
        try {
            return runner.query(connection, sql, new BeanListHandler<T>(type), params);
        } catch (SQLException e) {
            e.printStackTrace();
        }finally{
            //4. 释放资源
            JDBCUtils.releaseConnection();
        }
        return null;
    }

    /**
     * 功能:查询一条结果
     * @param type
     * @param sql
     * @param params
     * @return
     */
    public T getBean(Class type,String sql,Object...params){
        //1. 获得数据库连接
        Connection connection = JDBCUtils.getConnection();
        //3. 执行
        try {
            return runner.query(connection,sql,new BeanHandler<T>(type),params);
        } catch (SQLException e) {
            e.printStackTrace();
        }finally{
            //4. 释放资源
            JDBCUtils.releaseConnection();
        }
        return null;
    }

    /**
     * 功能:查询一个结果
     * @param sql
     * @param params
     * @return
     */
    public Object getObject(String sql,Object...params){
        //1. 获得数据库连接
        Connection connection = JDBCUtils.getConnection();
        //3. 执行
        try {
            return runner.query(connection,sql,new ScalarHandler(),params);
        } catch (SQLException e) {
            e.printStackTrace();
        }finally{
            //4. 释放资源
            JDBCUtils.releaseConnection();
        }
        return null;
    }
}

6.Thymeleaf

6.1 Thymeleaf简介

  • Thymeleaf是一款用于渲染XML/XHTML/HTML内容的模板引擎。他的组要功能是服务器的渲染,即将服务器的数据动态渲染到静态页面上
  • Thymeleaf的优势
    • SpringBoot官方推荐使用的视图模板技术,和SpringBoot完美整合。
    • 不经过服务器运算仍然可以直接查看原始值,对前端工程师更友好。

6.2 MVC

M:Model模型 JavaBean/pojo
V:View视图 html + 服务器的动态数据
C:Controller控制器 Servlet

  • View是当Servlet接收到service给的结果的时候,首先是到视图层(Thymeleaf),将动态数据和HTML进行拼接,从而产生一个View对象(视图),将View对象展示在浏览器上(用户看到的就是有动态数据的网页)
  • MVC是在表述层开发中运用的一种设计理念。主张把封装数据的『模型』显示用户界面的『视图』、**协调调度的『控制器』**分开。

image.png

6.3 物理视图和逻辑视图

① 物理视图
  • 在Servlet中,将请求转发到一个HTML文件时,使用的完整的转发路径就是物理视图,即服务器端下的路径
  • image.png

/pages/user/login_success.html
如果我们把所有的HTML页面都放在某个统一的目录下,那么转发地址就会呈现出明显的规律:
/pages/user/login.html
/pages/user/login_success.html
/pages/user/regist.html
/pages/user/regist_success.html
路径的开头都是:/pages/user/
路径的结尾都是::.html
所以,路径开头的部分我们称之为视图前缀,路径结尾的部分我们称之为视图后缀

② 逻辑视图
  • 物理视图=视图前缀+逻辑视图+视图后缀.
  • 逻辑视图就是去除视图前缀和视图后缀的物理视图
    | 视图前缀 | 逻辑视图 | 视图后缀 | 物理视图 |
    | — | — | — | — |
    | /pages/user/ | login | .html | /pages/user/login.html |
    | /pages/user/ | login_success | .html | /pages/user/login_success.html |

6.4 Thymeleaf的入门案例

  • 导入jar包
  • 配置全局参数(上下文参数)
    • 配置前缀
    • 配置后缀
<context-param>
    <param-name>view-prefix</param-name>
    <param-value>/WEB-INF/pages/</param-value>
</context-param>
<context-param>
    <param-name>view-suffix</param-name>
    <param-value>.html</param-value>
</context-param>
  • 创建Thymeleaf模板类
  • 创建页面和Servlet
    • Servlet类继承Thymeleaf模板类
    • HTML页面需要引用
    • 填写代码,最后通过 this.processTemplate(“Second”,req,resp);进行转发
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8" xmlns:th="http://www.thymeleaf.org">
    <title>Title</title>
</head>
<body>
<h1>这是服务器传来的数据:</h1>
<h1 th:text="${msg}"></h1>
</body>
</html>


@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//        PrintWriter writer = resp.getWriter();
//        writer.write("<h1>Welcome to my website!</h1>");
//        resp.sendRedirect("Second.html");
    req.setAttribute("msg","msg");
    this.processTemplate("Second",req,resp);
}
public class ViewBaseServlet extends HttpServlet {

    private TemplateEngine templateEngine;

    @Override
    public void init() throws ServletException {

        // 1.获取ServletContext对象
        ServletContext servletContext = this.getServletContext();

        // 2.创建Thymeleaf解析器对象
        ServletContextTemplateResolver templateResolver = new ServletContextTemplateResolver(servletContext);

        // 3.给解析器对象设置参数
        // ①HTML是默认模式,明确设置是为了代码更容易理解
        templateResolver.setTemplateMode(TemplateMode.HTML);

        // ②设置前缀
        String viewPrefix = servletContext.getInitParameter("view-prefix");

        templateResolver.setPrefix(viewPrefix);

        // ③设置后缀
        String viewSuffix = servletContext.getInitParameter("view-suffix");

        templateResolver.setSuffix(viewSuffix);

        // ④设置缓存过期时间(毫秒)
        templateResolver.setCacheTTLMs(60000L);

        // ⑤设置是否缓存
        templateResolver.setCacheable(true);

        // ⑥设置服务器端编码方式
        templateResolver.setCharacterEncoding("utf-8");

        // 4.创建模板引擎对象
        templateEngine = new TemplateEngine();

        // 5.给模板引擎对象设置模板解析器
        templateEngine.setTemplateResolver(templateResolver);

    }

    protected void processTemplate(String templateName, HttpServletRequest req, HttpServletResponse resp) throws IOException {
        // 1.设置响应体内容类型和字符集
        resp.setContentType("text/html;charset=UTF-8");

        // 2.创建WebContext对象
        WebContext webContext = new WebContext(req, resp, getServletContext());

        // 3.处理模板数据
        templateEngine.process(templateName, webContext, resp.getWriter());
    }
}

6.5 Thymeleaf的基本语法

6.5.1 th命名空间

image.png

  • 名称空间是用来指定每一个属性是用来干什么的,唯一的表示每一个属性
<html lang="en" xmlns:th="http://www.thymeleaf.org">
6.5.2 表达式语法
① 修改标签文本值 th:text
<p th:text="标签体新值">标签体原始值</p>

② 修改指定属性值 th:属性名
<input type="text" value="这是原始值" th:value="${msg}" >
③ 解析URL地址
  • 拿到url中的上下文路径 @{/}
<base href="/day07_Thymeleaf_war_exploded123/"  th:href="@{/}">
<!--网页是浏览器端的,所以是在当前主机地址下  -->
④ 获得域对象的数据
  • 应用域:ServletContext application ${appliaction.应用域中的key值}
  • 会话域:HttpSession session ${session.会话域中的key值}
  • 请求域:HttpServletRequest request ${请求域中的key值}

注意:如果页面想使用thymeleaf表达式的话,所有的页面都需要过Servlet,在过Thymeleaf(所以就有了ToIndexServlet)

6.5.2 Thymeleaf操作作用域(待补充)
  • 域对象是在服务器中有一定作用域范围的对象,在这个范围内的所有动态资源都能够共享域对象中保存的数据
① 请求域

HttpServletRequest对象内部给我们提供的存储空间

  • 请求域:HttpServletRequest request ${请求域中的key值}
  • Servlet中
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    String msg = "TestServlet";
    req.setAttribute("key","value");
    this.processTemplate("index",req,resp);
}
  • HTML
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <base th:href = "@{/}">
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <p th:text="${key}">111</p>
</body>
</html>
② 应用域

ServletContext application ${appliaction.应用域中的key值}

  • Servlet中
ServletContext application = req.getServletContext();
application.setAttribute("applicationMsg","application的数据");
  • HTML中
<p th:text="${application.applicationMsg}">111</p>
6.5.3 Thymeleaf获取请求参数
  • 请求参数,如下
<a href="admin?id=101&name=112&hobby=java&hobby=js&hobby=sing">跳转admin页面</a>
  • 方法
${param.参数名}
  • 实操
<p th:text="${param.id}">111</p>
<p th:text="${param.name}">111</p>
  • 如果参数的值为多个,想要精确获取某一个值,可以使用数组下标。页面代码:
<p th:text="${param.hobby[0]}">这里替换为请求参数的值</p>
<p th:text="${param.hobby[1]}">这里替换为请求参数的值</p>
6.5.4 内置对象
  • 所谓内置对象其实就是在Thymeleaf的表达式中可以直接使用的对象
① 基本内置对象
  • #request 就是Servlet中的HttpServletRequest对象
  • #response 就是Servlet中的HttpServletResponse对象
  • #session 就是Servlet中的HttpSession对象
  • #servletContext 就是Servlet中的ServletContext对象
<p th:text="${#request.getContextPath()}"></p>
<p th:text="@{/}"></p>
<p th:text="${#request.getParameter('id')}"></p>
<p th:text="${param.id}"></p>
<p th:text="${#servletContext.getAttribute('applicationMsg')}"></p>
<p th:text="${application.applicationMsg}"></p>
② 公共内置对象
  • #strings 提供了很多对字符串操作的方法 ☆
  • #arrays 提供了操作数组的常用方法
  • #lists 提供了操作List集合的常用方法 ☆
  • #sets 提供了操作set集合的常用方法
  • #maps 提供了操作Map集合的常用方法
String中的方法
<p th:text="${#strings.length(msg)}"></p>
<p th:text="${#strings.length(application.applicationMsg)}"></p>
<p th:text="${#strings.isEmpty(application.applicationMsg)}"></p>
<p th:text="${#strings.contains(application.applicationMsg,'数据')}"></p>
<p th:text="${#strings.contains(application.applicationMsg,'数据1')}"></p>
Array
<p th:text="${#arrays.length(names)}"></p>
<p th:text="${#arrays.isEmpty(names)}"></p>
<p th:text="${#arrays.contains(names,'java')}"></p>
List
<p th:text="${list}"></p>
<p th:text="${#lists.isEmpty(list)}"></p>
<p th:text="${#lists.size(list)}"></p>
<!--下面a不对是因为被识别为字符了,字符串!=字符-->
<p th:text="${#lists.contains(list,'a')}"></p>
<p th:text="${#lists.contains(list,'aa')}"></p>
<p th:text='${#lists.contains(list,"a")}'></p>
Set/Map不演示了
6.5.6 OGNL

OGNL:Object-Graph Navigation Language对象-图 导航语言
将复杂的对象或者集合放在域对象内,Thymeleaf如何去获取到数据

简单对象
Employee employee=new Employee(101,"法外狂徒张三",0,500000.0);
request.setAttribute("emp",employee);

${emp}    整个对象
${emp.id}    拿到对象内getId方法的返回值
复杂对象
Employee02 employee02=new Employee02(102,"熊二",1,34567d,new Computer(1,"联想",5000d));
 request.setAttribute("emp02",employee02);

 <div th:text="${emp02.salary}"></div>    员工的工资
 <div th:text="${emp02.computer}"></div>        员工的电脑对象
 <div th:text="${emp02.computer.id}"></div>     员工的电脑的getId方法的返回值
简单集合
List<String> names=new ArrayList<>();
names.add("java");
names.add("mysql");
names.add("oracle");
names.add("php");
request.setAttribute("names",names);

<div th:text="${names}"></div>
<div th:text="${names[0]}"></div>
<div th:text="${names[1]}"></div>
复杂集合
List<Employee> emps=new ArrayList<>();
emps.add(new Employee(101,"法外狂徒张三",0,500000.0));
emps.add(new Employee(102,"法外狂徒李四",1,600000.0));
emps.add(new Employee(103,"法外狂徒王五",0,700000.0));
request.setAttribute("emps",emps);

<p th:text="${emps}"></p>
<p th:text="${emps[0]}"></p>
<p th:text="${emps[0].id}"></p>
<p th:text="${emps[0].name}"></p>
Map集合
Map<String,Employee> map=new HashMap<>();
map.put("emp01",new Employee(101,"jack",0,500000.0));
map.put("emp02",new Employee(102,"rose",1,500000.0));
map.put("emp03",new Employee(103,"tom",0,500000.0));
request.setAttribute("map",map);

<p th:text="${map}"></p>
<p th:text="${map.emp01}"></p>
<p th:text="${map.emp01.id}"></p>
<p th:text="${map.emp01.name}"></p>

补充:

  • 遇到对象就通过.属性名的方式去获取属性值(原理是调用get方法)
  • 遇到List集合就通过下标获得到元素,如果元素是对象的话,还是回到上一句
  • 遇到Map集合就通过.key值的方式获得value值,如果value值是对象的话,还是回到上一句
6.5.7 分支
① if和unless

让标记了th:if、th:unless的标签根据条件决定是否显示。

  • if:th:if的值为真,则显示,反之,不显示
  • unless:th:unless的值为真,则不显示,反之,显示。
<p th:if="${#strings.length(msg)>5}">msg的数据长度大于5</p>
<p th:if="${not (#strings.length(msg)>5)}">msg的数据长度不大于5(1)</p>

<p th:unless="${#strings.length(msg)>5}">msg的数据长度不大于5(3)</p>
② swicth

看switch中的数据和哪个case相同,有相同的就显示哪个

<div th:switch="${#strings.length(msg)}">
    <p th:case="1">长度为1</p>
    <p th:case="2">长度为2</p>
    <p th:case="3">长度为3</p>
    <p th:case="4">长度为4</p>
    <p th:case="5">长度为5</p>
</div>
6.5.8 迭代
  • th:each=“obj,status : 后台请求域中数据的key”
  • status表示遍历的状态,有如下属性
    • index:元素的下标,从0开始
    • count:元素的计数,从开始,就等于index+1

简单数组迭代

List<String> list = new ArrayList<String>();
list.add("java");
list.add("sql");
list.add("go");
list.add("js");
req.setAttribute("list",list);
  
<ul>
    <li th:each="name,status : ${list}" th:text="${name}"></li>
</ul>

复杂数组的迭代

List<Employee> emps=new ArrayList<>();
emps.add(new Employee(101,"法外狂徒张三",0,500000.0));
emps.add(new Employee(102,"法外狂徒李四",1,600000.0));
emps.add(new Employee(103,"法外狂徒王五",0,700000.0));
request.setAttribute("emps",emps);

<table>
    <tr>
        <th>序号</th>
        <th>编号</th>
        <th>姓名</th>
        <th>性别</th>
        <th>薪资</th>
    </tr>
    <tr th:each="emp,status : ${emps}">
        <td th:text= "${status.count}"></td>
        <td th:text= "${status.index+1}"></td>
        <td th:text="${emp.id}"></td>
        <td th:text="${emp.name}"></td>
        <td th:if="${emp.gender} == 0"></td>
        <td th:if="${emp.gender} == 1"></td>
        <td th:text="${emp.gender} == 0 ? '男' : '女'"></td>
        <td th:text="${emp.salary}"></td>
    </tr>
</table>
6.5.9 Thymeleaf包含其他模板文件(即充当公共板块)

功能:网页内公共代码片段的提取

  1. 给公共的代码片段起个名字
<body>
    <div th:fragment="header" >公共数据</div>
</body>
  1. 在其他页面根据名字引用
// 将引入标签整体替换目标标签,div实际上是公共代码片段的div
<div th:replace="base::abc" id="aheader"></div>  
//将引入标签插入到目标标签内 本行在页面中有俩个div,一个id为header,一个id为aheader
<div th:insert="base::abc" id="aheader"></div>  
//将引入标签内容插入到目标标签内,div仍旧是id="aheader的div,只是将内容替换
<div th:include="base::abc" id="aheader"></div>   

7.会话

7.1 了解会话

7.1.1 会话的概念

一次交互(一次请求+一次响应)
一次会话(n次交互)
简单理解:用户点开一个浏览器,点击多个超链接,访问服务器多个web资源,然后关闭。整个过程称为一个会话

7.1.2 会话的功能

每个用户在使用浏览器与服务器进行会话的过程中,不可避免会产生一些数据,服务器想要为用户保存这些数据(登入信息,历史记录等)

7.1.2 会话域

会话域是从客户端连接上服务器开始,一直到客户端关闭,这一整个过程中发生的所有请求都在同一个会话域中;
而不同的客户端是不能共用会话域的

7.2 Cookie

7.2.1 Cookie的介绍

Cookie是一种客户端的会话技术。数据存储在浏览器中
image.png

7.2.2 Cookie的作用
  1. 在浏览器中存放数据
  2. 将浏览器中存放的数据携带到服务器
7.2.3 Cookie的使用场景

1.记住用户名
当我们在用户名的输入框中输入完用户名后,浏览器记录用户名,下一次再访问登录页面时,用户名自动填充到用户名的输入框.
2.保存电影的播放进度
在网页上播放电影的时候,如果中途退出浏览器了,下载再打开浏览器播放同一部电影的时候,会自动跳转到上次退出时候的进度,因为在播放的时候会将播放进度保存到cookie中
等等。

7.2.4 Cookie的应用

① 将数据保存到Cookie中

  • 创建Cookie对象并设置数据
  • 将cookie添加到响应报文内
 //创建Cookie对象并创建数据
Cookie cookie01 = new Cookie("adminKey1","adminValue1");
Cookie cookie02 = new Cookie("adminKey2","adminValue2");
//将cookie添加到响应报文内
resp.addCookie(cookie01);
resp.addCookie(cookie02);

② 将数据从cookie中取出来及信息

Cookie[] cookies = request.getCookies();
//获取cookie的name和value
if(cookies != null){
    for (Cookie cookie : cookies) {
        System.out.println(cookie.getName() + "=" + cookie.getValue());
    }
}

③ 设置cookie的有效时间(7.2.5)

cookie01.setMaxAge(60);//单位是秒

④ 设置cookie的携带条件(7.2.6)

protected void addCookie(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    //创建Cookie对象并创建数据
    Cookie cookie01 = new Cookie("adminKey1","adminValue1");
    Cookie cookie02 = new Cookie("adminKey2","adminValue2");
    //设置Cookie有效时间,单位是秒
    cookie01.setMaxAge(120);
    //设置Cookie的携带条件
    //当cookie只有访问当前项目下的user时才会携带
    cookie01.setPath(req.getContextPath() + "/user");
    //将cookie添加到响应报文内
    resp.addCookie(cookie01);
    resp.addCookie(cookie02);
    //给响应
}
7.2.5 Cookie的时效性

默认情况下Cookie的有效期是一次会话范围内,我们可以通过sexMaxAge()方法让Cookie持久话保存到浏览器中

  • 会话级Cookie
    • 服务器端并没有明确指定Cookie的存在时间
    • 在浏览器端,Cookie数据存在于内存中
    • 只要浏览器还开着,Cookie数据就一直都在
    • 浏览器关闭,内存中的Cookie数据就会被释放
  • 持久话Cookie
    • 服务器端明确设置了Cookie的存在时间
    • 在浏览器端,Cookie数据会被保存到硬盘上
    • Cookie在硬盘上存在的时间根据服务器端限定的时间来管控,不受浏览器关闭的影响
    • 持久化Cookie到达了预设的时间会被释放
7.2.6 Cookie的Path

上网时间长了,本地会保存很多Cookie。对浏览器来说,访问互联网资源时不能每次都把所有Cookie带上。浏览器会使用Cookie的path属性值来和当前访问的地址进行比较,从而决定是否携带这个Cookie。

7.3 Session

7.3.1 Session的介绍

session是服务器端的会话技术。服务器为每一个浏览器开辟一块内存空间,即session对象。由于session对象是每一个浏览器特有的,所以用户的记录可以存放在session对象中(每个服务器都对应一个session对象)
数据存储在服务器端
功能同Cookie

7.3.2 Session的应用

① 获得Session对象

//得到HttpSession对象
HttpSession session = req.getSession();
session.setMaxInactiveInterval(10);
System.out.println("session = " + session);

② 设置共享数据

//得到HttpSession对象
HttpSession session = req.getSession();
System.out.println("session = " + session);
session.setAttribute("sessionMsg","sessionValue");

③ 获得共享数据

//得到HttpSession对象
HttpSession session = req.getSession();
System.out.println("session = " + session);
Object sessionMsg = session.getAttribute("sessionMsg");
System.out.println("sessionMsg = " + sessionMsg);

④ 移除共享数据(只是将数据删除)

//得到HttpSession对象
HttpSession session = req.getSession();
System.out.println("session = " + session);
session.removeAttribute("sessionMsg");
7.3.3 服务器如何办到浏览器和Session对应(getSession工作原理)

通过Cookie,Session依赖于Cookie

  • 当浏览器第一次访问服务器时,调用getSession(),新建一个Session对象,并设置一个cookie给浏览器(jsessionid)
  • 当浏览器第二次访问服务器是,调用getSession(),就会到请求中查找了JSESSIONID的Cookie,根据value值找到session对象
7.3.4 会话什么时候结束
  • 客户端关闭(jsessionid这个cookie伴随着消失)
  • 强制失效
//得到HttpSession对象
HttpSession session = req.getSession();
System.out.println("session = " + session);
session.invalidate();//强制失效
  • 自动失效(达到最大空闲时间)
    • 默认是半小时(误操作/没有向服务器发送请求)

8.Ajax

Ajax(Asynchronous JavaScript And XML )异步的JavaScript和XML

服务器渲染(整个网页刷新)Thymeleaf同步请求
ajax渲染(局部刷新)js异步请求

8.1 服务端渲染

image.png

8.2 Ajax渲染

image.png

8.3 前后端分离

真正的前后端分离是前端项目和后端项目分服务器部署,在我们这里我们先理解为彻底舍弃服务器端渲染,数据全部通过Ajax方式以JSON格式来传递

8.4 同步和异步

Ajax(Asynchronous JavaScript And XML )异步的JavaScript和XML

8.4.1 同步

多个操作按顺序执行,前面的没完成,后面的操作必修等待。所以同步操作通常都是串行的。

8.4.2 异步

多个操作并发执行,即使开始的先后顺序不同,但由于他们各自是在自己独立的进程或线程中完成,所以互不干扰

8.5 Axios

http://www.axios-js.com/
使用原生的JavaScript程序执行Ajax极其繁琐,所以一定要使用框架来完成。而Axios就是目前最流行的前端Ajax框架。

8.5.1 Axios的使用(前端笔记,此处略讲)
  1. 在前端页面引入开发环境(Vue和axios)
<script src="js/axios.min.js"></script>
  1. 发送请求
<div id="app">
      <input type="button" value="按钮" @click="ajaxTest">
      <input type="button" value="按钮02" @click="ajaxTest02">
  </div>
  1. 编写前端函数
new Vue({
  el:"#app",
  data:{},
  methods:{
    ajaxTest:function (){
        //使用Axios请求框架
				//设置请求方式,请求路径,请求参数
        axios({
            method:"post",
            url:"ajax",
            params:{
                username:"admin",
                password:"root"
            }
        }).then((response)=>{
            //如果响应状态码为200,则执行函数(回调函数),如果识别返回的字符串格式符合json格式要求,则自动转化为json对象
            alert("成功" + response.data)//json对象,axios框架。
            console.log(response.data.id)
            console.log(response.data.name)
            console.log(response.data.gender)
            console.log(response.data.salary)
        }).catch((error) => {
            //如果响应状态码是500,则执行函数(回调函数)
            alert("服务器出现异常")
        });

    }
  1. 编写后端函数
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
      System.out.println("访问到ajaxServlet");
      String username = req.getParameter("username");
      System.out.println("username = " + username);
      String password = req.getParameter("password");
      System.out.println("password = " + password);
//        int i = 10/0;//异常
      resp.setContentType("text/html;charset=utf-8");
      //给响应。异步请求并不跳转,使用输出流的方式
      PrintWriter writer = resp.getWriter();
      //java类作为响应数据
      Employee employee = new Employee(101,"gpy",0,1000);
      //使用jason数据作为响应数据,json格式的字符串
      String str = "{\"id\":101,\"name\":\"关鹏越\",\"gender\":0,\"salary\":1000}";
//        writer.write(str);
      Gson gson = new Gson();
      String json = gson.toJson(employee);
      System.out.println("json = " + json);
//        writer.write(json);
      //list集合作为响应数据
      List<Employee> list = new ArrayList<>();
      list.add(new Employee(101,"gpy",0,1000));
      list.add(new Employee(102,"gpy",0,1000));
      list.add(new Employee(103,"gpy",0,1000));
      Gson gson1 = new Gson();
      String json1 = gson1.toJson(list);
      System.out.println("json1 = " + json1);
//        writer.write(json1);
      //Map集合
      Map<String,Employee> map = new HashMap<>();
      map.put("emp01",new Employee(101,"gpy",0,1000));
      map.put("emp02",new Employee(102,"gpy",0,1000));
      map.put("emp03",new Employee(103,"gpy",0,1000));
      map.put("emp04",new Employee(104,"gpy",0,1000));
      Gson gson2 = new Gson();
      String json2 = gson2.toJson(map.values());
      System.out.println("json2 = " + json2);
      writer.write(json2);
  }
8.5.2 Gson包

Gson是Google研发的一款非常优秀的JSON数据解析和生成工具,它可以帮助我们将数据在JSON字符串和Java对象之间互相转换。

Gson gson = new Gson();
String json = gson.toJson(employee);
writer.write(json);

9.Filter(过滤器)

9.1 Filter的概念

Filter:一个实现了特殊接口(Filter)的Java类. 实现对请求资源(jsp,servlet,html,)的过滤的功能. 过滤器是一个运行在服务器的程序, 优先于请求资源(Servlet或者jsp,html)之前执行. 过滤器是javaweb技术中最为实用的技术之一

9.2 Filter的功能

Filter的作用是对目标资源(Servlet,jsp)进行过滤,其应用场景有: 登录权限检查,解决网站乱码,过滤敏感字符等等

9.3 Filter的入门

9.3.1 案例目标

实现在请求到达Servlet之前解决请求参数的中文乱码

9.3.2 步骤
  1. 新建一个网页和Servlet等准备
  2. Servlet实现一个接口(javax.servlet.Filter)
  3. 实现接口的抽象方法
public class helloFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        //先访问FilterServlet
        System.out.println("访问到helloFilter");
        //解决请求参数的乱码
        HttpServletRequest request = (HttpServletRequest) req;
        request.setCharacterEncoding("UTF-8");
        //这句代码表示放行
        filterChain.doFilter(servletRequest, servletResponse);
        //在传回服务器之前在回一次Filter
        System.out.println("这是放行后的代码");//执行目标执行后执行
    }

    @Override
    public void destroy() {

    }
}
  1. 配置过滤器的过滤路径(web.xml)
<filter>
    <filter-name>HelloFilter</filter-name>
    <filter-class>com.atguigu.filter.HelloFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>HelloFilter</filter-name>
    <url-pattern>/hello</url-pattern>
</filter-mapping>

9.4 过滤器原理

  • 请求发出,如果符合过滤器的过滤要求,执行放行前代码
  • 放行,就是去执行目标资源
  • 目标资源执行完毕,会执行放行后的代码(filterChain.doFilter)
  • 最后把响应传回浏览器

image.png

9.5 Filter生命周期

生命周期阶段执行时机生命周期方法
创建对象Web应用启动时init方法,通常在该方法中做初始化工作
拦截请求接收到匹配的请求doFilter方法,通常在该方法中执行拦截过滤
销毁Web应用卸载前destroy方法,通常在该方法中执行资源释放

9.6 过滤器的匹配规则

主要研究的就是filter-mapping中的url-pattern的值有几种编写方式

//对应Servlet中的url-pattern
<servlet-mapping>
      <servlet-name>BServlet</servlet-name>
      <url-pattern>/b.yue</url-pattern>
  </servlet-mapping>
9.6.1 精准匹配
<url-pattern>/hello</url-pattern>   过滤项目下hello请求
<url-pattern>/a</url-pattern>       过滤项目下a请求
<url-pattern>/b</url-pattern>       过滤项目下b请求
9.6.2 目录匹配
<url-pattern>/user/*</url-pattern>   过滤项目下user请求下的所有请求(请求地址只要是/user开头的)
<!--		例如
        /user/demo01
        /user/demo02
        /user/demo03
-->
<url-pattern>/*</url-pattern>        过滤项目下所有请求
9.6.3 后缀匹配
<url-pattern>*.abc</url-pattern>   匹配后缀为.abc的请求(注意:不需要加/)

为什么又A.abc这样的东西呢,之前没见过啊,就是有,记就完了。例如a.com,b.com

9.7 过滤器链

如果出现一个请求存在多个过滤器对其过滤,出现了过滤器链
在放行前,过滤器是正序执行,放行后过滤器是倒序执行
是什么决定了过滤器的顺序呢?和filter-mapping配置上下位置有关

<filter-mapping>
    <filter-name>03Filter</filter-name>
    <url-pattern>/Target05Servlet</url-pattern>
</filter-mapping>
<filter-mapping>
    <filter-name>02Filter</filter-name>
    <url-pattern>/Target05Servlet</url-pattern>
</filter-mapping>
<filter-mapping>
    <filter-name>01Filter</filter-name>
    <url-pattern>/Target05Servlet</url-pattern>
</filter-mapping>

//先3 ---> 2 ---> 1
//后1 ---> 2 ---> 3

image.png

10.Listener(监听器 了解)

监听器:专门用于对其他对象身上发生的事件或状态改变进行监听和相应处理的对象,当被监视的对象发生情况时,立即采取相应的行动。
生活中的监听器:当发生一些事情的时候,会有程序执行。

10.1 Servlet监听器的分类

  • ServletContextListener
    • 监听ServletContext对象的创建与销毁(应用域 ServletContext)
    • 对象是web项目加载时创建。web项目卸载时销毁
  • HttpSessionListener
    • 监听HttpSession对象的创建与销毁(会话域 HttpSession)
    • 第一次调用getSession创建,销毁是强制销毁
  • ServletRequestListener
    • 监听ServletRequest对象的创建与销毁(请求域 HttpServletRequest)
    • 有请求就创建,响应结束就销毁

10.2 监听域对象内共享数据的添加、修改、删除

  • ServletContextAttributeListener 监听应用域中数据的添加、修改、删除
  • HttpSessionAttributeListener 监听会话域中数据的添加、修改、删除
  • ServletRequestAttributeListener 监听请求域中数据的添加、修改、删除

补充:Servlet中
setAttribute(String key,Object value) 添加数据
setAttribute(String key,Object value) 如果key值存在,此方法就是修改数据
removeAttribute(String key) 删除数据
补充:以上都是接口名!!!!

10.3 监听器的创建步骤

  1. 创建一个类并实现接口(根据功能选择接口)
  2. 实现接口中的抽象方法
  3. 注册监听器
    1. 位置:web.xml
    2. 代码:
<listener>
    <listener-class>com.atguigu.listener.HelloListener</listener-class>
</listener>

11.Servlet、Filter、Listener 的注解方式开发

功能:替代配置文件

① Servlet的注解

位置:类的上方
name对应,value对应

//@WebServlet(name = "HelloServlet",value = "/hello")//name可以省略,如果只有value,那么value这个单词可以省略
@WebServlet("/hello")
public class HelloServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("访问到HelloServlet");
    }
}

② Filter注解

位置:类的上方

  • filterName—>filte-name标签的值
  • urlPatterns—> url-pattern标签的值
@WebFilter(filterName = "helloFilter",urlPatterns = "/hello")
public class helloFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("访问到helloFilter");
        filterChain.doFilter(servletRequest, servletResponse);
        System.out.println("这是放行后的代码");//执行目标执行后执行
    }

    @Override
    public void destroy() {

    }
}

③ Listener的注解

位置:类的上方

@WebListener
public class HelloListener implements ServletContextListener {
    @Override
    public void contextInitialized(ServletContextEvent servletContextEvent) {
        System.out.println("会话域创建后执行");
    }

    @Override
    public void contextDestroyed(ServletContextEvent servletContextEvent) {
        System.out.println("会话域销毁后执行");
    }
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值