---
# System prepended metadata

title: 業務邏輯上使用的三層架構
tags: [Java Web-mvc, Java Web-常用知識點, Java Web-Servlet]

---

# 業務邏輯上使用的三層架構
###### 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>
```