项目从0到1(jdbc)
一、从哪几个层面入手
在我们要知道Java的项目是由三层架构组成的,具体有哪三层
1.dao层又称数据层--------------最底层的对于数据中的表中的数据进行差异化操作
2.service层又称业务层----------连接数据层与控制层,将数据层反馈回来的结果进行处理,传递给上面的控制层
3.contriller层又称控制层--------最上面的控制层通过与业务层创建连接接受业务层的返回值并进行差异化处理
二、使用步骤
具体的步骤思路
1.创建项目,导入jar包:选中jar包 右键 add as libary
2.src 下创建config包,创建jdbc.properties 属性文件
3.src 下创建util包,创建DBHelper类 (主页有一篇写SQL通用方法的文章专门有写DBHelper工具类)
创建PageHelper类------分页功能
4.src 下创建entity包,创建实体类(类名=表名,属性名=字段名 类型,数量一 一对应)
5.src 下创建dao包,创建dao层接口 ,再创建dao层实现类。
=====定义哪些方法,原子性的方法,一个方法只做一个sql处理。
6.src 下创建service包,创建service层接口,再创建service层实现类
7.src 下创建controller包,创建controller层类
8.src 下创建test包,创建Test类
数据库中表的设计模式
三.案例以及代码演示
以DVD管理系统项目为例
需要编写的代码有一下组成:
3.1 准备工作
3.1.1entity包
此包中书写了对象类,例如当前拿DVD举例,此类中写的是DVD的属性,以及get,set方法,以及构造器
注意:类名=表名,属性名=字段名 类型,数量一 一对应
这里就不过多展示了,截了张图,自行理解
3.1.2config包
这个包里创建一个.properties文件
里面书写以上内容为一会的工具类DBHelper中的获得数据库连接对象做准备
3.1.3util包
3.1.3.1DBHelper类
public class DBHelper {
//1.获得数据库连接对象
public Connection getCon(){
Connection con = null;
try{
Properties pro = new Properties();
//这里注意,如果你的config包前面没有前缀,就这样写路径,如果有前缀也要把前缀的包名加上,否则会报空指针的异常,
//例如:config包名是com.xx.config,那这里就该是con/xx/config/jdbc.properties
String str = DBHelper.class.getClassLoader().getResource("config/jdbc.properties").getPath();
FileReader fr = new FileReader(str);
pro.load(fr);
Class.forName(pro.getProperty("mysql.ClassName"));
String username = pro.getProperty("mysql.username");
String password = pro.getProperty("mysql.password");
String url = pro.getProperty("mysql.url");
con = DriverManager.getConnection(url,username,password);
} catch (SQLException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return con;
}
//2.关闭所有资源
public void closeAll(Connection con, PreparedStatement ps, ResultSet rs){
try{
if (con != null){con.close();}
if (ps != null){ps.close();}
if (rs != null){rs.close();}
} catch (SQLException e) {
e.printStackTrace();
}
}
//3.通用的增删改方法
public int update(String sql,Object...objs){
int i = 0;
Connection con = null;
PreparedStatement ps = null;
try{
con = getCon();
ps = con.prepareStatement(sql);
for (int j = 0; j < objs.length;j++){
ps.setObject(j+1,objs[j]);
}
i = ps.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}finally {
closeAll(con,ps,null);
}
return i;
}
//4.通用的查询方法
public ArrayList query(String sql,Class cla,Object...objs){
Connection con = null;
PreparedStatement ps = null;
ResultSet rs = null;
ArrayList list = new ArrayList();
try{
con = getCon();
ps = con.prepareStatement(sql);
for (int i = 0;i < objs.length;i++){
ps.setObject(i + 1,objs[i]);
}
rs = ps.executeQuery();
while (rs.next()){
Object o = cla.newInstance();
Field[] declaredFields = cla.getDeclaredFields();
for (Field f : declaredFields){
f.setAccessible(true);
f.set(o,rs.getObject(f.getName()));
}
list.add(o);
}
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}finally {
closeAll(con,ps,rs);
}
return list;
}
//5.查数据有多少条 ----> 为分页查看做准备
public int queryDataCount(String sql,Object...objs){
int count = 0;
Connection con = null;
PreparedStatement ps = null;
ResultSet rs = null;
try{
con = getCon();
ps = con.prepareStatement(sql);
for (int i = 0; i < objs.length;i++){
ps.setObject(i+1,objs[i]);
}
rs = ps.executeQuery();
if (rs.next()){
count = rs.getInt(1);
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
closeAll(con,ps,rs);
}
return count;
}
}
3.1.3.2PageHelper
/**
* 分页工具类:
* 1.查询一共有多少条数据?---sql
* 2.确定每页显示几条数据?----通过变量确定
* 3.计算一共有多少页?1%2==0?1/2:1/2+1;
* 4.确定当前是第几页?默认一开始是第一页
* 5.查询当前界面要显示的集合数据!
*/
public class PageHelper<T> {
private Integer countData;//数据的总条数
private Integer countPage;//数据的总页数
private Integer showData = 2;//每页显示多少条
private Integer indexPage = 1;//记录当前是第几页
private ArrayList<T> list;//记录当前页面显示的数据集合
public PageHelper() {
}
public PageHelper(Integer countData, Integer countPage, Integer showData, Integer indexPage, ArrayList<T> list) {
this.countData = countData;
this.countPage = countPage;
this.showData = showData;
this.indexPage = indexPage;
this.list = list;
}
public Integer getCountData() {
return countData;
}
public void setCountData(Integer countData) {
this.countData = countData;
}
public Integer getCountPage() {
countPage = this.countData % this.showData == 0?
this.countData / this.showData :
this.countData / this.showData + 1;
return countPage;
}
/*public void setCountPage(Integer countPage) {
this.countPage = countPage;路径
}*/
public Integer getShowData() {
return showData;
}
public void setShowData(Integer showData) {
this.showData = showData;
}
public Integer getIndexPage() {
return indexPage;
}
public void setIndexPage(Integer indexPage) {
this.indexPage = indexPage;
}
public ArrayList<T> getList() {
return list;
}
public void setList(ArrayList<T> list) {
this.list = list;
}
}
3.2dao层
3.2.1dao层接口
分析思路:
首先需求中有新增,删除,查看,借出,归还,分页查看几个功能
那么我们由推断得知,最底层一定会执行几个语句
新增:
insert语句,所以一定有一个抽象方法用来执行insert功能,参数列表是需要添加到表中各个列的数据,所以用一个整体传进来,只需要判断这个对象的各个属性是不是空就可以了
删除:
delete语句,所以要有一个抽象方法来执行delete语句,通过主键去删除,所以我们用了id为参数,但是我们在删除的时候一定会有个问题,结合实际,如果这张DVD不存在或者被借走了怎么办,所以我们还需要一个抽象方法把该主键对应的对象得到,所以有了另一个抽象方法,selectById,通过id获得对象,再去判断能不能删除
查看:
一定是一个select语句,所以selectDVDs,通过传入dvd对象,判断要查看的DVD,从模糊到精确,简称为动态查找。
借出/归还:
一定用到update语句,但是我们为了方便,借出去的时候状态一定被改为不可借,归还的时候一定被改为可借,所以我们把sql语句写死,逻辑上会简单一些,所以有了两个抽象方法
分页查看:
我们在PageHelper中可以自行计算总页数,首页页码,每页展示多少条都不用管了,但是在这些之前,都需要一个数据的总条数来动态的获取其他的数据,所以我们写一个方法专门查一下表里有多少条数据,查到总条数之后,我们最终目的是获取一个当前页的集合并输出,所以还需要个按照一个范围查找的方法。
至此,我们初步的底层接口全定完了。开始实现
public interface DVDDao {
int insertDVD(DVD dvd);
int deleteDVD(int id);
int updateByLendDVD(DVD dvd);
int updateByBackDVD(DVD dvd);
ArrayList<DVD> selectDVDs(DVD dvd);
DVD selectById(int id);
int selectCountData();//查数据总条数
ArrayList<DVD> selectIndexPageDate(PageHelper ph);//查询
}
3.2.2dao层实现类
public class DVDDaoImpl implements DVDDao {
DBHelper db = new DBHelper();
@Override
public int insertDVD(DVD dvd) {
String sql="insert into dvd(name,state,money,count) values(?,'可借',?,0)";
Object[] objs={dvd.getName(),dvd.getMoney()};
return db.update(sql,objs);
}
@Override
public int deleteDVD(int id) {
String sql="delete from dvd where id=?";
return db.update(sql,id);
}
@Override
public int updateByLendDVD(DVD dvd) {
String sql="update dvd set state='不可借',lendDate=?,count=count+1 where id=?";
Object[] objs={dvd.getLendDate(),dvd.getId()};
return db.update(sql,objs);
}
@Override
public int updateByBackDVD(DVD dvd) {
String sql="update dvd set state='可借',lendDate='' where id=?";
return db.update(sql,dvd.getId());
}
@Override
public ArrayList<DVD> selectDVDs(DVD dvd) {
StringBuilder sql=new StringBuilder("select * from dvd where 1=1");
ArrayList list=new ArrayList();
if(dvd.getId()!=null){
sql.append(" and id=?");
list.add(dvd.getId());
}
if(dvd.getName()!=null){
sql.append(" and name=?");
list.add(dvd.getName());
}
if(dvd.getState()!=null){
sql.append(" and state=?");
list.add(dvd.getState());
}
if(dvd.getLendDate()!=null){
sql.append(" and lendDate>=?");
list.add(dvd.getLendDate());
}
if(dvd.getMoney()!=null){
sql.append(" and money=?");
list.add(dvd.getMoney());
}
if(dvd.getCount()!=null){
sql.append(" and count=?");
list.add(dvd.getCount());
}
System.out.println(sql.toString());
return db.query(sql.toString(),DVD.class,list.toArray());
}
@Override
public DVD selectById(int id) {
String sql="select * from dvd where id=?";
ArrayList list = db.query(sql, DVD.class, id);
if(list.size()>0){
return (DVD)list.get(0);
}else{
return null;
}
}
@Override
public int selectCountData() {
String sql = "select count(*) from dvd";
return db.queryCountData(sql);
}
@Override
public ArrayList<DVD> selectIndexPageDate(PageHelper ph) {
//注意这里sql语句中的两个问号,第一个代表从下标是几开始,但不包括这个下标,第二个问号是截取的长度为几
String sql = "select * from dvd limit ?,?";
int index = (ph.getIndexPage() - 1) * ph.getShowData();
Object[] objs = {index,ph.getShowData()};
return db.query(sql,DVD.class,objs);
}
}
3.3service层
3.3.1service接口
这里只是对dao层实现类传回来的数据进行了个处理,接口还是刚才dao层里的那几种
public interface DVDService {
boolean addDVD(DVD dvd);
boolean removeDVD(int id);
boolean lendDVD(DVD dvd);
boolean backDVD(DVD dvd);
ArrayList<DVD> findDVDs(DVD dvd);
DVD findDVD(int id);
int selectCountData();//查数据总条数
ArrayList<DVD> selectIndexPageDate(PageHelper ph);//分页查询
}
3.3.2service实现类
大多数都是用三元运算符去实现,但是因为这个里面我需要处理后的结果为boolean类型,我就不需要加三元后面的?之后的部分了,但是如果返回值不是boolean需要使用三元。
public class DVDServiceImpl implements DVDService {
private DVDDao dvdDao=new DVDDaoImpl();
@Override
public boolean addDVD(DVD dvd) {
int i = dvdDao.insertDVD(dvd);
return i>0;
}
@Override
public boolean removeDVD(int id) {
return dvdDao.deleteDVD(id)>0;
}
@Override
public boolean lendDVD(DVD dvd) {
return dvdDao.updateByLendDVD(dvd)>0;
}
@Override
public boolean backDVD(DVD dvd) {
return dvdDao.updateByBackDVD(dvd)>0;
}
@Override
public ArrayList<DVD> findDVDs(DVD dvd) {
return dvdDao.selectDVDs(dvd);
}
@Override
public DVD findDVD(int id) {
return dvdDao.selectById(id);
}
@Override
public int selectCountData() {
return dvdDao.selectCountPage();
}
@Override
public ArrayList<DVD> selectIndexPageDate(PageHelper ph) {
return dvdDao.selectIndexPageDate(ph);
}
}
3.4Controller层
3.4.1Controller层实现类
public class DVDController {
private DVDService dvdService = new DVDServiceImpl();
private Scanner input = new Scanner(System.in);
//菜单
public void menu(){
System.out.println("欢迎使用迷你DVD管理系统");
System.out.println("----------------------");
System.out.println("----add.新增DVD-------");
System.out.println("----see.查看DVD-------");
System.out.println("----rel.删除DVD-------");
System.out.println("----lend.借出DVD------");
System.out.println("----ret.归还DVD-------");
System.out.println("----seepage.分页查看DVD-------");
System.out.println("----exit.退 出------");
System.out.println("----------------------");
System.out.println("请输入选择:");
String str = new Scanner(System.in).next();
try {
Class cls = DVDController.class;
Method m = cls.getMethod(str);
m.invoke(this);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
//输入0返回菜单
public void back(){
System.out.println("---输入0返回菜单---");
if (input.nextInt() == 0){
menu();
}else{
back();
}
}
//新增DVD
public void add(){
System.out.println("请输入新增DVD的名称:");
String name = input.next();
System.out.println("请输入新增DVD的日租金:");
Double money = input.nextDouble();
DVD d = new DVD();
d.setName(name);
d.setMoney(money);
if (dvdService.addDVD(d)){
System.out.println("新增《" + name + "》成功!");
}
back();
}
//查看DVD
public void see(){
DVD dvd=new DVD();
System.out.println("请输入查看DVD的编号:(输入N,不按照此条件查询)");
String id = input.next();
if (!"N".equals(id))dvd.setId(Integer.parseInt(id));
System.out.println("请输入查看DVD的名称:(输入N,不按照此条件查询)");
String name = input.next();
if (!"N".equals(name))dvd.setName(name);
System.out.println("请输入查看DVD的状态:(输入N,不按照此条件查询)");
String state = input.next();
if (!"N".equals(state))dvd.setState(state);
System.out.println("请输入查看DVD的日租金:(输入N,不按照此条件查询)");
String money = input.next();
if (!"N".equals(money))dvd.setMoney(Double.parseDouble(money));
System.out.println("请输入查看DVD的借出日期:(输入N,不按照此条件查询)");
String date = input.next();
if (!"N".equals(date))dvd.setLendDate(date);
System.out.println("请输入查看DVD的出借次数:(输入N,不按照此条件查询)");
String count = input.next();
if (!"N".equals(count))dvd.setCount(Integer.parseInt(count));
ArrayList<DVD> dvds = dvdService.findDVDs(dvd);
System.out.println("序号\t\t名字\t\t状态\t\t日租金\t\t借出日期\t\t出借次数");
for (DVD d : dvds) {
System.out.println(d.toString());
}
back();
}
//删除DVD
public void rel(){
System.out.println("请输入想要删除DVD的id:");
int id = input.nextInt();
DVD d = dvdService.findDVD(id);
if (d == null){
System.out.println("此DVD不存在!");
}else{
if ("不可借".equals(d.getState())){
System.out.println("这张DVD已被借出,不可删除");
}else{
dvdService.removeDVD(id);
System.out.println("删除成功!");
}
}
back();
}
//借出DVD
public void lend(){
System.out.println("请输入要借出DVD的id:");
int id = input.nextInt();
DVD dvd = dvdService.findDVD(id);
if (dvd == null){
System.out.println("这张DVD不存在");
}else{
if ("不可借".equals(dvd.getState())){
System.out.println("这张DVD已被借出");
}else{
System.out.println("请输入借出日期(yyyy-MM-dd):");
String date = input.next();
DVD d = new DVD();
d.setId(id);
d.setLendDate(date);
dvdService.lendDVD(d);
System.out.println("借出成功!");
}
}
back();
}
//归还DVD
public void ret() {
System.out.println("请输入要归还DVD的id:");
int id = input.nextInt();
DVD dvd = dvdService.findDVD(id);
if(dvd==null){
System.out.println("没有找到此DVD,请重试");
}else{
if(dvd.getState().equals("可借")){
System.out.println("你的这张DVD不是本店的!!!");
}else{
getZuJin(dvd);
dvdService.backDVD(dvd);
}
}
back();
}
//计算租金
public double getZuJin(DVD dvd){
long cust=0L;
System.out.println("请输入归还时间(年-月-日):");
String rDate =input.next();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date d1 = null;
Date d2 = null;
try {
d1 = sdf.parse(dvd.getLendDate());
d2 = sdf.parse(rDate);
long time1 = d1.getTime() / (1000 * 60 * 60 * 24);
long time2 = d2.getTime() / (1000 * 60 * 60 * 24);
cust= (long) ((time2 - time1) * dvd.getMoney());
System.out.println("归还成功!您此次借出产生的消费为:" + cust);
} catch (ParseException e) {
e.printStackTrace();
}
return cust;
}
PageHelper ph = new PageHelper();
//分页查看DVD
public void seepage(){
ph.setCountData(dvdService.selectCountPage());
System.out.println(ph.getIndexPage()+"/"+ph.getCountPage());
//最终目标:获得集合并遍历
System.out.println("编号\t名称\t租金\t状态\t借出日期\t借出次数");
ArrayList<DVD> dvds = dvdService.selectIndexPageDate(ph);
for(DVD dvd:dvds){
System.out.println(dvd.toString());
}
if(ph.getIndexPage()>1 && ph.getIndexPage() < ph.getCountPage()){
System.out.println("输入1下一页 输入0上一页 输入-1退出:");
int i=new Scanner(System.in).nextInt();
if(i==1){
ph.setIndexPage(ph.getIndexPage()+1);
seepage();
}else if(i==0){
ph.setIndexPage(ph.getIndexPage()-1);
seepage();
}else{
menu();
}
}
if(ph.getIndexPage()==1){
System.out.println("输入1下一页 输入-1退出:");
int i=new Scanner(System.in).nextInt();
if(i==1){
ph.setIndexPage(ph.getIndexPage()+1);
seepage();
}else{
menu();
}
}
if(ph.getIndexPage()==ph.getCountPage()){
System.out.println("输入0上一页 输入-1退出:");
int i=new Scanner(System.in).nextInt();
if(i==0){
ph.setIndexPage(ph.getIndexPage()-1);
seepage();
}else{
menu();
}
}
}
public void exit(){
System.out.println("谢谢使用!!!");
System.exit(1);
}
}
总结
以上就是以DVD阶段性项目为例,利用JDBC搭建项目的全过程源码以及思路。易错点,DBHelper,dao层实现类。