java分层设计_Java Spring MVC分层设计(转)

本文介绍了使用Java Spring框架进行Web开发的经验,推荐使用SpringToolSuite(IDE)以简化环境配置。文章详细阐述了Spring MVC的分层设计,包括模型-视图-控制器模式,并探讨了业务逻辑层与数据访问层的分离,通过Service和DAO接口实现低耦合。此外,还展示了如何使用工厂模式创建DAO对象,以提高系统的灵活性和可扩展性。
摘要由CSDN通过智能技术生成

原文:https://blog.csdn.net/chris_mao/article/details/48694243

第一次尝试着用Java做Web开发,使用了Java Spring框架,顺便说一句,如果使用Spring开发,建议使用STS(Spring Tool Suite) IDE,它很好的集成了Spring、Maven等框架,使用起来特别方便,尤其是第一次使用Spring框架进行开发,它极大的方便了开发人员,通过快捷菜单及可很简单的配置好Spring开发环境,自动下载、更新Maven依赖包。话不多讲,回到文章的正题。

Spring是一个在Java业界很流行的MVC框架,所谓MVC即模型-视图-控制器,将应用程序的逻辑层与展现层进行分离的一种设计模式。

模型(Model)代表数据控制器。数据的读取,插入,更新都是由模型来负责。

视图(View)是展示给用户的最终页面。视图负责将数据以用户友好的形式展现出来。

控制器(Controller)是模型,视图以及其他任何处理 HTTP 请求所必须的资源之前的中介

概述

一个典型的页面浏览行为在程序端的流程是这样的:

控制器最先被调用,并被赋予外部输入

控制器根据外部输入向模型请求数据

模型从数据库获取数据并发送数据到控制器

控制器处理该数据并发送封装好的数据到视图

视图根据接到的数据最终展示页面给用户浏览

使用Java进行MVC模式开发时,往往将数据模型分为两部分,即DAO(Data Access Object,数据访问对象)和Service(业务逻辑模型)。在第2步中,控制器向模型请求数据时,并不是直接向DAO请求数据,而是通过Service向DAO请求数据。这样做的好处是,可以将业务逻辑与数据库访问独立开,为将来系统更换数据保存介质(如目前系统使用文件系统存储数据,将来可以更换为使用数据库存储,又或者是现在使用了MSSQL存储数据,将来更换为Oracle或是Mysql等)提供了很大的灵活性。

下图给出了分层设计模型。控制器只需要调用Service接口中的方法获取或是处理数据,Service层对控制器传入的数据进行业务逻辑处理封装后,传给DAO层,由DAO层负责将处理后的数据写入数据库中。

在Service层使用了抽象工厂模式来实现Service层与DAO层的低耦合,Service层并不知道DAO层是如何实现的,实际上也不需要知道系统使用了哪种数据库或是文件系统。

在DAO层使用工厂模式来创建数据模型的实体对象。

46b81b24f83bbcc2f372651aa2991d72.png

Service层设计

接口代码,这里使用了泛型技巧,确保每个Service只处理一种数据类型。

1 packagecom.emerson.etao.service;2

3 importjava.sql.SQLException;4 importjava.util.List;5

6 /**

7 * 业务实现层接口8 *9 *@authorChris Mao(Zibing)10 *11 *@param12 */

13 public interface IBaseService{14

15 /**

16 * 将实体类对象持久化,写入到数据表中17 *18 *@paramT19 *@return返回新写入记录的自增ID20 *@throwsSQLException21 */

22 public longinsert(T entity);23

24 /**

25 * 根据Id值,将实体类数据回写到数据库26 *27 *@paramid28 *@paramT29 *@return返回更新的记录笔数30 *@throwsSQLException31 */

32 public int update(longid, T entity);33

34 /**

35 * 根据Id值从数据库中删除实体类数据36 *37 *@paramid38 *@return返回删除的记录笔数39 *@throwsSQLException40 */

41 public int delete(longid);42

43 /**

44 * 根据Id查询具体的实体类信息,并返回实体类对象45 * 若查询不到数据则返回null46 *47 *@paramid48 *@returnT49 */

50 public T getById(longid);51

52 /**

53 * 获取列表54 *55 *@returnList56 *@throwsSQLException57 */

58 public ListgetAll();59 }

