目录
一.工具类的封装
//问题: 每次进行CRUD操作,都要写一套JDBC,很繁琐
//解决方案:将重复的操作,抽取到工具类中封装
//1.加载驱动只需要一次---放到静态代码块
//问题2: 直接在工具类中将数据库驱动,数据库名,用户名,密码写死了,不方便后续变更---硬编码
//解决方案:需要变为软编码形式,使程序更灵活,维护性更强
public class LoginTest {
public static void main(String[] args) {
System.out.println("请输入用户名");
Scanner sc = new Scanner(System.in);
String username = sc.nextLine(); //获取一行内容
System.out.println("请输入密码");
String password = sc.nextLine();
if(login2(username,password)){ //登录功能
System.out.println("登录成功~!");
}else{
System.out.println("登录失败~!");
}
}
private static boolean login2(String username, String password) {
Connection conn = null;
PreparedStatement prst = null;
ResultSet rs = null;
try {
conn = DBUtils.getConnection();
prst = conn.prepareStatement("select count(*) from user where username=? and password=?");
//参数1:对应第一个占位符? 下标从1开始
prst.setString(1,username);
prst.setString(2,password);
//获取结果集
//sql注入的隐患
rs = prst.executeQuery();
if(rs.next()){
int result = rs.getInt(1); //聚合函数只有一个字段
return result>0; //result不小于0,则返回true
}
} catch (Exception e) {
e.printStackTrace();
} finally {
DBUtils.closeAll(rs,prst,conn);
}
return false;
}
private static boolean login(String username, String password) {
Connection conn = null;
Statement st = null;
ResultSet rs = null;
try {
conn = DBUtils.getConnection();
st = conn.createStatement();
//获取结果集
//sql注入的隐患
String sql = "select count(*) from user where username='"+username+"' and password='"+password+"'";
rs = st.executeQuery(sql);
if(rs.next()){
int result = rs.getInt(1); //聚合函数只有一个字段
return result>0; //result不小于0,则返回true
}
} catch (Exception e) {
e.printStackTrace();
} finally {
DBUtils.closeAll(rs,st,conn);
}
return false;
}
}
public class DBUtils {
private static Properties p = new Properties();
//静态代码块:只加载一次
static{
//反射对象调用getResourceAsStream
//从src目录下获取到db.properties的资源
try {
InputStream is = DBUtils.class.getResourceAsStream("/db.properties");
p.load(is);
Class.forName(p.getProperty("driver"));
} catch (Exception e) {
e.printStackTrace();
}
}
public static Connection getConnection(){
Connection conn = null;
try {
conn = DriverManager.getConnection(p.getProperty("url"), p.getProperty("username"), p.getProperty("password"));
} catch (SQLException e) {
e.printStackTrace();
}
return conn;
}
public static void closeAll(AutoCloseable...cs){
for(AutoCloseable c : cs){
if(c!=null){
try {
c.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
配置文件的抽取
driver=com.mysql.jdbc.Driver
url=jdbc:mysql:///mydb1
username=root
password=123
二.ORM
对象关系映射:对象-实体类(不放main方法的类),关系-数据表,两者数据的转换
简单地说,就是从数据表中取出数据后,存储到实体类中
//案例:获取岗位表的信息,存储到实体类中
//创建一个实体类与关系表对应: 对象属性=表字段
//将数据表中零散的字段值,封装到实体类中,方便操作
@Data //生成set/get及toString
@NoArgsConstructor //生成无参构造
@AllArgsConstructor //生成全参构造
class Jobs{
private String job_id;
private String job_title;
private String min_salary;
private String max_salary;
}
public class Test1 {
public static void main(String[] args) throws SQLException {
Connection conn = DBUtils.getConnection();
PreparedStatement prst = conn.prepareStatement("select * from t_jobs");
ResultSet rs = prst.executeQuery();
while(rs.next()){
String job_id = rs.getString("job_id");
String job_title = rs.getString("job_title");
String min_salary = rs.getString("min_salary");
String max_salary = rs.getString("max_salary");
Jobs jobs = new Jobs(job_id,job_title,min_salary,max_salary);
System.out.println(jobs); //对象关系映射:将表字段内容存到实体属性中
}
DBUtils.closeAll(rs,prst,conn);
}
}
三.Dao层的抽取
Dao层:数据访问层,用于做与数据库交互的事情
如果不将dao层抽取,例如登录功能,所有代码都放到测试类中,使得测试类代码特别臃肿
抽取后代码分离设计:
main方法中做业务逻辑操作; dao层只做jdbc操作
案例: Person数据表的增删改查操作
/*
#### 创建数据表
> - 创建一张表 Person,有以下列:
> - id:int,主键,自动增长
> - name:varchar(20) 非空
> - age:int 非空
> - bornDate:Date
> - email:字符串
> - address:字符串
*/
//在测试类中,进行业务逻辑操作
//操作步骤:
//1.创建数据表
//2.新建实体类
//3.编写工具类
//4.将jdbc抽象到dao层
//5.在测试类中编写业务逻辑
------------创建实体类------------
//实体类中的属性要与表字段一致--ORM
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Person {
private int id;
private String name;
private int age;
private Date bornDate;
private String email;
private String address;
}
------------创建测试类------------
public class Test1 {
public static void main(String[] args) {
System.out.println("请输入你要进行的操作:1.添加 2.修改 3 删除 4 查所有 5.根据id查");
PersonDaoImpl personDao = new PersonDaoImpl();
Scanner sc = new Scanner(System.in);
int num = sc.nextInt();
switch (num){
case 1: //添加传对象,一般主键自增长,id不用管
int result = personDao.insert(new Person(0,"ls",20,new Date(),"ls@163.com","湖北"));
System.out.println("插入:"+result);
break;
case 2: //修改传对象,要有修改的主键id,才能修改
result = personDao.update(new Person(2,"ww",44,new Date(),"ww@163.com","江西"));
System.out.println("修改:"+result);
break;
case 3:
result = personDao.delete(1); //删除id
System.out.println("删除:"+result);
break;
case 4: //查询所有,返回List集合
List<Person> list = personDao.selectAll();
System.out.println("查所有:"+list);
break;
case 5: //查询单个,往往根据id查,返回实体对象
Person person = personDao.selectById(2);
System.out.println("查对象:"+person);
break;
default:
System.out.println("您的输入有误~");
break;
}
}
}
------------创建dao层操作------------
//dao层--数据访问层(用于做jdbc操作)
public class PersonDaoImpl {
public int insert(Person person) {
Connection conn = null;
PreparedStatement prst = null;
try {
conn = DBUtils.getConnection();
prst = conn.prepareStatement("insert into person(name,age,bornDate,email,address) values(?,?,?,?,?)");
prst.setString(1,person.getName());
prst.setInt(2,person.getAge());
//sql包下的new Date(参数)可以long类型的毫秒值参数
prst.setDate(3,new Date(person.getBornDate().getTime()));
prst.setString(4,person.getEmail());
prst.setString(5,person.getAddress());
return prst.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
} finally {
DBUtils.closeAll(prst,conn);
}
return 0;
}
public int update(Person person) {
Connection conn = null;
PreparedStatement prst = null;
try {
conn = DBUtils.getConnection();
prst = conn.prepareStatement("update person set name=?,age=? where id=?");
prst.setString(1,person.getName());
prst.setInt(2,person.getAge());
prst.setInt(3,person.getId());
return prst.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
} finally {
DBUtils.closeAll(prst,conn);
}
return 0;
}
public int delete(int id) {
Connection conn = null;
PreparedStatement prst = null;
try {
conn = DBUtils.getConnection();
prst = conn.prepareStatement("delete from person where id=?");
prst.setInt(1,id);
return prst.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
} finally {
DBUtils.closeAll(prst,conn);
}
return 0;
}
public Person selectById(int id) {
Connection conn = null;
PreparedStatement prst = null;
ResultSet rs = null;
try {
conn = DBUtils.getConnection();
prst = conn.prepareStatement("select * from person where id=?");
prst.setInt(1,id);
rs = prst.executeQuery();
if(rs.next()){
String name = rs.getString("name");
int age = rs.getInt("age");
Date bornDate = rs.getDate("bornDate");
String email = rs.getString("email");
String address = rs.getString("address");
return new Person(id,name,age,bornDate,email,address);
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
DBUtils.closeAll(rs,prst,conn);
}
return null;
}
public List<Person> selectAll() {
Connection conn = null;
PreparedStatement prst = null;
ResultSet rs = null;
List<Person> list = new ArrayList<>();
try {
conn = DBUtils.getConnection();
prst = conn.prepareStatement("select * from person");
rs = prst.executeQuery();
while(rs.next()){
int id = rs.getInt("id");
String name = rs.getString("name");
int age = rs.getInt("age");
Date bornDate = rs.getDate("bornDate");
String email = rs.getString("email");
String address = rs.getString("address");
list.add(new Person(id,name,age,bornDate,email,address));
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
DBUtils.closeAll(rs,prst,conn);
}
return list;
}
}
四.DateUtils
日期工具类
在项目中,针对日期类可能需要相互转化
例如:String转Date,Date转String,Utils的Date转SQL的Date
//日期类的转换方法:
public class DateUtils {
private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
public static Date utilToSQL(java.util.Date date){
return new Date(date.getTime());
}
public static String utilToString(java.util.Date date){
return sdf.format(date);
}
public static java.util.Date stringToUtil(String strDate){
try {
return sdf.parse(strDate);
} catch (ParseException e) {
e.printStackTrace();
}
return null;
}
}
五.Service业务层
用于进行业务逻辑分析,一个业务功能可以包含一个或多个dao操作
例如:转账业务-->细化分析
一个业务-->多个dao,判断发送方账户,接收方账户正确性,钱是否足够
最后才能做转账功能--一个账户加钱,另一个用户减钱
以上都是业务分析范畴
案例:转账业务功能分解
/*
* 创建一张表account,有以下列:
- id:int,主键,自动增长
- cart :varchar(40) 非空
- password : 字符串
- money :double(8,2)
* */
//操作步骤:
//1.创建数据表,插入两条数据
//2.创建实体类Account
//3.创建DBUtils数据库工具类
//4.创建业务层,进行转账业务分析
//5.具体与数据库交互,交给dao层
//6.在测试类中进行测试
---------创建实体类---------
//创建实体类
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Account {
private int id;
private String card;
private String password;
private double money;
}
----------业务逻辑分析-----------
//转账业务类
public class AccountServiceImpl {
private AccountDaoImpl accountDao = new AccountDaoImpl();
//转账的业务功能
public String tansfer(String sendCard,double money,String recvCard,String password){
//1.根据发送方账户,获取对象,如果没有则报异常
Account sendAccount = accountDao.selectCard(sendCard);
if(sendAccount==null){
throw new RuntimeException("发送方账户不存在!");
}
//2.如果有,拿到了对象,看看密码是否正确,金额够不够
if(!password.equals(sendAccount.getPassword())){
throw new RuntimeException("密码错误");
}
if(sendAccount.getMoney()<money){
throw new RuntimeException("余额不足");
}
//3.判断接收方账户是否存在,如果不存在,则报异常
Account recvAccount = accountDao.selectCard(recvCard);
if(recvAccount==null){
throw new RuntimeException("接收方账户不存在");
}
//4.进行转账-->发送方减钱(update),接收方加钱(update)
sendAccount.setMoney(sendAccount.getMoney()-money);
int result = accountDao.update(sendAccount);
System.out.println("发送方修改:"+result);
recvAccount.setMoney(recvAccount.getMoney()+money);
result = accountDao.update(recvAccount);
System.out.println("发送方修改:"+result);
return "转账成功~~!";
}
}
----------数据访问层----------
public class AccountDaoImpl {
public Account selectCard(String card) {
Connection conn = null;
PreparedStatement prst = null;
ResultSet rs = null;
try {
conn = DBUtils.getConnection();
prst = conn.prepareStatement("select * from account where card=?");
prst.setString(1,card);
rs = prst.executeQuery();
if(rs.next()){
int id = rs.getInt("id");
String password = rs.getString("password");
double money = rs.getDouble("money");
return new Account(id,card,password,money);
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
DBUtils.closeAll(rs,prst,conn);
}
return null;
}
public int update(Account recvAccount) {
Connection conn = null;
PreparedStatement prst = null;
try {
conn = DBUtils.getConnection();
prst = conn.prepareStatement("update account set money=? where id=?");
prst.setDouble(1,recvAccount.getMoney());
prst.setInt(2,recvAccount.getId());
return prst.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}finally {
DBUtils.closeAll(prst,conn);
}
return 0;
}
}
-------------测试类-------------
public class Test1 {
public static void main(String[] args) {
AccountServiceImpl accountService = new AccountServiceImpl();
String res = accountService.tansfer("10010",1000,"10086","123");
System.out.println(res);
}
}
(=-=,JDBC的漫漫长路,应用层,业务层,表示层,代码量正在不断加大,有时候手速慢了还敲不赢,很充实,小白这里相信现在敲得每一行代码,都是通往成功路上的地砖,敲得越多,离成功越近,希望每个初学者都可以保持初心,嗯敲就完事了!)