Try   HackMD

業務邏輯上使用的三層架構

tags: Java Web-常用知識點
tags: Java Web-mvc
tags: Java Web-Servlet

1.三層架構的劃分

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

表述層:負責處理瀏覽器請求、返回響應、頁面調度

業務邏輯層:負責處理業務邏輯,根據業務邏輯把持久化層從數據庫查詢出來的數據進行運算、組裝,封裝好後返回給表述層,也可以根據業務功能的需要調用持久化層把數據保存到數據庫、修改數據庫中的數據、刪除數據庫中的數據

持久化層:根據上一層的調用對數據庫中的數據執行增刪改查的操作

2.三層架構的好處

如果不做三層構造:

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

所有和當前業務功能需求相關的代碼全部耦合在一起,如果其中有任何一個部分出現了問題,牽一發而動全身,導致其他無關代碼也要進行相應的修改。這樣的話代碼會非常難以維護。

所以為了提高開發效率,需要對代碼進行模塊化的拆分。整個項目模塊化、組件化程度越高,越容易管理和維護,出現問題更容易排查。

3.三層架構和模型的關係

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

模型對整個項目中三層架構的每一層都提供支持,具體體現是使用模型對象封裝業務功能數據。

​​​​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就是屬性名。
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後重寫

public interface UserBasicDAO { //根據帳號和密碼獲取特定用戶信息 public UserBasic getUserBasic(String loginId,String pwd); //獲取指定用戶的所有好友列表 public List<UserBasic> getUserBasicList(UserBasic userBasic); //根據id查詢UserBasic的信息 UserBasic getUserBasicById(Integer id); }

為了完成具體對數據庫的操作,另外編寫一個實現DAO的impl

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則是針對 實體類 進行操作

public interface UserBasicService { UserBasic login(String loginId,String pwd); List<UserBasic> getFriendList(UserBasic userBasic); //根據id獲取指定用戶信息 UserBasic getUserBasicById(Integer id); }

具體實現功能的impl

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的方法來實現

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?

private UserBasicService userBasicService;

答:因為在xml文件中,重新配置關鍵字與路徑的關係,因此雖然看起來是使用UserBasicService,實際上是UserBasicServiceImpl

<bean id="userBasicService" class="com.atguigu.qqzone.service.impl.UserBasicServiceImpl"> <property name="userBasicDAO" ref="userBasicDAO"/> </bean>