# 業務邏輯上使用的三層架構
###### tags: `Java Web-常用知識點`
###### tags: `Java Web-mvc`
###### tags: `Java Web-Servlet`
## 1.三層架構的劃分

表述層:負責處理瀏覽器請求、返回響應、頁面調度
業務邏輯層:負責處理業務邏輯,根據業務邏輯把持久化層從數據庫查詢出來的數據進行運算、組裝,封裝好後返回給表述層,也可以根據業務功能的需要調用持久化層把數據保存到數據庫、修改數據庫中的數據、刪除數據庫中的數據
持久化層:根據上一層的調用對數據庫中的數據執行增刪改查的操作
## 2.三層架構的好處
如果不做三層構造:

所有和當前業務功能需求相關的代碼全部耦合在一起,如果其中有任何一個部分出現了問題,牽一發而動全身,導致其他無關代碼也要進行相應的修改。這樣的話代碼會非常難以維護。
所以為了提高開發效率,需要對代碼進行模塊化的拆分。整個項目模塊化、組件化程度越高,越容易管理和維護,出現問題更容易排查。
## 3.三層架構和模型的關係

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