JDBC
JDBC简介
JDBC 指 Java 数据库连接,是一种标准Java应用编程接口( JAVA API),用来连接 Java 编程语言和广泛的数据库
JDBC快速入门
基本模板:
public class JDBCDemo {
public static void main(String[] args) throws SQLException {
String DRIVER ="com.mysql.cj.jdbc.Driver";
String URL = "jdbc:mysql://127.0.0.1:3306/myemployees";
String USER = "root";
String PWD = "xxxxx";
// 1.注册驱动
Class.forName(DRIVER); //forname一般会报错,需要自己抛异常
// 2.获取连接对象
Connection connection = DriverManager.getConnection(URL,USER,PWD);
// 3.定义sql
String sql = "sql语句"
// 4.获取执行sql对象(操作数据库的工具)
Statement statement = connection.createStatement();
// 5.执行sql
ResultSet rs = statement.executeQuery(sql); // 这里为执行查询语句,还可以使用executeUpdate
// 6.处理返回结果
...
// 7.释放资源
rs.close();
statement.close();
connection.close();
}
}
简单示例:
查询
String sql="select cust_id from orders";//只用于查询
ResultSet rs = statement.executeQuery(sql);//把字符串传给数据库执行 只用于查询
while (rs.next()) {
System.out.println(rs.getString(1));
}
增加
String sql="insert into orders (order_num) values (498)";
int n = statement.executeUpdate(sql);//返回数据变化条数,只用于增删改
// System.out.println(n);
删除
String sql = "delete from productnotes where prod_id='SAFE'";
int n = statement.executeUpdate(sql);
// System.out.println(n);
修改
String sql="update orders set order_date='2022-01-02' where cust_id='10001' ";
int n = statement.executeUpdate(sql);
// System.out.println(n);
JDBC API详解
DriverManager
DriverManager(驱动管理类)作用:
- 注册驱动
- 获取数据库连接
url语法:"jdbc:mysql://ip地址(域名):端口号/数据库名称?参数键值对1&参数键值对2..."
注意:如果连接的是本机mysql并且端口是默认的,3306可以简写jdbc:mysql:///xxxx
Connection
Connection(数据库连接对象)作用:
- 获取执行SQL的对象
- 管理事务
Resultset
next()----光标向下一行移动并判断当前是否有数据
将查询到的数据封装到java对象中,然后存储到ArrayList集合
也可以用vector 如下:
Vector<Vector<String>> vectorData = new Vector<>();
//...中间常规步骤省略
while (rs.next()) {
Vector<String> vector = new Vector<>();
vector.add(String.valueOf(rs.getInt(1)));
vector.add(rs.getString(2));
vector.add(rs.getString(3));
vector.add(rs.getString(4));
vector.add(rs.getString(5));
vector.add(rs.getString(6));
vectorData.add(vector);
}
System.out.println(vectorData);
Statement
Preparedstatement,预编译sql语句并执行,预防sql注入问题 PreparedStatement ps = connection.prepareStatement(sql)
sql注入是通过操作输入来修改事先定义好的sql语句,用以达到执行代码对服务器进行攻击的方法
执行存储过程的对象 CallableStatement cs = connection.prepareCall(sql)
典型例子:
public static void main(String[] args) throws SQLException {
Scanner scanner = new Scanner(System.in);
String user_name = scanner.nextLine();
String user_pwd = scanner.nextLine(); //从键盘输入名字和密码
Connection c = null; //初始化连接对象
String DRIVER ="com.mysql.cj.jdbc.Driver";
String URL = "jdbc:mysql://127.0.0.1:3306/myemployees";
String USER = "root";
String PWD = "xxxxx";
try {
Class.forName(DRIVER);
c = DriverManager.getConnection(URL,USER,PWD);
String sql = "select first_name,employee_id from student where first_name = ? and employee_id = ?";
PreparedStatement ps = c.prepareStatement(sql);
ps.setObject(1, user_name);
ps.setObject(2, user_pwd);
ResultSet rs = ps.executeQuery(); //sql语句已经预编译,不需要再执行一次
if (rs.next()) {
System.out.println("login in...");
} else {
System.out.println("wrong!");
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
c.close();
}
}
pojo文件夹: 存放实体类和简单的java对象
Druid使用
Druid是数据库连接池的一个第三方插件,使用步骤:
- 导入jar包 druid-1.1.12jar
- 定义配置文件
- 加载配置文件
- 获取数据库连接池对象
- 获取连接
public class DruidDemo {
public static void main(String[] args) throws Exception {
// 3.加载配置文件
Properties properties = new Properties();
properties.load(new FileInputStream("src/druid.properties"));
// 4.获取连接池对象
DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);
// 5.获取数据库连接Connection
Connection connection = dataSource.getConnection();
System.out.println(connection);
}
}
后期可以直接把url,root,username等信息直接配置到druid.properties
里
driverClassName = com.mysql.cj.jdbc.Driver
url = jdbc:mysql://127.0.0.1:3306/数据库名?useSSL=false&useServerPrepStmts=true
username=root
password=xxxxxxx
initialSize=5
maxActive=10
maxWait=3000
相关参数含义可以在官方文档查看
MyBatis
MyBatis是一款优秀的持久层框架,用于简化JDBC
Mybatis快速入门
使用步骤:
- 定义POJO类
- 加载核心配置文件,获取SqlSessionFactory对象
- 获取SqlSession对象,执行SQL语句
- 释放资源
Mybatis基本配置
配置依赖
<dependencies>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.9</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.2.11</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.11</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.32</version>
</dependency>
</dependencies>
xxxMapper.xml配置
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="xxxx"> <!--相当于一个包名-->
<select id="getUser" parameterType="int" resultType="com.hut.pojo.User">
SELECT * FROM locations WHERE location_id>1500
</select>
</mapper>
mybatis-config.xml配置
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<!-- 数据库连接信息-->
<property name="driver" value="com.mysql.cj.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/数据库名xxx?useSSL=false" />
<property name="username" value="root" />
<property name="password" value="xxxxxx" />
</dataSource>
</environment>
</environments>
<mappers>
<!-- 加载sql映射文件-->
<mapper resource="xxxMapper.xml" />
</mappers>
</configuration>
mybatis简单示例
public class Mybatis_Demo {
public static void main(String[] args) throws IOException {
// 1.加载mybatis的核心配置文件,获取sqlSessionFactory(固定的三条语句)
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 2.获取sqlSession对象(也是固定语句)
SqlSession sqlSession = sqlSessionFactory.openSession();
// 3.执行sql(路径取自mapper映射文件的“包名”+id)
List<User> users = sqlSession.selectList("test.getUser");
System.out.println(users);
// 4.关闭资源
sqlSession.close();
}
}
Mapper代理开发
- 定义与SQL映射文件同名的Mapper接口,并且将Mapper接口和SQL映射文件放置在同一目录下
- 设置SQL映射文件的namespace属性为Mapper接口全限定名
- 在Mapper接口中定义方法,方法名就是SQL映射文件中sql语句的id,并保持参数类型和返回值
类型一致 - 编码
通过SqlSession的getMapper方法获取Mapper接口的代理对象
mapper.xml修改
<mapper namespace="com.hut.mapper.UserMapper">
<select id="getUser" parameterType="int" resultType="com.hut.pojo.User">
SELECT * FROM locations WHERE location_id>1500
</select>
</mapper>
mapper接口
public interface UserMapper {
List<User> getUser();
}
getUser为mapper.xml配置的id名
sql执行修改
List<User> users = sqlSession.selectList("test.getUser");//执行sql
改为:
// 获取UserMapper接口的代理对象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
List<User> users = userMapper.getUser();
mybatis-config配置修改
加载sql映射文件 mapper代理—修改resource的路径
<mapper resource="com/hut/mapper/UserMapper.xml" />
起别名,简化mapper中resultType:从"com.hut.pojo.User"----->"user"或"User"不区分大小写
<typeAliases>
<package name="com.hut.pojo"/>
</typeAliases>
MyBatisX
增删改查步骤:
- 编写接口方法:Mapper接口
- 编写SQL语句:SQL映射文件
- 执行方法,测试
查询
查询操作
带参查询
参数占位符:
${}
:拼sql,会存在SQL注入问题。#{}
:会将其替换成?,防止SQL注入- 使用时机:
*参数传递时候:#{}
*表明或者类名不固定的情况下:${}
sql栗子:SELECT * FROM Jobs WHERE Job_id = #{id}
特殊字符处理:
比如sql语句中如果直接放<小于号,会被当做开始标签
解决方法:
- 转义字符 <
- CDATA区:
<![CDATA[ 特殊字符 ]]]>
条件查询
接口参数定义:
// *参数接收
// 1.散装参数:如果方法中有多个参数,需要使用@Param("SQL参数占位符名称")
// 2.对象参数:需要保证sql中参数名和实体类属性名对应
// 3.map集合参数:需要保证sql中的参数名和map集合的键的名称对应
// List<Job> selectByCondition(@Param("min_salary") int min_salary,@Param("job_title") String job_title,@Param("max_salary") int max_salary);
// List<Job> selectByCondition(Job job);
// List<Job> selectByCondition(Map map);
sql语句定义:
<select id="selectByCondition" resultType="Job">
SELECT * FROM Jobs
WHERE min_salary = #{min_salary}
and job_title like #{job_title}
and max_salary like #{max_salary}
</select>
测试类:
public void testSelectByCondition() throws IOException {
int minSalary = 4000;
int maxSalary = 9000;
String jobTitle = "R";
jobTitle = "%" + jobTitle + "%";
// Job job = new Job();
// job.setMin_salary(minSalary);
// job.setJob_title(jobTitle);
// job.setMax_salary(maxSalary);
Map map = new HashMap();
map.put("min_salary",minSalary);
map.put("job_title",jobTitle);
map.put("max_salary",maxSalary);
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
JobMapper jobMapper = sqlSession.getMapper(JobMapper.class);
// List<Job> jobs = jobMapper.selectByCondition(minSalary,jobTitle,maxSalary);
// List<Job> jobs = jobMapper.selectByCondition(job);
List<Job> jobs = jobMapper.selectByCondition(map);
System.out.println(jobs);
sqlSession.close();
}
动态条件查询
单条语句查询:
<select id="selectByCondition" resultType="Job">
SELECT * FROM Jobs
<where>
<choose>
<when test="min_salary != null">
min_salary = #{min_salary}
</when>
<when test="job_text != null and job_text != ''">
job_title like #{job_title}
</when>
<when test="max_salary != null">
max_salary like #{max_salary}
</when>
</choose>
</where>
</select>
动态语句查询:1.恒等式 2.where
<select id="selectByCondition" resultType="Job">
SELECT * FROM Jobs
<where>
<if test="min_salary != null">
and min_salary = #{min_salary}
</if>
<if test="job_text != null and job_text != ''">
and job_title like #{job_title}
</if>
<if test="max_salary != null">
and max_salary like #{max_salary}
</if>
</where>
</select>
增删改
要记得提交事务才会更改成功数据库内容sqlSession.commit();
删除多个记录:
int deleteByIds(@Param("job_ids") String[] job_ids);
Param定义map的key值,用来代替collection中的array
<delete id="deleteByIds">
delete from jobs where job_id in
<foreach collection="job_ids" item="job_id" separator="," open="(" close=")">#{job_id}</foreach>
</delete>
Mybatis参数传递
单个参数:
- POJO类型:直接使用,属性名 和 参数占位符名称一致
- Map集合:直接使用 键名 和 参数占位符名称一致
- Collection: 封装为Map集合
- List: 封装为Map集合
- Array: 封装为Map集合
- 其他类型: 直接使用
多个参数:封装为map集合,可以使用@Param注解,替换Map结合中默认的arg键名
map.put("arg0",参数值1)
map.put("param1",参数值1)
map.put("param2",参数值2)
map.out("arg1",参数值2)
@Param注解:@Param("min_salary") int min_salary
注解开发
在定义接口的时候就注解写sql语句,不需要再在xml映射 但是只适用于简单的sql语句
SqlSessionFactory工具类抽取
问题出现:
- 重复代码不利于后期的维护
- SqlSessionFactory工厂类进行重复创建
- 就相当于每次买手机都需要重新创建一个手机生产工厂来给你制造一个手机一样,资源消耗非常大但性能却非常低。所以这么做是不允许的。
优化方法:
- 代码重复可以抽取工具类
- 对指定代码只需要执行一次可以使用静态代码块
public class SqlSessionFactoryUtils {
private static SqlSessionFactory sqlSessionFactory;
static {
//静态代码块会随着类的加载而自动执行,且只执行一次
try {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
public static SqlSessionFactory getSqlSessionFactory(){
return sqlSessionFactory;
}
}
工具类抽取以后,以后在对Mybatis的SqlSession进行操作的时候,就可以直接使用
SqlSessionFactory sqlSessionFactory =SqlSessionFactoryUtils.getSqlSessionFactory();
Servlet
urlPattern配置
- 精确匹配:
@WebServlet("user/select")
- 目录匹配:
@WebServlet("/user/*")
- 扩展名匹配:
@WebServlet("*.do")
servlet作用域
servlet三大作用域:request,session,application
Application(ServletContext)
作用范围:所有的用户都可以取得此信息,此信息在整个服务器上被保留。Application属性范围值,只要设置一次,则所有的网页窗口都可以取得数据。ServletContext在服务器启动时创建,在服务器关闭时销毁,一个JavaWeb应用只创建一个ServletContext对象,所有的客户端在访问服务器时都共享同一个ServletContext对象;ServletContext对象一般用于在多个客户端间共享数据时使用;
获取Application对象方法(Servlet中):
ServletContext app01 = this.getServletContext();
app01.setAttribute("name", "kaixuan"); //设置一个值进去
ServletContext app02 = this.getServletContext();
app02.getAttribute("name"); //获取键值对
备注:服务器只会创建一个ServletContext 对象,所以app01就是app02,通过app01设置的值当然可以通过app02获取。
ServletContext同属于JSP九大内置对象之一,故可以直接使用
servlet跳转
- 转发:
request.getRequestDispatcher("main.jsp").forward(request , response);
- 重定向:
response.sendRedirect("index.jsp");
需要加上虚拟路径
两者区别:
- 重定向时 浏览器上的网址改变(地址栏改变)
转发 浏览器上的网址不变 - 重定向实际上产生了两次请求
转发只有一次请求 - 重定向可以跨服务器
转发不能
- 转发的速度更快,能用转发的就不用重定向
- 动态获取虚拟路径:
String contextPath = request.getContextPath();
response.sendRedirect(contextPath+"/xxx");
request
request请求
- 请求行
- getMethod()获取请求方式
- getContextPath()获取项目访问路径
- getRequestURL()获取请求URL
- getRequestURI()获取请求URI
- getQueryString()获取GET请求方式的请求参数
- 请求头
- getHeader(String name)根据请求头名称获取其对应的值
- 请求体
- 注意: 浏览器发送的POST请求才有请求体
- 如果是纯文本数据:getReader()
- 如果是字节数据如文件数据:getInputStream()
request获得请求体数据
字节流(inputstream,outputstream)和字符流(reader,writer)的区别:
字节流操作的基本单元为字节;字符流操作的基本单元为Unicode码元。
字节流默认不使用缓冲区;字符流使用缓冲区。
字节流通常用于处理二进制数据,实际上它可以处理任意类型的数据,但它不支持直接写入或读取Unicode码元;字符流通常处理文本数据,它支持写入及读取Unicode码元。
对于请求体中的数据,Request对象提供了如下两种方式来获取其中的数据,分别是:
- 获取字节输入流,如果前端发送的是字节数据,比如传递的是文件数据,则使用该方法
ServletInputStream getInputStream()
该方法可以获取字节
- 获取字符输入流,如果前端发送的是纯文本数据,则使用该方法
BufferedReader getReader()
中文乱码问题
中文乱码解决方案
-
POST请求和GET请求的参数中如果有中文,后台接收数据就会出现中文乱码问题
GET请求在Tomcat8.0以后的版本就不会出现了
-
POST请求解决方案是:设置输入流的编码
request.setCharacterEncoding("UTF-8");
注意:设置的字符集要和页面保持一致
- 通用方式(GET/POST):需要先解码,再编码
new String(username.getBytes("ISO-8859-1"),"UTF-8");
- URL编码实现方式:
- 编码:
URLEncoder.encode(str,"UTF-8");
- 解码:
URLDecoder.decode(s,"ISO-8859-1");
request存储数据
使用request对象提供的三个方法:
-
存储数据到request域[范围,数据是存储在request对象]中
void setAttribute(String name,Object o);
-
根据key获取值
-
Object getAttribute(String name);
-
根据key删除该键值对
void removeAttribute(String name);
response
Response响应字符数据
-
通过Response对象获取字符输出流:
PrintWriter writer = resp.getWriter();
-
通过字符输出流写数据:
writer.write("aaa");
-
如果字符串里面是html代码
writer.write("<h1>aaa</h1>");
,需要加上一句话response.setHeader("content-type","text/html");
,content-type,告诉浏览器返回的数据类型是HTML类型数据,这样浏览器才会解析HTML标签 -
解决字符输出流的乱码问题:
resp.setContentType("text/html;charset='utf-8'");
此时也可以默认解析html代码
Response响应字节数据
-
读取文件:
FileInputStream fis = new FileInputStream("d://a.jpg");
-
通过Response对象获取字节输出流:
ServletOutputStream outputStream = resp.getOutputStream();
-
通过字节输出流写数据:
outputStream.write(字节数据);
byte[] buff = new byte[1024];
int len = 0;
while ((len = fis.read(buff))!= -1){
os.write(buff,0,len);
}
上述代码中,对于流的copy的代码还是比较复杂的,所以我们可以使用别人提供好的方法来简化代码的开发,具体的步骤是:
(1)pom.xml添加依赖
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
(2)调用工具类方法
IOUtils.copy(fis,os);
jsp
jsp本质上就是一个servlet
JSP 脚本
JSP脚本用于在 JSP页面内定义 Java代码。
JSP 脚本有如下三个分类:
- <%…%>:内容会直接放到_jspService()方法之中
- <%=…%>:内容会放到out.print()中,作为out.print()的参数,展示在jsp页面中
- <%!…%>:内容会放到_jspService()方法之外,被类直接包含
EL表达式
表达式语言,用于简化 JSP 页面内的 Java 代码。
EL 表达式的主要作用是 获取数据。其实就是从域对象中获取数据,然后将数据展示在页面上。
而 EL 表达式的语法也比较简单,== e x p r e s s i o n = = 。 例 如 : {expression}== 。例如: expression==。例如:{brands} 就是获取域中存储的 key 为 brands 的数据。
javaweb的四大域对象:范围由上到下逐渐增大
- page:当前页面有效
- request:当前请求有效
- session:当前会话有效
- application:当前应用有效
el会一次从这4个域中寻找,直到找到为止
JSTL标签
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@page isELIgnored="false"%>
foreach的两种用法:
<c:forEach items="${brands}" var="brand" varStatus="status">
-
items:被遍历的容器
-
var:遍历产生的临时变量
-
varStatus:遍历状态对象
<c:forEach begin="0" end="10" step="1" var="i">
-
begin:开始数
-
end:结束数
-
step:步长
举个栗子:从0循环到10,变量名是 i
,每次自增1
<c:forEach begin="0" end="10" step="1" var="i">
${i}
</c:forEach>
MVC和三层架构
MVC模式
MVC 是一种分层开发的模式,其中:
-
M:Model,业务模型,处理业务
-
V:View,视图,界面展示
-
C:Controller,控制器,处理请求,调用模型和视图
控制器(serlvlet)用来接收浏览器发送过来的请求,控制器调用模型(JavaBean)来获取数据,比如从数据库查询数据;控制器获取到数据后再交由视图(JSP)进行数据展示。
三层架构
三层架构是将我们的项目分成了三个层面,分别是 表现层
、业务逻辑层
、数据访问层
。
- 数据访问层:对数据库的CRUD基本操作
- 业务逻辑层:对业务逻辑进行封装,组合数据访问层层中基本功能,形成复杂的业务逻辑功能。例如
注册业务功能
,我们会先调用数据访问层
的selectByName()
方法判断该用户名是否存在,如果不存在再调用数据访问层
的insert()
方法进行数据的添加操作 - 表现层:接收请求,封装数据,调用业务逻辑层,响应数据
区别与联系
MVC 模式
中的 C(控制器)和 V(视图)就是 三层架构
中的表现层,而 MVC 模式
中的 M(模型)就是 三层架构
中的 业务逻辑层 和 数据访问层。
可以将 MVC 模式
理解成是一个大的概念,而 三层架构
是对 MVC 模式
实现架构的思想。
会话技术
会话:用户打开浏览器,访问web服务器的资源,会话建立,直到有一方断开连接,会话结束。在一次会话中可以包含多次请求和响应。
会话跟踪:一种维护浏览器状态的方法,服务器需要识别多次请求是否来自于同一浏览器,以便在同一次会话的多次请求间共享数据。
(1)客户端会话跟踪技术:Cookie
(2)服务端会话跟踪技术:Session
这两个技术都可以实现会话跟踪,它们之间最大的区别:Cookie是存储在浏览器端而Session是存储在服务器端
Cookie
发送Cookie
- 创建Cookie对象,并设置数据
Cookie cookie = new Cookie("key","value");
- 发送Cookie到客户端:使用response对象
response.addCookie(cookie);
获取Cookie的值
//获取Cookie
//1. 获取Cookie数组
Cookie[] cookies = request.getCookies();
//2. 遍历数组
for (Cookie cookie : cookies) {
//3. 获取数据
String name = cookie.getName();
if("username".equals(name)){
String value = cookie.getValue();
System.out.println(name+":"+value);
break;
}
}
Cookie的原理分析
对于Cookie的实现原理是基于HTTP协议的,其中设计到HTTP协议中的两个请求头信息:
- 响应头:set-cookie
- 请求头: cookie
Cookie的使用细节
Cookie的存活时间
如何将Cookie持久化存储?
Cookie其实已经为我们提供好了对应的API来完成这件事,这个API就是setMaxAge,
- 设置Cookie存活时间
setMaxAge(int seconds)
参数值为:
1.正数:将Cookie写入浏览器所在电脑的硬盘,持久化存储。到时间自动删除
2.负数:默认值,Cookie在当前浏览器内存中,当浏览器关闭,则Cookie被销毁
3.零:删除对应Cookie
Cookie存储中文
- Cookie不能直接存储中文,解决办法:
1.对中文进行URL编码,采用URLEncoder.encode(),将编码后的值存入Cookie中
2.获取Cookie中的值,获取的值为URL编码后的值
3.将获取的值再进行URL解码,采用URLDecoder.decode(),就可以获取到对应的中文值
Session
session基本使用
具体的使用步骤为:
- 获取Session对象,使用的是request对象
HttpSession session = request.getSession();
-
Session对象提供的功能:
-
存储数据到 session 域中
void setAttribute(String name, Object o)
-
根据 key,获取值
Object getAttribute(String name)
-
根据 key,删除该键值对
void removeAttribute(String name)
-
Session的原理分析
- Session是基于Cookie实现的
Session的使用细节
Session钝化与活化
只要服务器是正常关闭和启动,session中的数据是可以被保存下来的
具体的原因就是:Session的钝化和活化:
-
钝化:在服务器正常关闭后,Tomcat会自动将Session数据写入硬盘的文件中
- 钝化的数据路径为:
项目目录\target\tomcat\work\Tomcat\localhost\项目名称\SESSIONS.ser
- 钝化的数据路径为:
-
活化:再次启动服务器后,从文件中加载数据到Session中
- 数据加载到Session中后,路径中的
SESSIONS.ser
文件会被删除掉
- 数据加载到Session中后,路径中的
-
浏览器被关闭启动后,重新建立的连接就已经是一个全新的会话,获取的session数据也是一个新的对象
-
session的数据要想共享,浏览器不能关闭,所以session数据不能长期保存数据
-
cookie是存储在客户端,是可以长期保存
Session的销毁
session的销毁会有两种方式:
-
默认情况下,无操作,30分钟自动销毁
-
对于这个失效时间,是可以通过配置进行修改的
-
在项目的web.xml中配置
<?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_3_1.xsd" version="3.1"> <session-config> <session-timeout>100</session-timeout> </session-config> </web-app>
-
如果没有配置,默认是30分钟,默认值是在Tomcat的web.xml配置文件中写死的
-
-
-
调用Session对象的invalidate()进行销毁
- 该销毁方法一般会在用户退出的时候,需要将session销毁掉。
cookie和session联系与区别
-
Cookie 和 Session 都是来完成一次会话内多次请求间数据共享的。
-
区别:
- 存储位置:Cookie 是将数据存储在客户端,Session 将数据存储在服务端
- 安全性:Cookie不安全,Session安全
- 数据大小:Cookie最大3KB,Session无大小限制
- 存储时间:Cookie可以通过setMaxAge()长期存储,Session默认30分钟
- 服务器性能:Cookie不占服务器资源,Session占用服务器资源
-
应用场景:
- 购物车:使用Cookie来存储
- 以登录用户的名称展示:使用Session来存储
- 记住我功能:使用Cookie来存储
- 验证码:使用session来存储
-
结论
- Cookie是用来保证用户在未登录情况下的身份识别
- Session是用来保存用户登录后的数据
Filter&Listener&Ajax
Filter
过滤器可以把对资源的请求拦截下来,从而实现一些特殊的功能。
开发步骤
进行 Filter
开发分成以下三步实现
- 定义类,实现 Filter接口,并重写其所有方法
- 配置Filter拦截资源的路径:在类上定义
@WebFilter
注解。而注解的value
属性值/*
表示拦截所有的资源 - 在doFilter方法中输出一句话,并放行
filterChain.doFilter(servletRequest, servletResponse);
Filter执行流程
执行放行前逻辑–→ 放行–→ 访问资源–→ 执行放行后逻辑
Filter拦截路径配置
拦截路径有如下四种配置方式:
- 拦截具体的资源:/index.jsp:只有访问index.jsp时才会被拦截
- 目录拦截:/user/*:访问/user下的所有资源,都会被拦截
- 后缀名拦截:*.jsp:访问后缀名为jsp的资源,都会被拦截
- 拦截所有:/*:访问所有资源,都会被拦截
过滤器链
过滤器链是指在一个Web应用,可以配置多个过滤器,这多个过滤器称为过滤器链。
简易的过滤器链执行是按照以下流程执行:
- 执行
Filter1
的放行前逻辑代码 - 执行
Filter1
的放行代码 - 执行
Filter2
的放行前逻辑代码 - 执行
Filter2
的放行代码 - 访问到资源
- 执行
Filter2
的放行后逻辑代码 - 执行
Filter1
的放行后逻辑代码
上面代码中为什么是先执行 FilterDemo
,后执行 FilterDemo2
呢?
我们现在使用的是注解配置Filter,而这种配置方式的优先级是按照过滤器类名(字符串)的自然排序。
比如有如下两个名称的过滤器 : BFilterDemo
和 AFilterDemo
。那一定是 AFilterDemo
过滤器先执行。
Listener
-
Listener 表示监听器,是 JavaWeb 三大组件(Servlet、Filter、Listener)之一。
-
监听器可以监听就是在
application
,session
,request
三个对象创建、销毁或者往其中添加修改删除属性时自动执行代码的功能组件。application
是ServletContext
类型的对象。ServletContext
代表整个web应用,在服务器启动的时候,tomcat会自动创建该对象。在服务器关闭时会自动销毁该对象。
JavaWeb 提供了8个监听器:
最常用的是ServletContextListener
,用来监听 ServletContext
对象的创建和销毁。
ServletContextListener
接口中有以下两个方法
void contextInitialized(ServletContextEvent sce)
:ServletContext
对象被创建了会自动执行的方法void contextDestroyed(ServletContextEvent sce)
:ServletContext
对象被销毁时会自动执行的方法
ServletContextListener
监听器的使用步骤:
- 定义一个类,实现
ServletContextListener
接口 - 重写所有的抽象方法
- 使用
@WebListener
进行配置
Ajax
AJAX
(Asynchronous JavaScript And XML):异步的 JavaScript 和 XML。
AJAX 作用有以下两方面:
-
与服务器进行数据交换:通过AJAX可以给服务器发送请求,服务器将数据直接响应回给浏览器。
-
异步交互:可以在不重新加载整个页面的情况下,与服务器交换数据并更新部分网页的技术,如:搜索联想、用户名是否可用校验,等等…
同步和异步
- 同步发送请求过程如下
浏览器页面在发送请求给服务器,在服务器处理请求的过程中,浏览器页面不能做其他的操作。只能等到服务器响应结束后才能,浏览器页面才能继续做其他的操作。
- 异步发送请求过程如下
浏览器页面发送请求给服务器,在服务器处理请求的过程中,浏览器页面还可以做其他的操作。
Ajax快速入门
服务端实现
创建名为 AjaxServlet
的servlet,添加代码
//1. 响应数据
response.getWriter().write("hello ajax~");
客户端实现
创建html,在js中加入下列代码(3步)
-
创建核心对象,不同的浏览器创建的对象是不同的
var xhttp; if (window.XMLHttpRequest) { xhttp = new XMLHttpRequest(); } else { // code for IE6, IE5 xhttp = new ActiveXObject("Microsoft.XMLHTTP"); }
-
发送请求
//建立连接 xhttp.open("GET", "http://localhost:8080/项目名/ajaxServlet"); //发送请求 xhttp.send();
-
获取响应
xhttp.onreadystatechange = function() { if (this.readyState == 4 && this.status == 200) { // 通过 this.responseText 可以获取到服务端响应的数据 alert(this.responseText); } };
测试发现filter过滤后的register页面的response还是filter返回的数据,怎么做到ajax响应标记替换此时的response
Axios
Axios 对原生的AJAX进行封装,简化书写。
使用步骤
axios 使用是比较简单的,分为以下两步:
-
引入 axios 的 js 文件
<script src="js/axios-0.18.0.js"></script>
-
使用axios 发送请求,并获取响应结果
-
发送 get 请求
axios({ method:"get", url:"http://localhost:8080/ajax-demo1/aJAXDemo1?username=zhangsan" }).then(function (resp){ alert(resp.data); })
-
发送 post 请求
axios({ method:"post", url:"http://localhost:8080/ajax-demo1/aJAXDemo1", data:"username=zhangsan" }).then(function (resp){ alert(resp.data); });
-
axios()
是用来发送异步请求的,小括号中使用 js 对象传递请求相关的参数:
method
属性:用来设置请求方式的。取值为get
或者post
。url
属性:用来书写请求的资源路径。如果是get
请求,需要将请求参数拼接到路径的后面,格式为:url?参数名=参数值&参数名2=参数值2
。data
属性:作为请求体被发送的数据。也就是说如果是post
请求的话,数据需要作为data
属性的值。
then()
需要传递一个匿名函数。我们将 then()
中传递的匿名函数称为 回调函数,意思是该匿名函数在发送请求时不会被调用,而是在成功响应后调用的函数。而该回调函数中的 resp
参数是对响应的数据进行封装的对象,通过 resp.data
可以获取到响应的数据。
快速入门
-
定义一个用于接收请求的servlet(后端实现)
-
即使用步骤内容(前端实现)
请求方法别名
为了方便起见, Axios 已经为所有支持的请求方法提供了别名。如下:
-
get
请求 :axios.get(url[,config])
-
delete
请求 :axios.delete(url[,config])
-
head
请求 :axios.head(url[,config])
-
options
请求 :axios.option(url[,config])
-
post
请求:axios.post(url[,data[,config])
-
put
请求:axios.put(url[,data[,config])
-
patch
请求:axios.patch(url[,data[,config])
JSON
概念:JavaScript Object Notation
。JavaScript 对象表示法.
JSON
的格式:(举个栗子)
{
"name":"zhangsan",
"age":23,
"city":"北京"
}
JSON 基础语法
基本格式
JSON
本质就是一个字符串,但是该字符串内容是有一定的格式要求的。
JSON
串的键要求必须使用双引号括起来,而值根据要表示的类型确定。value 的数据类型分为如下
var 变量名 = '{"key":value,"key":value,...}';
- 数字(整数或浮点数)
- 字符串(使用双引号括起来)
- 逻辑值(true或者false)
- 数组(在方括号中)
- 对象(在花括号中)
- null
JSON串和Java对象的相互转换
- 请求数据:JSON字符串转为Java对象
- 响应数据:Java对象转为JSON字符串
json数据和java对象转换:
Fastjson
是阿里巴巴提供的一个Java语言编写的高性能功能完善的 JSON
库,是目前Java语言中最快的 JSON
库,可以实现 Java
对象和 JSON
字符串的相互转换。
- 导入坐标
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.62</version>
</dependency>
-
Java对象转JSON
String jsonStr=JSON.toJSONString(obj)
-
JSON字符串转Java对象
User user = JSON.parseObject(jsonStr,User.class)