Java分层架构

总领:是企业开发中的一种模式、公式、套路。

现实生活中的分层:

大学为例

Java分层架构_第1张图片

程序世界中同样也采用了分层:

比如:

王者荣耀,注册用户时,要求昵称必须唯一。

1. 出现填写昵称的界面

                          ------都在用户界面上操作

2. 填写昵称,点击确定

3. 确定完成后

  如果昵称是唯一的,给你注册

                                                ----业务逻辑的判断

  如果昵称不唯一,提示错误信息“昵称已经存在!”

对于使用者而言,认为王者荣耀有一个注册的功能,程序中又称为一个注册业务。

业务:软件中的功能,有时也连起来说叫业务功能。

除了注册业务功能外,还有其他的业务功能,如:登录、抽奖、兑换、对战、积分、升级。。。。

这些都是业务功能。

4. 需要使用到数据访问对象,才能完成整体的业务。   -----------纯的数据访问

根据昵称查询数据库中是否已经存在用户了

如果不存在,就会在数据库中保存一条数据

如果存在,不保存。

分为三个独立的层

Java分层架构_第2张图片

分层具体在程序中如何体现?

使用的是包结构来体现

三个核心的包,uiservicedao包   +  辅助包,如:util、exception、test、。。。。

其中service、dao采用的是面向接口的编程方式:更抽象、更好使用多态、更好做替换、程序的可插拔行高、灵活。。。。。。。

又多出了两个包,service.impl 、dao.impl包

需求:

新闻系统,专门发布新闻。

功能:新闻发布功能,要求:标题、内容,不能含有脏话、不能含有反共的。。。

1. 创建合理的包结构 ----一定要体现分层

   现有公司域名+项目名称倒着写

  

   核心的包

  

   其他的辅助包

  Java分层架构_第3张图片

2. 之前封装的工具拷贝到util包中

Java分层架构_第4张图片

3. 具体开发新闻发布功能

可以从上层往下写,也可以从下层往上写,建议从下往上写

Java分层架构_第5张图片

建库、建表

Java分层架构_第6张图片

create table t_news (
    t_id int auto_increment primary key,
    t_title varchar(100),
    t_content varchar(1024),
    t_createtime datetime
) engine = Innodb;

Java分层架构_第7张图片

 

定义一个实体类News

package com.njwbhz.newssys.entity;

import march.part0320.util.DateUtil;

import java.util.Date;

/**
 * 新闻实体类
 */
public class News {
    private int id;
    private String title;
    private String content;
    private Date createTime;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

    public Date getCreateTime() {
        return createTime;
    }

    public void setCreateTime(Date createTime) {
        this.createTime = createTime;
    }

    @Override
    public String toString() {
        return "News{" +
                "id=" + id +
                ", title='" + title + '\'' +
                ", content='" + content + '\'' +
                ", createTime=" + DateUtil.dateToStr(createTime,"yyyy-MM-dd HH:mm:ss") +
                '}';
    }
}

定义NewsDao数据访问接口,只体现CURD操作

package com.njwbhz.newssys.dao;

import com.njwbhz.newssys.entity.News;

public interface NewsDao {
    /**
     * 保存一个新闻对象
     * @param news
     */
    void add(News news);
}

定义一个NewsDaoImpl

Java分层架构_第8张图片

package com.njwbhz.newssys.dao.imple;

import com.njwbhz.newssys.dao.NewsDao;
import com.njwbhz.newssys.entity.News;
import com.njwbhz.newssys.util.JdbcTemplate;

public class NewsDaoImpl implements NewsDao {
    @Override
    public void add(News news) {
        String sql = "insert into t_news(t_title,t_content,t_createtime) values (?,?,now())";
        JdbcTemplate.insert(sql , news.getTitle() , news.getContent());
    }
}

测试NewsDao

package com.njwbhz.newssys.test;

import com.njwbhz.newssys.dao.NewsDao;
import com.njwbhz.newssys.dao.imple.NewsDaoImpl;
import com.njwbhz.newssys.entity.News;

public class TestNewsDao {
    public static void main(String[] args) {
        NewsDao newsDao = new NewsDaoImpl();
        News news = new News();
        news.setTitle("test_title");
        news.setContent("test_content");
        newsDao.add(news);
    }
}

修改db.properties

driverClassName = com.mysql.jdbc.Driver
url = jdbc:mysql://localhost/news?characterEncoding=utf8
username = root
password = root
initialSize = 3

再测试

 

Java分层架构_第9张图片

 

package com.njwbhz.newssys.exception;

/**
 * 自定义的业务异常
 */
public class NewsSysException extends RuntimeException {
    public NewsSysException (String msg) {
        super(msg);
    }
}

新建业务类接口

NewsService

package com.njwbhz.newssys.service;

import com.njwbhz.newssys.entity.News;
import com.njwbhz.newssys.exception.NewsSysException;

public interface NewsService {
    //定义的方法体现出业务功能
    void publish (News news) throws NewsSysException;
}

