总领:是企业开发中的一种模式、公式、套路。
现实生活中的分层:
大学为例
程序世界中同样也采用了分层:
比如:
王者荣耀,注册用户时,要求昵称必须唯一。
1. 出现填写昵称的界面
------都在用户界面上操作
2. 填写昵称,点击确定
3. 确定完成后
如果昵称是唯一的,给你注册
----业务逻辑的判断
如果昵称不唯一,提示错误信息“昵称已经存在!”
对于使用者而言,认为王者荣耀有一个注册的功能,程序中又称为一个注册业务。
业务:软件中的功能,有时也连起来说叫业务功能。
除了注册业务功能外,还有其他的业务功能,如:登录、抽奖、兑换、对战、积分、升级。。。。
这些都是业务功能。
4. 需要使用到数据访问对象,才能完成整体的业务。 -----------纯的数据访问
根据昵称查询数据库中是否已经存在用户了
如果不存在,就会在数据库中保存一条数据
如果存在,不保存。
分为三个独立的层
分层具体在程序中如何体现?
使用的是包结构来体现
三个核心的包,ui、service、dao包 + 辅助包,如:util、exception、test、。。。。
其中service、dao采用的是面向接口的编程方式:更抽象、更好使用多态、更好做替换、程序的可插拔行高、灵活。。。。。。。
又多出了两个包,service.impl 、dao.impl包
需求:
新闻系统,专门发布新闻。
功能:新闻发布功能,要求:标题、内容,不能含有脏话、不能含有反共的。。。
1. 创建合理的包结构 ----一定要体现分层
现有公司域名+项目名称倒着写
核心的包
其他的辅助包
2. 之前封装的工具拷贝到util包中
3. 具体开发新闻发布功能
可以从上层往下写,也可以从下层往上写,建议从下往上写。
建库、建表
create table t_news (
t_id int auto_increment primary key,
t_title varchar(100),
t_content varchar(1024),
t_createtime datetime
) engine = Innodb;
定义一个实体类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
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
再测试
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());
}
}
}
按照目前为止,newsDao.add会不会出现异常?
答案:肯定不会。
原因:
JdbcTemplate中所有的方法都没有声明异常,即使内部出现异常了,都被
JdbcTemplate方法内部的catch处理了,不会对外暴露异常。
如何解决?
为了把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;
}
}
}