1、话不多说,直接看代码
首先准备一个数据库表 源码获取百度云链接:链接: https://pan.baidu.com/s/1iY0NNAHgdkOywr1G7rTZ6Q 密码: b29b
:
第二准备:域对象类:用于传输数据使用的
package cn.jdbcpractice.domain;
/**
*
* @author Administrator
*domain域-->一个对象
*/
public class Student {
private int id; //id
private String username;//用户名
private String passwrod;//用户密码
private int age;//用户年龄
private boolean sex;//用户性别
private String intro;//用户简介
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPasswrod() {
return passwrod;
}
public void setPasswrod(String passwrod) {
this.passwrod = passwrod;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getintro() {
return intro;
}
public void setintro(String intro) {
this.intro = intro;
}
public Student() {
super();
}
public boolean isSex() {
return sex;
}
public void setSex(boolean sex) {
this.sex = sex;
}
public Student(String username, String passwrod, int age, boolean sex, String intro) {
super();
this.username = username;
this.passwrod = passwrod;
this.age = age;
this.sex = sex;
this.intro = intro;
}
public Student(int id, String username, String passwrod, int age, boolean sex, String intro) {
super();
this.id = id;
this.username = username;
this.passwrod = passwrod;
this.age = age;
this.sex = sex;
this.intro = intro;
}
@Override //用于显示文字,不然只是地址值
public String toString() {
return "JdbcWork [id=" + id + ", username=" + username + ", passwrod=" + passwrod + ", age=" + age + ", sex="
+ sex + ", intro=" + intro + "]";
}
}
需要分层建一个dao包在下面建一个IStudentDao接口类: login和login2用于验证登陆是否成功,并比较优缺点安全等问题...
package cn.jdbcpractice.dao;
import java.util.List;
import cn.jdbcpractice.domain.Student;
/*
* @author Administrator
*业务层 :定义crud
*/
public interface IStudentDao {
public void save(Student stu); //添加用户
public void delete(int sid);//删除用户
public void update(Student stu);//修改用户信息
public Student queryIdSingle(int sid);//查询单个用户信息
public List<Student> queryIdAll();//查询多个用户信息
public Student login(String username,String passwrod);//用户登陆preparestatement发送
public Student login2(String username,String passwrod);//用户登陆statement发送
}
在dao包下再建一个impl包并建立IStudentDao的实现类StudentDaoImpl:
package cn.jdbcpractice.dao.impl;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import cn.jdbc.utils.*;
import cn.jdbcpractice.dao.IStudentDao;
import cn.jdbcpractice.domain.Student;
/**
*通过抽取类优化了增删改
*/
public class StudentDaoImpl implements IStudentDao {
Connection conn = null; //定义连接对象用于连接数据库
Statement st;//定义语句对象用于向数据库发送sql语句
ResultSet rs;//用于保存查询返回的信息;结果集ResultSet
List<Student> studentlist = new ArrayList<>();//用于保存多条信息的学生类集合
PreparedStatement prepare; //预编译语句对象,用于参数传值
@Override //通过抽取后的代码:同级下抽取类为-->BaseDAOImpl
public void save(Student stu) {// 添加
String sql = "insert into student2(username,passwrod,age,sex,in
tro)values(?,?,?,?,?)";
//调用BaseDAOImpl的executeUpdate(sql,values)方法,该类已经完成增删改,关闭资源
new BaseDAOImpl().executeUpdate(sql, stu.getUsername(), stu.getPasswrod(),
stu.getAge(), stu.isSex(),stu.getintro());
}
@Override //通过抽取后的代码:同级下抽取类为-->BaseDAOImpl
public void delete(int sid) { // 根據索引刪除
String sql = "delete from student2 where id=? ";
new BaseDAOImpl().executeUpdate(sql, sid);
}
@Override //通过抽取后的代码:同级下抽取类为-->BaseDAOImpl
public void update(Student stu) {// 根據索引修改整行信息
String sql = "update student2 set username=?,passwrod=?,age=?,sex=?,intro=? where id=?";
new BaseDAOImpl().executeUpdate(sql, stu.getUsername(), stu.getPasswrod(), stu.getAge(), stu.isSex(),
stu.getintro(), stu.getId());
}
@Override //查询单条数据(single单的)
public Student queryIdSingle(int sid) {
try {
conn = DbcpUtils.getJdbcUtils().getConnDb();
String sql = "select *from student2 where id=?";
prepare = conn.prepareStatement(sql);
prepare.setInt(1, sid);
prepare.executeQuery();
Student s = null;
while (rs.next()) {
s = new Student();
s.setId(rs.getInt("id"));
s.setUsername(rs.getString("username"));
s.setPasswrod(rs.getString("passwrod"));
s.setId(rs.getInt("age"));
s.setSex(rs.getBoolean("sex"));
s.setintro(rs.getString("intro"));
System.out.println(s);
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
DbcpUtils.getJdbcUtils().close(conn, st, rs);
}
return null;
}
@Override
public List<Student> queryIdAll() {// 查看多條數據
try {
conn = DbcpUtils.getJdbcUtils().getConnDb();
st = conn.createStatement();
String sql = "select *from student2";
rs = st.executeQuery(sql);
while (rs.next()) {
Student s2 = new Student();// 查詢到的保存在域對象
s2.setId(rs.getInt("id"));
s2.setUsername(rs.getString("username"));
s2.setPasswrod(rs.getString("passwrod"));
s2.setId(rs.getInt("age"));
s2.setSex(rs.getBoolean("sex"));
s2.setintro(rs.getString("intro"));
studentlist.add(s2);// 多條數據添加到集合裏
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
DbcpUtils.getJdbcUtils().close(conn, st, rs);
}
return studentlist;
}
/*----------------------------登陆使用发送sql语句安全问题----------*/
@Override
/**
* PreparedStatement比較安全,这种方式比较完善,可以判断用户名密码错误信息;通过界面比较 无需拼接,无注入漏洞;
*/
//登陆方式一
public Student login(String username, String passwrod) {
Student stu = null;
try {
conn = DbcpUtils.getJdbcUtils().getConnDb();
String sql = "select *from student2 where username=?";
PreparedStatement pst = conn.prepareStatement(sql);
pst.setString(1, username);
ResultSet rs = pst.executeQuery();
while (rs.next()) {
stu = new Student();
stu.setId(rs.getInt("id"));
stu.setUsername(rs.getString("username"));
stu.setPasswrod(rs.getString("passwrod"));
stu.setId(rs.getInt("age"));
stu.setSex(rs.getBoolean("sex"));
stu.setintro(rs.getString("intro"));
studentlist.add(stu);// 多條數據添加到集合裏
}
// 判断传入进来是否匹配数据库代码
if (stu != null && username.equals(stu.getUsername())) {
if (passwrod.equals(stu.getPasswrod())) {
System.out.println("登陆成功");
} else {
System.out.println("用户名密码错误");
}
} else {
System.out.println("用户不存在");
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
cn.jdbc.utils.DbcpUtils.getJdbcUtils().close(conn, st, rs);
}
return stu;
}
//登陆方式二
@Override
/**
* stataement拼接存在注入问题不安全;
*/
public Student login2(String username, String passwrod) {
try {
conn = DbcpUtils.getJdbcUtils().getConnDb();
st = conn.createStatement();
String sql = "select *from student2 where username='" + username + "'and passwrod='" + passwrod + "'";
System.out.println(sql);
ResultSet rs = st.executeQuery(sql);
Student s = null;
while (rs.next()) {
s = new Student();
s.setId(rs.getInt("id"));
s.setUsername(rs.getString("username"));
s.setPasswrod(rs.getString("passwrod"));
s.setId(rs.getInt("age"));
s.setSex(rs.getBoolean("sex"));
s.setintro(rs.getString("intro"));
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
DbcpUtils.getJdbcUtils().close(conn, st, rs);
}
return null;
}
}
建一个同等级下的测试类TestJdbcWork:测试crud
public class TestJdbcWork {
@Test //测试添加用户信息
public void testSave() throws Exception {
IStudentDao dao = new StudentDaoImpl();// 面向接口过程,实现类可以任意修改,但接口是固定的
for (int i = 0; i <2; i++) {
Student jk = new Student("架构师2", "666666", 18, true, "生当作人杰,死亦为鬼雄");
dao.save(jk);
}
}
@Test //测试删除功能
public void testDelete() throws Exception {
IStudentDao dao = new StudentDaoImpl();
dao.delete(28);
}
@Test //测试修改用户信息功能
public void testUpdate() throws Exception {
IStudentDao dao = new StudentDaoImpl();// 面向接口过程,实现类可以任意修改,但接口是固定的
Student s = new Student(27, "架构师大佬", "888888", 15, false, "很帅");
dao.update(s);
}
@Test //测试查询单个用户信息
public void testquery() throws Exception {
IStudentDao dao = new StudentDaoImpl();
dao.queryIdSingle(1);//查询id等于1的用户信息
}
@Test //用于测试多条用户信息
public void testqueryAll() throws Exception {
IStudentDao dao = new StudentDaoImpl();
List<Student> studentList = dao.queryIdAll();
if (studentList.size() != 0) { //判断下,加快效率
//迭代遍历出所有查询到的信息
for (Student student : studentList) {
System.out.println(student);
}
} else {
System.out.println("没有数据");
}
}
@Test //登陆方式一:可以查看用户其他信息,可以查询用户名还是密码错误
public void testlogin() throws Exception {
/**
* 安全不存在注入危险,因为它不拼接字符串
*/
IStudentDao dao = new StudentDaoImpl();
String username = "高级架构师2";
String passwrod = "000000";
Student login = dao.login(username, passwrod);
}
@Test //登陆方式二:不能清楚用户名还是密码错误,但可以查看其他信息;
public void testlogin2() throws Exception {
/**
* 存在注入危险,拼接可以'or 1=1 or'恒成立为true忽略后面附加限制
*/
IStudentDao dao = new StudentDaoImpl();
String username2 = "'or 1=1 or'";
String passwrod2 = "000000";
Student stu = dao.login2(username2, passwrod2);
if (username2 != null) {
System.out.println(stu);
System.out.println("登陆成功");
} else {
System.out.println("登录失败");
}
}
}
我封装的工具类DbcpUtils:用于加载驱动连接数据库;
首先解决的硬编码问题:创建一个资源文件-->写你自己的配置信息
配置信息
package cn.jdbc.utils;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
import org.apache.commons.dbcp.BasicDataSource;
import org.apache.commons.dbcp.BasicDataSourceFactory;
public class DbcpUtils { //单利模式:工具类不需要创建太多对象
private static DbcpUtils instance = null;
private DbcpUtils() {
}
// 用于读取资源文件
private static Properties p;
//创建一个变量用于保存连接池对象
private static BasicDataSource database;
static {//调用方法时就加载驱动
try {
p = new Properties();
// 通过当前类加载器获取资源
p.load(Thread.currentThread().getContextClassLoader().
getResourceAsStream("jdbc.properties"));
//创建一个连接池对象
database=new BasicDataSource();
//连接池对象去获取连接数据库信息
//通过BasicDataSourceFactory工厂拿到连接(内部已实现获取url、username、 password..等)
database=(BasicDataSource) BasicDataSourceFactory.createDataSource(p);
//连接池启动时的初始值
database.setInitialSize(1);
//创建对象
instance = new DbcpUtils();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//获取连接 直接从连接池里面拿
public Connection getConnDb() {
try {
return database.getConnection();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
public static DbcpUtils getJdbcUtils() {
return instance;
}
//关闭方法 用来之后,自动还给连接池
public void close(Connection conn, Statement st, ResultSet rs) {
// 关闭资源
try {
if (rs != null) {
rs.close();
}
} catch (Exception e2) {
e2.printStackTrace();
} finally {
try {
if (st != null) {
st.close();
}
} catch (Exception e3) {
e3.printStackTrace();
} finally {
try {
if (conn != null) {
conn.close();
}
} catch (Exception e3) {
e3.printStackTrace();
}
}
}
}
}
最后优化增删改类BaseDAOImpl :抽取重复代码
package cn.jdbcpractice.dao.impl;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import cn.jdbc.utils.DbcpUtils;
public class BaseDAOImpl {
Connection conn=null;
PreparedStatement pst=null;
/**
* 抽取 (增,删,改方法)
* Object ...params:各种类型字段,解决硬编码问题
* String sql:需要传入的sql执行语句
*/
public void executeUpdate(String sql,Object ...params){
try {
conn = DbcpUtils.getJdbcUtils().getConnDb();
pst = conn.prepareStatement(sql);
//传入的字段参数,长度为传入参数的长度
for(int i=1;i<=params.length;i++){
pst.setObject(i, params[i-1]);//填充值
}
pst.executeUpdate();//执行sql语句
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{//关闭资源;节约内存
DbcpUtils.getJdbcUtils().close(conn, pst, null);
}
}
}