在前面的小節中,我們已經成功的將前臺交給了yoman來處理。前后臺的完全分離,意味著,我們可以在一臺服務器上布署前臺代碼,然后在另一臺服務器上布署后臺代碼。也就是說,即使我們將前臺與后臺布署在了同一臺服務器上,實際上前臺和后臺也是兩套不同的系統。不同的系統間通訊較同一系統間的通信顯得復雜一些。
前臺與后臺大體是這樣通訊的:
1. 前臺 通過http協議,發送一個請求(GET\POST)。
2. 后臺 接收到這個請求后,返回json數據。
3. 前臺 接到json數據后,為用戶做出響應。
由于瀏覽器與后臺交互 ,本質上也是在進行get,post請求。所以javaee在接收數據時沒有什么不同。那么不同點就在于:以前我們返回的html數據,而此時,我們需要返回json格式的數據。
下面,我們設置我們的后臺,使其能夠返回前臺可用的JSON數據。
# 去除后臺冗余的代碼
我們在上一章中,在前臺建立了性別過濾器,所以后臺teacher實體中的getSexAttr()方法已經成為了冗余方法。實際在前后臺分離的開發中,我們也的確不會在后臺的實體中增加一些類似于getXXXXAttr()的方法來進行轉換運算。當然,在本教程中,如果我們不刪除getSexAttr()方法,還會引發一些json轉換錯誤。
`getSexAttr()`方法位于
`package com.mengyunzhi.javaee.entity.teacher`中
# 引入JSON Plugin
struts如果返回json格式的數據呢?還記得我們一直強調的:
> 做為初學者的我們,我們的需求早早的就被大牛們解決了。
沒錯,struts返回json也是如此.
我們仍然打開,struts2.5的docs文檔文件夾,并在此啟用一個http-server服務,然后在本地來快速查看struts的文檔。
> 我們可以使用:`http-server -p 端口號` 來自行指定一個端口來避免沖突。

