# 業務邏輯上使用的三層架構 ###### tags: `Java Web-常用知識點` ###### tags: `Java Web-mvc` ###### tags: `Java Web-Servlet` ## 1.三層架構的劃分 ![](https://i.imgur.com/tuzDxpB.png) 表述層:負責處理瀏覽器請求、返回響應、頁面調度 業務邏輯層:負責處理業務邏輯,根據業務邏輯把持久化層從數據庫查詢出來的數據進行運算、組裝,封裝好後返回給表述層,也可以根據業務功能的需要調用持久化層把數據保存到數據庫、修改數據庫中的數據、刪除數據庫中的數據 持久化層:根據上一層的調用對數據庫中的數據執行增刪改查的操作 ## 2.三層架構的好處 如果不做三層構造: ![](https://i.imgur.com/ux8zhHg.png) 所有和當前業務功能需求相關的代碼全部耦合在一起,如果其中有任何一個部分出現了問題,牽一發而動全身,導致其他無關代碼也要進行相應的修改。這樣的話代碼會非常難以維護。 所以為了提高開發效率,需要對代碼進行模塊化的拆分。整個項目模塊化、組件化程度越高,越容易管理和維護,出現問題更容易排查。 ## 3.三層架構和模型的關係 ![](https://i.imgur.com/K6SeyRE.png) 模型對整個項目中三層架構的每一層都提供支持,具體體現是使用模型對象封裝業務功能數據。 Java實體類有很多不同名稱: POJO:Plain old Java Object,傳統的普通的Java對象 entity:實體類 bean或Java bean domain:領域模型 ************* ### 下方以一個簡單的例子做說明 #### Java實體類的要求 必須有一個無參構造器 將來使用框架後,大量的對象都是框架通過反射來創建的。 Class<T> clazz = Class.forName("全類名"); clazz.newInstance(); 通過getXxx()、setXxx()方法定義屬性:getXxx()或setXxx()方法去掉get或set後,Xxx把首字母小寫,得到的xxx就是屬性名。 ```java= public class UserBasic { private Integer id; private String loginId; private String nickName; private String pwd; private String headImg; private UserDetail userDetail; //1:1 private List<Topic> topicList; //1:N private List<UserBasic> friendList; //1:N public UserBasic() { } ``` #### 持久化層(DAO):用來與數據庫連接,並進行數據庫增刪改查的操作 這裡選擇創建interface而不是class,是因為想保持彈性,讓之後如果有類似需求的DAO創建時,可以直接實現此interface後重寫 ```java= public interface UserBasicDAO { //根據帳號和密碼獲取特定用戶信息 public UserBasic getUserBasic(String loginId,String pwd); //獲取指定用戶的所有好友列表 public List<UserBasic> getUserBasicList(UserBasic userBasic); //根據id查詢UserBasic的信息 UserBasic getUserBasicById(Integer id); } ``` 為了完成具體對數據庫的操作,另外編寫一個實現DAO的impl ```java= public class UserBasicDAOImpl extends BaseDAO<UserBasic> implements UserBasicDAO{ @Override public UserBasic getUserBasic(String loginId, String pwd) { return super.load("sel * from t_user_basic where loginId = ? and pwd = ?",loginId,pwd); } @Override public List<UserBasic> getUserBasicList(UserBasic userBasic) { String sql = "SELECT fid as id FROM t_friend WHERE uid = ?"; return super.executeQuery(sql,userBasic.getId()); } @Override public UserBasic getUserBasicById(Integer id) { return load("select * from t_user_basic where id = ?",id); } } ``` #### 業務邏輯層(service):接收表述層(servlet)的請求,並轉達給持久化層(dao)進行增刪改查,再把結果回傳到表述層 這裡同樣是使用interface,方便之後的實現擴寫 可以注意到的是,Service與Dao的不同之處 Dao是對 **數據庫** 進行操作,Service則是針對 **實體類** 進行操作 ```java= public interface UserBasicService { UserBasic login(String loginId,String pwd); List<UserBasic> getFriendList(UserBasic userBasic); //根據id獲取指定用戶信息 UserBasic getUserBasicById(Integer id); } ``` 具體實現功能的impl ```java= public class UserBasicServiceImpl implements UserBasicService { private UserBasicDAO userBasicDAO = null; @Override public UserBasic login(String loginId, String pwd) { UserBasic userBasic = userBasicDAO.getUserBasic(loginId, pwd); return userBasic; } @Override public List<UserBasic> getFriendList(UserBasic userBasic) { //查詢到的只有好友的fid List<UserBasic> userBasicList = userBasicDAO.getUserBasicList(userBasic); //建立好友列表 List<UserBasic> friendList = new ArrayList<>(userBasicList.size()); //獲取完整的好友信息 for(int i = 0;i < userBasicList.size();i++){ UserBasic friend = userBasicList.get(i); friend = userBasicDAO.getUserBasicById(friend.getId()); friendList.add(friend); } return friendList; } @Override public UserBasic getUserBasicById(Integer id) { return userBasicDAO.getUserBasicById(id); } } ``` #### 表述層(Servlet):使用者發請求,透過請求來調用service的方法來實現 ```java= public class UserController { private UserBasicService userBasicService; private TopicService topicService; public String login(String loginId, String pwd, HttpSession session){ //1.登陸驗證 UserBasic userBasic = userBasicService.login(loginId, pwd); if(userBasic != null){ //1-1獲取相關好友信息 List<UserBasic> friendList = userBasicService.getFriendList(userBasic); //1-2獲取相關的日誌列表信息(但是只有id,沒有其他信息) List<Topic> topicList = topicService.getTopicList(userBasic); //將獲取的列表進行設置 userBasic.setFriendList(friendList); userBasic.setTopicList(topicList); //userBasic這個key是保存的是登錄者的信息 //friend這個key保存的是當前進入的是誰的空間 //如果進入到別人空間,userBasic不變(自己的),friend會改變(別人的) session.setAttribute("userBasic",userBasic); session.setAttribute("friend",userBasic); //登入成功,來到index頁面 return "index"; }else { //登入失敗,回到login頁面 return "login"; } } ``` 這裡可以留意到第三行、第四行,為何使用的是interface的UserBasicService,而不是clss? ```java= private UserBasicService userBasicService; ``` 答:因為在xml文件中,重新配置關鍵字與路徑的關係,因此雖然看起來是使用UserBasicService,實際上是UserBasicServiceImpl ```xml= <bean id="userBasicService" class="com.atguigu.qqzone.service.impl.UserBasicServiceImpl"> <property name="userBasicDAO" ref="userBasicDAO"/> </bean> ```