新建业务实现类

NewsServiceImpl

package com.njwbhz.newssys.service.impl;

import com.njwbhz.newssys.dao.NewsDao;
import com.njwbhz.newssys.dao.imple.NewsDaoImpl;
import com.njwbhz.newssys.entity.News;
import com.njwbhz.newssys.exception.NewsSysException;
import com.njwbhz.newssys.service.NewsService;

public class NewsServiceImpl implements NewsService {
    //持有一个NewsDao的引用
    private NewsDao newsDao = new NewsDaoImpl();
    @Override
    public void publish(News news) throws NewsSysException {
        //业务逻辑
        //发布的新闻标题、内容中不准有脏话,反共的话
        //模拟
        if (news.getTitle().contains("你妹") || news.getContent().contains("你妹")) {//含有脏话
            //不给你发布
            //非正常——>异常
            //抛出一个异常
            throw  new NewsSysException("不能含有脏话");
        } else {//给你发布
            //正常
            newsDao.add(news);
        }
    }
}

测试:

package com.njwbhz.newssys.test;

import com.njwbhz.newssys.entity.News;
import com.njwbhz.newssys.exception.NewsSysException;
import com.njwbhz.newssys.service.NewsService;
import com.njwbhz.newssys.service.impl.NewsServiceImpl;

public class TestNewsService {
    public static void main(String[] args) {
        NewsService newsService = new NewsServiceImpl();
        News news = new News();
        news.setTitle("test_title_你妹");
        news.setContent("test_content2");
        try {
            newsService.publish(news);
        } catch (NewsSysException e) {
            System.out.println(e.getMessage());
        }
    }
}

Java分层架构_第10张图片

 

Java分层架构_第11张图片

按照目前为止,newsDao.add会不会出现异常?

答案:肯定不会。

原因:

    Java分层架构_第12张图片

JdbcTemplate中所有的方法都没有声明异常,即使内部出现异常了,都被

JdbcTemplate方法内部的catch处理了,不会对外暴露异常。

Java分层架构_第13张图片

如何解决?

Java分层架构_第14张图片

为了把SQLException放出来,不能再JdbcTemplate中处理,应该直接对外抛出。

修改JdbcTemplate类

package com.njwbhz.newssys.util;

import org.apache.log4j.Logger;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

public class JdbcTemplate {
    //定义一个日志记录器org.apache.log4j.Logger
    private static Logger logger = Logger.getLogger(JdbcTemplate.class);
    /**
     * 专门处理insert update delete的模板方法
     * @param sql
     * @param params 参数列表 个数和sql中的占位符一致
     */
    public static void executeUpdate(String sql,Object ... params) throws SQLException {
        logger.info(JdbcLogger.getMessage(sql , params));
        //1. 加载驱动 封装好了
        //2. 获取连接
        Connection conn = null;
        conn = JdbcUtil.getConnection();
        PreparedStatement pstmt = null;
        try {
            pstmt = conn.prepareStatement(sql);
            setParams(pstmt,params);
            pstmt.executeUpdate();
        } finally {
            JdbcUtil.close(pstmt,conn);
        }
    }

