JavaWeb(10.21)
文章目录
- 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:密码,字符串形式
- url:指定连接路径
建立连接
// 建立链接
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()
- 获取执行 sql 的对象
获取执行的对象
// 连接数据库
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)
- 解决SQL注入问题:在拼接sql时,有一些sql的特殊关键字参与字符串的拼接。会造成安全性问题
- 预编译的SQL:参数使用?作为占位符
- 给?赋值:
* 方法: 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 管理事务
- 事务:一个包含多个步骤的业务操作。如果这个业务操作被事务管理,则这多个步骤要么同时成功,要么同时失败。
- 操作:
- 开启事务
- 提交事务
- 回滚事务
- 使用Connection对象来管理事务
- 开启事务:setAutoCommit(boolean autoCommit) :调用该方法设置参数为false,即开启事务
- 在执行sql之前开启事务
- 提交事务:commit()
- 当所有sql都执行完提交事务
- 回滚事务:rollback()
- 在catch中回滚事务
- 开启事务:setAutoCommit(boolean autoCommit) :调用该方法设置参数为false,即开启事务
开启事务
//开启事务
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 数据库连接池
概念:创建一个存放数据库连接的容器。
- 当系统初始化好后,容器被创建,容器中会申请一些连接对象,当用户来访问数据库时,从容器中获取连接对象,用户访问完之后,会将连接对象归还给容器。
好处:
- 节约资源
- 用户访问高效
实现:
标准接口:DataSource javax.sql包下的
- 方法:
- 获取连接:getConnection()
- 归还连接:Connection.close()。如果连接对象Connection是从连接池中获取的,那么调用Connection.close()方法,则不会再关闭连接了。而是归还连接
- 方法:
一般我们不去实现它,有数据库厂商来实现
- C3P0:数据库连接池技术
- Druid:数据库连接池实现技术,由阿里巴巴提供的
C3P0:数据库连接池技术
- 步骤:
导入jar包 (两个) c3p0-0.9.5.2.jar mchange-commons-java-0.2.12.jar
- 不要忘记导入数据库驱动jar包
定义配置文件:
- 名称: c3p0.properties 或者 c3p0-config.xml
- 路径:直接将文件放在src目录下即可。
创建核心对象 数据库连接池对象 ComboPooledDataSource
获取连接: 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. 导入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的开发
- 步骤:
- 导入jar包
- 创建JdbcTemplate对象。依赖于数据源 DataSource(数据库连接池)
- JdbcTemplate template = new JdbcTemplate(ds);
- 调用JdbcTemplate的方法来完成CRUD的操作
- update():执行DML语句。增、删、改语句
- queryForMap():查询结果将结果集封装为map集合,将列名作为key,将值作为value 将这条记录封装为一个map集合
- 注意:这个方法查询的结果集长度只能是1
- queryForList():查询结果将结果集封装为list集合
- 注意:将每一条记录封装为一个Map集合,再将Map集合装载到List集合中
- query():查询结果,将结果封装为JavaBean对象
- query的参数:RowMapper
- 一般我们使用BeanPropertyRowMapper实现类。可以完成数据到JavaBean的自动封装
- new BeanPropertyRowMapper<类型>(类型.class)
- query的参数:RowMapper
- 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请求的区别
- GET请求请求参数在请求行中,没有请求体。
POST请求请求参数在请求体中 - 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
- 软件架构
- C/S:客户端/服务器端
- B/S:浏览器/服务器端
- 资源分类
- 静态资源:每个人访问都是一样的页面,称为静态资源,可以直接被浏览器解析
- 如: html,css,JavaScript
- 动态资源:每个人访问页面可能不同,称为动态资源。动态资源需要先转换为静态资源,在返回给浏览器
- 如:servlet/jsp,php,asp…
- 静态资源:每个人访问都是一样的页面,称为静态资源,可以直接被浏览器解析
- 网络通信三要素
- IP:电子设备(计算机)在网络中的唯一标识。
- 端口:应用程序在计算机中的唯一标识。 0~65536
- 传输协议:规定了数据传输的规则
- 基础协议:
- tcp:安全协议,三次握手。 速度稍慢
- 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
重写其中的方法
- 执行原理:
- 服务器接受到客户端的请求后,会解析请求URL路径,获取访问的Servlet的资源路径
- 查找web.xml文件,是否有对应的标签体内容。
- 如果有,则在找到对应的全类名
- tomcat会将字节码文件加载进内存,并且创建其对象
- 调用其方法
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:
- 工作空间项目 和 tomcat部署的web项目
- tomcat真正访问的是“tomcat部署的web项目”,“tomcat部署的web项目"对应着"工作空间项目” 的web目录下的所有资源
- WEB-INF目录下的资源不能被浏览器直接访问。
- 断点调试:使用"小虫子"启动 dubug 启动
HttpServlet(是 javax 包下的)
请求消息数据格式
1. 请求行
请求方式 请求url 请求协议/版本
GET /login.html HTTP/1.1
- 请求方式:
- HTTP协议有7中请求方式,常用的有2种
- GET:
- 请求参数在请求行中,在url后。
- 请求的url长度有限制的
- 不太安全
- POST:
- 请求参数在请求体中
- 请求的url长度没有限制的
- 相对安全
- 请求头:客户端浏览器告诉服务器一些信息
请求头名称: 请求头值- 常见的请求头:
User-Agent:浏览器告诉服务器,我访问你使用的浏览器版本信息
- 可以在服务器端获取该头的信息,解决浏览器的兼容性问题
Referer:http://localhost/login.html
- 告诉服务器,我(当前请求)从哪里来?
作用:1. 防盗链:2. 统计工作:
- 告诉服务器,我(当前请求)从哪里来?
- 请求空行
空行,就是用于分割POST请求的请求头,和请求体的。 - 请求体(正文):
- 封装POST请求消息的请求参数的
- 常见的请求头:
Request & response
- request对象和response对象的原理
- request和response对象是由服务器创建的。我们来使用它们
- request对象是来获取请求消息,response对象是来设置响应消息
执行原理
- tomcat 服务器会根据请求的URL中的资源路径,创建对应的servlet 对象
- tomcat服务器,会创建request和response对象,request对象封装请求消息数据
- tomcat 将request 和 response 两个对象传递给service 方法,并且调用service方法
- 我们通过request 对象获取消息和数据,通过response对象设置响应消息和数据
- 服务器在给浏览器做出响应之前,会从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);
特点:
- 浏览器地址栏路径不发生变化
- 只能转发到当前服务器内部资源中。
- 转发是一次请求
共享数据
域对象:一个有作用范围的对象,可以在范围内共享数据
request域:代表一次请求的范围,一般用于请求转发的多个资源中共享数据
存储数据(setAttribute)
// 存储数据,可以在转发中使用
request.setAttribute("随便起名字","存入数据");
// 实现跳转
request.getRequestDispatcher("/资源路径").forward(request, response);
获取数据(setAttribute)
// 存储数据,可以在转发中使用
Object msg = request.getAttribute("刚刚起的名字");
通过键名移除该键值对(removeAttribute)
request.removeAttribute("起的名字");
获取ServletContext
ServletContext servletContext = request.getServletContext();
封装数据(beanutils)
这个包下
- 用于封装JavaBean的
- JavaBean:标准的Java类
1. 要求:- 类必须被public修饰
- 必须提供空参的构造器
- 成员变量必须使用private修饰
- 提供公共setter和getter方法
- 功能:封装数据
- 概念:
成员变量:
属性:setter和getter方法截取后的产物
例如:getUsername() --> Username–> username - 方法:
- setProperty()
- getProperty()
- populate(Object obj , Map map):将map集合的键值对信息,封装到对应的JavaBean对象中
- JavaBean:标准的Java类
设置属性(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. 请求行 2. 请求头 3. 请求空行 4. 请求体
- 响应消息:服务器端发送给客户端的数据
- 数据格式:
- 响应行
- 组成:协议/版本 响应状态码 状态码描述
- 响应状态码:服务器告诉客户端浏览器本次请求和响应的一个状态。
- 状态码都是3位数字
- 分类:
- 1xx:服务器接收客户端消息,但没有接受完成,等待一段时间后,发送1xx多状态码
- 2xx:成功。代表:200
- 3xx:重定向。代表:302(重定向),304(访问缓存)
- 4xx:客户端错误。
- 代表:
- 404(请求路径没有对应的资源)
- 405:请求方式没有对应的doXxx方法
- 代表:
- 5xx:服务器端错误。代表:500(服务器内部出现异常)
- 响应行
- 响应头:
1. 格式:头名称: 值
2. 常见的响应头:
1. Content-Type:服务器告诉客户端本次响应体数据格式以及编码格式
2. Content-disposition:服务器告诉客户端以什么格式打开响应体数据
* 值:
* in-line:默认值,在当前页面内打开
* attachment;filename=xxx:以附件形式打开响应体。文件下载
3. 响应空行
4. 响应体:传输的数据
- 数据格式:
Response 功能
- 功能:设置响应消息
- 设置响应行
- 格式:HTTP/1.1 200 ok
- 设置状态码:setStatus(int sc)
- 设置响应头:setHeader(String name, String value)
- 设置响应体:
- 使用步骤:
- 获取输出流
- 字符输出流:PrintWriter getWriter()
- 字节输出流:ServletOutputStream getOutputStream()
- 使用输出流,将数据输出到客户端浏览器
- 获取输出流
- 使用步骤:
- 设置响应行
重定向
跳转资源的方式
特点:
地址栏发生变化,可以访问其他站点的资源,是两次请求,不能使用 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的钝化:
session什么时候被销毁? 1. 服务器关闭
调用方法销毁(invalidate)
HttpSession session = request.getSession();
session.invalidate();
session默认失效时间 30分钟
选择性配置修改
<session-config><session-timeout>30</session-timeout></session-config>
session的特点
- session用于存储一次会话的多次请求的数据,存在服务器端
- session可以存储任意类型,任意大小的数据
session与Cookie的区别:
- session存储数据在服务器端,Cookie在客户端
- session没有数据大小限制,Cookie有
- session数据安全,Cookie相对于不安全
jsp & el表达式 & JSTL
jsp 运行原理
- 服务器解析请求信息,找到 index.jsp 资源
- 找到之hi会讲 index.jsp转换为 . java 文件
- 编译 . java 文件,生成 . class 字节码文件
- 由字节码文件提供访问
所以说:JSP本质上就是一个Servlet
作用:用于配置JSP页面,导入资源文件
jsp 脚本
在 service 方法内写 Java 代码
<%System.out.println(1);
%>
在类中方法外写 java 代码
成员位置
<%!int i = 5;
%>
定义 java 代码输出到页面上
只能定义输出语句
<%="hello"
%>
内置对象
request
response
out
可以再 jsp 代码块 中直接使用
response 和 out 的区别
- 当浏览器请求 jsp 页面的时候
- 有 response 和 out 两个字符输出流,他们都有缓冲区
- 给浏览器做响应的时候,tomcat 首先会找 response
- 然后再找 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
- 优点:
- 耦合性低,方便维护,可以利于分工协作
- 重用性高
- 缺点:
- 使得项目架构变得复杂,对开发人员要求高
El 表达式
作用:替换和简化jsp页面中java代码的编写
语法:${表达式}
忽略 el 表达式
忽略当前页面
<%@ page isELIgnored="true" %>
忽略单个el表达式
\${表达式}
算术运算符
- 算数运算符: + - * / (div) % (mod)
- 比较运算符: > < >= <= == !=
- 逻辑运算符: &&(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>
三层架构
- 界面层(表示层):用户看的得界面。用户可以通过界面上的组件和服务器进行交互
- 业务逻辑层:处理业务逻辑的。
- 数据访问层:操作数据存储文件。
JavaWeb(10.21)相关推荐
- 大数据早报:亚马逊最大风力发电站投入使用 MongoDB上市首日股价飙涨34%(10.21)
数据早知道,上36dsj看早报! 来源36大数据,作者:奥兰多 『IBM』IBM 忘记续域名导致云服务出现问题 IBM 的负载均衡和反向 DNS 服务器上个月发生了长达 21 小时的故障,蓝色巨人一开 ...
- 学习日志(10.21)
今天主要讲了脚本的使用基础 1脚本的循环语句 循环创建用户 #!/bin/sh for((i=0;i<3;i++)) douseradd $icd /home/$iecho "This ...
- 第一次笔记(10.21)
- 问题 G: 21级期末机试-谍影寻踪(10分)
问题 G: 21级期末机试-谍影寻踪(10分) 题目描述 2020年10月,国家安全机关组织实施"迅雷-2020"专项行动,破获数百起间谍窃密事件,有效维护了国家安全和利益.在行动 ...
- 资金互助社业务(软件)系统在浙江第一家农村资金互助社(临海市涌泉镇忘不了农村资金互助社)试运行(2009.10.21)
资金互助社业务(软件)系统(V1.0版)在浙江第一家农村资金互助社(临海市涌泉镇忘不了农村资金互助社)试运行(2009.10.21) 10月21日,资金互助社业务(软件)系统在浙江省临海市涌泉镇忘不了 ...
- 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 斐波那契(Fibonacci)数列前20项 (10 分)
7-7 斐波那契(Fibonacci)数列前20项 (10 分) 输出斐波那契(Fibonacci)数列(1,1,2,3,5,8,13--)的前20项 链接 输出格式: 每个数输出占8列. 输出样例: ...
- B题-具有自动泊车功能的电动车赛题解析TI杯2022年省级大学生电子设计竞赛联赛(10月)
1.赛题解析-具有自动泊车功能的电动车(B题) 2.完成本赛题必备的元器件清单 3.赛题实现与动作分解视频演示 4.任务实现软件部分讲解 5.倒车/侧方入库相关的参数调节方法 6.常见问题整理 无名小 ...
- [html] 如何优化大数据列表(10万+)的性能?说说你的方案
[html] 如何优化大数据列表(10万+)的性能?说说你的方案 定时器批量绘制, 过滤,查询使用serviceWorker ? 个人简介 我是歌谣,欢迎和大家一起交流前后端知识.放弃很容易, 但坚持 ...
- FX5U程序框架模板(10轴) 程序采用梯形图+ST语言写的 RS485通信
FX5U程序框架模板(10轴) 程序由老工程师费尽心力的整理,把控制允许整理成简单的模板架构程序. 程序讲解 1 轴的参数初始化 2 自动启动条件 3 安全条件(台湾称许可条件,这个可以避免运动打架, ...
最新文章
- java 反射 动态代理
- “中药资源创新院士团队”诚聘结构、合成和计算生物学博士后5-10名
- 过期页面SEO该如何进行处理?
- ALV输出的时候,输出字段内容前面的空格
- python 游戏脚本 vbs_用VBScript制作QQ自动登录的脚本代码
- AI以假乱真怎么办?TequilaGAN教你轻松辨真伪
- 18寒假最后一测+dijistra模板
- 从Pycharm说起
- vue的this.$set的作用
- 混合云是趋势?阿里云与私有云厂商 ZStack合作
- 中小微企业公共信用数据的风险评估
- 修改后的RSA 加密解密 可用于制作liscence
- exxi6.7如何传文件到win7_win7系统被删除文件如何恢复 恢复被删除的文件操作方法【详解】...
- 修改表结构的执行效率
- WMS系统多少钱?什么是WMS系统
- 题5 正确的Java垃圾回收说法
- 阿里云企业邮箱的imap和pop3设置
- Winfrom控件的使用
- 记事本文件管理器关联文本类
- 修理牧场(哈夫曼树)