下面是具体的Service层接口代码,

1 packagecom.emerson.etao.service.base;2

3 importjava.util.List;4

5 importcom.emerson.etao.entity.base.BusinessApp;6 importcom.emerson.etao.entity.base.Communicator;7 importcom.emerson.etao.entity.base.Customer;8 importcom.emerson.etao.service.IBaseService;9

10 /**

11 * 客服类操作接口12 *13 *@authorChris Mao(Zibing)14 *@param15 *16 *@param17 */

18 public interface ICommunicatorService extends IBaseService{19

20 public ListgetAll(Customer customer);21

22 /**

23 * 为客服分配商业应用24 *25 *@paramc26 *@paramappList27 *@seeBusinessApp28 */

29 public void assignBusinessApp(Communicator communicator, List appList, booleandeleteExists);30

31 /**

32 * 为客服分配客户33 *34 *@paramc35 *@paramcustomerList36 *@seeCustomer37 */

38 public void assingCustomer(Communicator communicator, List customerList, booleandeleteExists);39 }

实现接口。

1 /**

2 *3 */

4 packagecom.emerson.etao.service.imp;5

6 importjava.sql.SQLException;7 importjava.util.List;8

9 importcom.emerson.etao.dao.IBaseDao;10 importcom.emerson.etao.dao.IDaoFactory;11 importcom.emerson.etao.service.IBaseService;12

13 /**

14 * 业务层实现类基类15 *16 * 为了降低与数据访问层的耦合,在构造函数中传入DaoFactory接口用于创建具体的数据访问对象实例17 *18 *@authorChris Mao(Zibing)19 *20 */

21 public abstract class BaseServiceImp implements IBaseService{22

23 private IBaseDao dao = null;24

25 protected IBaseDaogetDao() {26 return this.dao;27 }28

29 /**

30 *31 *@paramfactory 降低耦合,传入DaoFactory接口32 *@seeIDaoFactory33 */

34 public BaseServiceImp(IDaoFactoryfactory) {35 super();36 this.dao =factory.getDao();37 }38

39 @Override40 public longinsert(T entity) {41 try{42 return this.getDao().insert(entity);43 } catch(SQLException e) {44 e.printStackTrace();45 }46 return 0;47 }48

49 @Override50 public int update(longid, T entity) {51 try{52 return this.getDao().update(id, entity);53 } catch(SQLException e) {54 e.printStackTrace();55 }56 return 0;57 }58

59 @Override60 public int delete(longid) {61 try{62 return this.getDao().delete(id);63 } catch(SQLException e) {64 e.printStackTrace();65 }66 return 0;67 }68

69 @Override70 public ListgetAll() {71 try{72 return this.getDao().getAll();73 } catch(SQLException e) {74 e.printStackTrace();75 }76 return null;77 }78

79 @Override80 public T getById(longid) {81 try{82 return this.getDao().getById(id);83 } catch(SQLException e1) {84 e1.printStackTrace();85 }86 return null;87 }88 }

1 packagecom.emerson.etao.service.base.imp;2

3 importjava.sql.PreparedStatement;4 importjava.sql.SQLException;5 importjava.text.SimpleDateFormat;6 importjava.util.ArrayList;7 importjava.util.Date;8 importjava.util.Iterator;9 importjava.util.List;10

11 importcom.emerson.etao.dao.IDaoFactory;12 importcom.emerson.etao.entity.base.BusinessApp;13 importcom.emerson.etao.entity.base.Communicator;14 importcom.emerson.etao.entity.base.Customer;15 importcom.emerson.etao.service.base.ICommunicatorService;16 importcom.emerson.etao.service.imp.BaseServiceImp;17

18 /**

19 *20 *@authorChris Mao(Zibing)21 *22 */