我們依次打開:struts2-plugins/ -> struts2-json-plugin/ -> apidocs/
最終打開struts2-plugins官方文檔: [http://127.0.0.1:8081/struts2-plugins/struts2-json-plugin/apidocs/](http://127.0.0.1:8081/struts2-plugins/struts2-json-plugin/apidocs/)
然后找到左側菜單,找到:

有前期,我們有教程的情況下,其實我們并不需要把官方文檔讀一遍。
但讀官方文檔絕對是學習一門新語言最正確的途徑。我們要嘗試著去讀官方的說明文檔,在前期結合google的情況下,能夠弄清楚怎么使用官方文檔。官方文檔中的一些示例代碼又是該如何應用到具體項目中的。
## 復制jar包
我們在下載的struts中的lib文件夾中,找到struts2-json-plugin-2.3.31

并復制到javaee項目中的WebContent下的WEB-INF下的lib文件夾中。
## 添加Libraries
然后,我們在javaee上右鍵 -> build path -> Configure Build Path -> add JARS 然后找到我們剛剛復制過來的struts2-json-plugin-2.3.31, 應用并添加.
## 配置struts.xml
1. 修改包繼承
```
...
<!-- 繼承自json-default. json-default是json插件為我們提供的 -->
<package name="teacher" namespace="/teacher" extends="json-default">
...
```
2. 修改action返回類型及設置攔截器
```http://localhost:8080/javaee/teacher/
...
<!-- 列表 -->
<action name="index" class="com.mengyunzhi.javaee.action.teacher.Index">
<!-- 返回類型設置為json -->
<result name="success" type="json">
</result>
<!-- 配置攔截器,使傳入的json數據能夠成功的通過setXXX()方法來傳值 -->
<interceptor-ref name="defaultStack" />
<interceptor-ref name="json">
<param name="enableSMD">true</param>
</interceptor-ref>
</action>
...
```
3. 重啟tomcat
修改struts后,如果控制臺沒有重新啟到tomcat的話,需要我們手動停止,然后再啟動.

## 測試
此時,我們打開瀏覽器,并打開瀏覽器控制臺。打開:[http://localhost:8080/javaee/teacher/](http://localhost:8080/javaee/teacher/)
查看返回信息:

返回值的類型為`application/json`,當瀏覽器接收到此信息時,會將接收到的數據做為json數據來處理。的確,當我們再查看JSON選項卡時,數據已經以json的形式展現給了我們。
我們再修改一下每頁顯示條數,然后查看數據返回是否正確。
[http://localhost:8080/javaee/teacher/?pageSize=3](http://localhost:8080/javaee/teacher/?pageSize=3)

數據返回3條數據,正確.
<hr />
### 刪除后實體代碼如下:
```
package com.mengyunzhi.javaee.entity;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Index;
import com.mengyunzhi.javaee.common.db.MysqlJavaee;
// 聲明主體
@Entity
public class Teacher {
// 聲明主鍵
// 聲明一個名為idGenerator的native類型構造器
// 使用這個構造器設置ID為自增屬性
@Id
@GenericGenerator(name = "idGenerator", strategy = "native")
@GeneratedValue(generator = "idGenerator")
private int id; // 主鍵
private String name; // 姓名
// 聲明長度(用戶名不超過20位長度,定長能夠提升效率)
@Column(columnDefinition = "char(20)")
// 聲明為索引(該字段將來用于查詢 ,增加索引將大幅提升查詢效率)
@Index(name = "username")
private String username; // 用戶名
private String email; // 郵箱
private Boolean sex = false; // 性別 0:男;1:女
// 密碼采用sha1 md5加密,長度固定。
@Column(columnDefinition = "char(40)")
private String password; // 密碼
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Boolean getSex() {
return sex;
}
public void setSex(Boolean sex) {
this.sex = sex;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Teacher() {
}
public Teacher(int id, String name, String username, String email,
Boolean sex, String password) {
// super();
this.id = id;
this.name = name;
this.username = username;
this.email = email;
this.sex = sex;
this.password = password;
}
public String toString() {
return "Teacher [id=" + id + ", name=" + name + ", username="
+ username + ", email=" + email + ", sex=" + sex
+ ", password=" + password + "]";
}
@SuppressWarnings("unchecked")
static public List<Teacher> all() {
// 實例化列表 teachers
List<Teacher> teachers = new ArrayList<Teacher>();
// 創建會話(這里的session也是會話的意思,我們以前接觸的http中的session,處理的是用戶與服務器的對話)
Session session = MysqlJavaee.getCurrentSession();
// 開啟事務(使用緩沖池進行數據庫的連接)
Transaction transaction = session.beginTransaction();
// 在這里,必須使用try catch finally語句。來確定會話正常關閉.
// 否則,當操作數據庫產生錯誤時,你可能需要重啟mysql服務
try {
// 查詢Teacher表,注意:是Teacher ,而不是 teacher
Query query = session.createQuery("from Teacher");
// 預查詢,只有在事務提交時,才進行查詢操作
teachers = query.list();
// 提交事務
transaction.commit();
// 捕獲異常
} catch (HibernateException e) {
// 如果事務執行異常,則回滾事務
if (null != transaction) {
transaction.rollback();
}
// 打印異常
e.printStackTrace();
} finally {
// 如果session處于開啟狀態,則關閉session
if (session.isOpen()) {
// 關閉會話
session.close();
}
}
return teachers;
}
/**
* 分頁數據
*
* @param page
* 第幾頁
* @param pageSize
* 每頁大小
* @return
*/
@SuppressWarnings("unchecked")
static public List<Teacher> paginate(int page, int pageSize) {
// 實例化列表 teachers
List<Teacher> teachers = new ArrayList<Teacher>();
// 創建會話(這里的session也是會話的意思,我們以前接觸的http中的session,處理的是用戶與服務器的對話)
Session session = MysqlJavaee.getCurrentSession();
// 開啟事務(使用緩沖池進行數據庫的連接)
Transaction transaction = session.beginTransaction();
// 在這里,必須使用try catch finally語句。來確定會話正常關閉.
// 否則,當操作數據庫產生錯誤時,你可能需要重啟mysql服務
try {
// 查詢Teacher表,注意:是Teacher ,而不是 teacher
Query query = session.createQuery("from Teacher");
// 計算并設置第一條記錄的位置
int index = (page - 1) * pageSize;
query.setFirstResult(index);
// 每頁大小
query.setMaxResults(pageSize);
teachers = query.list();
// 提交事務
transaction.commit();
// 捕獲異常
} catch (HibernateException e) {
// 如果事務執行異常,則回滾事務
if (null != transaction) {
transaction.rollback();
}
// 打印異常
e.printStackTrace();
} finally {
// 如果session處于開啟狀態,則關閉session
if (session.isOpen()) {
// 關閉會話
session.close();
}
}
return teachers;
}
/**
* 分頁數據
*
* @param page
* 第幾頁
* @param pageSize
* 每頁大小
* @return
*/
@SuppressWarnings("unchecked")
static public List<Teacher> paginate(String name, int page, int pageSize) {
// 實例化列表 teachers
List<Teacher> teachers = new ArrayList<Teacher>();
// 創建會話(這里的session也是會話的意思,我們以前接觸的http中的session,處理的是用戶與服務器的對話)
Session session = MysqlJavaee.getCurrentSession();
// 開啟事務(使用緩沖池進行數據庫的連接)
Transaction transaction = session.beginTransaction();
// 在這里,必須使用try catch finally語句。來確定會話正常關閉.
// 否則,當操作數據庫產生錯誤時,你可能需要重啟mysql服務
try {
// 查詢Teacher表,注意:是Teacher ,而不是 teacher
Query query = session.createQuery("from Teacher where name like '%"
+ name + "%'");
// 計算并設置第一條記錄的位置
int index = (page - 1) * pageSize;
query.setFirstResult(index);
// 每頁大小
query.setMaxResults(pageSize);
teachers = query.list();
// 提交事務
transaction.commit();
// 捕獲異常
} catch (HibernateException e) {
// 如果事務執行異常,則回滾事務
if (null != transaction) {
transaction.rollback();
}
// 打印異常
e.printStackTrace();
} finally {
// 如果session處于開啟狀態,則關閉session
if (session.isOpen()) {
// 關閉會話
session.close();
}
}
return teachers;
}
/**
* 通過ID獲取Teacher實體
*
* @param id
* @return
*/
static public Teacher getTeacherById(int id) {
// 實例化Teacher
Teacher teacher = new Teacher();
// 創建會話(這里的session也是會話的意思,我們以前接觸的http中的session,處理的是用戶與服務器的對話)
Session session = MysqlJavaee.getCurrentSession();
// 開啟事務(使用緩沖池進行數據庫的連接)
Transaction transaction = session.beginTransaction();
// 在這里,必須使用try catch finally語句。來確定會話正常關閉.
// 否則,當操作數據庫產生錯誤時,你可能需要重啟mysql服務
try {
// 使用Teacher.class來獲取到Teacher的類名(包括包名)
teacher = (Teacher) session.get(Teacher.class, id);
// 提交事務
transaction.commit();
// 捕獲異常
} catch (HibernateException e) {
// 如果事務執行異常,則回滾事務
if (null != transaction) {
transaction.rollback();
}
// 打印異常
e.printStackTrace();
} finally {
// 如果session處于開啟狀態,則關閉session
if (session.isOpen()) {
// 關閉會話
session.close();
}
}
return teacher;
}
public Boolean update() {
// 創建會話(這里的session也是會話的意思,我們以前接觸的http中的session,處理的是用戶與服務器的對話)
Session session = MysqlJavaee.getCurrentSession();
// 開啟事務(使用緩沖池進行數據庫的連接)
Transaction transaction = session.beginTransaction();
// 在這里,必須使用try catch finally語句。來確定會話正常關閉.
// 否則,當操作數據庫產生錯誤時,你可能需要重啟mysql服務
try {
// 更新
session.update(this);
// 提交事務
transaction.commit();
// 捕獲異常
} catch (HibernateException e) {
// 如果事務執行異常,則回滾事務
if (null != transaction) {
transaction.rollback();
}
// 打印異常
e.printStackTrace();
} finally {
// 如果session處于開啟狀態,則關閉session
if (session.isOpen()) {
// 關閉會話
session.close();
}
}
return true;
}
public Boolean delete() {
// 創建會話(這里的session也是會話的意思,我們以前接觸的http中的session,處理的是用戶與服務器的對話)
Session session = MysqlJavaee.getCurrentSession();
// 開啟事務(使用緩沖池進行數據庫的連接)
Transaction transaction = session.beginTransaction();
// 在這里,必須使用try catch finally語句。來確定會話正常關閉.
// 否則,當操作數據庫產生錯誤時,你可能需要重啟mysql服務
try {
// 刪除
session.delete(this);
// 提交事務
transaction.commit();
// 捕獲異常
} catch (HibernateException e) {
// 如果事務執行異常,則回滾事務
if (null != transaction) {
transaction.rollback();
}
// 打印異常
e.printStackTrace();
} finally {
// 如果session處于開啟狀態,則關閉session
if (session.isOpen()) {
// 關閉會話
session.close();
}
}
return true;
}
}
```
當習慣了完美的前端自動化開發后,我們好像已經不愿意在去手工去寫那么冗余的代碼了。
- README
- 第一章:準備
- 第二章:Hello World!
- 第一節:查看工程文件
- 第二節:JDK、JRE與環境變量
- 第三節:index.jsp
- 第三章:Hello Struts
- 第一節:Web.xml
- 第二節:單入口
- 第三節:Hello Struts
- 第四節:觸發C層
- 第四章:建立數據表
- 第一節:建立實體類
- 第二節:測試一
- 第三節:測試二
- 第四節:引入Hibernate
- 第五節:配置Hibernate
- 第六節:建立連接
- 第七節:實體類映射數據表
- 第八節:完善數據表
- 第五章:教師管理
- 第一節:增加數據--add
- 第二節:增加數據--save
- 1 獲取傳入數據數據
- 2 數據寫入測試
- 3 對接C層
- 第三節:數據列表
- 1 獲取數據
- 2 重構代碼
- 3 C層對接--初始化
- 4 C層添加數據
- 5 V層顯示數據
- 6 獲取數據庫中數據
- 7 顯示性別
- 8 分頁
- 9 條件查詢
- 第四節:修改數據
- 1 edit
- 2 update
- 第五節:刪除數據
- 第六節:總結
- 第六章:重構C層
- 第一節:繼承ActionSupport類
- 第二節:數據驗證
- 第七章:前臺分離(前臺)
- 第一節:環境搭建
- 第二節:運行環境
- 第三節:共享開發環境
- 第四節:生產環境
- 第八章:前臺開發(前臺)
- 第一節:本地化
- 第二節:教師列表
- 1 引入M層
- 2 模擬后臺返回數據
- 3 C與M對接
- 4 C與V對接
- 第九章:前后臺對接(前后臺)
- 第一節:后臺輸出json(后臺)
- 第二節:對接前臺(全棧)
- 第二節:對接API(前臺)
- 第二節:跨域請求(后臺)
- 第三節:重構代碼(前臺)
- 第十章:重構后臺M層
- 第一節:數據訪問DAO層
- 第二節:項目整體重構
- 第十一章:用戶登陸(前后臺)
- 第一節:制定規范
- 第二節:定制測試用例
- 第三節:后臺輸入測試代碼(后臺)
- 第四節:postman(后臺)
- 第五節:新建用戶登陸模塊(前臺)
- 第六節:代碼重構(前臺)
- 第十二章:班級管理(前后臺)
- 第一節:班級列表
- 1 原型開發
- 2 制定規范
- 3 后臺對接開發
- 4 前臺對接開發
- 第二節:Add
- 1 原型開發
- 2 制定規范
- 3 后臺對接開發
- 4 前臺對接開發
- 第三節:Save
- 1 制定規范
- 2 后臺對接開發
- 3 前臺對接開發
- 第四節:Edit
- 1 原型開發
- 2 制定規范
- 3 后臺對接開發
- 4 前臺對接開發
- 第五節:Update
- 1 制定規范
- 2 后臺對接開發
- 3 前臺對接開發
- 第六節:Delete
- 1 制定規范
- 2 后臺對接開發
- 3 前臺對接開發
- 第七節:小結
- 第十三章:班級管理(API)
- 第一節:ER圖
- 第二節:create
- 1 實體層
- 2 dao層
- 3 service(server)層
- 4 action層
- 第三節:ManyToOne
- 第四節:Read
- 1 service(server)層
- 2 action層
- 第五節:update
- 1 service(server)層
- 2 action層
- 第六節:update
- 第十四章:重構服務層