JDBC【封装工具类、SQL注入问题】

day54

JDBC

封装工具类01

创建配置文件

DBConfig.properties

driverName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/qnz01?characterEncoding=utf8&serverTimezone=UTC
username=root
password=root

新建配置文件,不用写后缀名
配置文件,不用写后缀

创建工具类

  1. 将变化的配置信息搬到配置文件中
  2. 工具类提供获取连接的方法
  3. 工具类提供关闭资源的方法
package com.qf.utils;/*** 数据库工具类*/
public class DBUtil {private static String url;private static String username;private static String password;static{//负责加载配置文件,只加载一次Properties properties = new Properties();try {properties.load(DBUtil.class.getClassLoader().getResourceAsStream("DBConfig.properties"));} catch (IOException e) {throw new RuntimeException(e);}String driverName = properties.getProperty("driverName");url = properties.getProperty("url");username = properties.getProperty("username");password = properties.getProperty("password");try {//加载驱动只加载一次Class.forName(driverName);} catch (ClassNotFoundException e) {throw new RuntimeException(e);}}/*** 获取连接对象*/public static Connection getConnection() throws SQLException {Connection connection = DriverManager.getConnection(url,username,password);return connection;}/*** 关闭资源*/public static void close(Connection connection, Statement statement, ResultSet resultSet){if(resultSet != null){try {resultSet.close();} catch (SQLException e) {throw new RuntimeException(e);}}if(statement != null){try {statement.close();} catch (SQLException e) {throw new RuntimeException(e);}}if(connection != null){try {connection.close();} catch (SQLException e) {throw new RuntimeException(e);}}}}
理解

(1)新建配置文件
把导入驱动包和获取连接对象的参数url、root、password写入配置文件
(2)将获取连接对象方法封装到工具类DBUtil
01:加载配置文件
new 一个配置文件对象,配置文件对象调用加载方法加载进来【报异常先用try-catch】
之后就可以配置文件对象调用方法拿到配置信息【注意要与配置文件的名字相同,否则找不到就是null】
02:导入驱动包

03:在获取连接对象方法里,调用方法获取连接对象,返回连接对象

04:对于关闭资源,不用每次都写,直接在工具类写个关闭资源方法传入可能关的资源,里面非空判断哪些要关就行了

注意:

通常会把加载配置文件和导入驱动包放在静态代码块里,提高效率,不用获取一次连接加载一次,加载一次就行
对于重复使用的属性先静态定义【注意静态代码块只能初始化静态的属性】

基本操作报错try-catch【例如类这里的forName类未找到异常就要么资源文件没导入,要么配置文件对应的名称没写对】,对于需要对应不同业务处理异常就需要抛异常,在外面处理

现在对于先前的增删改查就不用那么麻烦,每个都写导入驱动包和获取连接对象的一大坨代码,当然这里就涉及封装工具类
直接用工具类调用获取连接对象的方法,关闭资源方法

测试类

对day53的增删改查进行进一步优化

package com.qf.jdbc01;import com.qf.utils.DBUtil;
import org.junit.Test;import java.sql.*;public class Test01 {/*** 知识点:封装DBUtil - v1.0*///添加数据@Testpublic void test01() throws SQLException {//获取连接对象Connection connection = DBUtil.getConnection();//获取发送指令对象Statement statement = connection.createStatement();//发送SQL指令String sql = "INSERT INTO student(name,sex,age,salary,course) VALUES('柳如烟','女',28,6000,'HTML');";int num = statement.executeUpdate(sql);System.out.println("对于" + num + "行造成了影响");//关闭资源DBUtil.close(connection,statement,null);}//删除数据@Testpublic void test02() throws SQLException {//获取连接对象Connection connection = DBUtil.getConnection();//获取发送指令对象Statement statement = connection.createStatement();//发送SQL指令String sql = "DELETE FROM student WHERE id>10;";int num = statement.executeUpdate(sql);System.out.println("对于" + num + "行造成了影响");//关闭资源DBUtil.close(connection,statement,null);}//修改数据@Testpublic void test03() throws SQLException {//获取连接对象Connection connection = DBUtil.getConnection();//获取发送指令对象Statement statement = connection.createStatement();//发送SQL指令String sql = "UPDATE student SET age=21,salary=50000 WHERE id=3;";int num = statement.executeUpdate(sql);System.out.println("对于" + num + "行造成了影响");//关闭资源DBUtil.close(connection,statement,null);}//查询数据@Testpublic void test04() throws SQLException {//获取连接对象Connection connection = DBUtil.getConnection();//获取发送指令对象Statement statement = connection.createStatement();//发送SQL指令,并获取结果集对象String sql = "select * from student";ResultSet resultSet = statement.executeQuery(sql);//遍历结果集while(resultSet.next()){//判断是否有可迭代的数据行int id = resultSet.getInt("id");String name = resultSet.getString("name");String sex = resultSet.getString("sex");int age = resultSet.getInt("age");float salary = resultSet.getFloat("salary");String course = resultSet.getString("course");System.out.println(id + " -- " + name + " -- " + sex + " -- " + age + " -- " + salary + " -- " + course);}//关闭资源DBUtil.close(connection,statement,resultSet);}}

SQL注入问题

理解

ps:select * from student where name=‘’ or 1=1 #’ and passwd=‘111111’;

当输入用户名和密码
’ or 1=1 # '【对于它分不清sql命令和数据,就会or 1=1判断为true,#后面理解为注释,就直接登录进去了】
user表

sql注入问题

package com.qf.jdbc02;import com.qf.utils.DBUtil;public class Test01 {/*** 知识点:SQL注入问题** 出现原因:数据库分不清哪些是sql命令,哪些是数据** 需求:模拟登录功能*/public static void main(String[] args) throws SQLException {Connection connection = DBUtil.getConnection();Statement statement = connection.createStatement();Scanner scan = new Scanner(System.in);System.out.println("请输入账号:");String usernameVal = scan.nextLine();System.out.println("请输入密码:");String passwordVal = scan.nextLine();//select * from user where username='' or 1=1 #' and password='12312345'String sql = "select * from user where username='"+usernameVal+"' and password='"+passwordVal+"'";ResultSet resultSet = statement.executeQuery(sql);if(resultSet.next()){String username = resultSet.getString("username");String password = resultSet.getString("password");String nikeName = resultSet.getString("nike_name");System.out.println("登录成功");System.out.println(username);System.out.println(password);System.out.println(nikeName);}else{System.out.println("登录失败");}DBUtil.close(connection,statement,resultSet);}
}

解决

采用预编译对象来编程:告诉他,使用prepareStatement

sql命令中用?表示数据
注意:prepareStatement继承于statement
现在用prepareStatement拿到的sql是没有数据的,得到它的对象
再将输入的数据设置给这个对象,注意方法SetString的两个参数(下标,值)【注意下标从1开始】
sql注入问题解决

  1. 安全性,避免了SQL注入
  2. 性能,预编译,语句-编译-执行
package com.qf.jdbc02;import com.qf.utils.DBUtil;public class Test02 {/*** 知识点:SQL注入问题** 出现原因:数据库分不清哪些是sql命令,哪些是数据* 解决方案:告诉数据库哪些是sql命令,哪些是数据** 需求:模拟登录功能*/public static void main(String[] args) throws SQLException {Connection connection = DBUtil.getConnection();String sql = "select * from user where username=? and password=?";PreparedStatement statement = connection.prepareStatement(sql);//输入数据后,将数据设置给statement对象Scanner scan = new Scanner(System.in);System.out.println("请输入账号:");String usernameVal = scan.nextLine();System.out.println("请输入密码:");String passwordVal = scan.nextLine();statement.setString(1,usernameVal);statement.setString(2,passwordVal);ResultSet resultSet = statement.executeQuery();if(resultSet.next()){String username = resultSet.getString("username");String password = resultSet.getString("password");String nikeName = resultSet.getString("nike_name");System.out.println("登录成功");System.out.println(username);System.out.println(password);System.out.println(nikeName);}else{System.out.println("登录失败");}DBUtil.close(connection,statement,resultSet);}
}

封装工具类02

更新数据(添加、删除、修改):

01方法传的参数(一个sql命令,另一个数据不确定用可变参数)
02由于不知道下标和值用setObject设置给statement,但有多个参数需要遍历处理就写个方法来专门处理【处理statement对象参数数据的处理器,注意setObject下标从1开始】直接调用处理
03添加操作返回影响行数
04而考虑到关闭资源,处理异常就不会关闭资源,对代码进行try-finally,考虑作用域把定义对象放在之外

添加–主键回填:

就是添加数据后,不再是返回影响的行数,加一个查询返回主键
主键回填理解:
主键回填

查询:

以前查询就打印出来结果,现在查询的数据封装成对象,不同表封装不同的对象
01学生类:有参无参自动生成时,window+alt+回车快速生成,生成时涉及属性选择ctrl+1全选
02方法返回值设置成list集合,类型用泛型;传的参数(哪个类的对象clazz【反射创建】,一个sql,一个可变参数)
03对于拿到的结果集,需要遍历, 一个数据创建一个对象
先泛型创建对象【无数据】,获取数据字段名才可以利用反射去设置对象的属性
怎么获取:先用结果集对象调用方法获取表数据对象,再表数据对象调用方法获取字段个数,再在遍历中通过字段个数循环获取字段名,字段值

反射获取类的属性对象和设置对象的属性【对于反射设置属性回顾以前反射讲到的方法】

04然后将封装的对象添加到对象集合再返回

05而考虑到关闭资源,处理异常就不会关闭资源,对代码进行try-finally,考虑作用域把定义对象放在之外

package com.qf.utils;/*** 数据库工具类*/
public class DBUtil {private static String url;private static String username;private static String password;static{//负责加载配置文件,只加载一次Properties properties = new Properties();try {properties.load(DBUtil.class.getClassLoader().getResourceAsStream("DBConfig.properties"));} catch (IOException e) {throw new RuntimeException(e);}String driverName = properties.getProperty("driverName");url = properties.getProperty("url");username = properties.getProperty("username");password = properties.getProperty("password");try {//加载驱动只加载一次Class.forName(driverName);} catch (ClassNotFoundException e) {throw new RuntimeException(e);}}/*** 获取连接对象*/public static Connection getConnection() throws SQLException {Connection connection = DriverManager.getConnection(url,username,password);return connection;}/*** 关闭资源*/public static void close(Connection connection, Statement statement, ResultSet resultSet){if(resultSet != null){try {resultSet.close();} catch (SQLException e) {throw new RuntimeException(e);}}if(statement != null){try {statement.close();} catch (SQLException e) {throw new RuntimeException(e);}}if(connection != null){try {connection.close();} catch (SQLException e) {throw new RuntimeException(e);}}}/*** 更新数据(添加、删除、修改)*/public static int commonUpdate(String sql,Object... params) throws SQLException {Connection connection = null;PreparedStatement statement = null;try {connection = getConnection();statement = connection.prepareStatement(sql);paramHandler(statement,params);int num = statement.executeUpdate();return num;}finally {close(connection,statement,null);}}/*** 添加数据 - 主键回填(主键是int类型可以返回)*/public static int commonInsert(String sql,Object... params) throws SQLException {Connection connection = null;PreparedStatement statement = null;ResultSet resultSet = null;try {connection = getConnection();statement = connection.prepareStatement(sql,PreparedStatement.RETURN_GENERATED_KEYS);paramHandler(statement,params);statement.executeUpdate();resultSet = statement.getGeneratedKeys();int primaryKey = 0;if(resultSet.next()){primaryKey = resultSet.getInt(1);}return primaryKey;}finally {close(connection,statement,resultSet);}}/*** 查询数据*/public static <T> List<T> commonQuery(Class<T> clazz,String sql, Object... params) throws SQLException, InstantiationException, IllegalAccessException {Connection connection = null;PreparedStatement statement = null;ResultSet resultSet = null;try {connection = getConnection();statement = connection.prepareStatement(sql);paramHandler(statement,params);resultSet = statement.executeQuery();//获取表数据对象ResultSetMetaData metaData = resultSet.getMetaData();//获取字段个数int count = metaData.getColumnCount();List<T> list = new ArrayList<>();while(resultSet.next()){T t = clazz.newInstance();//获取字段名及数据for (int i = 1; i <= count; i++) {String fieldName = metaData.getColumnName(i);Object fieldVal = resultSet.getObject(fieldName);setField(t,fieldName,fieldVal);}list.add(t);}return list;} finally {DBUtil.close(connection,statement,resultSet);}}/*** 处理statement对象参数数据的处理器*/private static void paramHandler(PreparedStatement statement,Object... params) throws SQLException {for (int i = 0; i < params.length; i++) {statement.setObject(i+1,params[i]);}}/*** 获取当前类及其父类的属性对象* @param clazz class对象* @param name 属性名* @return 属性对象*/private static Field getField(Class<?> clazz,String name){for(Class<?> c = clazz;c != null;c = c.getSuperclass()){try {Field field = c.getDeclaredField(name);return field;} catch (NoSuchFieldException e) {} catch (SecurityException e) {}}return null;}/*** 设置对象中的属性* @param obj 对象* @param name 属性名* @param value 属性值*/private static void setField(Object obj,String name,Object value){Field field = getField(obj.getClass(), name);if(field != null){field.setAccessible(true);try {field.set(obj, value);} catch (IllegalArgumentException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();}}}
}

调用工具类的方法实现增删改查

package com.qf.jdbc03;import com.qf.utils.DBUtil;public class Test01 {/*** 知识点:封装数据库 - v2.0*///添加数据@Testpublic void test01() throws SQLException {String sql = "INSERT INTO student(name,sex,age,salary,course) VALUES(?,?,?,?,?)";int num = DBUtil.commonUpdate(sql, "天使萌", "女", 23, 10000, "HTML");System.out.println("对于" + num + "行造成了影响");}//删除数据@Testpublic void test02() throws SQLException {String sql = "delete from student where id=?";int num = DBUtil.commonUpdate(sql, 3);System.out.println("对于" + num + "行造成了影响");}//修改数据@Testpublic void test03() throws SQLException {String sql = "update student set salary=? where id=?";int num = DBUtil.commonUpdate(sql, 15000,1);System.out.println("对于" + num + "行造成了影响");}//添加数据 - 主键回填@Testpublic void test04() throws SQLException {String sql = "INSERT INTO student(name,sex,age,salary,course) VALUES(?,?,?,?,?)";int primaryKey = DBUtil.commonInsert(sql, "铃原爱蜜莉", "女", 23, 10000, "HTML");System.out.println("返回的主键是:" + primaryKey);}//查询数据@Testpublic void test05() throws SQLException, InstantiationException, IllegalAccessException {String sql = "select * from student where id<?";List<Student> list = DBUtil.commonQuery(Student.class, sql, 8);for (Student stu : list) {System.out.println(stu);}}
}

学生类

package com.qf.jdbc03;public class Student {private int id;private String name;private String sex;private int age;private float salary;private String course;public Student() {}public Student(int id, String name, String sex, int age, float salary, String course) {this.id = id;this.name = name;this.sex = sex;this.age = age;this.salary = salary;this.course = course;}public int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getSex() {return sex;}public void setSex(String sex) {this.sex = sex;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public float getSalary() {return salary;}public void setSalary(float salary) {this.salary = salary;}public String getCourse() {return course;}public void setCourse(String course) {this.course = course;}@Overridepublic String toString() {return "Student{" +"id=" + id +", name='" + name + '\'' +", sex='" + sex + '\'' +", age=" + age +", salary=" + salary +", course='" + course + '\'' +'}';}
}

小结:

JDBC:封装工具类,对增删改查优化,SQL注入问题

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/370360.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Elasticsearch】一、概述,安装

文章目录 概述全文搜索引擎概述ES&#xff08;7.x&#xff09; 安装ES&#xff08;Docker&#xff09;测试&#xff0c;是否启动成功 可视化工具配置中文 客户端Postman下载 概述 ES是开源的高扩展的分布式全文搜索引擎&#xff0c;实时的存储、检索数据&#xff1b;本身扩展性…

非对称加密算法原理与应用2——RSA私钥加密文件

作者:私语茶馆 1.相关章节 (1)非对称加密算法原理与应用1——秘钥的生成-CSDN博客 第一章节讲述的是创建秘钥对,并将公钥和私钥导出为文件格式存储。 本章节继续讲如何利用私钥加密内容,包括从密钥库或文件中读取私钥,并用RSA算法加密文件和String。 2.私钥加密的概述…

CTFShow的RE题(三)

数学不及格 strtol 函数 long strtol(char str, char **endptr, int base); 将字符串转换为长整型 就是解这个方程组了 主要就是 v4, v9的关系&#xff0c; 3v9-(v10v11v12)62d10d4673 v4 v12 v11 v10 0x13A31412F8C 得到 3*v9v419D024E75FF(1773860189695) 重点&…

【笔记】TimEP Safety Mechanisms方法论

1.TimEPM Overview 三大监控方法: Alive Supervision 实时监督Logical Supervision 逻辑监督Deadline Supervision 限时监督相关模块框图: 相关模块调用框图: 每个MCU核开启内狗(1核1狗),内狗用于监控相应核的TASK超时,超时后软reset MCU内狗时钟需要独立于OS时钟,两…

MongoDB集群搭建-最简单

目录 前言 一、分片概念 二、搭建集群的步骤 总结 前言 MongoDB分片&#xff08;Sharding&#xff09;是一种水平扩展数据库的方法&#xff0c;它允许将数据分散存储在多个服务器上&#xff0c;从而提高数据库的存储容量和处理能力。分片是MongoDB为了应对大数据量和高吞吐量需…

10.x86游戏实战-汇编指令lea

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 本次游戏没法给 内容参考于&#xff1a;微尘网络安全 工具下载&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1rEEJnt85npn7N38Ai0_F2Q?pwd6tw3 提…

【IT领域新生必看】 Java编程中的重载(Overloading):初学者轻松掌握的全方位指南

文章目录 引言什么是方法重载&#xff08;Overloading&#xff09;&#xff1f;方法重载的基本示例 方法重载的规则1. 参数列表必须不同示例&#xff1a; 2. 返回类型可以相同也可以不同示例&#xff1a; 3. 访问修饰符可以相同也可以不同示例&#xff1a; 4. 可以抛出不同的异…

Amesim应用篇-信号传递

前言 在Amesim中常见的信号传递是通过信号线连接&#xff0c;针对简单的模型通过信号线连接还可以是信号线清晰规整&#xff0c;方便查看。如果模型较复杂&#xff0c;传递信号的元件较多时&#xff0c;此时再继续使用信号线进行信号传递&#xff0c;可能会使草图界面看起来杂…

在原有的iconfont.css文件中加入新的字体图标

前言&#xff1a;在阿里图标库中&#xff0c;如果你没有这个字体图标的线上项目&#xff0c;那么你怎么在本地项目中的原始图标文件中添加新的图标呢&#xff1f; 背景&#xff1a;现有一个vue项目&#xff0c;下面是这个前端项目的字体图标文件。现在需要新开发功能页&#x…

磁盘分区工具 -- 傲梅分区助手 v10.4.1 技术员版

软件简介 傲梅分区助手是一款功能强大的磁盘分区工具&#xff0c;它专为Windows系统设计&#xff0c;帮助用户更高效地管理他们的硬盘。该软件支持多种分区操作&#xff0c;包括创建、格式化、调整大小、移动、合并和分割分区。此外&#xff0c;它还提供了复制硬盘和分区的功能…

InspireFace-商用级的跨平台开源人脸分析SDK

InspireFace-商用级的跨平台开源人脸分析SDK InspireFaceSDK是由insightface开发的⼀款⼈脸识别软件开发⼯具包&#xff08;SDK&#xff09;。它提供了⼀系列功能&#xff0c;可以满⾜各种应⽤场景下的⼈脸识别需求&#xff0c;包括但不限于闸机、⼈脸⻔禁、⼈脸验证等。 该S…

C++(Qt)-GIS开发-QGraphicsView显示瓦片地图简单示例

C(Qt)-GIS开发-QGraphicsView显示瓦片地图简单示例 文章目录 C(Qt)-GIS开发-QGraphicsView显示瓦片地图简单示例1、概述2、实现效果3、主要代码4、源码地址 更多精彩内容&#x1f449;个人内容分类汇总 &#x1f448;&#x1f449;GIS开发 &#x1f448; 1、概述 支持多线程加…

java版本工程项目管理系统 Spring Cloud+Spring Boot+Mybatis+Vue+ElementUI+前后端分离构建工程项目管理系统

工程项目管理系统 Spring CloudSpring BootMybatisVueElementUI前后端分离构建工程项目管理系统 1. 项目背景 一、随着公司的快速发展&#xff0c;企业人员和经营规模不断壮大。为了提高工程管理效率、减轻劳动强度、提高信息处理速度和准确性&#xff0c;公司对内部工程管理的…

【C++】模板进阶--保姆级解析(什么是非类型模板参数?什么是模板的特化?模板的特化如何应用?)

目录 一、前言 二、什么是C模板&#xff1f; &#x1f4a6;泛型编程的思想 &#x1f4a6;C模板的分类 三、非类型模板参数 ⚡问题引入⚡ ⚡非类型模板参数的使用⚡ &#x1f525;非类型模板参数的定义 &#x1f525;非类型模板参数的两种类型 &#x1f52…

Java视频点播网站

作者介绍&#xff1a;计算机专业研究生&#xff0c;现企业打工人&#xff0c;从事Java全栈开发 主要内容&#xff1a;技术学习笔记、Java实战项目、项目问题解决记录、AI、简历模板、简历指导、技术交流、论文交流&#xff08;SCI论文两篇&#xff09; 上点关注下点赞 生活越过…

ElementPlusError: [ElPagination] 你使用了一些已被废弃的用法,请参考 el-pagination 的官方文档

一、问题描述&#xff1a; 今天在使用elementui plus的时候遇到了一个奇葩的问题&#xff0c; 就是提示 使用了一些已被废弃的用法&#xff0c; 奇葩就在于我是 复制另一个页面的分页&#xff0c; 一摸一样的东西&#xff0c;就只这个页面报错&#xff0c; 分页也不出 为了这个…

初识STM32:开发方式及环境

STM32的编程模型 假如使用C语言的方式写了一段程序&#xff0c;这段程序首先会被烧录到芯片当中&#xff08;Flash存储器中&#xff09;&#xff0c;Flash存储器中的程序会逐条的进入CPU里面去执行。 CPU相当于人的一个大脑&#xff0c;虽然能执行运算和执行指令&#xff0c;…

linux centos 安装niginx并且添加ssl(https)模块

文章目录 前言一、nginx安装教程1.流程步骤 总结 前言 一、nginx安装教程 1.流程步骤 代码如下&#xff08;示例&#xff09;&#xff1a; 1.先下载linux安装包 2.解压安装命令 sudo tar -zxvf nginx-1.20.1.tar.gz3.进入解压后的目录 sudo cd nginx-1.20.14.安装 sudo y…

baomidou多数据源切换注解@DS没有效果

baomidou多数据源切换注解DS没有效果 <dependency><groupId>com.baomidou</groupId><artifactId>dynamic-datasource-spring-boot-starter</artifactId><version>3.1.1</version> </dependency> ##原因 方法上有Transaction…

jmeter-beanshell学习3-beanshell获取请求报文和响应报文

前后两个报文&#xff0c;后面报文要用前面报文的响应结果&#xff0c;这个简单&#xff0c;正则表达式或者json提取器&#xff0c;都能实现。但是如果后面报文要用前面请求报文的内容&#xff0c;感觉有点难。最早时候把随机数写在自定义变量&#xff0c;前后两个接口都用这个…