23 public class CommunicatorServiceImp extends BaseServiceImpimplementsICommunicatorService {24

25 @Override26 public ListgetAll(Customer customer) {27 List result = new ArrayList();28 try{29 result = this.getDao()30 .getAll("SELECT a.* FROM communicator AS a INNER JOIN customer_communicator cc USING(communicator_id) WHERE cc.customer_id = "

31 +customer.getCustomerId());32 } catch(SQLException e) {33 e.printStackTrace();34 }35 returnresult;36 }37

38 public CommunicatorServiceImp(IDaoFactoryfactory) {39 super(factory);40 }41

42 @Override43 public void assignBusinessApp(Communicator communicator, List appList, booleandeleteExists) {44 try{45 if (true ==deleteExists) {46 this.getDao().getStatement().executeUpdate("DELETE FROM communicator_application WHERE communicator_id = " +communicator.getCommunicatorId());47 }48

49 if (null == appList ||appList.isEmpty()) {50 return;51 }52

53 PreparedStatement pstmt = this.getDao().getConnection().prepareStatement("INSERT IGNORE INTO communicator_application(communicator_id, application_id, created_time) VALUES(?, ?, ?)");54 BusinessApp app = null;55 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//设置日期格式

56 Iterator ite =appList.iterator();57 while(ite.hasNext()) {58 app =ite.next();59 pstmt.setLong(1, communicator.getCommunicatorId());60 pstmt.setLong(2, app.getApplicationId());61 pstmt.setString(3, sdf.format(newDate()));62 pstmt.executeUpdate();63 }64 pstmt.close();65 } catch(SQLException e) {66 e.printStackTrace();67 }68 }69

70 /**

71 * 为客服人员分配客户72 *73 * 如果需要删除客服人员名下所有客户,只需将customers设为null或是空列表74 *75 *@paramcommunicator76 *@paramapps77 *@paramdeleteExists78 */

79 @Override80 public void assingCustomer(Communicator communicator, List customerList, booleandeleteExists) {81 try{82 if (true ==deleteExists) {83 this.getDao().getStatement().executeQuery("DELETE FROM customer_communicator WHERE communicator_id = " +communicator.getCommunicatorId());84 }85

86 if (null == customerList ||customerList.isEmpty()) {87 return;88 }89

90 PreparedStatement pstmt = this.getDao().getConnection().prepareStatement("INSERT IGNORE INTO customer_communicator(communicator_id, customer_id, created_time) VALUES(?, ?, ?)");91 Customer customer = null;92 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//设置日期格式

93 Iterator ite =customerList.iterator();94 while(ite.hasNext()) {95 customer =ite.next();96 pstmt.setLong(1, communicator.getCommunicatorId());97 pstmt.setLong(2, customer.getCustomerId());98 pstmt.setString(3, sdf.format(newDate()));99 pstmt.executeUpdate();100 }101 pstmt.close();102 } catch(SQLException e) {103 e.printStackTrace();104 }105 }106 }

DAO层的设计

这里需在为DAO层定义一个通个的基础接口IBaseDao,这里包含了对数据的增、删、改、查基础操作。抽象类BaseDao实现接口IBaseDao,并添加了访问限制为protected的数据库连接对象,方便子类使用。

8a6f36dc1b33a2922edfa2b43b4d5e92.png

DAO接口代码。

1 /**

2 *3 */

4 packagecom.emerson.etao.dao;5

6 importjava.sql.Connection;7 importjava.sql.SQLException;8 importjava.sql.Statement;9 importjava.util.List;10

11 /**

12 *13 * 数据访问层接口14 *15 *@authorChris Mao(Zibing)16 *17 */

18 public interface IBaseDao{19

20 /**

21 *22 *@returnConnection23 */

24 publicConnection getConnection();25

26 /**

27 *28 *@returnStatement29 */

30 publicStatement getStatement();31

32 /**

33 * 将值对象写入到数据表中,并返回其自增ID值34 *35 *@paramentity36 *@return返回新写入记录的自增ID37 *@throwsSQLException38 */

39 public long insert(T entity) throwsSQLException;40

41 /**

42 * 将值对象修改后的内容写入到数据表中,并返回其影响的记录笔数43 *44 *@paramid45 *@paramentity46 *@return返回更新的记录笔数47 *@throwsSQLException48 */

49 public int update(long id, T entity) throwsSQLException;50

51 /**

52 * 删除ID值,并返回其删除的记录笔数53 *54 *@paramid55 *@return返回删除的记录笔数56 *@throwsSQLException57 */

58 public int delete(long id) throwsSQLException;59

60 /**

61 * 依据Id值到数据表中查询数据,并返回值对象62 *63 *@paramid64 *@return

65 */

66 public T getById(long id) throwsSQLException;67

68 /**

69 * 返回数据表中所有记录70 *71 *@returnList72 *@throwsSQLException73 */

74 public List getAll() throwsSQLException;75

76 /**

77 * 返回符合条件的所有记录78 *79 *@paramqueryStr80 *@returnList81 *@throwsSQLException82 */

83 public List getAll(String queryStr) throwsSQLException;84 }

