up:: SQL注入攻击的解决策略
本篇博客还是沿用JDBC分析按部门查询员工功能这篇博客中的接口:
本篇博客篇幅很长,但核心内容就3点: (1)DbUtils; (2)【新增、更新、删除数据】的方法; (3)整体的包结构和类组织的套路;
一.封装DbUtils工具类:
【创建数据库连接】和【关闭数据库连接】的代码,需要经常用到。可以把这些需要重复使用的代码做成一个工具类,就是DbUtils工具类;
DbUtils类: 这个类没什么好说的,看下代码中的注释。
package com.imooc.jdbc.common;
import java.sql.*;
public class DbUtils {
/**
* 创建数据库连接
* @return
* @throws SQLException
* @throws ClassNotFoundException
*/
public static Connection getConnection() throws SQLException, ClassNotFoundException {
//加载并注册JDBC驱动,和,创建数据库连接会产生异常;
// 这儿将异常抛出,而不是捕获;在实际调用这个getConnection()方法的时候,再对这个异常捕获
Class.forName("com.mysql.cj.jdbc.Driver");
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/imooc?useSSL=false&useUincode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true", "root", "12345");
return conn;
}
/**
* 关闭数据库连接
* 注:因为关闭方法中,在关闭前都做了判断是不是null,所以当实参是null的时候也是没问题的。即比如新增、删除、更新操作没有ResultSet,因为这儿ResultSet形参可以为null;所以,插叙,新增,删除,更新都可以调用这个方法;
* @param rs:结果集对象;
* @param stmt:执行SQL的Statement对象;这儿的形参是Statement类型,因为PrepareStatement是Statement的子接口,所以当实参是PrepareStatement类型的时候也没问题。
* @param conn:连接对象;
*/
public static void closeConnection(ResultSet rs, Statement stmt,Connection conn){
try {
if (rs != null) { // 如果rs != null,代表rs被实例化了,所以这儿需要关闭一下,进行释放;
rs.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
try {
if (stmt != null) { // 如果rs != null,代表stmt被实例化了,所以这儿需要关闭一下,进行释放;
stmt.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
try {
if (conn != null && conn.isClosed() == false) { // conn.isClosed()==false代表这个连接还没有关闭,还正在使用中;
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
二:新增、更新、删除实现
包结构:
1.新增(写操作):InsertCommand类
(1)新增操作需要使用PreparedStatement(因为 PreparedStatement可以进行参数化设置啊);
(2)新增使用PreparedStatement对象的executeUpdate()方法;
(3)executeUpdate()方法返回值:本次写操作所影响的数据库的行数;
(4)和查询不同,新增操作没有返回结果集;而是返回了一个(3)中的影响数据库的行数;
InsertCommand类:
package com.imooc.jdbc.command;
import com.imooc.jdbc.common.DbUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Scanner;
public class InsertCommand implements Command{
@Override
public void execute() {
Scanner in = new Scanner(System.in);
System.out.println("请输入员工编号:");
int eno = in.nextInt();
System.out.println("请输入员工姓名");
String ename = in.next();
System.out.println("请输入员工薪资:");
Float salary = in.nextFloat();
System.out.println("请输入隶属部门:");
String dname = in.next();
Connection conn = null;
PreparedStatement pstmt = null;
try {
conn = DbUtils.getConnection();
String sql = "insert into employee(eno,ename,salary,dname) values(?,?,?,?)";
pstmt = conn.prepareStatement(sql);
pstmt.setInt(1,eno);
pstmt.setString(2,ename);
pstmt.setFloat(3, salary);
pstmt.setString(4, dname);
int cnt = pstmt.executeUpdate();
System.out.println(cnt);
System.out.println(dname+"员工入职手续已办理。");
} catch (SQLException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}finally {
DbUtils.closeConnection(null, pstmt, conn);
}
}
}
2.更新:UpdateCommand类
(1)更新也是使用PreparedStatement对象的executeUpdate()方法;
(2)executeUpdate()方法的返回值也是本次更新操作所影响的数据库的行数;
UpdateCommand类:
package com.imooc.jdbc.command;
import com.imooc.jdbc.common.DbUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Scanner;
public class UpdateCommand implements Command{
@Override
public void execute() {
Scanner in = new Scanner(System.in);
System.out.println("请输入员工编号:");
int eno = in.nextInt();
System.out.println("请输入员工薪资:");
Float salary = in.nextFloat();
Connection conn = null;
PreparedStatement pstmt = null;
Command command = null;
try {
conn = DbUtils.getConnection();
String sql = "update employee set salary=? where eno=?";
pstmt = conn.prepareStatement(sql);
pstmt.setFloat(1,salary);
pstmt.setInt(2,eno);
int cnt = pstmt.executeUpdate();
if (cnt == 1) {
System.out.println(eno + "员工薪资调整完毕。");
} else {
System.out.println(eno + "员工不存在。");
}
} catch (SQLException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}finally {
DbUtils.closeConnection(null,pstmt,conn);
}
}
}
3.删除:DeleteCommand类
(1)删除也是使用PreparedStatement对象的executeUpdate()方法;
(2)executeUpdate()方法的返回值也是本次删除操作所影响的数据库的行数;可能返回1,也可能返回0(表示本次删除操作没有删除任何一条数据);
DeleteCommand类:
package com.imooc.jdbc.command;
import com.imooc.jdbc.common.DbUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Scanner;
public class DeleteCommand implements Command {
/**
* 删除员工
*/
@Override
public void execute() {
Scanner in = new Scanner(System.in);
System.out.println("请输入员工编号:");
int eno = in.nextInt();
Connection conn = null;
PreparedStatement pstmt = null;
Command command = null;
try {
conn = DbUtils.getConnection();
String sql = "delete from employee where eno=?";
pstmt = conn.prepareStatement(sql);
pstmt.setInt(1,eno);
int cnt = pstmt.executeUpdate();
if (cnt == 1) {
System.out.println(eno + "员工离职成功。");
} else {
System.out.println(eno + "员工不存在。");
}
} catch (SQLException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}finally {
DbUtils.closeConnection(null,pstmt,conn);
}
}
}
4.Command接口内容
package com.imooc.jdbc.command;
/**
* 操作数据库的接口;
*/
public interface Command {
public void execute();
}
5.入口类:HumanResourceApplication类
package com.imooc.jdbc.hrapp;
import com.imooc.jdbc.command.*;
import java.util.Scanner;
public class HumanResourceApplication {
public static void main(String[] args) {
System.out.println("1-查询部门员工");
System.out.println("2-办理员工入职");
System.out.println("3-调整薪资");
System.out.println("4-员工离职");
System.out.println("请选择功能:");
Scanner in = new Scanner(System.in);
Integer cmd = in.nextInt();
Command command = null;// 将接口变量定义在外边,并初始化为null;在内部遇到不同操作的时候,再去实例化与之对应的类;
switch (cmd){
case 1: //查询部门员工
command = new PstmtQueryCommand();
command.execute();
break;
case 2: //办理员工入职
command = new InsertCommand();
command.execute();
break;
case 3: //调整薪资
command = new UpdateCommand();
command.execute();
break;
case 4: //员工离职
command = new DeleteCommand();
command.execute();
default:
}
}
}