Web编程规范之三层架构设计规范

本篇是我对Web开发规范中关于三层架构设计规范的一些浅见。虽然三层架构是比较普通,也比较简单的架构设计模式。可是随着业务的增加,涉及到的对象愈来愈多,处理的逻辑愈来愈复杂。这其中不免会出现设计不当,从而致使业务报错或逻辑代码混乱等问题的出现。下面我就来简单的谈一谈我是如何设计的?(注:本篇的看法是在基于当前比较流行的MVC设计模式,不知道什么是MVC设计模式的小伙伴,请自行查找相关资料。)数据库

逻辑划分

在三层的架构设计中一般会采用以下设计方案对逻辑进行划分:设计模式

Controller (表现层)

在MVC设计模式中使用Controller表明,它的主要做用为:安全

  • 针对用户的输入进行验证
  • 构建对象并调用 Service
  • 返回给用户VO或VM

Service(业务层,也叫服务层)

  • 接收Controller传过来的对象
  • 编写业务逻辑

在编写业务的时候有几个技巧: 1)对于全部更新操做,都把BO对象当成参数来接收,把更新后的对象当返回值架构

public OrderBO cancel(OrderBO orderBO) { return orderBO; }    /** 取消订单. */
public OrderBO finish(OrderBO orderBO) { return orderBO; }    /** 完成订单. */
public OrderBO paid(OrderBO orderBO) { return orderBO; }      /** 支付订单. */

2)对于查询而言,若是对象不存在,直接返回null或抛出异常都可。当返回为null时,上层调用须要进行判null处理 3) 若是是更新类操做,被操做的对象不存在时,这个时候必定要抛出异常 4)在须要抛出异常的地方使用日志详细的记录 5)若是在Service的方法中涉及到多个更新操做,须要在Service中开启事务。即便该方法的上层调用Service开启了事务,该方法也应该开启。以建立订单为例框架

@Transactional
    public OrderBO save(OrderBO orderBO) {
        // .....
        OrderMaster orderMaster = new OrderMaster();
        BeanUtils.copyProperties(orderBO, orderMaster);
        // 存储订单
        orderMasterRepository.save(orderMaster);
        productInfoService.decrStock(
                orderBO.getOrderDetailList().stream()
                        .map(e-> new StockBO(e.getProductId(),e.getProductQuantity()))
                        .collect(Collectors.toList())
        );
        return orderBO;
    }

    @Transactional //即便上层调用有这个标记,这里最好也加,由于可能会单独调用
    public void decrStock(List<StockBO> stockBOList) {
        stockBOList.stream().forEach(e -> {
            ProductInfo productInfo = this.findOne(e.getProductId());
            if (productInfo == null) {
                throw new WxbpException(ErrorCodeEnum.PRODUCT_NOT_EXIST);
            }
            Integer remainStock = productInfo.getProductStock() - e.getProductStock();
            if (remainStock < 0) {
                throw new WxbpException(ErrorCodeEnum.PRODUCT_STOCK_ERROR);
            }
            productInfo.setProductStock(remainStock);
            repository.save(productInfo);
        });
    }
  • 调用其余Service或Repository
  • 返回BO对象或POJO对象

Repository(数据访问层)

  • 由业务层调用和数据库进行交互来实现对数据的CRUD操做。为了提升效率,这通常会使用ORM框架,例如Mybatis或Hiberinate。
  • 返回POJO对象

模型对象定义

除基本的架构外,还会存在不少其余的实体对象,这些对象包括:工具

  • POJO: 普通的Java对象,映射数据表,内部属性均对应于数据表的列名。用于接收数据库的返回结果。一般在Service和Repository之间进行数据传递。
  • BO : 业务对象,是针对整个逻辑单元构成的对象,例如订单业务对象不只包含订单的信息,还包含订单明细。该对象主要在Controller和Service 之间进行数据传递,能够由不一样的POJO组成。若是POJO的属性与BO相同时,能够不用建立BO对象而直接使用POJO对象来充当BO,同理其余模型对象也如此。
  • VO : 视图对象,这类对象仅用于返回用户能够看到的信息。例如用户请求产品信息时,返回了一个产品业务对象,咱们不能直接把这个对象返回给用户,由于对象的内容包含了不少敏感信息(库存,采购价等),须要进一步对其处理,过滤掉这些敏感信息,从而构成了视图对象。
  • VM:视图模型,和VO很像,也是用户返回用户能够看到的信息。这个概念是MVC设计模式中的,对应于MVC中的M,这个对象一般对应于整个页面的信息,由一个或多个VO。例如我的中心的页面,不只包含用户信息,还有订单信息,积分的信息等。
  • PO:参数对象,这个对象映射到Controller方法中的参数。当Controller须要的参数过多时,咱们一般使用对象进行参数的接收,这个对象就是请求参数对象。

