三层架构
- 三层架构
- 结构一:
- 结构二:
三层架构
三层结构解释:
视图层:主要是用于与用户进行交互,比如接收用户输入的内容将返回结果向用户展示等。
业务逻辑层:实现每个功能的特定的逻辑方法。
数据访问层:主要是与数据库进行连接,然后对数据库进行增删改查工作。
结构一:
包的层级结构:
三层结构目录架构:
命名规则为公司域名反写 eg:com.li.xxx
bean:存放JavaBean,一张表对应一个类,一个字段对应一个属性
dao:存放连接数据库及对数据库进行增删改查的操作的接口
dao.impl:存放dao接口的实现类
service:存放逻辑层的接口
service.impl:存放逻辑层的接口的实现类
view:用户交互层的接口
view.impl:用户交互层的接口的实现类
包内的实现类:
在编写代码之前先要创建一个数据库:
CREATE TABLE `student` (`Sid` int NOT NULL AUTO_INCREMENT,`Sname` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,`birthday` datetime DEFAULT NULL,`ssex` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '男',`classid` int DEFAULT NULL,PRIMARY KEY (`Sid`) USING BTREE) ENGINE=InnoDB AUTO_INCREMENT=23 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC;
以学生类为例下面是实现代码:
Student的JavaBean:
public class Student {//JavaBean实体类private int sid;private String sname;private Date birthday;private String ssex;private int classid;public Student(){}public Student(int sid,String sname,Date birthday,String ssex,int classid){this.sid = sid;this.sname = sname;this.birthday = birthday;this.ssex = ssex;this.classid = classid;}public int getSid() {return sid;}public void setSid(int sid) {this.sid = sid;}public String getSname() {return sname;}public void setSname(String sname) {this.sname = sname;}public Date getBirthday() {return birthday;}public void setBirthday(Date birthday) {this.birthday = birthday;}public String getSsex() {return ssex;}public void setSsex(String ssex) {this.ssex = ssex;}public int getClassid() {return classid;}public void setClassid(int classid) {this.classid = classid;}@Overridepublic String toString() {return "Student{" +"sid=" + sid +", sname='" + sname + '\'' +", birthday=" + birthday +", ssex='" + ssex + '\'' +", classid=" + classid +'}';}
Dao层的接口:
稍作赘述:接口的出现实际上是为了制定规则,代码编写三要素:方法名、参数、返回值类型;而在接口中定义这三个东西然后让子类实现,当某一层未开发时也不影响其他层的开发。
public interface IStudentDao {//增加public int addStudent(Student s);//删除public int deleteStudent(int sid);//修改public int updateStudent(Student s);//查询public Student findStudentBySid(int sid);//全查public List<Student> findAllStudent();}
Dao层接口的实现类:
//增加记录@Overridepublic int addStudent(Student s) {Connection conn = null;PreparedStatement presta = null;int update = 0;try {Class.forName("com.mysql.cj.jdbc.Driver");String url = "jdbc:mysql://localhost:3306/myschool" />;String user = "root";String pwd = "123456";conn = DriverManager.getConnection(url, user, pwd);String sql = "insert into student(sname,birthday,ssex,classid) values (?,?,?,?)";presta = conn.prepareStatement(sql);//presta.setObject(1,s.getSid());presta.setObject(1,s.getSname());presta.setObject(2,s.getBirthday());presta.setObject(3,s.getSsex());presta.setObject(4,s.getClassid());update = presta.executeUpdate();} catch (ClassNotFoundException e) {e.printStackTrace();} catch (SQLException throwables) {throwables.printStackTrace();}finally {if (presta != null){try {presta.close();} catch (SQLException throwables) {throwables.printStackTrace();}}if (conn != null){try {conn.close();} catch (SQLException throwables) {throwables.printStackTrace();}}}return update;}//删除记录@Overridepublic int deleteStudent(int sid) {int update= 0;PreparedStatement presta = null;Connection conn = null;try {Class.forName("com.mysql.cj.jdbc.Driver");String url = "jdbc:mysql://localhost:3306/myschool?charset=utf8mb4&useSSL=false&useTimezone=true&serverTimezone=GMT%2B8&characterEncoding=utf-8&allowPublicKeyRetrieval=true";String user = "root";String pwd = "123456";conn = DriverManager.getConnection(url, user, pwd);String sql = "delete from student where sid = ?";presta = conn.prepareStatement(sql);presta.setObject(1,sid);update = presta.executeUpdate();} catch (ClassNotFoundException e) {e.printStackTrace();} catch (SQLException throwables) {throwables.printStackTrace();}finally {if(presta != null){try {presta.close();} catch (SQLException throwables) {throwables.printStackTrace();}}if(conn != null){try {conn.close();} catch (SQLException throwables) {throwables.printStackTrace();}}}return update;}//修改记录@Overridepublic int updateStudent(Student s) {int update= 0;PreparedStatement presta = null;Connection conn = null;try {Class.forName("com.mysql.cj.jdbc.Driver");String url = "jdbc:mysql://localhost:3306/myschool?charset=utf8mb4&useSSL=false&useTimezone=true&serverTimezone=GMT%2B8&characterEncoding=utf-8&allowPublicKeyRetrieval=true";String user = "root";String pwd = "123456";conn = DriverManager.getConnection(url, user, pwd);String sql = "update student set sname = ?,birthday = ? ,ssex = ? ,classid = ?where sid = ?";presta = conn.prepareStatement(sql);presta.setObject(1,s.getSname());presta.setObject(2,s.getBirthday());presta.setObject(3,s.getSsex());presta.setObject(4,s.getClassid());presta.setObject(5,s.getSid());update = presta.executeUpdate();} catch (ClassNotFoundException e) {e.printStackTrace();} catch (SQLException throwables) {throwables.printStackTrace();}finally {if (presta != null){try {presta.close();} catch (SQLException throwables) {throwables.printStackTrace();}}if (conn != null){try {conn.close();} catch (SQLException throwables) {throwables.printStackTrace();}}}return update;}//sid查询@Overridepublic Student findStudentBySid(int sid) {Connection conn = null;Student student = null;PreparedStatement statement = null;try {Class.forName("com.mysql.cj.jdbc.Driver");String url = "jdbc:mysql://localhost:3306/myschool?charset=utf8mb4&useSSL=false&useTimezone=true&serverTimezone=GMT%2B8&characterEncoding=utf-8&allowPublicKeyRetrieval=true";String user = "root";String pwd = "123456";conn = DriverManager.getConnection(url, user, pwd);String sql = "select * from student where sid = ?";statement = conn.prepareStatement(sql);statement.setObject(1,sid);ResultSet resultSet = statement.executeQuery();if(resultSet.next()){student = new Student();student.setSid(resultSet.getInt("sid"));student.setSname(resultSet.getString("sname"));student.setBirthday(resultSet.getDate("birthday"));student.setSsex(resultSet.getString("ssex"));student.setClassid(resultSet.getInt("classid"));}} catch (ClassNotFoundException e) {e.printStackTrace();} catch (SQLException throwables) {throwables.printStackTrace();}finally {if (statement != null){try {statement.close();} catch (SQLException throwables) {throwables.printStackTrace();}}if(conn != null){try {conn.close();} catch (SQLException throwables) {throwables.printStackTrace();}}}return student;}//全查@Overridepublic List<Student> findAllStudent() {Connection conn = null;PreparedStatement statement = null;List list = new ArrayList();try {Class.forName("com.mysql.cj.jdbc.Driver");String url = "jdbc:mysql://localhost:3306/myschool?charset=utf8mb4&useSSL=false&useTimezone=true&serverTimezone=GMT%2B8&characterEncoding=utf-8&allowPublicKeyRetrieval=true";String user = "root";String pwd = "123456";conn = DriverManager.getConnection(url, user, pwd);String sql = "select * from student";statement = conn.prepareStatement(sql);ResultSet resultSet = statement.executeQuery();while (resultSet.next()){Student stu = new Student();stu.setSid(resultSet.getInt("sid"));stu.setSname(resultSet.getString("sname"));stu.setBirthday(resultSet.getDate("birthday"));stu.setSsex(resultSet.getString("ssex"));stu.setClassid(resultSet.getInt("classid"));list.add(stu);}} catch (ClassNotFoundException e) {e.printStackTrace();} catch (SQLException throwables) {throwables.printStackTrace();}finally {if (statement != null){try {statement.close();} catch (SQLException throwables) {throwables.printStackTrace();}}if(conn != null){try {conn.close();} catch (SQLException throwables) {throwables.printStackTrace();}}}return list;}
service层的接口:
public interface IStudentService {//注册(添加字段)public boolean register(Student s);//删除学生public boolean deleteStu(int sid);//修改学生信息public boolean modifyStu(Student s);//Sid查询学生public Student info(int sid);//所有学生列表public List<Student> student();}
service层的接口的实现类:
//添加学生字段@Overridepublic boolean register(Student s) {boolean isok = false;IStudentDao isd = new StudentDaoImpl();int ret = isd.addStudent(s);if (ret > 0) {isok = true;}return isok;}//删除学生字段@Overridepublic boolean deleteStu(int sid) {boolean isok = false;IStudentDao isd = new StudentDaoImpl();int ret = isd.deleteStudent(sid);if (ret > 0){isok = true;}return isok;}//修改学生字段@Overridepublic boolean modifyStu(Student s) {boolean isok = false;IStudentDao isd = new StudentDaoImpl();int i = isd.updateStudent(s);if (i > 0){isok = true;}return isok;}//Sid查学生字段@Overridepublic Student info(int sid) {IStudentDao isd = new StudentDaoImpl();Student studentBySid = isd.findStudentBySid(sid);return studentBySid;}//学生字段全查@Overridepublic List<Student> student() {IStudentDao isd = new StudentDaoImpl();List<Student> allStudent = isd.findAllStudent();return allStudent;}
View的是接口:
public interface IStudentView {//学生的注册public void showstuadd();//学生的修改public void showstumodify();//学生的全部查询public void showstuinfo();//学生的Sid查询public void showstuinfoSid();//学生的删除public void showstudelete();//学生的菜单public void showstumenu();}
View的是接口的实现类:
//学生的注册(添加字段)@Overridepublic void showstuadd() {SimpleDateFormat format = new SimpleDateFormat();Scanner input= new Scanner(System.in);System.out.println("添加学生:");System.out.println("请输入学生姓名");String sname = input.next();System.out.println("请输入学生生日");String bir = input.next();System.out.println("请输入学生性别");String sex = input.next();System.out.println("请输入学生班级");int classid = input.nextInt();Student stu = new Student();stu.setSname(sname);try {stu.setBirthday(format.parse(bir));} catch (ParseException e) {stu.setBirthday(new Date());}stu.setSsex(sex);stu.setClassid(classid);IStudentService iss = new StudentServiceImpI();boolean register = iss.register(stu);if (register){System.out.println("插入成功");}else{System.out.println("插入失败");}}//学生的修改@Overridepublic void showstumodify() {SimpleDateFormat format = new SimpleDateFormat();Scanner input= new Scanner(System.in);System.out.println("修改学生信息:");System.out.println("请输入需要修改的学生编号");int sid = input.nextInt();System.out.println("请输入学生新姓名");String sname = input.next();System.out.println("请输入学生新生日");String bir = input.next();System.out.println("请输入学生新性别");String sex = input.next();System.out.println("请输入学生新班级");int classid = input.nextInt();Student stu = new Student();stu.setSname(sname);try {stu.setBirthday(format.parse(bir));} catch (ParseException e) {stu.setBirthday(new Date());}stu.setSsex(sex);stu.setClassid(classid);stu.setSid(sid);IStudentService iss = new StudentServiceImpI();boolean register = iss.modifyStu(stu);if (register){System.out.println("修改成功");}else{System.out.println("修改失败");}}//学生的全部查询@Overridepublic void showstuinfo() {IStudentService iss = new StudentServiceImpI();List<Student> list = iss.student();list.forEach(System.out::println);}//学生的Sid查询@Overridepublic void showstuinfoSid() {Scanner scan = new Scanner(System.in);System.out.println("请输入需要查询的ID:");int i = scan.nextInt();IStudentService iss = new StudentServiceImpI();Student info = iss.info(i);System.out.println(info);}//学生的删除@Overridepublic void showstudelete() {Scanner scan = new Scanner(System.in);System.out.println("请输入要删除学生的ID:");int anInt = scan.nextInt();IStudentService iss = new StudentServiceImpI();boolean deleteStu = iss.deleteStu(anInt);if (deleteStu){System.out.println("删除成功!");}else{System.out.println("删除失败!");}}//学生的菜单@Overridepublic void showstumenu() {Scanner input = new Scanner(System.in);System.out.println("欢迎使用校园系统--学生模块管理");int key = -1;do {System.out.println("输入:\n1.添加学生\n2.根据ID查看信息\n3.查看所有学生\n4.修改学生\n5.开除学生\n0.退出程序");System.out.println("请输入:");if(input.hasNextInt()) {key = input.nextInt();switch(key) {case 1:{showstuadd();}break;case 2:{showstuinfoSid();}break;case 3:{showstuinfo();}break;case 4:{showstumodify();}break;case 5:{showstudelete();}break;default:System.out.println("请输入正确的序号");break;}}else {System.out.println("请输入菜单中的序号,否则打死你");input.next();}}while(key != 0);System.out.println("感谢使用");}
测试类:
public static void main(String[] args) { IStudentView isv = new IStudentViewImpI(); isv.showstumenu();}
结构二:
结构一中,在DAO层中频繁的进行数据连接创建访问对象等,结构复杂,代码重复率高,因此结构二中对DAO层进行了抽象。
创建DaoUtil类:将加载驱动,获取连接,流的释放进行抽象。
public class DaoUtil {//加载驱动//驱动的加载只需加载一次,因此使用静态代码块,当加载此类时,会随着类的加载而加载一次static {try {Class.forName("com.mysql.cj.jdbc.Driver");} catch (ClassNotFoundException e) {e.printStackTrace();}}//获取连接public static Connection getConn(){Connection conn = null;try {String url = "jdbc:mysql://localhost:3306/myschool?charset=utf8mb4&useSSL=false&useTimezone=true&serverTimezone=GMT%2B8&characterEncoding=utf-8&allowPublicKeyRetrieval=true";String user = "root";String pwd = "123456";conn = DriverManager.getConnection(url, user, pwd);} catch (SQLException throwables) {throwables.printStackTrace();}return conn;}//关闭连接public static void closeResource(Connection conn, PreparedStatement prep, ResultSet res){if (res != null){try {res.close();} catch (SQLException throwables) {throwables.printStackTrace();}}if (prep != null){try {prep.close();} catch (SQLException throwables) {throwables.printStackTrace();}}if (conn != null){try {conn.close();} catch (SQLException throwables) {throwables.printStackTrace();}}}}
创建BaseDao:用来存放增删改和查的方法;这里需要注意的是,增删改操作时返回值是int的整数值,表示数据库中的受影响的行数。而查询操作返回的是ResultSet类型的结果,因此需要分开进行写。
public class BaseDao {protected Connection conn;protected PreparedStatement prepstat;protected ResultSet rs;//增删改protected int update(String sql,Object...args){int ret = 0;try {conn = DaoUtil.getConn();prepstat = conn.prepareStatement(sql);if (args != null) {for (int i = 0; i < args.length; i++) {prepstat.setObject(i + 1,args[i]);}}ret = prepstat.executeUpdate();} catch (SQLException throwables) {throwables.printStackTrace();}finally {DaoUtil.closeResource(conn, prepstat, rs);}return ret;}//查询protected ResultSet query(String sql,Object...args){ResultSet rs = null;try {conn = DaoUtil.getConn();prepstat = conn.prepareStatement(sql);if (args != null){for (int i = 0; i < args.length; i++) {prepstat.setObject(i + 1,args[i]);}}rs = prepstat.executeQuery();} catch (SQLException throwables) {throwables.printStackTrace();}return rs;}}
抽象后的实现类如下:
public class StudentDaoImpl extends BaseDao implements IStudentDao {//增加记录@Overridepublic int addStudent(Student s) {String sql = "insert into student(sname,birthday,ssex,classid) values (?,?,?,?)";return update(sql,s.getSname(),s.getBirthday(),s.getSsex(),s.getClass());}//删除记录@Overridepublic int deleteStudent(int sid) {String sql = "delete from student where sid = ?";return update(sql,sid);}//修改记录@Overridepublic int updateStudent(Student s) {String sql = "update student set sname = ?,birthday = ? ,ssex = ? ,classid = ?where sid = ?";return update(sql,s.getSname(),s.getBirthday(),s.getSsex(),s.getClassid(),s.getSid());}//sid查询@Overridepublic Student findStudentBySid(int sid) {Student s = null;SimpleDateFormat format = new SimpleDateFormat();try {String sql = "select * from student where sid = ?";rs = query(sql, sid);if (rs.next()) {s = new Student();s.setSid(rs.getInt("sid"));s.setSname(rs.getString("sname"));try {s.setBirthday(format.parse(rs.getString("birthday")));} catch (ParseException e) {e.printStackTrace();}s.setSsex(rs.getString("ssex"));s.setClassid(rs.getInt("classid"));s.setSid(rs.getInt("sid"));}} catch (SQLException throwables) {throwables.printStackTrace();}finally {DaoUtil.closeResource(conn, prepstat, rs);}return s;}//全查@Overridepublic List<Student> findAllStudent() {Student s = null;List list = new ArrayList();SimpleDateFormat format = new SimpleDateFormat();try {String sql = "select * from student where sid = ?";rs = query(sql);if (rs.next()) {s = new Student();s.setSid(rs.getInt("sid"));s.setSname(rs.getString("sname"));try {s.setBirthday(format.parse(rs.getString("birthday")));} catch (ParseException e) {e.printStackTrace();}s.setSsex(rs.getString("ssex"));s.setClassid(rs.getInt("classid"));s.setSid(rs.getInt("sid"));list.add(s);}} catch (SQLException throwables) {throwables.printStackTrace();}finally {DaoUtil.closeResource(conn, prepstat, rs);}return list;}}
不同的分法可能会略微有所区别,划分程度不同,划分的层级可能也不同,但本质思想不变,将代码功能模块化,实现高内聚低耦合,例如Dao用来做数据库连接等操作,就尽量只需调方法传参就能执行即可,不要在执行的过程中还需要其他层数据的介入,主要也是为了开发的高效性,同时便于对代码进行测试。