使用Bootstrap模態框實現增刪改查功能
模態框(Modal)是覆蓋在父窗體上的子窗體。通常,目的是顯示來自一個單獨的源的內容,可以在不離開父窗體的情況下有一些互動。子窗體可提供資訊、互動等。
本文實現的是使用模態框實現簡單的增刪改查的功能。主要思想是 使用一個模態框,使用jquery呼叫一個控制器方法返回一個分部視圖表單,載入到這個模態框中。然後,使用jquery 註冊 單擊事件,當模態框中的按鈕點選的時候,提交相應的表單。由於 不同的操作 將會返回不同的分部視圖表單,因此,表單提交到的控制器方法也不同,而分別實現了增刪改查。
一、新建一個檔案_Category.Modal.cshtml,裡面存放一個模態框categoryModal。分部檢視檔名約定使用 _ 開頭。
_Category.Modal.cshtml:
<!-- 模態框 -->
<div class="modal fade" id="categoryModal" tabindex="-1" role="dialog" aria-labelledby="categoryModalLabel" aria-hidden="true"> //該Modal 預設隱藏
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> //關閉模態框X按鈕
<h4 class="modal-title" id="catetoryModalLabel">
正在載入模態框標題
</h4>
</div>
<div class="modal-body" id="categoryPreview">
正在載入內容
</div>
<div class="modal-footer"> //讓關閉模態框的按鈕和操作按鈕並排放置。
<button type="button" class="btn btn-info" data-dismiss="modal">
關閉
</button>
<button type="button" class="btn btn-success" id="operateCategory-btn" >正在載入按鈕功能</button>
</div>
</div>
</div>
</div>
二、將模態框作為分部檢視存放在主檢視中,@{ Html.RenderPartial("_Category.Modal");}
1、主控制器和主檢視 Index 方法和Index檢視,javascript 指令碼本例是直接放在主檢視中,也可以放在單獨的js檔案或cshtml中。放在cshtml檔案中。定義一個cshtml檔案比單獨定義一個js檔案更加有用。居然在js裡面還可以使用url、html輔助方法。
主控制器
public ActionResult Index(string sortOrder,int page =1)
{
ViewBag.CurrentSort = sortOrder;
ViewBag.SortByNumber = string.IsNullOrEmpty(sortOrder) ? "CategoryNumber_desc": "";
ViewBag.SortByCreateTime = sortOrder == "CategoryCreateTime" ? "CategoryCreateTime_desc":"CategoryCreateTime";
ViewBag.SortByCategoryName = sortOrder == "CategoryName" ? "CategoryName_desc" : "CategoryName";
ViewBag.SortByIsUse =sortOrder == "IsUse" ? "IsUse_desc" : "IsUse";
var categories = from category in db.Categories.Include(c =>c.ReviewProjects).Include(c =>c.ReviewIndexItems).Include(c =>c.ReviewIndexSystems) select category; //用Linq方法語法就會提示需要轉換IOrderable<category>,用查詢表示式語法就不會提示需要轉換。
switch (sortOrder)
{
case "CategoryNumber_desc":
categories =categories.OrderByDescending(c =>c.CategoryNumber);
break;
case "CategoryCreateTime":
categories = categories.OrderBy(c => c.CategoryCreateTime);
break;
case "CategoryCreateTime_desc":
categories = categories.OrderByDescending(c => c.CategoryCreateTime);
break;
case "CategoryName":
categories = categories.OrderBy(c => c.CategoryName);
break;
case "CategoryName_desc":
categories = categories.OrderByDescending(c => c.CategoryName);
break;
case "IsUse":
categories =categories.OrderBy(c =>c.IsUsed);
break;
case "IsUse_desc":
categories = categories.OrderByDescending(c => c.IsUsed);
break;
default:
categories =categories.OrderBy(c =>c.CategoryNumber);
break;
}
int pageSize = 10;
foreach (var category in categories) //重新整理Index頁的時候就更新Category 類別 的使用狀態(使用還是未使用)
{
// if (category.ReviewProjects.Count >0 || category.ReviewIndexItems.Count >0 || category.ReviewIndexSystems.Count>0) 使用屬性返回Enumber元素的個數。也可以使用Count()方法返回。返回計數器的值
if(category.ReviewProjects.Any() ||category.ReviewIndexItems.Any() || category.ReviewIndexSystems.Any()) //Any()的效能優於count().
{
category.IsUsed = true;
}
else
{
category.IsUsed = false;
}
}
db.SaveChanges();
return View(categories.ToPagedList(page, pageSize));
}
主檢視 Index.cshtml
@model PagedList.IPagedList<UniversalReviewSystem.Models.Category>
@using PagedList.Mvc;
@{
ViewBag.Title = "評審專案類別";
}
<h2>@ViewBag.Title</h2>
<button class="btn btn-primary btn-lg" data-toggle="modal" data-target="#categoryModal" id="triggerModal-btn">新建類別</button>
<table class="table table-hover table-striped">
<thead>
<tr>
<th>
序號
</th>
<th>
@Html.ActionLink("評審專案類別編號", "Index", new { sortOrder = ViewBag.SortByNumber })
</th>
<th>
@Html.ActionLink("評審專案類別", "Index", new { sortOrder =ViewBag.SortByCategoryName })
</th>
<th>
@Html.ActionLink("建立時間", "Index", new { sortOrder = ViewBag.SortByCreateTime })
</th>
<th>
@Html.ActionLink("是否使用", "Index", new { sortOrder = ViewBag.SortByIsUse })
</th>
<th></th>
</tr>
</thead>
<tbody>
@{ int count = 0;}
@foreach (var item in Model)
{
<tr>
<td>
@{ count = count + 1;} @* 給行加序號 *@
@count
</td>
<td>
@Html.DisplayFor(modelItem =>item.CategoryNumber)
</td>
<td>
@Html.DisplayFor(modelItem => item.CategoryName)
</td>
<td>
@Html.DisplayFor(modelItem => item.CategoryCreateTime)
</td>
<td>
@(item.IsUsed ? "已使用" : "未使用")
</td>
<td>
@* @Html.ActionLink("編輯", "Edit", new { id = item.CategoryID })*@
<a href="javascript:updateCategory('@item.CategoryID', 'edit')">編輯</a> @* item.CategoryID 必須加引號,因為它本身不是數字,而是字元,為string 型別*@ 更新、刪除操作使用同一個javascript函式。
@if (!item.IsUsed) //如果該類別已經使用,則在檢視不能點選刪除按鈕
{
<text> |</text>
@* @Html.ActionLink("刪除", "Delete", new { id = item.CategoryID })*@
<a href="javascript:updateCategory('@item.CategoryID', 'delete')">刪除</a>
}
</td>
</tr>
}
</tbody>
<tfoot>
<tr>
<td class="text-muted" colspan="4">
每頁 @Model.PageSize 條記錄,共有 @Model.TotalItemCount 條記錄。第 @(Model.PageCount < Model.PageNumber ? 0 : Model.PageNumber) 頁,共 @Model.PageCount 頁。
</td>
</tr>
</tfoot>
</table>
@Html.PagedListPager(Model, page => Url.Action("Index", new { page, sortOrder=ViewBag.CurrentSort}),
new PagedListRenderOptions { LinkToFirstPageFormat = "首頁", LinkToNextPageFormat = "下一頁", LinkToPreviousPageFormat = "上一頁", LinkToLastPageFormat = "末頁", MaximumPageNumbersToDisplay = 3, DisplayItemSliceAndTotal = false }
)
@{ Html.RenderPartial("_Category.Modal");} //使用模態框作為分部檢視存放在主檢視中 @*模態框 在檢視層級中越往外層越好。*@
@section Scripts{
@Scripts.Render("~/bundles/jqueryval") //載入jqueryval驗證檔案。
<script>
$(function () {
$("#triggerModal-btn").click(function () {
$("#categoryModal #catetoryModalLabel").text("新建專案類別")
$("#categoryModal #operateCategory-btn").text("新建");
$("#categoryModal #categoryPreview").load('@Url.Action("GetEmptyCategory")'); //先彈出模態框,再Ajax載入內容。
});
//將父元素載入一個事件, 單擊它的子元素後就執行。jquery中繫結事件的方法有bind,delegate等多種,但on方法是最新的,最好的。
$("#categoryModal").on("click", "#operateCategory-btn", function () {
$("#categoryModal #categoryForm").submit();
});
});
function updateCategory(id, action) {
var currentId = id;
switch (action) {
case 'edit':
$.post("/Category/GetEditCategory", { id: currentId }).success(function (data) {
$("#categoryModal #categoryPreview").html(data); //使用ajax返回的資料使用 jquery的html()獲得的資料,只能讀取,不能更改。 因此修改ajax 返回的表單上執行 $("#categoryForm").attr('action', '@Url.Action("Edit")');會不起作用
});
$("#categoryModal #catetoryModalLabel").text("編輯專案類別");
$("#categoryModal #operateCategory-btn").text("確認修改");
// $("#categoryForm").attr('action', '@Url.Action("Edit")'); //在javascript 中 只能使用控制器操作方法的如 @* @Url.Action("Delete") ,而不能使用帶路由值的Url方法,如@Url.Action("Delete", new { id = currentId })。*@
//使用attr 屬性與設定的值必須加引號,單引號或雙引號都可以。
// $("#categoryForm").attr('action', '/Category/Edit' + currentId);
$("#categoryModal").modal('show');
break;
case 'delete':
$.post("/Category/GetDeleteCategory", { id: currentId }).success(function (data) {
$("#categoryModal #categoryPreview").html(data); //使用ajax返回的資料使用 jquery的html()獲得的資料,只能讀取,不能更改。
});
$("#categoryModal #catetoryModalLabel").text("刪除專案類別");
$("#categoryModal #operateCategory-btn").text("確認刪除");
// $("#categoryForm").attr('action', '@Url.Action("Delete")');
$("#categoryModal").modal('show');
/*
$("#categoryModal #operateCategory-btn").click(function () {
$("#categoryModal #CategoryForm").submit();
});
*/
break;
default:
console.debug('Unknown action ' + action); //寫給瀏覽器除錯用的,按F12鍵會在瀏覽器 控制檯視窗顯示資訊。
}
}
</script>
}
三、實現新增類別功能。
執行的順序是:當單擊主檢視上的按鈕觸發模態框顯示,然後更新模態框的標題及按鈕文字,使用jquery load ajax方法訪問控制器操作方法,返回分部視圖表單到模態框。最後當單擊模態框按鈕的時候,提交表單。
(1)|主檢視Index 中有觸發模態框的按鈕。
<button class="btn btn-primary btn-lg" data-toggle="modal" data-target="#categoryModal" id="triggerModal-btn">新建類別</button> //data-toggle ="modal" data-tartget="#categoryModal" 自動實現 單擊按鈕,觸發#categoryModal.
當然,也可以通過 $("#categoryModal").modal('show'),來觸發顯示模態框。
javascript:
$(function () {
$("#triggerModal-btn").click(function () {
$("#categoryModal #catetoryModalLabel").text("新建專案類別")
$("#categoryModal #operateCategory-btn").text("新建");
$("#categoryModal #categoryPreview").load('@Url.Action("GetEmptyCategory")'); //先彈出模態框,再Ajax載入分部檢視。
});
(2)新建一個增加 類別的模態框表單檔案。_AddCategory.Modal.Preview.cshtml 。實際上也是從基架自動建立的Create 檢視中直接拷貝作為此分部檢視的內容。
_AddCategory.Modal.Preview.cshtml:
@model UniversalReviewSystem.Models.Category
<!-- Form標籤中的id 大小寫敏感,id =CategoryForm 會導致jquery 無響應-->
@using (Html.BeginForm("Create", "Category", FormMethod.Post, htmlAttributes: new { id = "categoryForm" }))
{
@Html.AntiForgeryToken()
<div class="form-horizontal">
@Html.ValidationSummary(true, "", new { @class = "text-danger" })
<div class="form-group">
@Html.LabelFor(model => model.CategoryNumber, htmlAttributes: new { @class = "control-label col-md-4" })
<div class="col-md-8">
@Html.EditorFor(model => model.CategoryNumber, new { htmlAttributes = new { @class = "form-control", placeholder = "請輸入評審專案類別編號,如01" } })<span class="help-block">評審類別編碼不能與系統中已有的編碼重複,否則,就會新建不成功。</span>
@Html.ValidationMessageFor(model => model.CategoryNumber, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.CategoryName, htmlAttributes: new { @class = "control-label col-md-4" })
<div class="col-md-8">
@Html.EditorFor(model => model.CategoryName, new { htmlAttributes = new { @class = "form-control", placeholder = "請輸入評審專案類別名稱" } })<span class="help-block">專案類別名稱如:人才培養方案。如果系統中存在此類別,就不用重新新建了。</span>
@Html.ValidationMessageFor(model => model.CategoryName, "", new { @class = "text-danger" })
</div>
</div>
@* <div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="新建" class="btn btn-default" />
</div>
</div>
*@
</div>
}
(3)新增一個控制器操作方法GetEmptyCategory,用於返回包含表單的 _AddCategory.Modal.Preview 分部檢視檔案,載入到模態框中。
[HttpGet]
[Authorize(Roles = "SuperAdministrator")]
public ActionResult GetEmptyCategory()
{
return PartialView("_AddCategory.Modal.Preview");
}
(4)因為使用jquery on方法註冊,模態框按鈕的單擊事件,從而觸發模態框,提交表單。因為模態框是載入的是 新增 類別 的表單,因此,新增檢視的表單會被提交到Create控制器。
//將父元素載入一個事件, 單擊它的子元素後就執行
$("#categoryModal").on("click", "#operateCategory-btn", function () {
$("#categoryModal #categoryForm").submit();
});
(5)執行Create Post控制器方法: 現在不需要get版本的方法和Create檢視了。
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "CategoryNumber,CategoryName")] Category category)
{
if (ModelState.IsValid)
{
ValidateCategoryNumberDumplicate(category);
}
if (ModelState.IsValid)
{
db.Categories.Add(category);
db.SaveChanges();
return RedirectToAction("Index");
}
var CategoryNumberErrorMessages = "";
foreach (var error in ModelState["CategoryNumber"].Errors)
{
CategoryNumberErrorMessages += error.ErrorMessage;
}
throw new Exception(CategoryNumberErrorMessages); //丟擲異常不是一個驗證錯誤的好方法。可以使用Remote 註解實現遠端伺服器驗證。
}
//檢查專案類別編號是否重複,如果重複,給模型狀態的 類別程式碼欄位設定錯誤資訊,返回給檢視。
private void ValidateCategoryNumberDumplicate(Category category)
{
if (category.CategoryNumber != null)
{
var dumplicateCategory = db.Categories.Where(c => c.CategoryNumber == category.CategoryNumber).AsNoTracking().SingleOrDefault();
if (dumplicateCategory != null && dumplicateCategory.CategoryNumber == category.CategoryNumber)
{
string errorMessage = string.Format("該編號與 {0} 評審專案類別的編號重複,請重新編號!!!", dumplicateCategory.CategoryName);
ModelState.AddModelError("CategoryNumber", errorMessage);
}
}
}
二、實現更新和刪除功能。
1、在Index 檢視中 每條記錄的編輯、刪除連線 改設定為執行javascript函式。
<td>
@* @Html.ActionLink("編輯", "Edit", new { id = item.CategoryID })*@
<a href="javascript:updateCategory('@item.CategoryID', 'edit')">編輯</a> @* item.CategoryID 必須加引號,因為它本身不是數字,而是字元,為string 型別*@
@if (!item.IsUsed)
{
<text> |</text>
@* @Html.ActionLink("刪除", "Delete", new { id = item.CategoryID })*@
<a href="javascript:updateCategory('@item.CategoryID', 'delete')">刪除</a>
}
</td>
2、執行主檢視 Index中的 javascript 。執行順序於增加類別 是一樣的。通過jquery 訪問控制器方法,返回相應分部視圖表單載入到模態框,顯示模態框,點選模態框的按鈕觸發對應的表單提交至控制器。完成操作。
function updateCategory(id, action) {
var currentId = id;
switch (action) {
case 'edit':
$.post("/Category/GetEditCategory", { id: currentId }).success(function (data) {
$("#categoryModal #categoryPreview").html(data); //使用ajax返回的資料使用 jquery的html()獲得的資料,只能讀取,不能更改。 因此修改ajax 返回的表單上執行 $("#categoryForm").attr('action', '@Url.Action("Edit")');會不起作用
});
$("#categoryModal #catetoryModalLabel").text("編輯專案類別");
$("#categoryModal #operateCategory-btn").text("確認修改");
// $("#categoryForm").attr('action', '@Url.Action("Edit")'); //在javascript 中 只能使用控制器操作方法的如 @* @Url.Action("Delete") ,而不能使用帶路由值的Url方法,如@Url.Action("Delete", new { id = currentId })。*@
//使用attr 屬性與設定的值必須加引號,單引號或雙引號都可以。
// $("#categoryForm").attr('action', '/Category/Edit' + currentId);
$("#categoryModal").modal('show');
break;
case 'delete':
$.post("/Category/GetDeleteCategory", { id: currentId }).success(function (data) {
$("#categoryModal #categoryPreview").html(data); //使用ajax返回的資料使用 jquery的html()獲得的資料,只能讀取,不能更改。
});
$("#categoryModal #catetoryModalLabel").text("刪除專案類別");
$("#categoryModal #operateCategory-btn").text("確認刪除");
// $("#categoryForm").attr('action', '@Url.Action("Delete")');
$("#categoryModal").modal('show');
/*
$("#categoryModal #operateCategory-btn").click(function () {
$("#categoryModal #CategoryForm").submit();
});
*/
break;
default:
console.debug('Unknown action ' + action); //寫給瀏覽器除錯用的,按F12鍵會在瀏覽器 控制檯視窗顯示資訊。
}
}
3、在相應控制器的檢視資料夾中新建一個編輯類別和刪除類別的分部視圖表單 _EditCategory.Modal.Preview.cshtml和 _DeleteCategory.Modal.Preview.cshtml。只執行客戶端驗證。
_EditCategory.Modal.Preview.cshtml:
@model UniversalReviewSystem.Models.Category
@using (Html.BeginForm("Edit", "Category", FormMethod.Post,htmlAttributes: new { id = "categoryForm" }))
{
@Html.AntiForgeryToken()
<div class="form-horizontal">
@Html.ValidationSummary(true, "", new { @class = "text-danger" })
@* @Html.HiddenFor(model => model.CategoryID) *@
<input type="hidden" value="@Model.CategoryID" name="id" /> @* 在編輯和刪除情況下,由基架自動生成的action和View中 會自動在表單標籤的action 屬性中生成controller/action/id 的值,預設是此檢視的路由值,從而正確提交。但是換成了模態框,不存在了Get 方式的控制器了,因此,hiddenfor 輔助方法生成的name =CategoryID 與預設控制器接收的引數id的值不匹配,會找不到id值。*@
<div class="form-group">
@Html.LabelFor(model => model.CategoryNumber, htmlAttributes: new { @class = "control-label col-md-4" })
<div class="col-md-8">
<p class="form-control-static">@Html.DisplayFor(model => model.CategoryNumber)</p> @*使用靜態控制元件的方法*@
@*@Html.EditorFor(model => model.CategoryNumber, new { htmlAttributes = new { @class = "form-control" } })*@
@*<input type="text" value="@Model.CategoryNumber" class="form-control" disabled name="CategoryNumber" />*@
@Html.ValidationMessageFor(model => model.CategoryNumber, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.CategoryName, htmlAttributes: new { @class = "control-label col-md-4" })
<div class="col-md-8">
@Html.EditorFor(model => model.CategoryName, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.CategoryName, "", new { @class = "text-danger" })
</div>
</div>
@*
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="儲存" class="btn btn-default" />
</div>
</div>*@
</div>
}
3、定義Edit 和Delete Post版本的操作方法,分別返回編輯和更新的 分部視圖表單載入到模態框。
[HttpPost]
[Authorize(Roles = "SuperAdministrator")]
public ActionResult GetEditCategory(string id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Category category = db.Categories.Find(id);
if (category == null)
{
return HttpNotFound();
}
return PartialView("_EditCategory.Modal.Preview", category);
}
[HttpPost]
[Authorize(Roles = "SuperAdministrator")]
public ActionResult GetDeleteCategory(string id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Category category = db.Categories.Find(id);
if (category == null)
{
return HttpNotFound();
}
return PartialView("_DeleteCategory.Modal.Preview", category);
}
4、通過jquery 事件繫結,點選模態框中的按鈕觸發表單提交。
on 方法實現,於增加 類別相同。
5、表單提交至Edit 和Delete Post 版本的控制器方法,執行編輯和刪除操作。
[HttpPost]
[ValidateAntiForgeryToken]
[ActionName("Edit")]
public ActionResult EditPost(string id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
var categoryToUpdate = db.Categories.Include(c => c.ReviewIndexItems).Include(c => c.ReviewIndexSystems).Include(c => c.ReviewProjects).SingleOrDefault(c => c.CategoryID == id);
if (TryUpdateModel(categoryToUpdate, new string[] { "CategoryName" }))
//TryUpdateModel或者UpdateModel 與[Bind(Include ="","") model] 的差別的是Bind白名單 使用 模型繫結的引數model去替換資料庫中的白名單欄位,使用的是引數model物件,如果白名單裡面沒有某個屬性,就為空。因此,如果有構造方法中指定了建立時間,他會使用引數model中的預設建立的值去更新。
// 而TryUpdateModel(model,new string [] {"properties"})) 先在資料庫中找到這個模型,然後,只更新這個模型的指定屬性。如果不包括某些屬性的話,就不會更新。因此,如果有構造方法中指定了建立時間,他也不會去更新。
{
// ValidateCategoryNumberDumplicate(categoryToUpdate); 在編輯操作方法中已經用不著驗證編碼是否重複了,因為編輯檢視不修改類別編碼;
if (categoryToUpdate.ReviewIndexItems.Count() >0 ||categoryToUpdate.ReviewIndexSystems.Count() >0 || categoryToUpdate.ReviewProjects.Count() >0)
{
categoryToUpdate.IsUsed = true;
}
else
{
categoryToUpdate.IsUsed = false;
}
//已不需要下面的語句,來設定資料庫上下文跟蹤實體的狀態了,TryUpdateModel 顯式繫結 已自動設定跟蹤狀態的EntityState.Modified標記。
// db.Entry(categoryToUpdate).State = EntityState.Modified;
db.SaveChanges();
if (Request.UrlReferrer != null)
{
var returnUrl = Request.UrlReferrer.ToString();
return new RedirectResult(returnUrl); //由於使用的是表單提交而非Ajax無重新整理非同步提交。所以使用jquery將表單提交到控制器後,返回Request.UrlReferrer返回到上一個頁面將是資料庫更新後的狀態,篩選、排序、分頁都保持不變。
}
return RedirectToAction("Index");
}
return View(categoryToUpdate);
}
// POST: Category/Delete/5
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public ActionResult DeleteConfirmed(string id)
{
Category category = db.Categories.Find(id);
db.Categories.Remove(category);
db.SaveChanges();
if (Request.UrlReferrer != null)
{
var returnUrl = Request.UrlReferrer.ToString();
return new RedirectResult(returnUrl); //由於使用的是表單提交而非Ajax無重新整理非同步提交。所以使用jquery將表單提交到控制器後,返回Request.UrlReferrer返回到上一個頁面將是資料庫更新後的狀態,篩選、排序、分頁都保持不變。
}
return RedirectToAction("Index");
}
這樣,就實現了使用模態框的增刪改查功能。需要以下步驟就可以修改為模態框 。新建一個模態框並放置在檢視中。將單獨的頁面檢視修改成分部檢視,定義返回分部檢視的控制器方法,定義jqueryl訪問控制器方法載入分部檢視到模態框,通過模態框按鈕提交表彰。
同時,可以刪去get版本的方法。