    private static void setParams(PreparedStatement preparedStatement,Object ... params) {
        if (!(null == preparedStatement || params.length == 0)) {//有参数
            for (int i = 0 ; i < params.length ; i++) {
                try {
                    preparedStatement.setObject((i + 1),params[i]);
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 专门处理select的模板方法
     * @param sql
     * @param rowMapping
     * @param params
     * @param 
     * @return
     */
    public static List executeQuery (String sql , RowMapping rowMapping , Object ... params) throws SQLException {
        logger.info(JdbcLogger.getMessage(sql, params));
        List datas = new ArrayList();//返回任何一类的实体对象
        //模板化的步骤
        //1. 加载驱动
        //2. 获取链接
        Connection conn = null;
        conn = JdbcUtil.getConnection();
        //3. 获取SQL执行器
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        try {
            pstmt = conn.prepareStatement(sql);
            //4. 执行SQL
            setParams(pstmt , params);
            rs = pstmt.executeQuery();
            //处理结果
            while (rs.next()) {
                //一行数据——>映射成实体对象
                //User user = new User() 或Dept dept = new Dept()各种各样
                //通用的Object object = new Object(),object没有set方法——>没有办法做映射
                T data = rowMapping.mapper(rs);
                //实体对象添加到集合中
                datas.add(data);
            }
        } finally {
            JdbcUtil.close(rs , pstmt , conn);
        }
        return datas;
    }

    /**
     * 查询稽核数据
     * @param sql
     * @param rowMapping
     * @param params
     * @param 
     * @return
     */
    public static  List selectList(String sql , RowMapping rowMapping , Object ... params) throws SQLException {
        return executeQuery(sql , rowMapping , params);
    }

    /**
     * 查询单个
     * @param sql
     * @param rowMapping
     * @param params
     * @param 
     * @return
     */
    public static  T selectOne(String sql , RowMapping rowMapping , Object ... params) throws SQLException {
        List datas = selectList(sql , rowMapping , params);
        if (datas.size() > 0) {
            return datas.get(0);
        } else {
            return null;
        }
    }

    public static void insert(String sql , Object ... params) throws SQLException {
        executeUpdate(sql , params);
    }

    public static void delete(String sql , Object ... params) throws SQLException {
        executeUpdate(sql , params);
    }

    public static void update(String sql , Object ... params) throws SQLException {
        executeUpdate(sql , params);
    }
}

其他5个方法,只要在方法的签名上throws SQLException

package com.njwbhz.newssys.dao;

import com.njwbhz.newssys.entity.News;

import java.sql.SQLException;

public interface NewsDao {
    /**
     * 保存一个新闻对象
     * @param news
     */
    void add(News news) throws SQLException;
}

package com.njwbhz.newssys.dao.imple;

import com.njwbhz.newssys.dao.NewsDao;
import com.njwbhz.newssys.entity.News;
import com.njwbhz.newssys.util.JdbcTemplate;

import java.sql.SQLException;

public class NewsDaoImpl implements NewsDao {
    @Override
    public void add(News news) throws SQLException {
        String sql = "insert into t_news(t_title,t_content,t_createtime) values (?,?,now())";
        JdbcTemplate.insert(sql , news.getTitle() , news.getContent());
    }
}

package com.njwbhz.newssys.test;

import com.njwbhz.newssys.dao.NewsDao;
import com.njwbhz.newssys.dao.imple.NewsDaoImpl;
import com.njwbhz.newssys.entity.News;

import java.sql.SQLException;

public class TestNewsDao {
    public static void main(String[] args) {
        NewsDao newsDao = new NewsDaoImpl();
        News news = new News();
        news.setTitle("test_title");
        news.setContent("test_content");
        try {
            newsDao.add(news);
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

package com.njwbhz.newssys.service.impl;

import com.njwbhz.newssys.dao.NewsDao;
import com.njwbhz.newssys.dao.imple.NewsDaoImpl;
import com.njwbhz.newssys.entity.News;
import com.njwbhz.newssys.exception.NewsSysException;
import com.njwbhz.newssys.service.NewsService;

import java.sql.SQLException;

public class NewsServiceImpl implements NewsService {
    //持有一个NewsDao的引用
    private NewsDao newsDao = new NewsDaoImpl();
    @Override
    public void publish(News news) throws NewsSysException {
        //业务逻辑
        //发布的新闻标题、内容中不准有脏话,反共的话
        //模拟
        if (news.getTitle().contains("你妹") || news.getContent().contains("你妹")) {//含有脏话
            //不给你发布
            //非正常——>异常
            //抛出一个异常
            throw  new NewsSysException("不能含有脏话");
        } else {//给你发布
            //正常
            try {
                newsDao.add(news);
            } catch (SQLException e) {//捕获数据库的异常
                e.printStackTrace();
                //异常的转换
                throw new NewsSysException("系统维护中或系统故障");
            }
            //如果数据库挂了,或者字段的长度超过了数据库的限制
            //都会添加不成功
        }
    }
}

最后写UI层

package com.njwbhz.newssys.ui;

import com.njwbhz.newssys.entity.News;
import com.njwbhz.newssys.exception.NewsSysException;
import com.njwbhz.newssys.service.NewsService;
import com.njwbhz.newssys.service.impl.NewsServiceImpl;

import java.util.Scanner;

public class PublishNewsUi {
    private NewsService newsService = new NewsServiceImpl();
    public void publish () {
        Scanner scanner = new Scanner(System.in);
        System.out.println("新闻发布页");
        System.out.print("新闻标题:");
        String title = scanner.next();
        System.out.print("新闻的正文:");
        String content = scanner.next();
        News news = new News();
        news.setTitle(title);
        news.setContent(content);
        //调用业务层逻辑,千万记住不能调用dao,不能越级
        try {
            newsService.publish(news);
            System.out.println("新闻发布成功");
        } catch (NewsSysException e) {
            System.out.println("新闻发布失败:原因->" + e.getMessage());
        }
    }
}

测试界面

package com.njwbhz.newssys.ui;

import java.util.Scanner;

/**
 * 新闻应用
 */
public class NewsApp {
    public static void main(String[] args) {
        System.out.println("新闻管理系统");
        System.out.println("1. 发布新闻");
        System.out.print("请输入菜单编号:");
        Scanner input = new Scanner(System.in);
        int menuNo = input.nextInt();
        switch (menuNo) {
            case 1 :
                //发布新闻
                //发布界面
                PublishNewsUi publishNewsUi = new PublishNewsUi();
                publishNewsUi.publish();
                break;
        }
    }
}

Java分层架构_第15张图片

 

你可能感兴趣的:(数据库,database,mysql,jdbc,java)