• ASP.NET Core MVC 打造一个简单的图书馆管理系统 (修正版)(四)图书信息的增删改查


    前言:

    本系列文章主要为我之前所学知识的一次微小的实践,以我学校图书馆管理系统为雏形所作。

    本系列文章主要参考资料:

    微软文档:https://docs.microsoft.com/zh-cn/aspnet/core/getting-started/?view=aspnetcore-2.1&tabs=windows

    《Pro ASP.NET MVC 5》、《锋利的 jQuery》

    此系列皆使用 VS2017+C# 作为开发环境。如果有什么问题或者意见欢迎在留言区进行留言。 

    项目 github 地址:https://github.com/NanaseRuri/LibraryDemo

    本章内容:分页、自定义 HtmlHelper、通过模态窗口确认是否提交表单、上传文件、获取文件、预览文件、select 元素、表单提交数组、checkbox、js 确认关闭页面

    注:在对 EF 中的数据进行更改时,需要调用对应 Context 的 SaveChange 方法才能对更改进行保存。

    一、视图分页视图模型

    首先创建一个视图模型用于确定每页的书籍数、页数

     1     public class PagingInfo
     2     {
     3         public int TotalItems { get; set; }
     4         public int ItemsPerPage { get; set; }
     5         public int CurrentPage { get; set; }
     6 
     7         public int TotalPages
     8         {
     9             get => (int)Math.Ceiling((decimal)TotalItems / ItemsPerPage);
    10         }
    11     }

    然后创建另一个视图模型用于确定该分页信息以及各分页的书籍:

    1      public class BookListViewModel
    2      {
    3          public IEnumerable<BookDetails> BookDetails { get; set; }
    4          public PagingInfo PagingInfo { get; set; }
    5      }

    创建一个自定义 HtmlHelper 用于在视图中使用 Razor 语法获取分页,在 ASP.NET Core 中 TagBuilder 继承自 IHtmlContent,不能直接对 TagBuilder 进行赋值,需调用 MergeAttribute 方法和 InnerHtml 属性的 AppendHtml 方法编写标签;并且 TagBuilder 没有实现 ToString 方法,只能通过其 WriteTo 方法将内容写到一个 TextWriter 对象中以取出其值:

     1     public static class PagingHelper
     2     {
     3         public static HtmlString PageLinks(this IHtmlHelper html, PagingInfo pagingInfo, Func<int, string> pageUrl)
     4         {
     5             StringWriter writer=new StringWriter();
     6             for (int i = 1; i <= pagingInfo.TotalPages; i++)
     7             {
     8                 TagBuilder tag=new TagBuilder("a");
     9                 tag.MergeAttribute("href",pageUrl(i));
    10                 tag.InnerHtml.AppendHtml(i.ToString());
    11                 if (i==pagingInfo.CurrentPage)
    12                 {
    13                     tag.AddCssClass("selected");
    14                     tag.AddCssClass("btn-primary");
    15                 }
    16                 tag.AddCssClass("btn btn-default");
    17                 tag.WriteTo(writer,HtmlEncoder.Default);
    18             }
    19             return new HtmlString(writer.ToString());
    20         }
    21     }

    二、编辑图书信息页面的首页

    在此准备使用 Session 更快地获取图书信息,为了在使用时更直观,此处对 Session 类进行扩展:

     1     public static class SessionExtensions
     2     {
     3         public static void Set<T>(this ISession session, string key, T value)
     4         {
     5             session.SetString(key, JsonConvert.SerializeObject(value));
     6         }
     7 
     8         public static T Get<T>(this ISession session, string key)
     9         {
    10             var value = session.GetString(key);
    11             return value == null ? default(T) : JsonConvert.DeserializeObject<T>(value);
    12         }
    13     }

    创建一个 BookInfo 控制器:

    1    public class BookInfoController : Controller
    2     {
    3         private LendingInfoDbContext _lendingInfoDbContext;
    4 
    5         public BookInfoController(LendingInfoDbContext context)
    6         {
    7             _lendingInfoDbContext = context;
    8         }
    9     }

    创建学生浏览的首页:

    在此使用 Session 获取书籍列表:

    创建 BookInfo 控制器并确定其中每个分页的书籍数,使用 Session 获取更快地获取书籍信息:

     1     public class BookInfoController : Controller
     2     {
     3         private LendingInfoDbContext _context;
     4         private static int amout = 4;
     5 
     6         public BookInfoController(LendingInfoDbContext context)
     7         {
     8             _context = context;
     9         }
    10 
    11         public IActionResult Index(string category, int page = 1)
    12         {
    13             IEnumerable<BookDetails> books = null;
    14             if (HttpContext.Session != null)
    15             {
    16                 books = HttpContext.Session.Get<IEnumerable<BookDetails>>("bookDetails");
    17             }
    18             if (books == null)
    19             {
    20                 books = _context.BooksDetail;
    21                 HttpContext.Session?.Set<IEnumerable<BookDetails>>("books", books);
    22             }
    23             BookListViewModel model = new BookListViewModel()
    24             {
    25                 PagingInfo = new PagingInfo()
    26                 {
    27                     ItemsPerPage = amout,
    28                     TotalItems = books.Count(),
    29                     CurrentPage = page,
    30                 },
    31                 BookDetails = books.OrderBy(b => b.FetchBookNumber).Skip((page - 1) * amout).Take(amout)
    32             };            
    33             return View(model);
    34         }
    35 
    36         public FileContentResult GetImage(string isbn)
    37         {
    38             BookDetails target = _context.BooksDetail.FirstOrDefault(b => b.ISBN == isbn);
    39             if (target != null)
    40             {
    41                 return File(target.ImageData, target.ImageMimeType);
    42             }
    43             return null;
    44         }
    45     }

    视图页面:

    33 行利用 BookListViewModel 中 PagingInfo 的 CurrentPage 获取各序号,32 行中使 img 元素的 src 指向 BookInfoController 的 GetImage 方法以获取图片:

     1 @using LibraryDemo.HtmlHelpers
     2 @model BookListViewModel
     3 @{
     4     ViewData["Title"] = "Index";
     5     int i = 1;
     6     Layout = "_LendingLayout";
     7 }
     8 <style type="text/css">
     9     tr > td {
    10         padding: 5px;
    11         padding-left: 20px;
    12     }
    13     tr+tr {
    14         border-top: thin solid black;
    15         padding-top: 10px;
    16     }
    17 </style>
    18 
    19 <hr />
    20 <table>
    21     <tbody>
    22     @foreach (var book in Model.BookDetails)
    23     {
    24         <tr>
    25             <td style=" 3%">@((@Model.PagingInfo.CurrentPage-1)*4+i++)</td>
    26             <td style="text-align: center;  150px; height: 200px;">
    27                 @if (book.ImageData == null)
    28                 {
    29                     <label>No Image</label>
    30                 }
    31                 else
    32                 {
    33                     <img class="img-thumbnail pull-left" src="@Url.Action("GetImage", "BookInfo", new {book.ISBN})" />
    34                 }   
    35             </td>
    36             <td style="text-align: left;">
    37                 <a style="margin-left: 1em;" href="@Url.Action("Detail",new{isbn=@book.ISBN})">@book.Name</a>
    38                 <div style="margin-left: 2em;margin-top: 5px">
    39                     <span>@book.Author</span>
    40                     <br />
    41                     <span>@book.Press</span>
    42                     <p>@book.FetchBookNumber</p>
    43                 </div>
    44                 <div style="text-indent: 2em">
    45                     <p>@book.Description</p>
    46                 </div>
    47             </td>
    48         </tr>
    49     }
    50     </tbody>    
    51 </table>    
    52 <div class="btn-group pull-right">
    53     @Html.PageLinks(Model.PagingInfo, x => Url.Action("Index", new { page = x}))
    54 </div>

    在此同样使用 Session 获取书籍列表:

    利用 [Authorize] 特性指定 Role 属性确保只有 Admin 身份的人才能访问该页面:

     1         [Authorize(Roles = "Admin")]
     2         public IActionResult BookDetails(string isbn, int page = 1)
     3         {
     4             IEnumerable<BookDetails> books = null;
     5             BookListViewModel model;
     6             if (HttpContext.Session != null)
     7             {
     8                 books = HttpContext.Session.Get<IEnumerable<BookDetails>>("bookDetails");
     9             }
    10             if (books == null)
    11             {
    12                 books = _context.BooksDetail.AsNoTracking();
    13                 HttpContext.Session?.Set<IEnumerable<BookDetails>>("books", books);
    14 
    15             }
    16             if (isbn != null)
    17             {
    18                 model = new BookListViewModel()
    19                 {
    20                     BookDetails = new List<BookDetails>() { books.FirstOrDefault(b => b.ISBN == isbn) },
    21                     PagingInfo = new PagingInfo()
    22                 };
    23                 return View(model);
    24             }
    25             model = new BookListViewModel()
    26             {
    27 
    28                 PagingInfo = new PagingInfo()
    29                 {
    30                     ItemsPerPage = amout,
    31                     TotalItems = books.Count(),
    32                     CurrentPage = page,
    33                 },
    34                 BookDetails = books.OrderBy(b => b.FetchBookNumber).Skip((page - 1) * amout).Take(amout)
    35             };
    36             return View(model);
    37         }

    BookDetails 视图,confirmDelete 为删除按钮添加了确认的模态窗口;

    53 行为 glyphicon 为 Bootstrap 提供的免费图标,只能通过 span 元素使用:

     1     @using LibraryDemo.HtmlHelpers
     2     @model BookListViewModel
     3     @{
     4         ViewData["Title"] = "BookDetails";
     5         int i = 1;
     6     }
     7 
     8     <script>
     9         function confirmDelete() {
    10             var isbns = document.getElementsByName("isbns");
    11             var message="确认删除";
    12             for (i in isbns) {
    13                 if (isbns[i].checked) {
    14                     var book = isbns[i].parentElement.nextElementSibling.nextElementSibling.firstElementChild.innerHTML;
    15                     message=message+""+book+"";
    16                 }
    17             }
    18             message = message + "?";
    19             if (confirm(message) == true) {
    20                 return true;
    21             } else {
    22                 return false;
    23             }
    24         }
    25     </script>
    26 
    27     <style type="text/css">
    28         tr + tr {
    29             border-top: thin solid gray;
    30         }
    31 
    32         .container {
    33              1200px;
    34         }
    35     </style>
    36 
    37 
    38     <hr />
    39     @if (TempData["message"] != null)
    40     {
    41         <p>@TempData["message"]</p>
    42         <br />
    43         <br />
    44     }
    45     <form class="pull-left" action="@Url.Action("Search")">
    46         @Html.DropDownList("keyword",new List<SelectListItem>()
    47         {
    48             new SelectListItem("书名","Name"),
    49             new SelectListItem("ISBN","ISBN"),
    50             new SelectListItem("索书号","FetchBookNumber"),
    51         })
    52         <input type="text" name="value"/>
    53         <button type="submit"><span class="glyphicon glyphicon-search"></span></button>
    54     </form>
    55     <br />
    56     <br />
    57 
    58     <form method="post" asp-action="RemoveBooksAndBookDetails">
    59         <table width="1000">
    60             <tbody>
    61             <tr>
    62                 <th></th>
    63                 <th >序号</th>
    64                 <th>标题</th>
    65                 <th ></th>
    66                 <th style="text-align: right">ISBN</th>            
    67             </tr>
    68             @foreach (var book in Model.BookDetails)
    69             {
    70                 <tr>
    71                     <td><input type="checkbox" name="isbns" value="@book.ISBN" /></td>
    72                     <td style=" padding-left: 10px">@((Model.PagingInfo.CurrentPage-1)*4+i++)</td>
    73                     <td><a asp-action="EditBookDetails" asp-route-isbn="@book.ISBN">@book.Name</a></td>
    74                     <td></td>
    75                     <td style="text-align: right;">@book.ISBN</td>                
    76                 </tr>
    77             }
    78             </tbody>
    79         </table>
    80         <br/>
    81         <div>
    82             <a class="btn btn-primary" href="@Url.Action("AddBookDetails")">添加书籍</a>
    83             <button type="submit" class="btn btn-danger" onclick="return confirmDelete()"> 删除书籍</button>        
    84         </div>
    85     </form>
    86 
    87     <br />
    88     <div class="btn-group pull-right">
    89         @Html.PageLinks(Model.PagingInfo, x => Url.Action("BookDetails", new { page = x }))
    90     </div>

    Index 页面:

    BookDetails 页面:

    三、添加书籍信息

    在此为了接受图片需要使用 IFormFile 接口,为了使图片以原有的格式在浏览器中显示,需要用另一个字段 ImageType 保存文件的格式;

    39 页使用 TempData 传递一次性信息告知书籍添加成功,在传递完成后 TempData 将被立即释放:

     1         [Authorize(Roles = "Admin")]
     2         public IActionResult AddBookDetails(BookDetails model)
     3         {
     4             if (model == null)
     5             {
     6                 model = new BookDetails();
     7             }
     8             return View(model);
     9         }
    10 
    11         [HttpPost]
    12         [ValidateAntiForgeryToken]
    13         [Authorize(Roles = "Admin")]
    14         public async Task<IActionResult> AddBookDetails(BookDetails model, IFormFile image)
    15         {
    16             BookDetails bookDetails = new BookDetails();
    17             if (ModelState.IsValid)
    18             {
    19                 if (image != null)
    20                 {
    21                     bookDetails.ImageMimeType = image.ContentType;
    22                     bookDetails.ImageData = new byte[image.Length];
    23                     await image.OpenReadStream().ReadAsync(bookDetails.ImageData, 0, (int)image.Length);
    24                 }
    25 
    26                 bookDetails.ISBN = model.ISBN;
    27                 bookDetails.Name = model.Name;
    28                 bookDetails.Author = model.Author;
    29                 bookDetails.Description = model.Description;
    30                 bookDetails.FetchBookNumber = model.FetchBookNumber;
    31                 bookDetails.Press = model.Press;
    32                 bookDetails.PublishDateTime = model.PublishDateTime;
    33                 bookDetails.SoundCassettes = model.SoundCassettes;
    34                 bookDetails.Version = model.Version;
    35 
    36                 await _lendingInfoDbContext.BooksDetail.AddAsync(bookDetails);
    37 
    38                 _lendingInfoDbContext.SaveChanges();
    39                 TempData["message"] = $"已添加书籍《{model.Name}》";
    40                 return RedirectToAction("EditBookDetails");
    41             }
    42             return View(model);
    43         }
     

    AddBookDetails 视图:

    为了使表单可以上传文件,需要指定表单的 enctype 属性值为 multipart/form-data,66 行中使用一个 a 元素包含用来上传文件的 input ,指定其 class 为 btn 以生成一个按钮,指定 href="javascript:;" 使该元素不会返回任何值。

    指定 input 的 name 属性为 image 以在上传表单时进行模型绑定,指定其 accept 属性令其打开文件选择框时只接收图片。

    JS 代码为 input 添加 onchange 事件以预览上传的图片,并为关闭或刷新页面时添加模态窗口进行确认,同时为提交按钮添加事件以重置 window.onbeforeunload 事件从而不弹出确认窗口:

     1 @model LibraryDemo.Models.DomainModels.BookDetails
     2 @{
     3     ViewData["Title"] = "AddBookDetails";
     4 }
     5 
     6 <script>
     7     function preview(file) {
     8         $(".image").addClass("hidden");
     9         $('.preview').wrap("<div></div>");
    10         $(".preview").removeClass("hidden");
    11         if (file.files && file.files[0]) {
    12             var reader = new FileReader();
    13             reader.onload = function (evt) {
    14                 $('.preview').attr('src', evt.target.result);
    15             }
    16             reader.readAsDataURL(file.files[0]);
    17         } else {
    18             $('.preview').attr('src', file.value);
    19         }
    20     }        
    21     window.onbeforeunload = function () {
    22         return "您的数据未保存,确定退出?";
    23     }
    24     function removeOnbeforeunload() {
    25         window.onbeforeunload = "";
    26     }
    27 </script>
    28 
    29 <h2>添加书籍</h2>
    30 
    31 <form enctype="multipart/form-data" method="post">
    32     <div class="panel-body">
    33         <div class="form-group">
    34             @Html.LabelFor(m => m.ISBN)
    35             @Html.TextBoxFor(m => m.ISBN, new { @class = "form-control" })
    36         </div>
    37         <div class="form-group">
    38             @Html.LabelFor(m => m.Name)
    39             @Html.TextBoxFor(m => m.Name, new { @class = "form-control" })
    40         </div>
    41         <div class="form-group">
    42             @Html.LabelFor(m => m.Author)
    43             @Html.TextBoxFor(m => m.Author, new { @class = "form-control" })
    44         </div>
    45         <div class="form-group">
    46             @Html.LabelFor(m => m.Press)
    47             @Html.TextBoxFor(m => m.Press, new { @class = "form-control" })
    48         </div>
    49         <div class="form-group">
    50             @Html.LabelFor(m => m.FetchBookNumber)
    51             @Html.TextBoxFor(m => m.FetchBookNumber, new { @class = "form-control" })
    52         </div>
    53         <div class="form-group">
    54             @Html.LabelFor(m => m.SoundCassettes)
    55             @Html.TextBoxFor(m => m.SoundCassettes, new { @class = "form-control" })
    56         </div>
    57         <div class="form-group">
    58             @Html.LabelFor(m => m.Description)
    59             @Html.TextAreaFor(m => m.Description, new { @class = "form-control", rows = 5 })
    60         </div>
    61         <div class="form-group">
    62             @Html.LabelFor(m => m.PublishDateTime)
    63             <div>@Html.EditorFor(m => m.PublishDateTime)</div>
    64         </div>
    65         <div class="form-group">
    66             @Html.LabelFor(m => m.Version)
    67             <div>@Html.EditorFor(m => m.Version)</div>
    68         </div>
    69         <div class="form-group">
    70             <div style="position: relative;">
    71                 <label>Image</label>
    72                 <a class="btn" href="javascript:;">
    73                     选择图片
    74                     <input type="file" name="Image" size="40" accept="image/*"
    75                            style="position: absolute; z-index: 2; top: 0; left: 0; filter: alpha(opacity=0); opacity: 0; background-color: transparent; color: transparent"
    76                            onchange="preview(this)" />
    77                 </a>
    78                 <img style=" 150px;" class="hidden preview img-thumbnail">
    79             </div>
    80         </div>        
    81         <input type="submit" onclick="removeOnbeforeunload()"/>
    82     </div>
    83 </form>

    结果:

    四、删除书籍信息

    删除书籍的动作方法:

    此处通过在之前的 BookDetails 视图中指定 input 元素的 type 为 checkbox,指定 name 为 isbns 以实现多个字符串的模型绑定:

     1         [Authorize(Roles = "Admin")]
     2         [HttpPost]
     3         [ValidateAntiForgeryToken]
     4         public async Task<IActionResult> RemoveBooksAndBookDetails(IEnumerable<string> isbns)
     5         {
     6             StringBuilder sb = new StringBuilder();
     7             foreach (var isbn in isbns)
     8             {
     9                 BookDetails bookDetails = _lendingInfoDbContext.BooksDetail.First(b => b.ISBN == isbn);
    10                 IQueryable<Book> books = _lendingInfoDbContext.Books.Where(b => b.ISBN == isbn);
    11                 _lendingInfoDbContext.BooksDetail.Remove(bookDetails);
    12                 _lendingInfoDbContext.Books.RemoveRange(books);
    13                 sb.Append("" + bookDetails.Name + "");
    14                 await _lendingInfoDbContext.SaveChangesAsync();
    15             }
    16             TempData["message"] = $"已移除书籍{sb.ToString()}";
    17             return RedirectToAction("BookDetails");
    18         }

    结果:

    五、编辑书籍信息

    动作方法:

     1         [Authorize(Roles = "Admin")]
     2         public async Task<IActionResult> EditBookDetails(string isbn)
     3         {
     4             BookDetails book = await _lendingInfoDbContext.BooksDetail.FirstOrDefaultAsync(b => b.ISBN == isbn);
     5             if (book != null)
     6             {
     7                 return View(book);
     8             }
     9             else
    10             {
    11                 return RedirectToAction("BookDetails");
    12             }
    13         }
    14 
    15         [HttpPost]
    16         [ValidateAntiForgeryToken]
    17         [Authorize(Roles = "Admin")]
    18         public async Task<ActionResult> EditBookDetails(BookDetails model, IFormFile image)
    19         {
    20             BookDetails bookDetails = _lendingInfoDbContext.BooksDetail.FirstOrDefault(b => b.ISBN == model.ISBN);
    21             if (ModelState.IsValid)
    22             {
    23                 if (bookDetails != null)
    24                 {
    25                     if (image != null)
    26                     {
    27                         bookDetails.ImageMimeType = image.ContentType;
    28                         bookDetails.ImageData = new byte[image.Length];
    29                         await image.OpenReadStream().ReadAsync(bookDetails.ImageData, 0, (int)image.Length);
    30                     }
    31 
    32                     BookDetails newBookDetails = model;
    33 
    34                     bookDetails.Name = newBookDetails.Name;
    35                     bookDetails.Author = newBookDetails.Author;
    36                     bookDetails.Description = newBookDetails.Description;
    37                     bookDetails.FetchBookNumber = newBookDetails.FetchBookNumber;
    38                     bookDetails.Press = newBookDetails.Press;
    39                     bookDetails.PublishDateTime = newBookDetails.PublishDateTime;
    40                     bookDetails.SoundCassettes = newBookDetails.SoundCassettes;
    41                     bookDetails.Version = newBookDetails.Version;
    42 
    43                     await _lendingInfoDbContext.SaveChangesAsync();
    44                     TempData["message"] = $"《{newBookDetails.Name}》修改成功";
    45                     return RedirectToAction("EditBookDetails");
    46                 }
    47             }
    48             return View(model);
    49         }

    此处视图与之前 AddBookDetails 大致相同,但在此对一些视图中的 ISBN 字段添加了 readonly 属性使它们不能被直接编辑:

      1 @model LibraryDemo.Models.DomainModels.BookDetails
      2 
      3 @{
      4     ViewData["Title"] = "EditBookDetails";
      5 }
      6 
      7 <script>
      8     function preview(file) {
      9         $(".image").addClass("hidden");
     10         $('.preview').wrap("<div></div>");
     11         $(".preview").removeClass("hidden");
     12         if (file.files && file.files[0]){  
     13             var reader = new FileReader();  
     14             reader.onload = function(evt){
     15                 $('.preview').attr('src' , evt.target.result);
     16             }    
     17             reader.readAsDataURL(file.files[0]);  
     18         }else{  
     19             $('.preview').attr('src' , file.value);
     20         }
     21     }
     22     window.onload = function() {
     23         $("div>input").addClass("form-control");
     24         var isbn = document.getElementById("ISBN");
     25         isbn.setAttribute("readonly","true");
     26     }
     27     window.onbeforeunload = function (event) {
     28         return "您的数据未保存,确定退出?";
     29     }
     30     function removeOnbeforeunload() {
     31         window.onbeforeunload = "";
     32     }
     33 </script>
     34 
     35 <h2>编辑书籍</h2>
     36 
     37 @section Scripts
     38 {
     39     
     40 }
     41 
     42 <form enctype="multipart/form-data" method="post">
     43     <div class="panel-body">
     44         <div class="form-group">
     45             @Html.LabelFor(m => m.ISBN)
     46             @Html.EditorFor(m => m.ISBN)
     47         </div>
     48         <div class="form-group">
     49             @Html.LabelFor(m => m.Name)
     50             @Html.TextBoxFor(m => m.Name, new {@class = "form-control"})
     51         </div>
     52         <div class="form-group">
     53             @Html.LabelFor(m => m.Author)
     54             @Html.TextBoxFor(m => m.Author, new {@class = "form-control"})
     55         </div>
     56         <div class="form-group">
     57             @Html.LabelFor(m => m.Press)
     58             @Html.TextBoxFor(m => m.Press, new {@class = "form-control"})
     59         </div>
     60         <div class="form-group">
     61             @Html.LabelFor(m => m.FetchBookNumber)
     62             @Html.TextBoxFor(m => m.FetchBookNumber, new {@class = "form-control"})
     63         </div>
     64         <div class="form-group">
     65             @Html.LabelFor(m => m.SoundCassettes)
     66             @Html.TextBoxFor(m => m.SoundCassettes, new {@class = "form-control"})
     67         </div>
     68         <div class="form-group">
     69             @Html.LabelFor(m => m.Description)
     70             @Html.TextAreaFor(m => m.Description, new {@class = "form-control", rows = 5})
     71         </div>
     72         <div class="form-group">
     73             @Html.LabelFor(m => m.PublishDateTime)
     74             <div>@Html.EditorFor(m => m.PublishDateTime)</div>
     75         </div>
     76         <div class="form-group">
     77             @Html.LabelFor(m => m.Version)
     78             <div>@Html.EditorFor(m => m.Version)</div>
     79         </div>
     80         <div class="form-group">
     81             <div style="position: relative;">
     82                 <label>Image</label>
     83                 <a class="btn" href="javascript:;">
     84                     选择图片
     85                     <input type="file" name="Image" size="40" accept="image/*"
     86                            style="position: absolute; z-index: 2; top: 0; left: 0; filter: alpha(opacity=0); opacity: 0; background-color: transparent; color: transparent"
     87                            onchange="preview(this)" />
     88                 </a>
     89                 <img style=" 150px;" class="hidden preview img-thumbnail">
     90             </div>
     91             @if (Model.ImageData == null)
     92             {
     93             <div class="form-control-static image">No Image</div>
     94             }
     95             else
     96             {
     97             <img class="img-thumbnail image" style=" 150px;" src="@Url.Action("GetImage", "BookInfo", new {Model.ISBN})" />
     98             }
     99         </div>
    100         <br />
    101         <a class="btn btn-primary" asp-action="Books" asp-route-isbn="@Model.ISBN" onclick="return removeOnbeforeunload()">编辑外借书籍信息</a>
    102         <br />
    103         <br />
    104         <input type="submit" class="btn btn-success" onclick="return removeOnbeforeunload()"/>
    105     </div>
    106 </form>

    结果:

    六、查询特定书籍

    此处和之前的账号登录处一样使用 switch 对不同的关键词进行检索:

     1         public async Task<IActionResult> Search(string keyWord, string value)
     2         {
     3             BookDetails bookDetails = new BookDetails();
     4             switch (keyWord)
     5             {
     6                 case "Name":
     7                     bookDetails =await _context.BooksDetail.FirstOrDefaultAsync(b => b.Name == value);
     8                     break;
     9                 case "ISBN":
    10                     bookDetails =await _context.BooksDetail.FirstOrDefaultAsync(b => b.ISBN == value);
    11                     break;
    12                 case "FetchBookNumber":
    13                     bookDetails =await _context.BooksDetail.FirstOrDefaultAsync(b => b.FetchBookNumber == value);
    14                     break;
    15             }
    16 
    17             if (bookDetails!=null)
    18             {
    19                 return RedirectToAction("EditBookDetails", new {isbn = bookDetails.ISBN});
    20             }
    21 
    22             TempData["message"] = "找不到该书籍";
    23             return RedirectToAction("BookDetails");
    24         }

     结果:

  • 相关阅读:
    JS运行机制之 Event Loop 的思考
    模块机制 之commonJs、node模块 、AMD、CMD
    git报错:'fatal:remote origin already exists'怎么处理?附上git常用操作以及说明。
    Uncaught RangeError: Maximum call stack size exceeded-栈溢出
    对循环内部反复声明变量的写法的一点想法?
    JS的forEach和map方法的区别
    函数的属性和方法之call、apply 及bind
    利用Apach ab对nodejs进行并发负载的压力测试
    怎么判断一个对象是不是数组类型?
    Python模块学习之fabric
  • 原文地址:https://www.cnblogs.com/gokoururi/p/10382292.html
Copyright © 2020-2023  润新知