文章目录

  • JDBC
      • 注册驱动(forName)
      • 驱动管理对象(DriverManager)
        • 注册驱动
      • 获取数据库连接(getConnection)
        • 数据库连接对象(Connection)
        • 执行 / 查询 sql 的对象(Statement)
      • 结果集对象,封装查询结果(ResultSet)
      • 安全执行sql的对象(PreparedStatement)
      • JDBC 管理事务
    • JDBC 数据库连接池
      • 创建连接池对象(C3P0)
        • 获取连接对象
        • 配置文件
      • 创建连接池对象(Druid)
        • 创建配置文件读取对象
        • 获取连接池对象
        • 获取连接
        • 连接池的使用,工具类
      • Spring JDBC框架
        • 入门案例
        • 将单个结果封装map(queryForMap)
        • 将所有结果转换成 list(queryForList)
        • 将所有结果封装成 自定义JavaBean类(query)
  • Maven 项目
    • 依赖关系
  • Git
    • 常用指令
  • HTTP&Tomcat&Servlet
      • HTTP
        • HTTP - 请求数据格式
        • HTTP - 响应状态码
    • Web & Servlet
      • 常见的服务器
      • servlet(是 javax 包下的)
        • 实现 servlet 接口
        • servlet 的方法
          • init 方法只执行一次
          • service 执行多次
          • destroy 被销毁
          • doPost
          • doGet
        • web.xml文件
      • IDEA 与 Tomcat 相关配置
      • HttpServlet(是 javax 包下的)
    • Request & response
      • request 继承 实现 体系
    • request 功能
      • 获取请求行数据
        • 获取请求方式
        • 获取虚拟目录
        • 获取 servlet 路径
        • 获取get方式请求参数(不常用)
        • 获取请求的URL(getRequestURL)
        • 获取协议和版本(getProtocol)
        • 获取客户机的 ip 地址(getRemoteAddr)
      • 获取请求头数据
        • 获取所有的请求头数据(getHeaderNames)
        • 根据请求名获取数据(getHeader)
        • 防盗链练习
      • 获取请求体数据
        • 获取流对象(getReader)
        • 读取数据(readLine)
      • 获取请求参数通用方式
        • 根据参数名称获取参数值(getParameter)
        • 根据参数名称获取参数值的数组(getParameterValues)
        • 获取所有的请求参数名称(getParameterNames)
        • 获取所有参数封装成 map 集合
        • 请求转发(getRequestDispatcher)
          • 共享数据
        • 存储数据(setAttribute)
        • 获取数据(setAttribute)
        • 通过键名移除该键值对(removeAttribute)
        • 获取ServletContext
        • 封装数据(beanutils)
        • 设置属性(setProperty)
        • 获取属性值(setProperty)
        • 获取所有参数,(populate)
      • 乱码问题
      • 常见报错
    • Http 协议
    • Response 功能
      • 重定向
      • 相对路径
      • 绝对路径
      • 获取字符输出流(getWriter)
      • 获取字节输出流(getOutputStream)
        • 输出流乱码问题
        • 输出数据(println)
        • 服务启动就初始化
      • 修改默认启动页面
      • 知识点
    • 图像
      • 创建内存中的图片
        • 输出图片到页面上
      • 创建画笔对象(getGraphics)
        • 设置画笔颜色(setColor)
        • 填充图片(fillRect)
        • 画边框(drawRect)
        • 往图片上输入文字(drawString)
        • 画线条
        • 小知识
      • 读取 json字符串
    • 获取公共域(getServletContext)
      • xml 提前初始化变量
      • 获取 MIME(getMimeType)
      • 共享数据,设置
      • 共享数据,获取
      • 共享数据,移除
      • 获取文件的真实(服务器)路径(getRealPath)
        • 简单方式
        • 在WEB-INF目录下
        • 在 src 目录下
      • 案例实现文件下载
    • Jsp 页面获取其他域(pageContext)
      • 获取 request
  • 会话技术
    • Cookie 客户端会话
      • 创建 Cookie 对象
      • 在响应中添加 cookie
      • 获取cookie 数组
      • 细节1:可不可以发送多个cookie
      • 细节2:cookie设置存活时间(setMaxAge)
      • 细节3: 在tomcat 8 之后支持存储中文
      • 细节4:共享 cookie 问题
      • Cookie 特点和作用
      • URL 编码(URLEncoder.encode)
      • URL 解码(URLDecoder.decode)
    • Session 服务端会话
      • 获取 session 对象(getSession)
        • 设置数据(setAttribute)
        • 获取数据(getAttribute)
        • 删除数据(removeAttribute)
      • session 原理
        • 服务器如何确保在一次会话中,多次获取的 session 对象是同一个?
        • 当客户端关闭后,服务器不关闭,两次获取session是否为同一个?
        • 客户端不关闭,服务器关闭后,两次获取的session是同一个吗?
        • session什么时候被销毁? 1. 服务器关闭
        • session的特点
        • session与Cookie的区别:
  • jsp & el表达式 & JSTL
    • jsp 运行原理
    • jsp 脚本
      • 在 service 方法内写 Java 代码
      • 在类中方法外写 java 代码
      • 定义 java 代码输出到页面上
      • 内置对象
      • response 和 out 的区别
    • 头部信息
      • 错误信息
      • include 包含资源
      • taglib 导入资源
    • 注释
    • 内置对象
    • MVC
    • El 表达式
      • 忽略 el 表达式
      • 算术运算符
      • 获取域中值
      • 获取域中对象的值
      • 获取集合值
      • 空运算符(empty)
      • 隐式对象
    • JSTL
      • 标签
        • c:if 判断
        • c:choose 选择
        • c:forEach 循环
      • 三层架构

JDBC

注册驱动(forName)

只是把类加载到内存,mysql 版本5以上可以不写

// 注册mysql驱动
Class.forName("com.mysql.jdbc.Driver");

驱动管理对象(DriverManager)

注册驱动

Class.forName源码中使用了静态代码块注册驱动,利用DriverManager.registerDriver