抽象工厂接口。

1 packagecom.emerson.etao.dao;2

3 /**

4 * 数据访问类工厂接口5 *6 * 负责创建具体的数据访问对象实例7 *8 *@authorChris Mao(Zibing)9 *10 *@param11 */

12 public interface IDaoFactory{13 /**

14 * 创建数据访问对象实例15 *16 *@return

17 *@seeIBaseDao18 */

19 public IBaseDaogetDao();20 }

抽象类BaseDao实现接口IBaseDao。

1 packagecom.emerson.etao.dao;2

3 importjava.sql.Connection;4 importjava.sql.ResultSet;5 importjava.sql.SQLException;6 importjava.sql.Statement;7

8 importorg.slf4j.Logger;9 importorg.slf4j.LoggerFactory;10

11 importcom.emerson.etao.db.DBUtils;12

13 /**

14 *15 * 数据访问层基类16 *17 * 所有数据访问对象都需要继承此类18 *19 *@authorChris Mao(Zibing)20 *21 */

22 public abstract class BaseDao implements IBaseDao{23

24 private static final Logger logger = LoggerFactory.getLogger(BaseDao.class);25

26 publicConnection getConnection() {27 returnDBUtils.getConnection();28 }29

30 publicStatement getStatement() {31 Statement stmt = null;32 try{33 Connection conn =DBUtils.getConnection();34 stmt =conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);35 } catch(SQLException e) {36 logger.error("创建 Statement 对象发生错误!!");37 e.printStackTrace();38 }39 returnstmt;40 }41 }

实体类创建工厂接口。

1 packagecom.emerson.etao.entity;2

3 importjava.sql.ResultSet;4

5 /**

6 *7 * 实体类工厂接口8 *9 * 所有实体类对象实例需要通过此工厂接口创建10 *11 *@authorChris Mao(Zibing)12 *13 */

14 public interface IEntityFactory{15

16 /**

17 * 创建空的实体类18 *19 *@return

20 */

21 publicT createEntity();22

23 /**

24 * 创建实体类,并将参数rs中的内容赋值到实体类属性当中25 *26 *@paramrs27 *@return

28 */

29 publicT createEntity(ResultSet rs);30

31 }

具体的DAO对象,继承BaseDao,并实现实体类创建工厂接口。这里使用了内部匿名类实现DAO的抽象工厂接口。

1 packagecom.emerson.etao.dao.base;2

3 importjava.sql.PreparedStatement;4

5 importjava.sql.ResultSet;6 importjava.sql.SQLException;7 importjava.sql.Statement;8 importjava.text.SimpleDateFormat;9 importjava.util.ArrayList;10 importjava.util.Date;11 importjava.util.List;12

13 importcom.emerson.etao.dao.BaseDao;14 importcom.emerson.etao.dao.IBaseDao;15 importcom.emerson.etao.dao.IDaoFactory;16 importcom.emerson.etao.entity.IEntityFactory;17 importcom.emerson.etao.entity.base.Communicator;18

19 /**

20 * 客服人员数据访问对象21 *22 *@authorChris Mao(Zibing)23 *24 */

