1.首先项目分为五个层
DAO层、ENTITY层、SERVICE层、CONTROLLER层、View层
1、DAO层: 持久层 主要与数据库进行交互
DAO层主要是做数据持久层的工作,主要与数据库进行交互。
DAO层首先会创建DAO接口,接着就可以在模块中就可以调用DAO 的接口进行数据业务的而处理,并且不用关注此接口的具体实现类是哪一个类。DAO 层的数据源和数据库连接的参数都是在配置文件中进行配置的。
2、Entity层: 实体层 数据库在项目中的类
3、Service层:业务层 控制业务
Service层主要负责业务模块的逻辑应用设计。和DAO层一样都是先设计放接口的类,再创建实现的类,然后在配置文件中进行配置其实现的关联。接下来就可以在service层调用接口进行业务逻辑应用的处理。
封装Service层的业务逻辑有利于业务逻辑的独立性和重复利用性。
4、Controller层: 控制层 控制业务逻辑
Controller层负责具体的业务模块流程的控制,其实就是与前台互交,把前台传进来的参数进行处理,controller层主要调用Service层里面的接口控制具体的业务流程,控制的配置也需要在配置文件中进行。
5、View层: 此层与控制层结合比较紧密,需要二者结合起来协同工发。View层主要负责前台jsp页面的表示,
Util工具类:存放DAO、JDBC工具类
Conroller层和Service层的区别是:Controlle层负责具体的业务模块流程的控制;Service层负责业务模块的逻辑应用设计;
总结:在具体的项目中,其流程为:Controller层调用Service层的方法,Service层调用Dao层中的方法,其中调用的参数是使用Entity层进行传递的。总的来说这样每层做什么的分类只是为了使业务逻辑更加清晰,写代码更加方便,所以有时候也需要根据具体情况来,但是大体的都是这样处理的,因为它其实就是提供一种规则,让你把相同类型的代码放在一起,这样就形成了层次,从而达到分层解耦、复用、便于测试和维护的目的。
2 项目文件整体截图
3 项目代码
3.1util层工具类
JDBCUtil.java
里面用到了druid.properties配置文件来加载驱动,用数据库连接池来获取连接对象dataSource
package util;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import javax.sql.DataSource;
import java.io.IOException;
import java.sql.*;
import java.util.Properties;
/**
* JdbaUtil功能概述
* 1.程序预处理驱动问题和连接所需数据
* 2.获取数据库连接对象
* 3.关闭数据库操作所需资源
*
* @author 陈聪聪
*/
public class JdbcUtil {
/*
定义一个DataSource数据库连接池静态成员变量
*/
private static DataSource dataSource = null;
static {
try {
/*
加载druid.properties文件
*/
Properties properties = new Properties();
/*
JdbcUtil.class.getClassLoader()获取类加载器
在类加载位置检索"druid.properties"文件,创建对应文件的InputStream字节输入流对象
*/
properties.load(JdbcUtil.class.getClassLoader().getResourceAsStream("druid.properties"));
/*
DruidDataSourceFactory.createDataSource(properties)
通过DruidDataSourceFactory Druid数据库连接池工厂类,创建新的数据库连接对象
*/
dataSource = DruidDataSourceFactory.createDataSource(properties);
} catch (Exception e) {
e.printStackTrace();
}
}
/*
直接在JdbcUtil工具类中创建ComboPooledDataSource类对象,返回值类型
可以认为是DataSource 数据库连接池对象
private static DataSource dataSource = new ComboPooledDataSource();
*/
/**
* 获取Connection 数据库连接对象
*
* @return Connection 对象。如果没有获取到数据库连接对象,返回null
*/
public static Connection getConnection() {
Connection connection = null;
try {
/*
这里是通过数据库连接池获取数据库连接对象
数据库连接池中的对象在调用close方法时,会被拦截,不是真的关闭
数据库连接对象,而是规划给数据库连接池。
*/
connection = dataSource.getConnection();
} catch (SQLException e) {
e.printStackTrace();
}
return connection;
}
/**
* 获取当前JdbcUtil工具类中处理得到的数据连接对象
* @return
*/
public static DataSource getDataSource(){
return dataSource;
}
public static void close(Connection connection) {
close(connection, null, null);
}
public static void close(Connection connection, Statement statement) {
close(connection, statement, null);
}
public static void close(Connection connection, Statement statement, ResultSet resultSet) {
try {
if (resultSet != null) {
resultSet.close();
}
if (statement != null) {
statement.close();
}
if (connection != null) {
connection.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 关闭资源使用方法,需要的参数是AutoCloseable接口实现类对象,
* 不定长参数
*
* @param source AutoCloseable... 不定长参数
*/
public static void close(AutoCloseable... source) {
// 不定长参数在方法中就是一个数组!!!
for (AutoCloseable closeable : source) {
try {
closeable.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
druid.properties
# 文件名 druid.properties 存储在src目录下
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mydb2
username=root
password=root
# 初始化数据库连接池容量
initialSize=10
# 最大容量
maxActive=30
# TimeOut 等待超时时间
maxWait=2000
BaseDAO.java
里面使用了轻量级ORM框架的dbUtils的querryRunner对象调用开源query、update方法来与数据库进行交互
package util;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.*;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
public class BaseDao {
/**
* 当前BaseDao中使用的DbUtils核心类 QueryRunner对象,并且使用
* 静态成员变量处理方式在类文件加载阶段完成对象的创建过程,简化
* 后期代码逻辑
*/
private static QueryRunner queryRunner = new QueryRunner(JdbcUtil.getDataSource());
/**
* 通用查询操作方法,处理insert,delete,update 对应SQL语句
*
* @param sql String SQL语句
* @param parameters SQL语句对应的参数列表,不定长参数
* @return 当前SQL语句操作对应当前数据库的受到影响的行数
* @throws SQLException SQL异常
*/
public int update(String sql, Object... parameters) throws SQLException {
return queryRunner.update(sql, parameters);
}
/**
* 查询用户指定符合JavaBean规范的类对象。
*
* @param sql select查询语句,查询数据行结果为一行或则empty
* @param cls 用户指定查询结果对象的类对象类对象类型的Class
* @param parameters 对应当前SQL语句的参数,为不定长参数
* @param <T> 泛型约束数据类型
* @return 用户通过Class<T> cls约束的数据类型,要求符合JavaBean规范
* @throws SQLException SQL异常
*/
public <T> T queryBean(String sql, Class<T> cls, Object... parameters) throws SQLException {
return queryRunner.query(sql, new BeanHandler<>(cls), parameters);
}
/**
* 查询用户指定符合JavaBean规范的类对象List集合。
*
* @param sql select查询SQL语句
* @param cls 用户指定的数据类型,要求符合JavaBean规范
* @param parameters 对应SQL语句的参数,为不定长参数
* @param <T> 泛型约束数据类型
* @return 包含用户指定数据类型的List集合对象
* @throws SQLException SQL异常
*/
public <T> List<T> queryBeanList(String sql, Class<T> cls, Object... parameters) throws SQLException {
return queryRunner.query(sql, new BeanListHandler<>(cls), parameters);
}
/**
* 查询用户指定SQL语句对应结果集数据行的Object数组,一般用于多表查询情况下的数据处理。
*
* @param sql select查询SQL语句
* @param parameters 对应SQL语句的参数,为不定长参数
* @return 包含数据行所有数据的Object类型数组
* @throws SQLException SQL异常
*/
public Object[] queryArray(String sql, Object... parameters) throws SQLException {
return queryRunner.query(sql, new ArrayHandler(), parameters);
}
/**
* 查询用户指定SQL语句结果集所有数据行的Object数组,一般用于多表查询情况下的数据处理。
*
* @param sql select查询SQL语句,结果为多行数据
* @param parameters 对应SQL语句的参数,为不定长参数
* @return List集合中包含所有数据行对应的Object数组数据
* @throws SQLException SQL异常
*/
public List<Object[]> queryArrayList(String sql, Object... parameters) throws SQLException {
return queryRunner.query(sql, new ArrayListHandler(), parameters);
}
/**
* 查询SQL语句对应结果集数据行的Map双边队列,字段对应Key为String类型,数据对应Value为
* Object类型。
*
* @param sql select查询语句
* @param parameters 对应SQL语句的参数,为不定长参数
* @return Map<String, Object>包含所有数据行对应数据的Map双边队列
* @throws SQLException SQL异常
*/
public Map<String, Object> queryMap(String sql, Object... parameters) throws SQLException {
return queryRunner.query(sql, new MapHandler(), parameters);
}
/**
* 查询SQL语句对应结果集所有数据行的Map双边队列List集合,字段对应Key为String类型,数据对应Value为
* Object类型。每一行数据都是一个Map,所有的数据行存储在一个List集合中
*
* @param sql select查询语句
* @param parameters 对应SQL语句的参数,为不定长参数
* @return List<Map<String, Object>> List集合,包含每一行数据对应的Map双边队列
* @throws SQLException SQL异常
*/
public List<Map<String, Object>> queryMapList(String sql, Object... parameters) throws SQLException {
return queryRunner.query(sql, new MapListHandler(), parameters);
}
}
c3p0-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
<!-- 默认配置,只可以出现一次 -->
<default-config>
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/mydb2</property>
<property name="user">root</property>
<property name="password">root</property>
<!-- 连接超时设置30秒 -->
<property name="checkoutTimeout">3000</property>
<!-- 30秒检查一次connection的空闲 -->
<property name="idleConnectionTestPeriod">30</property>
<!--初始化的池大小 -->
<property name="initialPoolSize">10</property>
<!-- 最多的一个connection空闲时间 -->
<property name="maxIdleTime">30</property>
<!-- 最多可以有多少个连接connection -->
<property name="maxPoolSize">30</property>
<!-- 最少的池中有几个连接 -->
<property name="minPoolSize">10</property>
<!-- 批处理的语句
-->
<property name="maxStatements">50</property>
<!-- 每次增长几个连接 -->
<property name="acquireIncrement">3</property>
</default-config>
</c3p0-config>
3.2 Entity层
Student.java
对应数据库中表中各字段的属性
package com.cc.project.entity;
public class Student {
private int id;
private String name;
private int age;
private boolean gender;
private int score;
public Student(){
}
public Student(String name, int age, boolean gender, int score) {
}
public Student(int id, String name, int age, boolean gender, int score) {
this.id = id;
this.name = name;
this.age = age;
this.gender = gender;
this.score = score;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public boolean isGender() {
return gender;
}
public void setGender(boolean gender) {
this.gender = gender;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
", gender=" + gender +
", score=" + score +
'}';
}
}
3.2 DAO层(与数据库交互)
StudentDao.interface
接口中定义符合规范的操作数据库的方法,数据持久层
package com.cc.project.dao;
import com.cc.project.entity.Student;
import java.util.List;
/**
* StudentDao接口,是Student数据持久层接口
* 用于规范关于Student类对象操作数据库的方式方法。
*/
public interface StudentDao {
/**
* 添加学生对象到当前数据库中保存对应数据
*
* @param student Student类对象
* @return 当前SQL语句操作对应数据库的影响行数
*/
int addStudent(Student student);
/**
* 根据指定ID删除对应的Student类对象
*
* @param id 用户指定ID号
* @return 当前SQL语句操作对应数据库的影响行数
*/
int deleteStudent(int id);
/**
* 更新对应学生的数据库信息
*
* @param student Student类对象
* @return 当前SQL语句操作对应数据库的影响行数
*/
int updateStudent(Student student);
/**
* 找出对应id号的Student类对象
*
* @param id 用户指定的ID号
* @return 找到返回Student类对象,未找到返回null
*/
Student findStudent(int id);
/**
* 找出当前数据库中的所有学生对象List集合
*
* @return List集合,包含所有的Student类对象,如果当前数据库中数据行为空
* 返回null
*/
List<Student> findAll();
}
StudentDaoImpl.java
实现类继承BaseDao的方法实现StudentDao接口内定义的方法,方法内提供SQL语句
package com.cc.project.dao.impl;
import com.cc.project.dao.StudentDao;
import com.cc.project.entity.Student;
import util.BaseDao;
import java.sql.SQLException;
import java.util.List;
/**
* StudentDaoImpl 数据持久化操作的实现类
* 1. 继承BaseDao,可以使用BaseDao提供的通用方法
* 2. 遵从StudentDao接口,可以用于其他方法中使用。
*/
public class StudentDaoImpl extends BaseDao implements StudentDao {
@Override
public int addStudent(Student student) {
String sql = "insert into student(name, age, gender, score) VALUES (?,?,?,?)";
Object[] parameters = {student.getName(), student.getAge(), student.isGender(), student.getScore()};
try {
return super.update(sql, parameters);
} catch (SQLException e) {
e.printStackTrace();
}
return 0;
}
@Override
public int deleteStudent(int id) {
String sql = "delete from student where id = " + id;
try {
return super.update(sql);
} catch (SQLException e) {
e.printStackTrace();
}
return 0;
}
@Override
public int updateStudent(Student student) {
String sql = "update student set name = ?, age = ?, gender = ?, score = ? where id = ?";
Object[] parameters = {student.getName(), student.getAge(), student.isGender(), student.getScore(),
student.getId()};
try {
return super.update(sql, parameters);
} catch (SQLException e) {
e.printStackTrace();
}
return 0;
}
@Override
public Student findStudent(int id) {
String sql = "select * from student where id = " + id;
Student student = null;
try {
student = super.queryBean(sql, Student.class);
} catch (SQLException e) {
e.printStackTrace();
}
return student;
}
@Override
public List<Student> findAll() {
String sql = "select * from student";
try {
return super.queryBeanList(sql, Student.class);
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
}
3.3 Service层(调用Dao层,面向用户交互)
StudentService.interface
面向用户提供操作Student方式,增删改查
package com.cc.project.service;
import java.sql.SQLException;
/**
* 对外提供关于Student操作服务
* 1.增加学生
* 2.开除学生
* 3.查询指定id学生
* 4.修改学生信息
* 5.查询所有学生
* 6.按照指定条件过滤学生
* 7.按照指定条件排序学生
*/
public interface StudentService {
/**
* 添加学生
*/
void addStudent() ;
/**
* 开除学生
*/
void removeStudent() ;
/**
* 查询指定学生信息
*/
void findOnestudent();
/**
* 修改指定学生信息
*/
void modifyStudent() ;
/**
* 查询所有学生
*/
void findAllStudent() ;
/**
* 过滤条件展示学生信息
*/
void filterStudent() ;
/**
* 按照指定条件展示学生信息
*/
void sortStudent() ;
}
StudentServiceImpl.java
* 当前StudentServiceImpl实现类中需要操作数据库持久操作* 这里需要StudentDao实现类支持
将操作上传到数据库执行,直接调用StudentDao类的方法
package com.cc.project.service.impl;
import com.cc.project.dao.StudentDao;
import com.cc.project.dao.impl.StudentDaoImpl;
import com.cc.project.entity.Student;
import com.cc.project.service.StudentService;
import java.util.List;
import java.util.Scanner;
public class StudentServiceImpl implements StudentService {
/**
* 当前StudentServiceImpl实现类中需要操作数据库持久操作
* 这里需要StudentDao实现类支持
*/
private StudentDao studentDao = new StudentDaoImpl();
private static Scanner sc = new Scanner(System.in);
@Override
public void addStudent() {
System.out.println("请输入学生的姓名:");
String name = sc.nextLine();
System.out.println("请输入学生的年龄:");
int age = sc.nextInt();
System.out.println("请输入学生的性别:");
boolean gender = sc.nextBoolean();
System.out.println("请输入学生的成绩:");
int score = sc.nextInt();
Student student = new Student(name, age, gender, score);
studentDao.addStudent(student);
}
@Override
public void removeStudent() {
System.out.println("请输入学生的ID号");
int id = sc.nextInt();
studentDao.deleteStudent(id);
}
@Override
public void findOnestudent() {
System.out.println("请输入学生的ID号");
int id = sc.nextInt();
System.out.println(studentDao.findStudent(id));
}
@Override
public void modifyStudent() {
System.out.println("请输入要修改的学生的信息:");
System.out.println("1.修改学生的姓名:");
System.out.println("2.修改学生的年龄:");
System.out.println("3.修改学生的性别:");
System.out.println("4.修改学生的分数:");
Student student = new Student();
int choose = sc.nextInt();
switch (choose){
case 1:
String name = sc.nextLine();
break;
case 2:
int age = sc.nextInt();
break;
case 3:
String gender = sc.nextLine();
break;
case 4:
int score = sc.nextInt();
break;
}
studentDao.updateStudent(new Student());
}
@Override
public void findAllStudent() {
List<Student> list = studentDao.findAll();
if (list != null) {
for (Student stu : list) {
System.out.println(stu);
}
}
}
@Override
public void filterStudent() {
List<Student> list = studentDao.findAll();
if (list != null) {
System.out.println("1. 年龄大于20的");
System.out.println("2. 成绩小于60的");
int choose = sc.nextInt();
switch (choose) {
case 1:
list.stream()
.filter(s -> s.getAge() > 20)
.forEach(System.out::println);
break;
case 2:
list.stream()
.filter(s -> s.getScore() < 60)
.forEach(System.out::println);
break;
}
}
}
@Override
public void sortStudent() {
List<Student> list = studentDao.findAll();
if (list != null) {
System.out.println("1. 年龄升序");
System.out.println("2. 成绩降序");
int choose = sc.nextInt();
switch (choose) {
case 1:
list.stream()
.sorted((s1, s2) -> s1.getAge() - s2.getAge())
.forEach(System.out::println);
break;
case 2:
list.stream()
.sorted((s1, s2) -> s2.getScore() - s1.getScore())
.forEach(System.out::println);
break;
}
}
}
}
3.4 Controller层(调用Service层)
用Map键值对方式在前台与用户交互
StudentController.java
package com.cc.project.controller;
import com.cc.project.service.StudentService;
import com.cc.project.service.impl.StudentServiceImpl;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
public class StudentController {
private Scanner sc = new Scanner(System.in);
/**
* 提供Student范围。StudentService实现类
*/
private StudentService service = new StudentServiceImpl();
public void controller() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Map<Integer, String> methodMap = getMethodMap();
while (true) {
System.out.println("1. 添加学生 addStudent");
System.out.println("2. 开除指定学生 removeStudent");
System.out.println("3. 修改指定学生 modifyStudent");
System.out.println("4. 查询指定学生 findOneStudent");
System.out.println("5. 查询所有学生 findAllStudent");
System.out.println("6. 过滤条件展示学生信息 filterStudent");
System.out.println("7. 按照指定条件展示学生信息 sortStudent");
System.out.println("8. 退出");
int choose = sc.nextInt();
sc.nextLine();
if (8 == choose) {
break;
/*
choose不得大于8 不得小于等于0,不然无法在map双边队列中获取对应的数据
*/
} else if (choose <= 0 || choose > 8) {
continue;
}
/*
从Map中跟腱对应的choose获取对应MethodName方法名字,从StudentServiceImpl对应Class对象
中获取对应的方法Method对象,invoke执行操作
*/
StudentServiceImpl.class.getMethod(methodMap.get(choose)).invoke(service);
}
}
/**
* 预处理对应的Map方法双边队列
*
* @return Integer类型映射String方法名字的Map双边队列
*/
private Map<Integer, String> getMethodMap() {
HashMap<Integer, String> map = new HashMap<>();
map.put(1, "addStudent");
map.put(2, "removeStudent");
map.put(3, "modifyStudent");
map.put(4, "findOneStudent");
map.put(5, "findAllStudent");
map.put(6, "filterStudent");
map.put(7, "sortStudent");
return map;
}
}
3.5 MainProject(调用Controller层)
StudentSystem.java
package com.cc.project.mainproject;
import com.cc.project.controller.StudentController;
import util.MethodEnum;
import java.lang.reflect.InvocationTargetException;
public class StudentSystem {
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
new StudentController().controller();
}
}