1.JavaBean是什么?
当一个POJO可序列化,有一个无参的构造函数,使用get和set方法来访问属性时,他就是一个JavaBean。
2.JavaWeb项目。
一个简单的Web项目,它的框架大概分为领域对象层pojo、数据链路层Dao、业务层Service和ServiceImpl、控制层Servlet、以及Jsp。下边简单说一下pojo、Dao、Service和ServiceImpl的浅含义。
- Pojo:刚开始我的理解是pojo其实就是JavaBean,但是实际上不是的。pojo具备业务逻辑的处理能力,只是存在private修饰的属性和set和get访问属性的方法,它不能理解为JavaBean,并且它不能继承父类以及不能实现接口。但是呢,当外界调用pojo时,给予了pojo的JavaBean规则,那么它就成为JavaBean了。
- Dao:1.封装数据库的的增删查改操作。2.接收业务层接口实现的数据,将pojo转换为po。
- Po:将对象与关系数据库进行绑定,用对象来表示关系数据库的数据。
- Service:理解为业务层的接口。
- ServiceImpl:单词字面上看意为业务层接口的实现。
3.一个简单的JavaWeb项目。
首先,先在数据库创建表并且载入数据,然后通过项目分层以及代码实现,最终获取想要的数据,下边我以我的数据库作为项目数据。这个项目最终我要实现的业务是ID查询和姓名查询。
3.1领域对象层pojo:pojo的含义前边也说过了,按数据库的数据来说,我们需要在pojo里边创建字段,也就是属性的private。以及set和get方法来访问字段。
package com.pojo;//领域对象层
public class Employee {
//字段或属性
private String id;
private String username;
private double salary;
private int age;
private String depart;
//无参构造
public Employee() {
// TODO Auto-generated constructor stub
}
//set和get方法访问属性
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getDepart() {
return depart;
}
public void setDepart(String depart) {
this.depart = depart;
}
//toString方法
@Override
public String toString() {
return "Employee [id=" + id + ", username=" + username + ", salary=" + salary + ", age=" + age + ", depart="
+ depart + "]";
}
}
3.2工具类Utils:上一篇文章我将JDBC的部分代码已经封装好了,现在添入查找的功能。在数据库中,我们查找的要么是一个对象,要么是多个对象。所以这里的查找封装,我们需要使用到单条查询或者多条查询。
3.2.1单条查询封装:首先我们单条查询要获得的是一个对象,那么我们需要使用到的是Object,就以ID查询来说,一般而言ID是一个指定的字段,不会存在重复的ID,那么也就是说ID查询获得的结果是单个对象。当我们连接数据库并且获得Resultset对象后,需要获取Resultset对象里边的数据,进而按照项目分层来说,我们下一步到达数据链路层Dao进而获取到Resultset对象里边的数据。
public Object queryByOne(String sql){
Object obj = null;
try {
conn = getConnection(); //获取连接对象
st = conn.createStatement(); //获取statement对象
ResultSet rs = st.executeQuery(sql); //sql语句查询后获取的Resultset对象
obj = rsToObj(rs); //跳转到数据链路层解释Resultset对象数据
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
jdbcClose(conn, st); //资源释放
}
return obj;
}
3.2.2多条查询封装:按照事先的业务需求,当我们使用姓名来进行查询时。一般而言,姓名是会出现重复的,也就是说,使用姓名查询获得的对象数据它会有可能是多条的,所以我们需要使用到List链表类型。那么我们进行多条查询的封装,大概的步骤和单条查询一致,只要获取到的对象数据不一致。同样的,最终获取到的Resultset对象我们需要转移到数据链路层Dao将里边的对象数据获取出来。
public List queryByAll(String sql){
List list = null;
try {
conn = getConnection(); //获取连接对象
st = conn.createStatement(); //获取statement对象
ResultSet rs = st.executeQuery(sql); //sql语句查询
list = rsToList(rs); //解释Resultset对象的数据进而获取
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
jdbcClose(conn, st); //释放创建的对象资源
}
return list;
}
3.2.3工具类Utils代码
package com.utils;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;
public abstract class JDBCUtils {
private String driver = "com.mysql.jdbc.Driver";
private static String url = "jdbc:mysql://localhost:3306/demo";
private static String username = "root";
private static String password = "113846";
private Connection conn = null;
private Statement st = null;
private ResultSet rs = null;
//因为加载驱动这件事情 在程序启动的时候就被加载且只执行一次
static{
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* 获取连接对象
* @return
* @throws SQLException
*/
public static Connection getConnection() throws SQLException{
return DriverManager.getConnection(url, username,password);
}
/**
* 添加,修改,删除
*/
public void update(String sql){
try {
conn = getConnection();
st = conn.createStatement();
int bRet = st.executeUpdate(sql); //语句更新的方法
if(bRet>0){
System.out.println("数据更新成功,更新记录数:"+bRet+"条");
}else{
System.out.println("数据更新失败,更新记录数:"+bRet+"条");
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
jdbcClose(conn, st);
}
}
/**
* 多条记录的查询 List ArrayList
*/
public List queryByAll(String sql){
List list = null;
try {
conn = getConnection(); //获取连接对象
st = conn.createStatement(); //获取statement对象
ResultSet rs = st.executeQuery(sql); //sql语句查询
list = rsToList(rs); //解释Resultset对象的数据进而获取
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
jdbcClose(conn, st); //释放创建的对象资源
}
return list;
}
/**
* 单条记录的查询 Object
*/
public Object queryByOne(String sql){
Object obj = null;
try {
conn = getConnection(); //获取连接对象
st = conn.createStatement(); //获取statement对象
ResultSet rs = st.executeQuery(sql); //sql语句查询后获取的Resultset对象
obj = rsToObj(rs); //跳转到数据链路层解释Resultset对象数据
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
jdbcClose(conn, st); //资源释放
}
return obj;
}
/**
* 释放资源 connection、statement、Resultset对象
* mysql的连接资源 比较珍稀的资源
* 尽晚的获取连接,尽早释放资源
* @param conn
* @param st
* @param rs
*/
public static void jdbcClose(Connection conn,Statement st,ResultSet rs){
try {
rs.close();
if(rs != null){
rs = null;
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
try {
st.close();
if(st!=null){
st = null;
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
try {
conn.close();
if(conn!=null){
conn = null;
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
//释放资源 connection、statement对象
public static void jdbcClose(Connection conn,Statement st){
try {
st.close();
if(st!=null){
st = null;
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
try {
conn.close();
if(conn!=null){
conn = null;
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
//因为这是一个工具类,当我们需要查询的表字段不一时候,我们每次需要操作的属性也就不一样,所以查询Resultset对象数据获取定义为抽象方法
public abstract Object rsToObj(ResultSet rs);
public abstract List rsToList(ResultSet rs);
}
3.3数据链路层Dao:这一层是为了解析提取Resultset对象的数据,所以继承工具类Utils从而实现定义的抽象方法rsToObj(单条查询数据获取)、rsToList(多条查询数据获取)。
3.3.1rsToObj(单条查询数据获取):实现这一抽象方法,领域对象层pojo已经创立好了,这时候我们需要的是将获取的Resultset对象数据进行解析,解析提取后的数据形成一个对象(也就是pojo包层创建的类Employee),之后将这一个对象返回。
public Object rsToObj(ResultSet rs) {
Object obj = null;
try {
Employee emp = new Employee(); //创建一个对象变量
if(rs.next()){ //不为空,意思是还有数据
emp.setId(rs.getString("id")); //获取字段id数据
emp.setUsername(rs.getString("username"));//获取字段username数据
emp.setSalary(rs.getDouble("salary")); //获取字段salary数据
emp.setAge(rs.getInt("age")); //获取字段age数据
emp.setDepart(rs.getString("depart")); //获取字段depart数据
obj = emp; //获取的数据导入了创建的对象emp中
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return obj;
}
3.3.2rsToList(多条查询数据获取):实现这一抽象方法,领域对象层pojo已经创立好了,这时候我们需要的是将获取的Resultset对象数据进行解析,与单条查询不同的是,解析的对象不止一个,也就是Resultset对象中每一个对象数据提取完后到达下一个对象,直到下一个对象数据为空停止。每一次Resultset对象中的对象解析的数据形成一个对象(也就是pojo包层创建的类Employee),然后将形成的对象放入链表List中,最后将链表返回。
public List rsToList(ResultSet rs) {
List list = new ArrayList();
try {
Employee emp = new Employee(); //创建一个对象变量
while(rs.next()){ //不为空,意思是还有数据
emp.setId(rs.getString("id")); //获取字段id数据
emp.setUsername(rs.getString("username"));//获取字段username数据
emp.setSalary(rs.getDouble("salary")); //获取字段salary数据
emp.setAge(rs.getInt("age")); //获取字段age数据
emp.setDepart(rs.getString("depart")); //获取字段depart数据
list.add(emp); //获取的数据导入了创建的对象emp中,然后将对象emp放入链表
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return list;
}
3.3.3数据链路层代码:
package com.openlab.dao;//数据链路层
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import com.pojo.Employee;
import com.utils.JDBCUtils;
public class EmployeeServcieDao extends JDBCUtils{
@Override
public Object rsToObj(ResultSet rs) {
Object obj = null;
try {
Employee emp = new Employee(); //创建一个对象变量
if(rs.next()){ //不为空,意思是还有数据
emp.setId(rs.getString("id")); //获取字段id数据
emp.setUsername(rs.getString("username"));//获取字段username数据
emp.setSalary(rs.getDouble("salary")); //获取字段salary数据
emp.setAge(rs.getInt("age")); //获取字段age数据
emp.setDepart(rs.getString("depart")); //获取字段depart数据
obj = emp; //获取的数据导入了创建的对象emp中
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return obj;
}
@Override
public List rsToList(ResultSet rs) {
List list = new ArrayList();
try {
Employee emp = new Employee(); //创建一个对象变量
while(rs.next()){ //不为空,意思是还有数据
emp.setId(rs.getString("id")); //获取字段id数据
emp.setUsername(rs.getString("username"));//获取字段username数据
emp.setSalary(rs.getDouble("salary")); //获取字段salary数据
emp.setAge(rs.getInt("age")); //获取字段age数据
emp.setDepart(rs.getString("depart")); //获取字段depart数据
list.add(emp); //获取的数据导入了创建的对象emp中,然后将对象emp放入链表
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return list;
}
}
3.4业务层Service:前边已经说了,业务需求是ID查询和姓名查询,所以这一层要创建一个接口来包含两个查询方法。
package com.service;// 业务层接口
import java.util.List;
import com.pojo.Employee;
public interface EmployeeService {
public Employee queryById(String id); //ID查询获取的是单个对象数据
public List queryByUserName(String username); //姓名查询获取的是多个对象数据
}
3.5业务层ServiceImpl:对业务层Service接口的实现。
package com.service.impl; //业务层接口实现
import java.util.List;
import com.dao.EmployeeServcieDao;
import com.pojo.Employee;
import com.service.EmployeeService;
public class EmployeeServiceImpl implements EmployeeService{
EmployeeServcieDao edao = new EmployeeServcieDao(); //创建链路数据层对象edao
//ID查询
@Override
public Employee queryById(String id) {
String sql = "select * from user where id='"+id+"'"; //user:我的表名
Object obj = edao.queryByOne(sql); //子类对象调用父类方法
Employee em =(Employee) obj; //Utils中的方法返回类型是Objec,强转
return em;
}
//姓名查询
@Override
public List queryByUserName(String username) {
String sql ="select * from user where username='"+username+"'";
List list = edao.queryByAll(sql); //子类对象调用父类方法
return list;
}
}
3.7测试类:ID查询、姓名查询测试。
package com.test;
import java.util.List;
import org.junit.Test;
import com.pojo.Employee;
import com.service.impl.EmployeeServiceImpl;
import junit.framework.TestCase;
public class EmployeeServiceImplTest {
//接口实现,因为要调用里边的查询方法,创建对象
EmployeeServiceImpl eimpl = new EmployeeServiceImpl();
//ID查询测试
@Test
public void testQueryById() {
Employee e = eimpl.queryById("006"); //ID:006查询
System.out.println(e); //查询结果输出
//.assertEquals方法:如果预期值与真实值相等,则运行success,反之Failure
TestCase.assertEquals("zhangsan", e.getUsername());
}
//姓名查询测试
@Test
public void testQueryByUserName(){
List list = eimpl.queryByUserName("zhangsan");//姓名:zhangsan查询
System.out.println(list); //查询结果输出
TestCase.assertEquals(2, list.size());//2:2条数据 list.size():链表长度
}
}
3.8项目的业务实现总结:
3.8.1最重要的一点首先要明确业务需求,从业务需求展开,层层深入完成项目构建。
3.8.2建议观看顺序:pojo->test->impl(service接口实现)->dao->utils,个人感觉从测试开始往回看比较清晰。
3.8.3项目开发实现的步骤:pojo->utils->dao->impl(service接口实现)->test。
3.8.4Resultset对象解析获取数据放入创建的Employee对象,放入对象的含义是我创建的pojo里边的类,也就是Employee类然后new一个对象用来存储解析的Resultset对象里边的数据。Resultset对象这个里边不止含有数据库的数据记录,除了数据记录还有其他的东西。
3.8.5Resultset.next()方法:当前指针位于第一行的前一行,也就是第一个数据的上一个结点,按链表来说就是位于虚拟头结点位置。所以dao层中解析Resultset对象需要先判断.next()是否为空。