JDBC文档

JDBC概述

JDBC概述

Java DataBase Connectivity Java 数据库连接技术

JDBC的作用

通过Java语言操作数据库,操作表中的数据

SUN公司为**了简化、**统一对数据库的操作,定义了一套Java操作数据库的规范,称之为JDBC

JDBC的本质

是官方(sun公司)定义的一套操作所有关系型数据库的规则(接口)。各个数据库厂商去实现这套接口,提供数据库驱动jar包。我们可以使用这套接口(JDBC)编程,运行时的代码其实是驱动jar包中的实现类。

总结:

在java中要想访问数据库只能通过JDBC.
JDBC是java访问数据库的基础,其他数据库访问技术都是对JDBC的封装(Hibernate,MyBatis)
JDBC是为了访问不同的数据库,提供了一种统一的访问方式
JDBC本身是java连接数据库的一个标准,是进行数据库连接的抽象层.由java编写的一组类和接口,接口的实现由各大数据库厂商来实现

JDBC 入门案例

使用junit测试用例

/*** @Auther: yanqi* 只有无返回值和没有参数据的情况下才能使用junit,点击方法用右击运行JUnit run * @Desc:*      在同一个类中只能有一个main方法,这个main是被jvm所调用*      我还想测试main2,没办法去运行这个main2*      为了解决多次测试问题?*      提供了一个  【测试用例】 junit*/
public class JdbcDemo1 {/*使用junit测试用例:1:在方法上加@Test2: 前提-测试的方法返回值只能是void , 不能参数3:注意 类名不能叫 test*///单元测试@Testpublic void test1(){System.out.println("aaaa");}//单元测试@Testpublic void test2(){System.out.println("bbbb");}}

JDBC_CRUD操作

实现步骤

1、要连接mysql数据库。有一个mysql的数据库,并且要启动
2、创建一个数据库,创建一个表,把表添加一些数据。
3、找到msyql的驱动,并且拷贝到工程中。build-path
4、书写java代码。

准备数据库

CREATE TABLE `t_user` (`id` int(11) NOT NULL AUTO_INCREMENT,`username` varchar(25) DEFAULT NULL,`passworld` varchar(25) DEFAULT NULL,`age` int(11) DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

创建JavaWeb工程

添加驱动jar包

JDBC的查询操作

    /*** 通过jdbc连接数据库步骤* 1、加载驱动* 2、连接数据库* 3、创建statement对象* 4、发送sql* 5、处理结果集* 6、关闭连接*/
public class JDBC_CRUD {/*** jdbc实现查询操作*/@Testpublic void TestSelectUser() throws Exception {// 1、加载驱动Class.forName("com.mysql.jdbc.Driver");// 2、连接数据库String url="jdbc:mysql://localhost:3306/test";String user="root";String password ="root";Connection conn = DriverManager.getConnection(url, user, password);// 3、创建statement对象,这个对象是可以发送sqlStatement statm = conn.createStatement();//4、发送sqlString sql="select * from t_user";ResultSet rs = statm.executeQuery(sql);//5、处理结果集while (rs.next()){//指针一个一个的去找,如果找到就取出int id = rs.getInt("id");String username = rs.getString("username");String passworld2 = rs.getString("passworld");int age = rs.getInt("age");System.out.println(id+"-"+username+"-"+passworld2+"-"+age);}// 6、关闭连接 后打开的先关闭rs.close();statm.close();conn.close();}
}

两种取值方式

//5、处理结果集
while (rs.next()){//指针一个一个的去找,如果找到就取出/*** 取值方式有两种:* 1、按字段名来取,比较真观,推荐使用(常用)* 2、按列号来取,可以在字段少的情况下使用*/int id = rs.getInt(1);//表示第一列id字段String username = rs.getString(2);//表示第二列username字段String passworld2 = rs.getString("passworld");int age = rs.getInt("age");System.out.println(id+"-"+username+"-"+passworld2+"-"+age);
}

JDBC的添加操作

/*** jdbc实现添加操作*/
@Test
public void TestAddUser() throws Exception {// 1、加载驱动Class.forName("com.mysql.jdbc.Driver");//2、连接数据库String url="jdbc:mysql://127.0.0.1:3306/test";String user="root";String pwd="root";Connection conn = DriverManager.getConnection(url, user, pwd);//3、创建statement对象Statement stmt = conn.createStatement();//4、发送sql  添加,修改,删除 都用executeUpdate()方法String sql = "INSERT INTO `test`.`t_user`(`id`, `username`, `passworld`, `age`) VALUES (null, 'rose', '123', 97)";int i = stmt.executeUpdate(sql);System.out.println(i);//表示的影响的行数//5、关闭连接stmt.close();conn.close();
}

JDBC的删除操作

/*** jdbc实现删除操作*/
@Test
public void TestDeleteUser() throws Exception {// 1、加载驱动Class.forName("com.mysql.jdbc.Driver");// 2、连接数据库String url="jdbc:mysql://127.0.0.1:3306/test";String user="root";String pwd="root";Connection conn = DriverManager.getConnection(url, user, pwd);// 3、创建statement对象Statement stmt = conn.createStatement();// 4、发送sqlString sql="delete from t_user";int i = stmt.executeUpdate(sql);System.out.println(i);// 5、关闭连接stmt.close();conn.close();
}

JDBC的修改操作

/*** jdbc实现修改操作*/
@Test
public void TestUpdateUser() throws Exception {// 1、加载驱动Class.forName("com.mysql.jdbc.Driver");// 2、连接数据库String url="jdbc:mysql://127.0.0.1:3306/test";String user="root";String pwd="root";Connection conn = DriverManager.getConnection(url, user, pwd);// 3、创建statement对象Statement stmt = conn.createStatement();// 4、发送sqlString sql="update t_user set username ='张三' where id = 4 ";int i = stmt.executeUpdate(sql);System.out.println(i);// 5、关闭连接stmt.close();conn.close();
}

异常的处理

public class JdbcEx {/*** jdbc实现查询操作*/@Testpublic void TestSelectUser(){// 1、加载驱动try {Class.forName("com.mysql.jdbc.Driver");} catch (ClassNotFoundException e) {e.printStackTrace();}// 2、连接数据库
`      String url="jdbc:mysql://localhost:3306/test";String user="root";String password ="root";Connection conn = null;Statement statm = null;ResultSet rs = null;try {conn = DriverManager.getConnection(url, user, password);// 3、创建statement对象,这个对象是可以发送sqlstatm = conn.createStatement();//4、发送sqlString sql="select * from t_user";rs = statm.executeQuery(sql);//5、处理结果集while (rs.next()){//批针一个一个的去找,如果找到就取出/*** 取值方式有两种:* 1、按字段名来取,比较真观,推荐使用(常用)* 2、按列号来取,可以在字段少的情况下使用*/int id = rs.getInt(1);//表示第一列id字段String username = rs.getString(2);//表示第二列username字段String passworld2 = rs.getString("passworld");int age = rs.getInt("age");System.out.println(id+"-"+username+"-"+passworld2+"-"+age);}} catch (SQLException e) {e.printStackTrace();}finally {// 6、关闭连接 后打开的先关闭try {if(rs != null){rs.close();rs =null;//关闭连接,给赋值null,gc垃圾回收回机制会优先处理这些对象}} catch (SQLException e) {e.printStackTrace();}try {if(statm != null){statm.close();statm=null;}} catch (SQLException e) {e.printStackTrace();}try {if(conn != null){conn.close();conn = null;}} catch (SQLException e) {e.printStackTrace();}}}
}

工具类的抽取

public class JDBCUtil {//静态代码块,随着类的加载而加载,并且只加载一次static {try {Class.forName("com.mysql.jdbc.Driver");} catch (ClassNotFoundException e) {e.printStackTrace();}}//获取连接public static Connection getConnection(){String url="jdbc:mysql://localhost:3306/test";String user="root";String password ="root";Connection conn = null;try {conn =  DriverManager.getConnection(url, user, password);} catch (SQLException e) {e.printStackTrace();}return conn;}//关闭方法public static void close(ResultSet rs , Statement statm, Connection conn){try {if(rs != null){rs.close();rs =null;//关闭连接,给赋值null,gc垃圾回收回机制会优先处理这些对象}} catch (SQLException e) {e.printStackTrace();}try {if(statm != null){statm.close();statm=null;}} catch (SQLException e) {e.printStackTrace();}try {if(conn != null){conn.close();conn = null;}} catch (SQLException e) {e.printStackTrace();}}//关闭方法public static void close( Statement statm, Connection conn){try {if(statm != null){statm.close();statm=null;}} catch (SQLException e) {e.printStackTrace();}try {if(conn != null){conn.close();conn = null;}} catch (SQLException e) {e.printStackTrace();}}
}

工具类的测试

public class UtilTest {@Testpublic void testUpdate(){Connection conn = null;Statement stmt = null;try {conn = JDBCUtil.getConnection();stmt = conn.createStatement();int i = stmt.executeUpdate("update t_user set username = '江一燕' where id = 4");System.out.println(i);} catch (SQLException e) {e.printStackTrace();}finally {JDBCUtil.close(stmt,conn);}}/*** 测试的查询*/@Testpublic void test(){Connection conn = null;Statement stmt = null;ResultSet rs = null;try {conn =  JDBCUtil.getConnection();stmt = conn.createStatement();rs = stmt.executeQuery("select * from t_user");while (rs.next()){int id = rs.getInt("id");String username = rs.getString("username");String passworld = rs.getString("passworld");int age = rs.getInt("age");System.out.println(id);System.out.println(username);System.out.println(passworld);System.out.println(age);}} catch (SQLException e) {e.printStackTrace();}finally {JDBCUtil.close(rs,stmt,conn);}}
}

工具类的优化

jdbc.properties

ClassforName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/test
user=root
password=root
public class JDBCUtil {private static  String classforName;private static String url;private static  String user;private static String password;private static Connection conn = null;//静态代码块,随着类的加载而加载,并且只加载一次static {//FileInputStream fis = null;  //获取的配置文件方式一Properties pro = null;try {//fis = new FileInputStream("src/jdbc.properties"); //获取的配置文件方式一,web项目中无法用//获取的配置文件二(通过类加载器)InputStream is=JDBCUtil.class.getClassLoader().getResourceAsStream("jdbc.properties");pro = new Properties();//加载到Properties集合对象中pro.load(is);} catch (IOException e) {e.printStackTrace();}finally {try {is.close();} catch (IOException e) {e.printStackTrace();}}classforName= pro.getProperty("ClassforName");url = pro.getProperty("url");user = pro.getProperty("user");password = pro.getProperty("password");//加载驱动try {Class.forName(classforName);} catch (ClassNotFoundException e) {e.printStackTrace();}//创建连接try {conn =  DriverManager.getConnection(url, user, password);} catch (SQLException e) {e.printStackTrace();}}//获取连接public static Connection getConnection(){return conn;}//关闭方法public static void close(ResultSet rs , Statement statm, Connection conn){try {if(rs != null){rs.close();rs =null;//关闭连接,给赋值null,gc垃圾回收回机制会优先处理这些对象}} catch (SQLException e) {e.printStackTrace();}try {if(statm != null){statm.close();statm=null;}} catch (SQLException e) {e.printStackTrace();}try {if(conn != null){conn.close();conn = null;}} catch (SQLException e) {e.printStackTrace();}}//关闭方法public static void close( Statement statm, Connection conn){try {if(statm != null){statm.close();statm=null;}} catch (SQLException e) {e.printStackTrace();}try {if(conn != null){conn.close();conn = null;}} catch (SQLException e) {e.printStackTrace();}}
}

封装实现体类

public class UserTest {@Testpublic void queryUser() throws SQLException {Connection conn = JDBCUtil.getConnection();Statement stmt = conn.createStatement();ResultSet rs = stmt.executeQuery("select * from t_user");List<User> list = new ArrayList<>();while (rs.next()){           User u = new User();u.setId(rs.getInt("id"));u.setUsername(rs.getString("username"));u.setPassworld(rs.getString("passworld"));u.setAge(rs.getInt("age"));list.add(u);}list.forEach(System.out::println);JDBCUtil.close(rs,stmt,conn);}
}

MVC三层架

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ERyu1jsE-1676683410519)(assets/image-20211122171228868.png)]

案例-登录功能

所用的技术: jdbc mysql 接口 实现类 三层架构 web – service – dao

创建工程: web工程

所需要的jar包: mysql的驱动包

数据库准备

CREATE TABLE `t_user` (`id` int(11) NOT NULL AUTO_INCREMENT,`username` varchar(25) DEFAULT NULL,`passworld` varchar(25) DEFAULT NULL,`age` int(11) DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;

实体对象

public class User {private int id;private String username;private String pwd;private int age;//提供有参无参构造方法//提供get set 方法//提供 toString 方法
}

dao层

方法

    public User login(User user);
public class UserDaoImpl implements UserDao {@Overridepublic User login(User u) {try {Class.forName("com.mysql.jdbc.Driver");} catch (ClassNotFoundException e) {e.printStackTrace();}//如果你的数据是本地的,并且端口是默认3306,是可以省略String url = "jdbc:mysql:///test";String user ="root";String pwd ="root";Connection conn = null;Statement stmt = null;try {conn = DriverManager.getConnection(url, user, pwd);stmt =  conn.createStatement();String sql ="select * from t_user where username = '"+u.getUsername()+"' and passworld = '"+u.getPassworld()+"' ";ResultSet rs = stmt.executeQuery(sql);//登录,只有两个结果,查到,查不到if(rs.next()){String username = rs.getString("username");String passworld = rs.getString("passworld");//如果有数据封装并返回User user1 = new User();user1.setUsername(username);user1.setPassworld(passworld);return user1;}} catch (SQLException e) {e.printStackTrace();}//TODO关闭连接//如果没有查到用户,整体返回nullreturn null;}
}

dao单元测试

/*** 测试dao层代码是否正常使用*/
@Test
public void login() {//创建dao层UserDao dao = new UserDaoImpl();User user = new User();user.setUsername("dfdfdf");user.setPassworld("123");//调用dao方法User u = dao.login(user);if(u!=null){System.out.println("登录成功");}else{System.out.println("登录失败");}
}

service层

public interface UserService {public boolean login(User user);
}
public class UserServiceImpl implements UserService {//创建dao对象private UserDao userDao = new UserDaoImpl();@Overridepublic boolean login(User user) {//调用dao层方法User res = userDao.login(user);if(res != null){//不能null表示dao查到数据,登录成功return true;}//否则登录失败return false;}
}

测试service

@Test
public void login() {//创建对象UserService service = new UserServiceImpl();User user = new User();user.setUsername("rose");user.setPassworld("123");boolean login = service.login(user);if(login){System.out.println("登录成功");}else{System.out.println("登录失败");}
}

web层

public class UserWeb {public static void main(String[] args) {//创建对象UserService service = new UserServiceImpl();User user = new User();user.setUsername("jack");user.setPassworld("123");boolean login = service.login(user);if(login){System.out.println("登录成功");}else{System.out.println("登录失败");}}
}

sql注入问题

-- 原sql
select * from t_user where username = "jack" and passworld = '123'-- 什么是sql注入: 通过字符串拼接,篡改sql,这就是sql注入
select * from t_user where username = ''or '1'='1' and passworld = ''or '1'='1'
select * from t_user where 1 = 1

解决sql注入问题的思路

-- 解决sql注入问题?
-- 出现的sql注入原因:字符串拼接,篡改sql
-- 解决思想,就让sql进行拼接
select * from t_user where username = ? and passworld = ?

PreparedStatement解决sql注入

1,执行效率:Statement 采取直接编译 SQL 语句的方式,扔给数据库去执行,而 PreparedStatement 则先将 SQL 语句预编译一遍,再填充参数,这样效率会高一些。SQL 语句被预编译并且存储在 PreparedStatement 对象中,其后可以使用该对象高效地多次执行该语句。2,代码可读性:Statement 中 SQL 语句中需要 Java 中的变量,加就得进行字符串的运算,还需要考虑一些引号、单引号的问题,参数变量越多,代码就越难看,而且会被单引号、双引号搞疯掉;而 PreparedStatement,则不需要这样,参数可以采用“?”占位符代替,接下来再进行参数的填充,
这样利于代码的可读性,并且符合面向对象的思想。3,安全性:Statement 由于可能需要采取字符串与变量的拼接,很容易进行 SQL 注入攻击,而 PreparedStatement 由于是预编译,再填充参数的,不存在 SQL 注入问题。
public class UserDaoImpl implements UserDao {@Overridepublic User login(User u) {try {Class.forName("com.mysql.jdbc.Driver");} catch (ClassNotFoundException e) {e.printStackTrace();}//如果你的数据是本地的,并且端口是默认3306,是可以省略String url = "jdbc:mysql:///test";String user ="root";String pwd ="root";Connection conn = null;PreparedStatement pstmt = null;ResultSet rs = null;try {conn = DriverManager.getConnection(url, user, pwd);/*stmt =  conn.createStatement();String sql ="select * from t_user where username = '"+u.getUsername()+"' and passworld = '"+u.getPassworld()+"' ";ResultSet rs = stmt.executeQuery(sql);*///预处理,提前把sql进行处理,可以防止sql注入问题String sql ="select * from t_user where username = ? and passworld = ?";pstmt = conn.prepareStatement(sql);pstmt.setString(1,u.getUsername());pstmt.setString(2,u.getPassworld());//执行,再发送rs = pstmt.executeQuery();//登录,只有两个结果,查到,查不到if(rs.next()){String username = rs.getString("username");String passworld = rs.getString("passworld");//如果有数据封装并返回User user1 = new User();user1.setUsername(username);user1.setPassworld(passworld);return user1;}} catch (SQLException e) {e.printStackTrace();}//TODO关闭连接//如果没有查到用户,整体返回nullreturn null;}
}

PreparedStatement进行了预编译处理,当下次执行相同的sql,sql就不会再编译了,比Statement的效率高。

Statement每执行一次sql进行编译一次

jdbc批处理-了解

业务场景:当需要向数据库中发送一批sql时,就可以用jdbc的批处理机制,以提升执行效率,避免向数据库一条条的发送

statement批处理

 /*** statement批处理*/@Testpublic void test1(){Connection conn = null;Statement statement = null;try {conn =  JDBCUtil.getConnection();statement = conn.createStatement();for(int i = 1; i<= 10000; i++){String sql ="insert into t_user (id,username, passworld,age) values(null,'"+i+"', '123', 28)";statement.addBatch(sql);//一次性向数据库中添加了3000条if(i % 3000 == 0 ){//执行批次statement.executeBatch();//清空批次statement.clearBatch();}}//执行批次statement.executeBatch();//清空批次statement.clearBatch();} catch (SQLException e) {e.printStackTrace();}finally {JDBCUtil.close(statement,conn);}}

PreparedStatement批处理

    /*** PreparedStatement* @throws SQLException*/@Testpublic void test2() throws SQLException {Connection conn = JDBCUtil.getConnection();String sql ="insert into t_user (username, passworld,age) values(?, ?, ?)";PreparedStatement pstmt = conn.prepareStatement(sql);for (int i = 1; i <=10000 ; i++) {pstmt.setString(1,"u"+i);pstmt.setString(2,"p"+i);pstmt.setInt(3,i);pstmt.addBatch();if(i % 3000 == 0){pstmt.executeBatch();pstmt.clearBatch();}}pstmt.executeBatch();pstmt.clearBatch();JDBCUtil.close(pstmt,conn);}

ent.clearBatch();
} catch (SQLException e) {
e.printStackTrace();
}finally {
JDBCUtil.close(statement,conn);
}

}

**PreparedStatement批处理**```java/*** PreparedStatement* @throws SQLException*/@Testpublic void test2() throws SQLException {Connection conn = JDBCUtil.getConnection();String sql ="insert into t_user (username, passworld,age) values(?, ?, ?)";PreparedStatement pstmt = conn.prepareStatement(sql);for (int i = 1; i <=10000 ; i++) {pstmt.setString(1,"u"+i);pstmt.setString(2,"p"+i);pstmt.setInt(3,i);pstmt.addBatch();if(i % 3000 == 0){pstmt.executeBatch();pstmt.clearBatch();}}pstmt.executeBatch();pstmt.clearBatch();JDBCUtil.close(pstmt,conn);}

张晨光-JAVA零基础保姆式JDBC技术教程相关推荐

  1. 张晨光-JAVA零基础保姆式技术教程之-事务

    事务 课程目标 1.什么是事务 2.jdbc如何控制事务 3.设置事务的回滚点 4.事务的特性ACID 5.数据库事务的隔高级别 事务理解 什么是事务: 指逻辑上一组操作,要么同时成功,要么同时失败. ...

  2. Java零基础笔记自用版(一)

    系列文章目录 一.Java零基础笔记自用版(一) 目录 系列文章目录 前言 一.⭐️Java概述 二.⭐️变量 三.⭐️运算符 四.⭐️控制结构 五.⭐️数组.排序.查找 写在最后 前言 最近在学习J ...

  3. java零基础Ⅲ-- 4.Mysql基础

    java零基础Ⅲ-- 4.Mysql基础 MySQL安装配置 MySQL数据库的安装和配置 软件下载 特别说明 安装步骤 使用命令行窗口连接MYSQL数据库 Navicat 安装和使用 介绍:图形化M ...

  4. 黑马程序员Java零基础视频教程_下部(P135-P200)

    黑马程序员Java零基础视频教程_下部(P135-P200) 1 多线程 1.1 什么是多线程? 1.2 多线程的并发与并行 1.3 多线程的实现方式 1.3.1 继承Thread类的方式进行实现 1 ...

  5. Java零基础好学吗?Java该怎么学?

    Java零基础好学吗?Java该怎么学?在IT行业中,Java开发工程师是一个很吃香的职业,薪资水平也是几乎过万,许多人想转行Java开发,但又担心零基础能不能学会,学起来有多难,如果是零基础自学Ja ...

  6. 【JAVA零基础入门系列】Day14 Java对象的克隆

    [JAVA零基础入门系列](已完结)导航目录 Day1 开发环境搭建 Day2 Java集成开发环境IDEA Day3 Java基本数据类型 Day4 变量与常量 Day5 Java中的运算符 Day ...

  7. 一篇文章让你从JAVA零基础入门`OOP`编程12.19

    一篇文章让你从JAVA零基础入门OOP编程 前言: 此文为玄子,复习ACCP-S1课程后,整理的文章,文中对知识点的解释仅为个人理解. 配套PPT,站点源码,等学习资料 一.预科 1.1 JAVA 介 ...

  8. 视频教程-由浅入深Java零基础入门-Java

    由浅入深Java零基础入门 负责过多个软件项目的研发.设计和管理工作,拥有项目管理师认证.项目监理师中级认证.出版过的图书有<微信小程序开发图解案例教程><Axure RP8原型设计 ...

  9. Java零基础小白的福利来了!!高淇老师带你飞~

    经过一年时间的沉淀,高淇老师终于带着他的Java300集走来啦!!简直就是新手小白入门编程的福音,内容讲解细致,画面丰富. 课件所有图形做了重新绘制和配色,图解学习Java,让学习成为一种享受 本套教 ...

最新文章

  1. 性能压测服务器502报错,一种交易系统的性能测试方法及相关服务器
  2. 今日 Paper | 手部和物体重建;三维人体姿态估计;图像到图像变换等
  3. ORA-12919: Can not drop the default permanent tablespace
  4. Confluence 6 重要缓存和监控
  5. 14条最佳JS代码编写技巧
  6. 【Java进阶】Eureka讲解与应用
  7. ajaxReturn 之前dump调试,导致$.ajax不能正常运行
  8. 中英翻译机c语言实验报告引言,课程设计--C语言关键字中英翻译机.doc
  9. Golang实践录:反射reflect的一些研究及代码汇总
  10. 解码(五):sws_getContext和sws_scale像素格式和尺寸转换函数详解
  11. S5PV210体系结构与接口09:SD卡启动详解
  12. SpringBoot-Feign
  13. Android状态栏语言,Android实现3种Notification(状态栏通知)
  14. FFMPEG安装及入门
  15. AD637_高精度,宽带RMS-DC转换器
  16. Intellij IDEA 插件下载慢或无法查询
  17. 11,SFDC 管理员篇 - 报表和数据的可视化
  18. SSM+服装管理系统 毕业设计-附源码080948
  19. 删除任务栏锁定,任务栏图标的位置,查找可行性文件的方式
  20. 长沙云图VR丨VR纪录片《我生命中的60秒》入围威尼斯国际电影节

热门文章

  1. PHP之stripslashes()函数和htmlspecialchars()函数
  2. 全球“黑客大赛”冠军霸气讲述:我是如何让50个文件一起骗过AI安防系统的?...
  3. 极光科研中心 · 资源开发区(ACM工程/MEP工程/STL标准库/先进书写)
  4. word文档转pdf,支持.doc和.docx
  5. Elasticsearch全文检索:根据关键词对全文查询检索,关键词也分词处理
  6. RTOS之必备汇编指令(老干妈笔记)
  7. 携程移动App架构优化之旅
  8. 如何长URL转换为短URL
  9. p5.js 临摹作品“随鼠标转动的三角形”及自主作品“太阳花”
  10. python如何设置画布开始位置_只要十分钟,Python绘图神器Turtle了解一下?