25 public class CommunicatorDao extends BaseDaoimplements IEntityFactory{26

27 public static IDaoFactory factory = new IDaoFactory() {28

29 @Override30 public IBaseDaogetDao() {31 return newCommunicatorDao();32 }33

34 };35

36 @Override37 publicCommunicator createEntity() {38 return newCommunicator();39 }40

41 @Override42 publicCommunicator createEntity(ResultSet rs) {43 Communicator c = this.createEntity();44 try{45 c.setCommunicatorId(rs.getInt("communicator_id"));46 c.setCommunicatorName(rs.getString("communicator_name"));47 c.setPhone(rs.getString("phone"));48 c.setFax(rs.getString("fax"));49 c.setEmail(rs.getString("email"));50 c.setReportTo(rs.getInt("report_to"));51 c.setReportToName(rs.getString("report_to_name"));52 c.setValid(rs.getByte("is_valid"));53 c.setCreatedTime(rs.getTimestamp("created_time"));54 c.setUpdatedTime(rs.getTimestamp("update_time"));55 } catch(SQLException e) {56 e.printStackTrace();57 }58 returnc;59 }60

61 @Override62 public Communicator getById(long id) throwsSQLException {63 Communicator result = null;64 ResultSet rs = this.getStatement().executeQuery("SELECT * FROM vw_communicator WHERE communicator_id = " +id);65 while(rs.next()) {66 result = this.createEntity(rs);67 }68 rs.close();69 returnresult;70 }71

72 @Override73 public long insert(Communicator entity) throwsSQLException {74 Long newId = (long) 0;75

76 StringBuilder sql = newStringBuilder();77 sql.append("INSERT IGNORE INTO communicator");78 sql.append("(communicator_name, phone, fax, email, report_to, created_time) ");79 sql.append("VALUES(?, ? ,? ,?, ?, ?)");80

81 PreparedStatement pstmt = this.getConnection().prepareStatement(sql.toString(), Statement.RETURN_GENERATED_KEYS);82 pstmt.setString(1, entity.getCommunicatorName());83 pstmt.setString(2, entity.getPhone());84 pstmt.setString(3, entity.getFax());85 pstmt.setString(3, entity.getFax());86 pstmt.setString(4, entity.getEmail());87 pstmt.setInt(5, entity.getReportTo());88 SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//设置日期格式

89 pstmt.setString(6, df.format(newDate()));90 pstmt.executeUpdate();91 ResultSet rs =pstmt.getGeneratedKeys();92 if(rs.next()) {93 newId = rs.getLong(1);94 entity.setCommunicatorId(rs.getInt(1));95 //System.out.println("新增客服记录ID为:" + newId);

96 }97 rs.close();98 pstmt.close();99 returnnewId;100 }101

102 @Override103 public int update(long id, Communicator entiry) throwsSQLException {104 int result = 0;105 StringBuffer sql = newStringBuffer();106 Communicator c =(Communicator) entiry;107 //System.out.println(c);

108 sql.append("UPDATE communicator");109 sql.append(" SET communicator_name = ?, phone = ?, fax = ?, email = ?, report_to = ?, is_valid = ?");110 sql.append(" WHERE communicator_id = ?");111

112 PreparedStatement pstmt = this.getConnection().prepareStatement(sql.toString());113 pstmt.setString(1, c.getCommunicatorName());114 pstmt.setString(2, c.getPhone());115 pstmt.setString(3, c.getFax());116 pstmt.setString(3, c.getFax());117 pstmt.setString(4, c.getEmail());118 pstmt.setInt(5, c.getReportTo());119 pstmt.setInt(6, c.getIsValid());120 pstmt.setLong(7, c.getCommunicatorId());121 result =pstmt.executeUpdate();122 //System.out.println("更新客服记录数为:" + result);

123 pstmt.close();124 returnresult;125 }126

127 @Override128 public int delete(long id) throwsSQLException {129 int result = 0;130 String sql = "DELETE FROM communicator WHERE communicator_id = ?";131

132 PreparedStatement pstmt;133

134 pstmt = this.getConnection().prepareStatement(sql);135 pstmt.setLong(1, id);136 result =pstmt.executeUpdate();137 //System.out.println("删除客服记录数为:" + result);

138 pstmt.close();139 returnresult;140 }141

142 @Override143 public List getAll() throwsSQLException {144 List result = null;145 ResultSet rs = this.getStatement().executeQuery("SELECT * FROM vw_communicator");146 result = new ArrayList();147 while(rs.next()) {148 result.add(this.createEntity(rs));149 }150 rs.close();151 returnresult;152 }153

154 @Override155 public List getAll(String queryStr) throwsSQLException {156 List result = new ArrayList();157

158 ResultSet rs = this.getStatement().executeQuery(queryStr);159 while(rs.next()) {160 result.add(this.createEntity(rs));161 }162 rs.close();163 returnresult;164 }165 }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值