static {try {// 使用registerDriver 注册驱动,之前那样写简单DriverManager.registerDriver(new Driver());} catch (SQLException var1) {throw new RuntimeException("Can't register driver!");}}

获取数据库连接(getConnection)

  • 参数

    • url:指定连接路径

      • 语法:jdbc:mysql://ip地址(域名):端口号/数据库名称
      • 扩展:如果连接本机的数据库,并且端口还是3306,那么可以省略IP地址和端口号 ---- jdbc:mysql:///数据库名称
    • root:账号,字符串形式
    • password:密码,字符串形式

建立连接

// 建立链接
Connection root = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/aa", "root", "1234");

简写

DriverManager.getConnection("jdbc:mysql:///10_18", "root", "1234");

返回 Connection 对象

数据库连接对象(Connection)

  • 功能

    • 获取执行 sql 的对象

      • Statement createStatement()
      • PreparedStatement prepareStatement(String sql)
    • 管理事务
      • 开启事务:setAutoCommit(boolean autoCommit) :调用该方法设置参数为false,即开启事务
      • 提交事务:commit()
      • 回滚事务:rollback()

获取执行的对象

// 连接数据库
Connection root = DriverManager.getConnection("jdbc:mysql:///10_18", "root", "1234");
// 获取执行语句对象
Statement stmt = root.createStatement();

执行 / 查询 sql 的对象(Statement)

  • 执行 sql 语句

    • boolean execute(String sql) :可以执行任意的sql 了解 (不常用)
    • int executeUpdate(String sql) :执行DML(insert、update、delete)语句、DDL(create,alter、drop)语句
      返回值:影响的行数,如果是DDL语句返回 0
    • ResultSet executeQuery(String sql) :执行DQL(select)语句
      返回结果集 ResultSet

执行语句对象 executeUpdate

// 连接数据库
Connection root = DriverManager.getConnection("jdbc:mysql:///10_18", "root", "1234");
// 获取执行语句
Statement stmt = root.createStatement();
// 执行sql sql 是一个字符串  sql 语句
int count = stmt.executeUpdate(sql);

查询语句对象 executeQuery

try (// 连接数据库Connection root = DriverManager.getConnection("jdbc:mysql:///10_18", "root", "1234");// 获取执行语句Statement stmt = root.createStatement();// 执行sqlResultSet res = stmt.executeQuery(sql);
) {} catch (SQLException e) {e.printStackTrace();
}

结果集对象,封装查询结果(ResultSet)

  • boolean next() 类似于迭代器,初始值为0,就是起始值,如果有数据为true,否则是false
  • getXxx(参数):获取数据,getInt,getString
    • 参数:
      1. int:代表列的编号,从1开始 如: getString(1)
      2. String:代表列名称。 如: getDouble(“Money”)
try (// 连接数据库Connection root = DriverManager.getConnection("jdbc:mysql:///10_18", "root", "1234");// 获取执行对象Statement sta = root.createStatement();// 执行sql语句获取结果集ResultSet res = sta.executeQuery("select * from account");
) {// 遍历结果集while (res.next()) {int id = res.getInt("id");String name = res.getString("name");int money = res.getInt("money");stus.add(new Stu(id, name, money));}
} catch (SQLException e) {e.printStackTrace();
}

安全执行sql的对象(PreparedStatement)

  1. 解决SQL注入问题:在拼接sql时,有一些sql的特殊关键字参与字符串的拼接。会造成安全性问题
  2. 预编译的SQL:参数使用?作为占位符
  3. 给?赋值:
    * 方法: setXxx(参数1,参数2)
    * 参数1:?的位置编号 从1 开始
    * 参数2:?的值

创建对象

// 连接数据库
Connection root = DriverManager.getConnection("jdbc:mysql:///10_18", "root", "1234");
// 获取执行对象,必须要给参数,不给参数是父类的方法
PreparedStatement sta = root.prepareStatement("select * from account where id = ?");

设置值 并执行语句

// 给第一个问号设置 值
sta.setString(1, idname);
// 执行sql语句获取结果集,不需要传参
ResultSet res = sta.executeQuery();

JDBC 管理事务

  1. 事务:一个包含多个步骤的业务操作。如果这个业务操作被事务管理,则这多个步骤要么同时成功,要么同时失败。
  2. 操作:
    1. 开启事务
    2. 提交事务
    3. 回滚事务
  3. 使用Connection对象来管理事务
    • 开启事务:setAutoCommit(boolean autoCommit) :调用该方法设置参数为false,即开启事务

      • 在执行sql之前开启事务
    • 提交事务:commit()
      • 当所有sql都执行完提交事务
    • 回滚事务:rollback()
      • 在catch中回滚事务

开启事务

//开启事务
conn.setAutoCommit(false);

回滚事务

conn.rollback();

案例

//定义sql
// 张三 - 500
String sql1 = "update account set balance = balance - ? where id = ?";
// 李四 + 500
String sql2 = "update account set balance = balance + ? where id = ?";
Connection conn = null;
try {// 获取连接conn = DriverManager.getConnection("jdbc:mysql:///10_18", "root", "1234");// 获取执行sql对象PreparedStatement ps1 = conn.prepareStatement(sql1);PreparedStatement ps2 = conn.prepareStatement(sql2);//开启事务conn.setAutoCommit(false);//4. 设置参数ps1.setDouble(1, 500);ps1.setInt(2, 1);ps2.setDouble(1, 500);ps2.setInt(2, 2);//5.执行sqlps1.executeUpdate();// 手动制造异常int i = 3 / 0;ps2.executeUpdate();//提交事务conn.commit();
} catch (Exception e) {//事务回滚try {conn.rollback();} catch (SQLException ex) {throw new RuntimeException(ex);}
}
}

JDBC 数据库连接池

  1. 概念:创建一个存放数据库连接的容器。

    1. 当系统初始化好后,容器被创建,容器中会申请一些连接对象,当用户来访问数据库时,从容器中获取连接对象,用户访问完之后,会将连接对象归还给容器。
  2. 好处:

    1. 节约资源
    2. 用户访问高效
  3. 实现:

    1. 标准接口:DataSource javax.sql包下的

      1. 方法:

        • 获取连接:getConnection()
        • 归还连接:Connection.close()。如果连接对象Connection是从连接池中获取的,那么调用Connection.close()方法,则不会再关闭连接了。而是归还连接
    2. 一般我们不去实现它,有数据库厂商来实现

      1. C3P0:数据库连接池技术
      2. Druid:数据库连接池实现技术,由阿里巴巴提供的
  4. C3P0:数据库连接池技术

    • 步骤:

      1. 导入jar包 (两个) c3p0-0.9.5.2.jar mchange-commons-java-0.2.12.jar

        • 不要忘记导入数据库驱动jar包
      2. 定义配置文件:

        • 名称: c3p0.properties 或者 c3p0-config.xml
        • 路径:直接将文件放在src目录下即可。
      3. 创建核心对象 数据库连接池对象 ComboPooledDataSource

      4. 获取连接: getConnection

创建连接池对象(C3P0)

一定要导入 mysql 的包

// 1. 创建数据库连接池对象
DataSource source = new ComboPooledDataSource();

获取连接对象

传递的参数name,表示,使用的哪一个配置

// 2. 获取连接对象
Connection coon = source.getConnection();

配置了十个,下面获取十一个,等待三秒报错

// 1. 创建数据库连接池对象
DataSource source = new ComboPooledDataSource();
for (int i = 0; i < 11; i++) {// 2. 获取连接对象Connection coon = source.getConnection();System.out.println(coon);
}

配置文件

<c3p0-config><!-- 使用默认的配置读取连接池对象 --><default-config><!--  连接参数 --><property name="driverClass">com.mysql.jdbc.Driver</property><!--  连接数据库地址  --><property name="jdbcUrl">jdbc:mysql://localhost:3306/10_18</property><!--    登录账号    --><property name="user">root</property><!--    登录密码    --><property name="password">1234</property><!-- 连接池参数 --><!--    申请五个连接对象    --><property name="initialPoolSize">5</property><!--    最大的连接数量    --><property name="maxPoolSize">10</property><!--    连接时长最多等待3秒    --><property name="checkoutTimeout">3000</property></default-config><named-config name="otherc3p0"><!--  连接参数 --><property name="driverClass">com.mysql.jdbc.Driver</property><property name="jdbcUrl">jdbc:mysql://localhost:3306/10_18</property><property name="user">root</property><property name="password">1234</property><!-- 连接池参数 --><property name="initialPoolSize">5</property><property name="maxPoolSize">8</property><property name="checkoutTimeout">1000</property></named-config>
</c3p0-config>

创建连接池对象(Druid)

  1. 步骤:
    1. 导入jar包 druid-1.0.9.jar
    2. 定义配置文件:
    * 是properties形式的
    * 可以叫任意名称,可以放在任意目录下
    3. 加载配置文件。Properties
    4. 获取数据库连接池对象:通过工厂来来获取 DruidDataSourceFactory
    5. 获取连接:getConnection

创建配置文件读取对象

// 1. 创建配置文件读取对象
Properties pro = new Properties();
// 2. 安全方式获取 druid 配置文件,并加载读取
pro.load(lin.class.getResourceAsStream("/druid.properties"));

获取连接池对象

// 3. 通过工厂获取连接池对象
DataSource source = DruidDataSourceFactory.createDataSource(pro);

获取连接

// 4. 获取连接
Connection coon = source.getConnection();

连接池的使用,工具类

工具类设置

public class JDBCUtils {// Druid连接池的工具类private static DataSource ds; // 私有化成员变量// 配置static {try {Properties pro = new Properties();pro.load(JDBCUtils.class.getResourceAsStream("/druid.properties"));ds = DruidDataSourceFactory.createDataSource(pro);} catch (Exception e) {e.printStackTrace();}}// 获取连接public static Connection getConnection() throws SQLException {return ds.getConnection();}
}

使用

public static void main(String[] args) {try (// 获取连接Connection coon = JDBCUtils.getConnection();// 获取执行语句对象PreparedStatement sta = coon.prepareStatement("insert into account values (?,?,?)");) {sta.setInt(1, 5);sta.setString(2, "李四");sta.setInt(3, 3000);// 执行语句int i = sta.executeUpdate();System.out.println(i);} catch (SQLException e) {e.printStackTrace();}
}

Spring JDBC框架

Spring框架对JDBC的简单封装。提供了一个JDBCTemplate对象简化JDBC的开发

  • 步骤:

    1. 导入jar包
    2. 创建JdbcTemplate对象。依赖于数据源 DataSource(数据库连接池)
      • JdbcTemplate template = new JdbcTemplate(ds);
    3. 调用JdbcTemplate的方法来完成CRUD的操作
      • update():执行DML语句。增、删、改语句
      • queryForMap():查询结果将结果集封装为map集合,将列名作为key,将值作为value 将这条记录封装为一个map集合
        • 注意:这个方法查询的结果集长度只能是1
      • queryForList():查询结果将结果集封装为list集合
        • 注意:将每一条记录封装为一个Map集合,再将Map集合装载到List集合中
      • query():查询结果,将结果封装为JavaBean对象
        • query的参数:RowMapper

          • 一般我们使用BeanPropertyRowMapper实现类。可以完成数据到JavaBean的自动封装
          • new BeanPropertyRowMapper<类型>(类型.class)
      • queryForObject:查询结果,将结果封装为对象
        • 一般用于聚合函数的查询

入门案例

工具类

package util;import com.alibaba.druid.pool.DruidDataSourceFactory;import javax.sql.DataSource;
import java.sql.SQLException;
import java.util.Properties;public class JDBCUtils {// Druid连接池的工具类private static DataSource ds; // 私有化成员变量// 配置static {try {Properties pro = new Properties();pro.load(JDBCUtils.class.getResourceAsStream("/druid.properties"));ds = DruidDataSourceFactory.createDataSource(pro);} catch (Exception e) {e.printStackTrace();}}// 获取连接池public static DataSource getConnection() throws SQLException {return ds;}}

代码

public static void main(String[] args) {try {// 创建 template 对象JdbcTemplate template = new JdbcTemplate(JDBCUtils.getConnection());// 调用方法String sql = "update account set money = '5000' where name = ?";// update修改int update = template.update(sql, "张三");System.out.println(update);} catch (SQLException e) {e.printStackTrace();}
}

将单个结果封装map(queryForMap)

字段变成 键 数据变成值
这个方法查询结果只能是一条数据,否则会报错

JdbcTemplate template = new JdbcTemplate(JDBCUtils.getConnection());
String sql = "select * from student where Sid = ?";
// 把 id 为 01 的同学 数据封装成map 集合
Map<String, Object> map = template.queryForMap(sql,"01");
// 字段变成 键 数据变成值
System.out.println(map);
//{Sid=01, Sname=赵雷, Sage=1990-01-01T00:00, Ssex=男}

将所有结果转换成 list(queryForList)

JdbcTemplate template = new JdbcTemplate(JDBCUtils.getConnection());
String sql = "select * from student";
// 把所有的同学 数据封装成 list 集合
List<Map<String, Object>> maps = template.queryForList(sql);
for (Map<String, Object> map : maps) {System.out.println(map);
}

将所有结果封装成 自定义JavaBean类(query)

利用BeanPropertyRowMapper 实现转换

JdbcTemplate template = new JdbcTemplate(JDBCUtils.getConnection());
String sql = "select * from student";
// 把所有的同学 数据封装成 list 集合
List<Student> list = template.query(sql, new BeanPropertyRowMapper<>(Student.class));
for (Student student : list) {System.out.println(student);
}

查询总计数,返回自定义结果

JdbcTemplate template = new JdbcTemplate(JDBCUtils.getConnection());
String sql = "select count(Sid) from student";
// 查询总计数
// 封装返回结果类型
Long aLong = template.queryForObject(sql, long.class);
System.out.println(aLong); // 9

Maven 项目

命令

  • compile 是 maven 工程的编译命令,作用是将 src/main/java 下的文件编译为 class 文件输出到 target 目录下。
  • test 是 maven 工程的测试命令 mvn test,会执行 src/test/java 下的单元测试类。
  • clean 是 maven 工程的清理命令,执行 clean 会删除 target 目录及内容。
  • package 是 maven 工程的打包命令,对于 java 工程执行 package 打成 jar 包,对于 web 工程打成 war包。
  • nstall 是 maven 工程的安装命令,执行 install 将 maven 打成 jar 包或 war 包发布到本地仓库。

依赖关系

一个 maven 工程都有一个 pom.xml 文件,通过 pom.xml 文件定义项目的坐标、项目依赖、项目信息、插件目标等。

Git

常用指令

指令
设置当前目录为git仓库 git init
工作区 --> 暂存区 git add
暂存区 --> 本地仓库 git commit -m “注释”
查看当前状态 git status
作用:查看提交记录 git log [option]
–all 显示所有分支
–pretty=oneline 将提交信息显示为一行
–abbrev-commit 使得输出的commitId更简短
–graph 以图的形式显示
git-log好用
版本回退 git reset --hard 回退编号
查看删除的提交记录 git reflog

.gitignore 的文件 可以指定哪些文件不需要传递给 git

HTTP&Tomcat&Servlet

HTTP

规定了浏览器和服务器之间数据传输的规则

HTTP协议特点
基于TCP协议:面向链接,安全
一次请求对应一次响应
每次请求响应都是独立的
缺点:多次请求不能共享数据 java中使用会话技术解决这个问题
优点:速度快 Cookie,Session

HTTP - 请求数据格式

  • 请求行:请求数据的第一行。其中GET表示请求方式
    /表示请求资源路径,HTTP/1.1表示协议版本

  • 请求头:从第二行开始,都是键值对

  • 请求体:POST请求的最后一部分,存放请求参数,独有

常见的HTTP请求头
Host 表示请求的主机名
User-Agent 浏览器版本,例如Chrome浏览器的标识类似Mozilla/5.0
Chrome/79 IE浏览器的标识类似Mozilla/5.0(WindowsNT…)likeGecko
Accept 表示浏览器能接收的资源类型,如text/*
image/*
*/*表示所有
Accept-Language 表示浏览器偏好的语言,服务器可以据此返回不同语言的网页
Accept-Encoding 表示浏览器可以支持的压缩类型,例如gzip,deflate等。

GET请求和POST请求的区别

  1. GET请求请求参数在请求行中,没有请求体。
    POST请求请求参数在请求体中
  2. GET请求请求参数大小有限制,POST没有

HTTP - 响应状态码

  • 响应行:响应数据的第一行。其中HTTP/1.1表示协议版
    本,200表示响应状态码,OK表示状态码描述

  • 响应头:从第二行开始,都是键值对

  • 响应体:最后一部分。存放响应数据

常见的HTTP响应头
ContentType 表示该响应内容的类型,例如text/html,image/jpeg
Conten-Length 表示该响应内容的长度(字节数)
Content-Encoding 表示该响应压缩算法,例如gzip
Cache-Control 指示客户端应如何缓存,例如max-age=300, 表示可以最多缓存300秒

Web & Servlet

  1. 软件架构

    1. C/S:客户端/服务器端
    2. B/S:浏览器/服务器端
  2. 资源分类
    1. 静态资源:每个人访问都是一样的页面,称为静态资源,可以直接被浏览器解析

      • 如: html,css,JavaScript
    2. 动态资源:每个人访问页面可能不同,称为动态资源。动态资源需要先转换为静态资源,在返回给浏览器
      • 如:servlet/jsp,php,asp…
  3. 网络通信三要素
    1. IP:电子设备(计算机)在网络中的唯一标识。
    2. 端口:应用程序在计算机中的唯一标识。 0~65536
    3. 传输协议:规定了数据传输的规则
      1. 基础协议:

        1. tcp:安全协议,三次握手。 速度稍慢
        2. udp:不安全协议。 速度快

常见的服务器

  • 常见的java相关的web服务器软件:

    • webLogic:oracle公司,大型的JavaEE服务器,支持所有的JavaEE规范,收费的。
    • webSphere:IBM公司,大型的JavaEE服务器,支持所有的JavaEE规范,收费的。
    • JBOSS:JBOSS公司的,大型的JavaEE服务器,支持所有的JavaEE规范,收费的。
    • Tomcat:Apache基金组织,中小型的JavaEE服务器,仅仅支持少量的JavaEE规范servlet/jsp。开源的,免费的。

servlet(是 javax 包下的)

实现 servlet 接口

public class 类名 implements Servlet

重写其中的方法

  • 执行原理:

    1. 服务器接受到客户端的请求后,会解析请求URL路径,获取访问的Servlet的资源路径
    2. 查找web.xml文件,是否有对应的标签体内容。
    3. 如果有,则在找到对应的全类名
    4. tomcat会将字节码文件加载进内存,并且创建其对象
    5. 调用其方法
Servlet中的生命周期方法
1. 被创建:执行init方法,只执行一次
Servlet什么时候被创建? 默认第一次被访问时,Servlet被创建
可以配置执行Servlet的创建时机
在<servlet>标签下配置
1. 第一次被访问时,创建 <load-on-startup>的值为负数
2. 在服务器启动时,创建 <load-on-startup>的值为0或正整数

Servlet就是一个接口,定义了Java类被浏览器访问到(tomcat识别)的规则。

将来我们自定义一个类,实现Servlet接口,复写方法。

需要重写 dogit 方法

servlet 的方法

init 方法只执行一次

多个用户同时访问时,可能存在线程安全问题。
解决:尽量不要在Servlet中定义成员变量。即使定义了成员变量,也不要对修改值

@Override
public void init(ServletConfig servletConfig) throws ServletException {}
service 执行多次

每次访问Servlet时,Service方法都会被调用一次。

destroy 被销毁
  • servlet / 服务器正常关闭时,才会执行destroy方法。
  • destroy方法在Servlet被销毁之前执行,一般用于释放资源
@Override
public void destroy() {}
doPost
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {System.out.println(123);
}
doGet
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {System.out.println(334);
}

web.xml文件

可以在类上加注解

注解:不需要配置复杂的xml

如果只有一个属性,那么value = urlPatterns,表示路径,只有一个属性,value可以省略

@WebServlet(name = "helloServlet", value = "/资源路径")

可以写多个路径,表示多个路径都可以访问这个接口

@WebServlet(name = "helloServlet", value = {"/资源路径","/dd","dd2"})

接口源码

public @interface WebServlet {String name() default "";//相当于<Servlet-name>String[] value() default {};//代表urlPatterns()属性配置String[] urlPatterns() default {};//相当于<url-pattern>int loadOnStartup() default -1;//相当于<load-on-startup>
<servlet><!-- 表示名字 --><servlet-name>test</servlet-name><!-- 连接到哪一个java文件,中间以 . 隔开 --><servlet-class>com.tledu.gitAll_24.TestServlet</servlet-class><load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping><!-- 必须和上面名字对应 --> <servlet-name>text</servlet-name><url-pattern>/test</url-pattern>
</servlet-mapping>

IDEA 与 Tomcat 相关配置

IDEA 会为每一个 tomcat 部署的项目单独建立一份配置文件
控制台的
log:Using CATALINA_BASE:

  1. 工作空间项目 和 tomcat部署的web项目

    • tomcat真正访问的是“tomcat部署的web项目”,“tomcat部署的web项目"对应着"工作空间项目” 的web目录下的所有资源
    • WEB-INF目录下的资源不能被浏览器直接访问。
  2. 断点调试:使用"小虫子"启动 dubug 启动

HttpServlet(是 javax 包下的)

请求消息数据格式
1. 请求行
请求方式 请求url 请求协议/版本
GET /login.html HTTP/1.1

  • 请求方式:

    • HTTP协议有7中请求方式,常用的有2种
    • GET:
      1. 请求参数在请求行中,在url后。
      2. 请求的url长度有限制的
      3. 不太安全
    • POST:
      1. 请求参数在请求体中
      2. 请求的url长度没有限制的
      3. 相对安全
  1. 请求头:客户端浏览器告诉服务器一些信息
    请求头名称: 请求头值

    • 常见的请求头:

      1. User-Agent:浏览器告诉服务器,我访问你使用的浏览器版本信息

        • 可以在服务器端获取该头的信息,解决浏览器的兼容性问题
      2. Referer:http://localhost/login.html

        • 告诉服务器,我(当前请求)从哪里来?
          作用:1. 防盗链:2. 统计工作:
    1. 请求空行
      空行,就是用于分割POST请求的请求头,和请求体的。
    2. 请求体(正文):
      • 封装POST请求消息的请求参数的

Request & response

  1. request对象和response对象的原理

    1. request和response对象是由服务器创建的。我们来使用它们
    2. request对象是来获取请求消息,response对象是来设置响应消息

执行原理

  1. tomcat 服务器会根据请求的URL中的资源路径,创建对应的servlet 对象
  2. tomcat服务器,会创建request和response对象,request对象封装请求消息数据
  3. tomcat 将request 和 response 两个对象传递给service 方法,并且调用service方法
  4. 我们通过request 对象获取消息和数据,通过response对象设置响应消息和数据
  5. 服务器在给浏览器做出响应之前,会从response对象中拿程序员设置响应消息数据

request 继承 实现 体系

继承 ServletRequest
接口 HttpServletRequest
实现类 org.apache.catalina.connector.RequestFacade 类(tomcat)

request 功能

获取请求行数据

获取请求方式

// 获取请求方式
String method = request.getMethod();
System.out.println(method); // GET

获取虚拟目录

// 获取虚拟目录
String contextPath = request.getContextPath();
System.out.println(contextPath); // 我的是空,一般默认都有

获取 servlet 路径

// 获取servlet路径
String servletPath = request.getServletPath();
System.out.println(servletPath); // /pro

获取get方式请求参数(不常用)

会用 & 分割多个参数 name=zhangsan&name=lisi

// 获取get方式请求参数
String queryString = request.getQueryString();
System.out.println(queryString); // name=zhangsan&name=lisi

获取请求的URL(getRequestURL)

URI 大,URL表示当前

// 获取请求的URL
StringBuffer requestURL = request.getRequestURL();
String requestURI = request.getRequestURI();
System.out.println(requestURL); // http://localhost:8080/pro
System.out.println(requestURI); // /pro

获取协议和版本(getProtocol)

// 返回协议和版本
String protocol = request.getProtocol();
System.out.println(protocol); // HTTP/1.1

获取客户机的 ip 地址(getRemoteAddr)

// 返回客户机的 ip 地址
String remoteAddr = request.getRemoteAddr();
System.out.println(remoteAddr); // 127.0.0.1

获取请求头数据

获取所有的请求头数据(getHeaderNames)

Enumeration<String> names = request.getHeaderNames();
// hasMoreElements 迭代器,进行迭代
while (names.hasMoreElements()){// 获取当前迭代器名字String s = names.nextElement();// 根据名字获取 请求头的值String header = request.getHeader(s);//打印System.out.println(s + "---" + header);//host---localhost:8080//connection---keep-alive//cache-control---max-age=0
}

根据请求名获取数据(getHeader)

// 根据名字获取 请求头的值
// 字符串不区分大小写
String header = request.getHeader("User-Agent");
System.out.println(header);
//(Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36 Edg/107.0.1418.35

防盗链练习

// 字符串不区分大小写
String header = request.getHeader("Referer");
System.out.println(header); //
//http://localhost:8080/sk.html
if(header != null){if(header.contains("sk.html")){System.out.println("正常");}else {System.out.println("异常");}
}

获取请求体数据

请求体:只有POST请求方式,才有请求体,在请求体中封装了POST请求的请求参数

获取流对象(getReader)

这个对象也不需要关闭,因为是 servlet 的

// 获取字符流
BufferedReader reader = request.getReader();

读取数据(readLine)

// 获取请求消息体 请求参数
// 获取字符流
BufferedReader reader = request.getReader();
// 读取数据
String line;
while ((line = reader.readLine()) != null) {System.out.println(line);
}

获取请求参数通用方式

不论 get 还是 post

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

 String userName = req.getParameter("参数名称");

根据参数名称获取参数值的数组(getParameterValues)

这是 h5

<form action="pro" method="post"><input type="text" placeholder="请输入用户名:" name="username"><input type="password" placeholder="请输入密码:" name="password"><input type="checkbox" name="hobby" value="game">游戏<input type="checkbox" name="hobby" value="study">学习<input type="submit" value="注册">
</form>

案例

@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {// 获取所有的 name为 hobby 的数组String[] hobbies = request.getParameterValues("hobby");// 遍历for (String hobby : hobbies) {System.out.println(hobby); //game study}
}

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

<form action="pro" method="post"><input type="text" placeholder="请输入用户名:" name="username"><input type="password" placeholder="请输入密码:" name="password"><input type="checkbox" name="hobby" value="game">游戏<input type="checkbox" name="hobby" value="study">学习<input type="submit" value="注册">
</form>

案例

@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {// 获取所有的请求Enumeration<String> names = request.getParameterNames();while (names.hasMoreElements()){// 获取名字String name = names.nextElement();System.out.println(name);// 根据名字获取值String parameter = request.getParameter(name);System.out.println(parameter);}
}

注意:hobby 勾选了两个,也只能是一个,因为getParameter 返回的是一个,不是数组

获取所有参数封装成 map 集合

<form action="pro" method="post"><input type="text" placeholder="请输入用户名:" name="username"><input type="password" placeholder="请输入密码:" name="password"><input type="checkbox" name="hobby" value="game">游戏<input type="checkbox" name="hobby" value="study">学习<input type="submit" value="注册">
</form>

案例

@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {// 获取所有参数的map集合Map<String, String[]> parameterMap = request.getParameterMap();parameterMap.forEach((s, strings) -> {System.out.println(s);for (String nameValue : strings) {System.out.println(nameValue);//username fulicheng password dadaa hobby game study}});
}

请求转发(getRequestDispatcher)

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

request.getRequestDispatcher("/资源路径").forward(request, response);

特点:

  1. 浏览器地址栏路径不发生变化
  2. 只能转发到当前服务器内部资源中。
  3. 转发是一次请求
共享数据

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

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

存储数据(setAttribute)

// 存储数据,可以在转发中使用
request.setAttribute("随便起名字","存入数据");
// 实现跳转
request.getRequestDispatcher("/资源路径").forward(request, response);

获取数据(setAttribute)

// 存储数据,可以在转发中使用
Object msg = request.getAttribute("刚刚起的名字");

通过键名移除该键值对(removeAttribute)

request.removeAttribute("起的名字");

获取ServletContext

ServletContext servletContext = request.getServletContext();

封装数据(beanutils)

这个包下

  • 用于封装JavaBean的

    1. JavaBean:标准的Java类
      1. 要求:

      1. 类必须被public修饰
      2. 必须提供空参的构造器
      3. 成员变量必须使用private修饰
      4. 提供公共setter和getter方法
      5. 功能:封装数据
    2. 概念:
      成员变量:
      属性:setter和getter方法截取后的产物
      例如:getUsername() --> Username–> username
    3. 方法:
      1. setProperty()
      2. getProperty()
      3. populate(Object obj , Map map):将map集合的键值对信息,封装到对应的JavaBean对象中

设置属性(setProperty)

一定要有get set 方法,否则报错

User user = new User();
BeanUtils.setProperty(user,"属性名","属性值");
System.out.println(user);
//User{id = null, username = zhangsan, password = null}

获取属性值(setProperty)

一定要有get set 方法,否则报错

User user = new User(1, "user", "123456");
BeanUtils.getProperty(user, "username");
System.out.println(user);
//User{id = 1, username = user, password = 123456}

案例,封装

获取所有参数,(populate)

import org.apache.commons.beanutils.BeanUtils;
// 把所有的参数都转变成 map 集合
Map<String, String[]> map = request.getParameterMap();
// 创建user 对象 ,把结果封装成 user 对象
User loginUser = new User();
// apache 下的 bean 工具类,可以把参数转变成用户
try {BeanUtils.populate(loginUser, map);//user{username = superbaby, password = 123}
} catch (IllegalAccessException | InvocationTargetException e) {throw new RuntimeException(e);
}

乱码问题

中文乱码问题:

  • get方式:tomcat 8 已经将get方式乱码问题解决了
  • post方式:会乱码
  • 解决:在获取参数前,设置request的编码
    request.setCharacterEncoding(“utf-8”);
request.setCharacterEncoding("utf-8");

常见报错

Http 协议

  1. 请求消息:客户端发送给服务器端的数据

    • 数据格式:1. 请求行 2. 请求头 3. 请求空行 4. 请求体
  2. 响应消息:服务器端发送给客户端的数据
    • 数据格式:

      1. 响应行

        1. 组成:协议/版本 响应状态码 状态码描述
        2. 响应状态码:服务器告诉客户端浏览器本次请求和响应的一个状态。
          1. 状态码都是3位数字
          2. 分类:
            1. 1xx:服务器接收客户端消息,但没有接受完成,等待一段时间后,发送1xx多状态码
            2. 2xx:成功。代表:200
            3. 3xx:重定向。代表:302(重定向),304(访问缓存)
            4. 4xx:客户端错误。
              • 代表:

                • 404(请求路径没有对应的资源)
                • 405:请求方式没有对应的doXxx方法
            5. 5xx:服务器端错误。代表:500(服务器内部出现异常)
    1. 响应头:
      1. 格式:头名称: 值
      2. 常见的响应头:
      1. Content-Type:服务器告诉客户端本次响应体数据格式以及编码格式
      2. Content-disposition:服务器告诉客户端以什么格式打开响应体数据
      * 值:
      * in-line:默认值,在当前页面内打开
      * attachment;filename=xxx:以附件形式打开响应体。文件下载
      3. 响应空行
      4. 响应体:传输的数据

Response 功能

  • 功能:设置响应消息

    1. 设置响应行

      1. 格式:HTTP/1.1 200 ok
      2. 设置状态码:setStatus(int sc)
    2. 设置响应头:setHeader(String name, String value)
    3. 设置响应体:
      • 使用步骤:

        1. 获取输出流

          • 字符输出流:PrintWriter getWriter()
          • 字节输出流:ServletOutputStream getOutputStream()
        2. 使用输出流,将数据输出到客户端浏览器

重定向

跳转资源的方式

特点:
地址栏发生变化,可以访问其他站点的资源,是两次请求,不能使用 request 共享资源。

// 设置状态码
response.setStatus(302);
// 设置响应头
response.setHeader("location", "/资源地址");

方法简化,重定向

response.sendRedirect("/demoSer2");

相对路径

相对路径:通过相对路径不可以确定唯一资源
不以/开头,以.开头路径
规则:找到当前资源和目标资源之间的相对位置关系
. / :当前目录
… / :后退一级目录

绝对路径

建议使用动态获取虚拟目录

判断定义的路径是给谁用的?判断请求将来从哪儿发出。给客户端浏览器使用:需要加虚拟目录

转发路径不是给客户端使用的

获取字符输出流(getWriter)

// 获取字符输出流
PrintWriter writer = response.getWriter();

获取字节输出流(getOutputStream)

// 千万不要设置 UTF-8 字符编码,会乱码, 原始ie都乱码
// response.setContentType("text/html;charset=utf-8");
// 获取字节输出流
ServletOutputStream stream = response.getOutputStream();
// 输出数据 , 如果是文本要加 getBytes
stream.write("你好".getBytes());

输出流乱码问题

流的默认编码是 ISO-8859-1

修改流的编码

response.setCharacterEncoding("utf-8");

告诉浏览器用什么方式解码

response.setHeader("content-type", "text/html;charset=utf-8");

简单方式完成上面步骤

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

输出数据(println)

// 输出数据
writer.println("<h1>嗨~~~</h1>");

服务启动就初始化

<load-on-startup>1</load-on-startup>

服务器已启动就初始化这个类

<servlet><servlet-name>demo</servlet-name><servlet-class>com.example.demo.user</servlet-class><load-on-startup>1</load-on-startup>
</servlet>

修改默认启动页面

在 xml 里添加

知识点

如果没有写 post 请求方法体,那么就会 405错误
并且没有写 action 那么就会,以当前页面提交

图像

创建内存中的图片

参数:宽,高,图片形式 Rgb

BufferedImage image = new BufferedImage(100, 50, BufferedImage.TYPE_INT_BGR);

输出图片到页面上

参数:输出的图片,后缀名,输出流

// 在内存中创建图片
BufferedImage image = new BufferedImage(100, 50, BufferedImage.TYPE_INT_BGR);
// 输出到页面
ImageIO.write(image, "jpg", response.getOutputStream());

创建画笔对象(getGraphics)

// 创建图片对象
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_BGR);
// 创建画笔对象
Graphics graphics = image.getGraphics();

设置画笔颜色(setColor)

// 创建画笔对象
Graphics graphics = image.getGraphics();
// 设置画笔颜色
graphics.setColor(Color.pink);

填充图片(fillRect)

参数:x , y, 宽度,高度

// 创建画笔对象
Graphics graphics = image.getGraphics();
// 填充
graphics.fillRect(0, 0, width, height);

画边框(drawRect)

参数:x , y, 宽度,高度

// 创建画笔对象
Graphics graphics = image.getGraphics();
// 画边框
graphics.setColor(Color.blue); // 设置颜色
graphics.drawRect(0, 0, width - 1, height - 1);

往图片上输入文字(drawString)

参数:输入的文字, x, y
// 往图片上输入文字
graphics.drawString("a", 20, 25);

画线条

参数:-x 坐标, x 坐标, y 坐标, -y 坐标

// 创建画笔对象
Graphics graphics = image.getGraphics();
// 画线条
graphics.drawLine(x1, y1, x2, y2);

小知识

let number = new Date().getTime();
let byId = document.getElementById("code");
// 连接一个接口,后面是毫秒数
// 因为图片是会缓存到本地,所以需要连接毫秒数,让数字用不重复,更改浏览器内存
byId.src = "/war/xiao?"+number;

读取 json字符串

req.getReader();

获取公共域(getServletContext)

概念:代表整个web应用,可以和程序的容器(服务器)来通信

通过request对象获取

req.getServletContext();

通过HttpServlet获取

this.getServletContext();

xml 提前初始化变量

<init-param><param-name>name</param-name><param-value>张三</param-value>
</init-param>

获取

this.getServletConfig().getInitParameter("name")

注解形式,完成这个

// add 属性,1 初始化就加载, 初始化变量
@WebServlet(value = "/add",loadOnStartup = 1,initParams = {@WebInitParam(name = "name",value = "张三")
})

获取 MIME(getMimeType)

MIME类型 : 在互联网通信过程中定义的一种文件数据类型

格式: 大类型/小类型 text / html image / jpeg

// 获取整个WEB域对象
ServletContext context = this.getServletContext();
String s = "a.jpg";
// 根据文件名获取文件类型
String type = context.getMimeType(s);
System.out.println(type); //image/jpeg

共享数据,设置

ServletContext对象范围:所有用户所有请求的数据

// 最大域
ServletContext context = this.getServletContext();
// 设置属性
context.setAttribute("名称","值");

共享数据,获取

// 最大域
ServletContext context = this.getServletContext();
// 获取属性
Object msg = context.getAttribute("名称");

共享数据,移除

// 最大域
ServletContext context = this.getServletContext();
// 移除
context.removeAttribute("名称");

获取文件的真实(服务器)路径(getRealPath)

简单方式

// 获取最大域
ServletContext context = this.getServletContext();
// 获取服务器的真实路径
String path = context.getRealPath("/gran.html");
System.out.println(path);
//D:\line\apache-tomcat-9.0.50\apache-tomcat-9.0.50\demo\target\demo-1.0-SNAPSHOT\gran.html

在WEB-INF目录下

// 获取最大域
ServletContext context = this.getServletContext();
// 获取服务器的真实路径, 在 WEB-INF下
String path = context.getRealPath("/WEB-INF/c.txt");
System.out.println(path);
//D:\line\apache-tomcat-9.0.50\apache-tomcat-9.0.50\demo\target\demo-1.0-SNAPSHOT\WEB-INF\c.txt

在 src 目录下

我不会

案例实现文件下载

downloadUtils 工具类

public class DownLoadUtils {public static String getFileName(String agent, String filename) throws UnsupportedEncodingException {if (agent.contains("MSIE")) {// IE浏览器filename = URLEncoder.encode(filename, "utf-8");filename = filename.replace("+", " ");} else if (agent.contains("Firefox")) {// 火狐浏览器BASE64Encoder base64Encoder = new BASE64Encoder();filename = "=?utf-8?B?" + base64Encoder.encode(filename.getBytes("utf-8")) + "?=";} else {// 其它浏览器filename = URLEncoder.encode(filename, "utf-8");}return filename;}
}

主代码

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {// 获取传过来的参数,这里是文件名字String filename = request.getParameter("filename");// 根据名字加载到内存// 需要用到 web域ServletContext context = this.getServletContext();// 这就得到了服务器位置的真实路径String path = context.getRealPath("img/" + filename);// 根据文件名字获取文件名类型String type = context.getMimeType(filename);// 设置响应头类型response.setHeader("content-type", type);// 获取user-agent 请求头String header = request.getHeader("user-agent");// 解决中文乱码问题filename = DownLoadUtils.getFileName(header, filename);// 设置文件打开方式response.setHeader("content-disposition", "attachment;filename=" + filename);// 使用 IO 框架,将文件直接复制出去IOUtils.copy(Files.newInputStream(Paths.get(path)), response.getOutputStream());}

Jsp 页面获取其他域(pageContext)

好像是 去掉get 并且方法的首字母小写

获取 request

pageContext.request.contextPath

会话技术

功能:在一次会话中多次请求,共享数据

Cookie 客户端会话

两个客户端就是两个独立的会话

创建 Cookie 对象

// 创建 cookie 对象
Cookie cookie = new Cookie("coo", "123asd");

在响应中添加 cookie

// 创建 cookie 对象
Cookie c = new Cookie("coo", "123asd");
// 在响应中添加 cookie
response.addCookie(c);

获取cookie 数组

// 获取 cookie 数组
Cookie[] cookies = request.getCookies();
for (Cookie cookie : cookies) {// getName 获取名字String name = cookie.getName();// getValue 获取值String value = cookie.getValue();
}


第一次访问服务端,响应头里接收到数据,set-cookie:key=value
第二次访问获取cookies数组,请求头里接收到数据,cookie:key=value

细节1:可不可以发送多个cookie

可以创建多个cookie,发送多个cookie既可

细节2:cookie设置存活时间(setMaxAge)

默认情况:浏览器关闭,cookie 销毁
持久化存储:

// 创建 cookie 对象
Cookie cookie = new Cookie("coo", "123asd");
// 存活时间 10秒
cookie.setMaxAge(10);

正数:cookie 存活多少秒,持久化不会因为浏览器关闭销毁
负数,默认值,浏览器关闭,cookie 销毁
0 :删除 cookie

细节3: 在tomcat 8 之后支持存储中文

如果不支持,需要 url 编码和解码存储

细节4:共享 cookie 问题

一个服务器,部署多个Web项目,默认cookie是不能共享的

设置共享范围(setPath)

默认情况下,设置的是当前虚拟目录,如果要共享多个项目,设置为 /

// 创建 cookie 对象
Cookie cookie = new Cookie("coo", "123asd");
// 设置共享范围
cookie.setPath("/");

不同的服务器 cookie 共享范围(setDomain)

如果填写一级域名,那么可以实现多个服务器共享

// 创建 cookie 对象
Cookie cookie = new Cookie("coo", "123asd");
// 根据域名设置共享范围
cookie.setDomain(".baidu.com");

Cookie 特点和作用

  • 特点:

    • cookie 存储的数据在客户端,浏览器
    • 浏览器对 cookie 大小是 4kb
    • 同一个域名下的 cookie 最多 20 个
  • 作用
  • cookie 一般用于存储少量的不敏感数据
  • 在不登录的情况下,完成对客户端身份的识别

URL 编码(URLEncoder.encode)

// 创建当前时间
String format = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss").format(new Date());
// 使用 import java.net.URLEncoder; 对时间进行 url 编码
String encode = URLEncoder.encode(format, "utf-8");
System.out.println(encode);
// 2022%E5%B9%B411%E6%9C%8816%E6%97%A5+11%3A05%3A09

URL 解码(URLDecoder.decode)

// 使用 import java.net.URLDecoder; 对时间进行 url 解码
String decode = URLDecoder.decode(encode, "utf-8");
System.out.println(decode);
//2022年11月16日 11:08:30

Session 服务端会话

一次会话中服务端共享数据

获取 session 对象(getSession)

// 获取 session 对象
HttpSession session = request.getSession();

设置数据(setAttribute)

// 获取 session 对象
HttpSession session = request.getSession();
// 设置属性 key value
session.setAttribute("msg","hello");

获取数据(getAttribute)

// 获取 session 对象
HttpSession session = request.getSession();
// 根据 键 找值
Object msg = session.getAttribute("msg");

删除数据(removeAttribute)

// 获取 session 对象
HttpSession session = request.getSession();
// 删除数据
session.removeAttribute("msg");

session 原理

在一次会话中,多个文件获取 session 也是同一个 session

服务器如何确保在一次会话中,多次获取的 session 对象是同一个?

  • Session 是依赖于 cookie 的
  • 第一次获取 session 的时候,没有 cookie,会在内存中创建一个新的 session 对象
  • 浏览器访问服务器做响应的时候,发送响应头,set-cookie:jsessionid = 刚刚创建的session对象值
  • 客户端浏览器收到了这个set-cookie头,会存储到浏览器内部
  • 下次再访问当前项目其他资源的时候,会通过请求头 cookie 携带者 JSESSIONID,服务器会自动获取这个信息
  • 服务器根据 cookie信息 查找 内存中有没有 id 为这个的session对象
  • 所以能保证获取的session为同一个

Session的实现是依赖于Cookie的。

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

不是同一个

如果需要相同,需要手动设置 JSESSIONID

HttpSession session = request.getSession();
// 手动创建一个 cookie 名字必须是 JSESSIONID     // getid 就是 cookie 的 id
Cookie cookie = new Cookie("JSESSIONID", session.getId());
// 这个 id 只能存活 一个小时
cookie.setMaxAge(60 * 60);
response.addCookie(cookie);

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

  • 不是同一个,但是要确保数据不丢失。tomcat自动完成以下工作

    • session的钝化:
      在服务器正常关闭之前,将session对象系列化到硬盘上
    • session的活化:
      在服务器启动后,将session文件转化为内存中的session对象即可。

session什么时候被销毁? 1. 服务器关闭

调用方法销毁(invalidate)

HttpSession session = request.getSession();
session.invalidate();

session默认失效时间 30分钟

选择性配置修改
<session-config><session-timeout>30</session-timeout></session-config>

session的特点

  1. session用于存储一次会话的多次请求的数据,存在服务器端
  2. session可以存储任意类型,任意大小的数据

session与Cookie的区别:

  1. session存储数据在服务器端,Cookie在客户端
  2. session没有数据大小限制,Cookie有
  3. session数据安全,Cookie相对于不安全

jsp & el表达式 & JSTL

jsp 运行原理

  1. 服务器解析请求信息,找到 index.jsp 资源
  2. 找到之hi会讲 index.jsp转换为 . java 文件
  3. 编译 . java 文件,生成 . class 字节码文件
  4. 由字节码文件提供访问

所以说:JSP本质上就是一个Servlet

作用:用于配置JSP页面,导入资源文件

jsp 脚本

在 service 方法内写 Java 代码

<%System.out.println(1);
%>

在类中方法外写 java 代码

成员位置

<%!int i = 5;
%>

定义 java 代码输出到页面上

只能定义输出语句

<%="hello"
%>

内置对象

request
response
out
可以再 jsp 代码块 中直接使用

response 和 out 的区别

  1. 当浏览器请求 jsp 页面的时候
  2. 有 response 和 out 两个字符输出流,他们都有缓冲区
  3. 给浏览器做响应的时候,tomcat 首先会找 response
  4. 然后再找 out 缓冲区,out 永远再最后面

尽量不用 response 输出,会打乱布局

头部信息

<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
  • contentType 设置响应体的mime类型以及字符集
  • pageEncoding=“UTF-8” 低级编辑工具配置字符集

错误信息

<%@ page isErrorPage="false" errorPage="index.jsp" %>
  • isErrorPage
    为true 表示是错误页面,可以使用内置对象exception
    为 false:否。默认值。不可以使用内置对象exception
  • errorPage 如果当前页面错误了,跳转哪里

include 包含资源

<%@include file="top.jsp"%>
  • 表示把这个页面和当前页面合并在一起,生成一个class 文件

taglib 导入资源

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
  • prefix=“c” 前缀,自定义的
  • uri 资源路径

注释

jsp注释:<%-- --%>:可以注释所有,注释的 html 代码无法被路径查到

<%! %> 表示servlet 的类体
<% %> 表示 servlet( ) 的方法体
<% = %> 表示 printLn 输出

内置对象

在jsp页面中不需要创建,直接使用的对象

九大内置对象
变量名 真实类型 作用
pageContext PageContext 当前页面共享数据,还可以获取其他八个内置对象
request HttpServletRequest 一次请求访问的多个资源(转发)
session HttpSession 一次会话的多个请求间
application ServletContext 所有用户间共享数据
response HttpServletResponse 响应对象
page Object 当前页面(Servlet)的对象 this
out JspWriter 输出对象,数据输出到页面上
config ServletConfig Servlet的配置对象
exception Throwable 异常对象

MVC

  1. 优点:

    1. 耦合性低,方便维护,可以利于分工协作
    2. 重用性高
  2. 缺点:
    1. 使得项目架构变得复杂,对开发人员要求高

El 表达式

作用:替换和简化jsp页面中java代码的编写
语法:${表达式}

忽略 el 表达式

忽略当前页面

<%@ page isELIgnored="true" %>

忽略单个el表达式

\${表达式}

算术运算符

  1. 算数运算符: + - * / (div) % (mod)
  2. 比较运算符: > < >= <= == !=
  3. 逻辑运算符: &&(and) ||(or) !(not)

获取域中值

el 表达式只能从域对象中获取值

${域名称.键名}
对比 java
pageScope pageContext
requestScope request
sessionScope session
applicationScope application
${requestScope.名称}

依次从最小的域开始找键名,直到找到为止

${键名}

获取域中对象的值

这个本质上调用的是getter 和 setter 方法

${域名称.键名.属性名}
${requestScope.user.username}

获取集合值

list 集合

${域名称.键名[索引]}
${requestScope.list[0]}

Map 集合

HashMap<String, String> map = new HashMap<>();
map.put("2", "123");
map.put("gender", "bodys");
request.setAttribute("map", map);

JSP 调用

${域名称.键名.key名称} // 不适应基本数据类型
${requestScope.map.gender}
${域名称.键名["key名称"]} // 适用数字类型
${requestScope.map["2"]}

空运算符(empty)

用于判断 集合 数组 对象是否为空,或者长度为0

${empty list} // 判断是否是空
${not empty str} // 判断是否不是空

隐式对象

el 表达式有十一个隐式对象

PageContext

可以获得其他八个隐式对象,直接 点 对象就可以了

${pageContext.request.contextPath} // 动态获取虚拟目录

JSTL

作用:用于简化和替换jsp页面上的java代码

需要依赖

<dependency><groupId>javax.servlet.jsp</groupId><artifactId>jsp-api</artifactId><version>2.2.1-b03</version>
</dependency><dependency><groupId>org.glassfish.web</groupId><artifactId>jstl-impl</artifactId><version>1.2</version><scope>runtime</scope>
</dependency>

// 核心库
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
// 格式化
<%@taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
// 函数
<%@taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>

标签

<jsp:include page=“index.jsp” flush=“true”/> 动态合并,生成两个class 文件 如果flush 为 true 那么会一步步执行

c:if 判断

test 必须属性,布尔类型,为 true 执行

<c:if test="el表达式">内容
</c:if>

c:choose 选择

选择标签,根据值找对应的语句执行

  • when标签:判断
  • otherwise标签:when 都不成立,执行
<c:choose><c:when test="${number == 2}">星期二</c:when><c:otherwise>输入有误</c:otherwise>
</c:choose>

c:forEach 循环

普通 for

  • begin 开始
  • end 结束
  • var 临时变量
  • step 自增
  • varStatus 循环状态对象
<c:forEach begin="1" end="10" var="i" step="2" varStatus="s">${i}, ${s.count}
</c:forEach>

增强 for

  • items 容器对象
  • var 容器中元素的索引,从0 开始
  • varStatus 循环状态对象
    • index 索引
    • count 循环次数
<c:forEach items="${list}" var="eve" varStatus="s">${s.index} ${s.count} ${eve}
</c:forEach>

三层架构

  1. 界面层(表示层):用户看的得界面。用户可以通过界面上的组件和服务器进行交互
  2. 业务逻辑层:处理业务逻辑的。
  3. 数据访问层:操作数据存储文件。

JavaWeb(10.21)相关推荐

  1. 大数据早报:亚马逊最大风力发电站投入使用 MongoDB上市首日股价飙涨34%(10.21)

    数据早知道,上36dsj看早报! 来源36大数据,作者:奥兰多 『IBM』IBM 忘记续域名导致云服务出现问题 IBM 的负载均衡和反向 DNS 服务器上个月发生了长达 21 小时的故障,蓝色巨人一开 ...

  2. 学习日志(10.21)

    今天主要讲了脚本的使用基础 1脚本的循环语句 循环创建用户 #!/bin/sh for((i=0;i<3;i++)) douseradd $icd /home/$iecho "This ...

  3. 第一次笔记(10.21)

  4. 问题 G: 21级期末机试-谍影寻踪(10分)

    问题 G: 21级期末机试-谍影寻踪(10分) 题目描述 2020年10月,国家安全机关组织实施"迅雷-2020"专项行动,破获数百起间谍窃密事件,有效维护了国家安全和利益.在行动 ...

  5. 资金互助社业务(软件)系统在浙江第一家农村资金互助社(临海市涌泉镇忘不了农村资金互助社)试运行(2009.10.21)

    资金互助社业务(软件)系统(V1.0版)在浙江第一家农村资金互助社(临海市涌泉镇忘不了农村资金互助社)试运行(2009.10.21) 10月21日,资金互助社业务(软件)系统在浙江省临海市涌泉镇忘不了 ...

  6. 7-2 打印九九口诀表 (10 分)

    7-2 打印九九口诀表 (10 分) 下面是一个完整的下三角九九口诀表: 1*1=1 1*2=2 2*2=4 1*3=3 2*3=6 3*3=9 1*4=4 2*4=8 3*4=12 4*4=16 1 ...

  7. 7-7 斐波那契(Fibonacci)数列前20项 (10 分)

    7-7 斐波那契(Fibonacci)数列前20项 (10 分) 输出斐波那契(Fibonacci)数列(1,1,2,3,5,8,13--)的前20项 链接 输出格式: 每个数输出占8列. 输出样例: ...

  8. B题-具有自动泊车功能的电动车赛题解析TI杯2022年省级大学生电子设计竞赛联赛(10月)

    1.赛题解析-具有自动泊车功能的电动车(B题) 2.完成本赛题必备的元器件清单 3.赛题实现与动作分解视频演示 4.任务实现软件部分讲解 5.倒车/侧方入库相关的参数调节方法 6.常见问题整理 无名小 ...

  9. [html] 如何优化大数据列表(10万+)的性能?说说你的方案

    [html] 如何优化大数据列表(10万+)的性能?说说你的方案 定时器批量绘制, 过滤,查询使用serviceWorker ? 个人简介 我是歌谣,欢迎和大家一起交流前后端知识.放弃很容易, 但坚持 ...

  10. FX5U程序框架模板(10轴) 程序采用梯形图+ST语言写的 RS485通信

    FX5U程序框架模板(10轴) 程序由老工程师费尽心力的整理,把控制允许整理成简单的模板架构程序. 程序讲解 1 轴的参数初始化 2 自动启动条件 3 安全条件(台湾称许可条件,这个可以避免运动打架, ...

最新文章

  1. java 反射 动态代理
  2. “中药资源创新院士团队”诚聘结构、合成和计算生物学博士后5-10名
  3. 过期页面SEO该如何进行处理?
  4. ALV输出的时候,输出字段内容前面的空格
  5. python 游戏脚本 vbs_用VBScript制作QQ自动登录的脚本代码
  6. AI以假乱真怎么办?TequilaGAN教你轻松辨真伪
  7. 18寒假最后一测+dijistra模板
  8. 从Pycharm说起
  9. vue的this.$set的作用
  10. 混合云是趋势?阿里云与私有云厂商 ZStack合作
  11. 中小微企业公共信用数据的风险评估
  12. 修改后的RSA 加密解密 可用于制作liscence
  13. exxi6.7如何传文件到win7_win7系统被删除文件如何恢复 恢复被删除的文件操作方法【详解】...
  14. 修改表结构的执行效率
  15. WMS系统多少钱?什么是WMS系统
  16. 题5 正确的Java垃圾回收说法
  17. 阿里云企业邮箱的imap和pop3设置
  18. Winfrom控件的使用
  19. 记事本文件管理器关联文本类
  20. 修理牧场(哈夫曼树)

热门文章

  1. Compilation failed to complete
  2. 一次macbook安装iftop失败的经历及解决方式
  3. 损失函数MSE和MAE的区别以及如何选择
  4. Java file outside of source root
  5. AI 重聚知名已故歌手,发布四首原创歌曲
  6. leetcode | 回文数
  7. 51单片机程序存储器和数据存储器
  8. 第82次上Topic课(Eyewitness)
  9. 8个深度学习/计算机视觉错误,应该如何避免它们
  10. Android 开发常用性能优化工具总结