简化理解

对于上述三层架构中涉及的业务和对象,咱们能够简化这样理解,假设有这样一个情景。 BOSS把总监(Controller)叫到办公室 ,说:公司经营的情况如何了,给我出个整体报告我看看。总监收到指令后把A部门的经理(Service)叫到了办公室,并说:我须要近一年A部门的总结报告。A部门经理须要收到请求后,开始使用报表工具作事(Repository),当遇到了本身处理不了的地方又会叫其余有关联的经理帮助处理(调用其余的Service),最后完成了整件事。把报告交给了总监,总监看过以后发现没什么问题,又把B部门的经理叫到了办公室,并说了需求(有时候须要给B看A部门的报告的部分或全部结果), B部门的经理收到请求后,也是同A同样的处理办法,把报告交给了总监。此时总监这里已经有了BOSS要的全部数据,而后进行汇总,交给BOSS。而在这个过程当中,为保密和方便各方之间的沟通,BOSS和总监之间的对话能够理解成 PO -> BO 的过程,总监和经理的对话能够理解成BO->POJO的过程,固然有些经理对业务理解比较透彻就不须要转换了(直接使用BO,此时BO=POJO)。而这个对话过程反过来就是,进行逐层汇报的时候,应该言简意赅,一语中的,至于你怎么作的,就不要向上层反映了。最后达到BOSS那里只要看到满意的结果就好。this

##Service分层设计 Service分层设计是什么意思呢? 让咱们来看一个例子编码

public interface OrderService{
    /** 查询一个订单. */
    OrderBO findOne(String orderId);

    /** 取消订单. */
    void cancel(OrderBO orderBO);
}

在上述的代码中OrderService包含根据orderId获取订单这个操做。那么对于买家而言调用此方法是须要对买家进行安全性验证的,非该用户的订单则不能返回给调用方。为了代码的整洁性咱们衍生出来一个BuyerService,这个BuyerService主要处理和买家相关的业务,对买家进行验证后在进行调用相应的Service。spa

public class BuyerService{

    public OrderBO checkOrderOwner(String userId,String orderId){
           OrderBO orderBO = orderService.findOne(orderId);
            if(!orderBO.getUserID().equals(userId)) { //抛出异常; }
            return orderBO;
    }
    
    /** 查询用户的订单列表. */
    public OrderBO findOrderList(String userId,String orderId){
            OrderBo orderBO =checkOrderOwner(userId,orderId);
            return orderBO 
    }
}

这个分层理解起来也和三层架构相似,你固然能够在Controller中直接使用 OrderService 进行操做,就像你也能够直接使用Repository操做同样,只不过是比较麻烦而已。更好的设计有助于提升代码的整洁性,可读性和可维护性。架构设计

提高效率小妙招

如上的设计中涉及复杂业务的同时又衍生出了不少不一样种类的对象,在开发的过程当中会不免会形成代码的可读性,安全性和可维护性下降,下面咱们看一些能够提高总体的开发效率的小妙招。

  • 对象转换工具:实现不一样对象间的转换操做,能够由一个对象拆分为多个对象,也能够由多个对象组合成一个对象。
  • 统一返回的对象:这一点对调用方而言很重要,若是咱们的返回值结构多种多样,这会让调用方不知如何处理,从而增长使用难度。故须要统一的返回值结构,一般返回值的JSON结构以下:
{ "code":"0","msg":"操做成功","data":"须要返回给用户的数据"} 
  或
{ "code":"错误的状态码","msg":"错误的信息" }
  • 统一返回对象工具:该工具主要是封装一些快捷返回【统一返回的对象】的方法,避免大量冗余的代码。
  • 全局的异常处理拦截器:虽然上面有了【统一返回的对象】,可是当抛出异常的时候,返回给用户的信息破坏了这个对象的结构,致使用户处理起来困难。因此须要全局的异常拦截器,拦截异常而后处理成【统一返回的对象】格式。
  • 统一异常类型和异常代码:若是在代码中存在各式各样的异常类型和异常信息的硬编码,一经修改就有可能致使遗漏或逻辑报错等问题,让代码难以维护。因此须要统一的异常类型和集中管理异常代码是必要的。
相关文章
相关标签/搜索