淺談 SpringMVC 中各層職責的設計

我妻禮彌發表於2018-06-10

SpringMVC

SpringMVC應該是目前web開發最常用的框架。他的專案結構也相對固定,一般都會有以下幾層。

  • controller層
  • service層
  • mapper介面層
  • 實體層
  • 可能還有什麼 DTO VO 等層次。

這裡主要講下controller層 和 service層,因為我實際工作中發現,什麼該放在controller層,什麼該放在 service層,似乎每家公司都有自己的做法。

最近一個專案是這樣安排的

public class DepartmentController {
    @Autowired
    private DepartmentService departmentService;

    /**
     * 刪除部門
     * @param departmentId
     * @return
     */
    @RequestMapping(value = "/department", method= RequestMethod.DELETE)
    public Result delete(String departmentId){
        return departmentService.delete(departmentId);
    }
}


public class DepartmentService {
    @Autowired
    private DepartmentMapper departmentMapper;
    @Autowired
    private UserService userService;

    /**
     * 刪除部門
     * @param departmentId
     * @return
     */
    @RequestMapping(value = "department", method= RequestMethod.DELETE)
    public Result delete(String departmentId){
        if(departmentId == null || "".equals(departmentId)){
            return new FailResult("部門id不合法");
        }
        //刪除部門前,檢視部門下是否存在人員
        Result result =  userService.getUserList(departmentId);
        //拆解result 找出結果
        List<User> List = result.getDate();
        if(if list != null && list.size > 0){
            return new FailResult("部門下是否存在人員");
        }
        int i =  departmentService.delete(departmentId);
        if(i == 1){
            return new SuccessResult<Boolean>(true);
        }
        return new FailResult("刪除失敗");
    }
}
複製程式碼

上面程式碼中,Controller層的任務非常簡單,接收前端的引數然後傳給service,service處理完後返回最終結果,至於 引數傳沒穿,格式對不對,甚至最後返回結果的封裝,都放到service中去處理。
我們可以看到service的任務非常集中,非常重,而Controller的任務非常輕,就只做了一個轉發的操作。其實這樣分配非常不合理,特別是 最終返回結果的封裝,非常不應該放在service裡面。
上面程式碼中我們想刪除一個部門,先要判斷部門下是否存在人員,於是我們呼叫人員的service,結果他返回的是給前端展示的物件,於是我們不得不,拆解物件,取出我們想要的結果,非常麻煩。如果他把Result的封裝放在Controller層就非常方便了,service層可以直接返回處理結果。

經過這次專案後,我一直在思考,Controller層和service層的職責應該怎樣設計才好。下面說下我的看法。

Controller層

Controller層是前端直接接觸的層,離使用者最近,同時也代表著一個介面。
他的任務應該是你按照我的要求傳遞規定的引數,並且引數的值也合法的話,我就返回給你想要的結果。
從上面分析可以看出Controller層關注點在兩個方面,請求引數,和響應結果。

因此,controller層的任務是

  • 在呼叫業務層(Serivce)之前,保證業務所需要的引數的個數和內容都要合法。換句話說,在呼叫service之前,service要求的每個引數都要有,並且在內容上要合法,而不要把這些操作延遲都service中去做。
    這樣設計的理由也很簡單,你引數都不對,還有必要進入業務層去執行嗎?
  • 不要讓業務層(Serivce)返回最終結果(前端需要的結果)。這個也很好理解
    • mapper層應該返回查詢資料庫的結果。
    • service層應該返回業務結果
    • controller層應該根據業務層的返回結果做判斷,然後封裝成前端需要的最終結果

所以Controller層的職責總結起來就兩點。

  • 在呼叫業務方法之前,保證業務方法所需引數的合法性
  • 接收業務方法的返回值,根據返回值做判斷,然後封裝成前端需要的最終結果

Service層

service層負責的是業務的處理,它的關注的是業務,不應該做與業務沒有直接關係的事情。 比如:

  • 檢查業務引數的合法性。乍一看好像跟業務相關,但我們換一個角度思考,業務引數不合法就沒有必要進入到業務方法裡面來,再說業務引數是Controller層傳遞過來的,你把不合法的引數傳遞進來是想幹什麼。
  • 業務層只返回業務結果,不返回最終結果。這點很容易理解,應為業務結果不一定就是最終結果,業務層只要負責好自己的業務就好了,至於最終結果,當然是由介面(Controller)層去返回。

這樣設計的原因是希望各層職責分明,每層負責自己的事,這樣做還有一個好處,那就是,不會存在某層非常 “重”,而某層又非常 “輕” 的情況。

相關文章