模仿天貓實戰【SSM版】——後臺開發

上一篇文章連接:模仿天貓實戰【SSM版】——項目起步css

後臺需求分析

在開始碼代碼以前,仍是須要先清楚本身要作什麼事情,後臺具體須要實現哪些功能:html

  • 注意: 訂單、用戶、訂單、推薦連接均不提供增刪的功能。

後臺界面設計

不像前端那樣有原型直接照搬就能夠了,後臺的設計還真的有難到我...畢竟我是一個對美有必定要求的人,一方面想盡可能的簡潔、簡單,另外一方面又不想要太難看,那怎麼辦呢?前端

那固然是找模板了,找到一個順眼的下載下來就開始改,java

這個模板的原地址在這裏:戳這裏jquery

順便安利一下 FireFox ,真是開發神器,配合着修改,棒棒噠:git

通過一番折騰...

摁,就這風格了,並且我還發現右上角的【Search】框是下載的模板用 js 實現的...對於管理來講更加方便了....並且竟然還實現了分頁....github

一個邪惡的想法又誕生了...web

一些規定

  • 爲了下降項目的難度,咱們作了不少的精簡,如今咱們做出以下的規定:
  • 全站沒有商家,只有一家 Tmall ,後臺沒有驗證,能夠直接進入
  • 前臺的路徑就是默認路徑,後臺的路徑須要加上 「/admin」 後綴,如訪問後臺則爲:localhost/admin (默認爲分類管理頁
  • 管理路徑統一爲:admin/listXxxxx,如分類管理路徑爲:admin/listCategory,用戶管理路徑爲:admin/listUser,諸如此類
  • 編輯路徑統一爲:admin/editXxxxx,如編輯分類路徑爲:admin/editCategory,產品編輯頁爲:admin/editProduct,諸如此類
  • 刪除路徑統一爲:admin/deleteXxxxx
  • 更新路徑統一爲:admin/updateXxxxx
  • 關於頁面路徑的一些規定:
  • 前端頁面統一在【WEB-INF/views】下,後端頁面統一在【WEB-INF/views/admin】下

分類管理

正式開始編寫咱們的代碼,以 Category 爲例。spring

編寫 Service 層

咱們須要在這一層上考慮須要完成的功能,對應咱們上面畫的後臺功能圖,分類管理也就是完成分類的查詢還有修改的工做:sql

package cn.wmyskxz.service;

import cn.wmyskxz.pojo.Category;

import java.util.List;

public interface CategoryService {

    /**
     * 返回分類列表
     * @return
     */
    List<Category> list();

    /**
     * 經過id獲取對應的數據
     * @param id
     * @return
     */
    Category get(Integer id);

    /**
     * 更新分類
     * @param category
     * @return
     */
    void update(Category category);
}
  • 編寫 CategoryServiceImpl :
    在同一包下編寫實現類
package cn.wmyskxz.service;

import cn.wmyskxz.mapper.CategoryMapper;
import cn.wmyskxz.pojo.Category;
import cn.wmyskxz.pojo.CategoryExample;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * CategoryService 的實現類
 *
 * @author: @我沒有三顆心臟
 * @create: 2018-04-27-下午 16:35
 */
@Service
public class CategoryServiceImpl implements CategoryService {

    @Autowired
    CategoryMapper categoryMapper;

    public List<Category> list() {
        CategoryExample example = new CategoryExample();
        List<Category> categories = categoryMapper.selectByExample(example);
        return categories;
    }

    public Category get(Integer id) {
        return categoryMapper.selectByPrimaryKey(id);
    }

    public void update(Category category) {
        categoryMapper.updateByPrimaryKey(category);
    }
}

編寫 CategoryController

根據業務需求能夠很容易的編寫出來:

package cn.wmyskxz.controller;

import cn.wmyskxz.pojo.Category;
import cn.wmyskxz.service.CategoryService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

import java.util.List;

/**
 * Category 的控制類
 *
 * @author: @我沒有三顆心臟
 * @create: 2018-04-27-下午 16:37
 */
@Controller
@RequestMapping("/admin")
public class CategoryController {

    @Autowired
    CategoryService categoryService;

    @RequestMapping("/listCategory")
    public String list(Model model) {
        List<Category> categories = categoryService.list();
        model.addAttribute("categories", categories);
        return "admin/listCategory";
    }

    @RequestMapping("/editCategory")
    public String edit(Category category,Model model) {
        model.addAttribute("category", category);
        return "admin/editCategory";
    }

    @RequestMapping("/updateCategory")
    public String update(Category category) {
        categoryService.update(category);
        return "redirect:listCategory";
    }
}

JSP 相關文件編寫

本身研究了一下子這個模板,感受仍是挺好改的,而後就給改爲了大概如下這個樣子(本身在數據庫中加入了 16 條數據):

  • 分類管理頁

  • 分類編輯頁

模板下載下來以後文件目錄是這樣的:

咱們直接整個拷貝【assets】文件夾放在【webapp】目錄下,而後根據模板裏面的代碼就能夠開始修改了,修改下來的兩個文件源碼以下:

  • listCategory.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
         pageEncoding="UTF-8" isELIgnored="false" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>模仿天貓-後臺</title>
    <!-- Bootstrap Styles-->
    <link href="../assets/css/bootstrap.css" rel="stylesheet" />
    <!-- FontAwesome Styles-->
    <link href="../assets/css/font-awesome.css" rel="stylesheet" />
    <!-- Morris Chart Styles-->

    <!-- Custom Styles-->
    <link href="../assets/css/custom-styles.css" rel="stylesheet" />
    <!-- Google Fonts-->
    <link href='https://fonts.googleapis.com/css?family=Open+Sans' rel='stylesheet' type='text/css' />
    <!-- TABLE STYLES-->
    <link href="../assets/js/dataTables/dataTables.bootstrap.css" rel="stylesheet" />
</head>
<body>
<div id="wrapper">
    <nav class="navbar navbar-default top-navbar" role="navigation">
        <div class="navbar-header">
            <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".sidebar-collapse">
                <span class="sr-only">Toggle navigation</span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
            </button>
            <a class="navbar-brand" href="listCategory">Tmall</a>
        </div>
    </nav>

    <!--/. NAV TOP  -->
    <nav class="navbar-default navbar-side" role="navigation">
        <div class="sidebar-collapse">
            <ul class="nav" id="main-menu">

                <li>
                    <a class="active-menu" href="listCategory"><i class="fa fa-bars"></i> 分類管理</a>
                </li>
                <li>
                    <a href="listUser"><i class="fa fa-user"></i> 用戶管理</a>
                </li>
                <li>
                    <a href="listOrder"><i class="fa fa-list-alt"></i> 訂單管理</a>
                </li>
                <li>
                    <a href="listProduct"><i class="fa fa-th-list"></i> 產品管理</a>
                </li>
                <li>
                    <a href="listLink"><i class="fa fa-link"></i> 推薦連接管理</a>
                </li>
            </ul>
        </div>

    </nav>
    <!-- /. NAV SIDE  -->
    <div id="page-wrapper">
        <div id="page-inner">
            <div class="row">
                <div class="col-md-12">
                    <h1 class="page-header">
                        分類管理
                        <small></small>
                    </h1>
                </div>
            </div>

            <div class="row">
                <div class="col-md-12">
                    <!-- Advanced Tables -->
                    <div class="panel panel-default">
                        <div class="panel-heading">
                            分類管理表
                        </div>
                        <div class="panel-body">
                            <div class="table-responsive">
                                <table class="table table-striped table-bordered table-hover" id="dataTables-example">
                                    <thead>
                                    <tr>
                                        <th>分類id</th>
                                        <th>分類名稱</th>

                                        <th>編輯分類</th>
                                        <th>產品管理</th>
                                        <th>屬性管理</th>
                                    </tr>
                                    </thead>
                                    <tbody>
                                    <c:forEach items="${categories}" var="c">
                                        <tr>
                                            <td>${c.id}</td>
                                            <td>${c.name}</td>

                                            <td><a href="editCategory?id=${c.id}&name=${c.name}"><span class="glyphicon glyphicon-th-list"></span></a></td>
                                            <td><a href="listProduct?category_id=${c.id}"><span class="glyphicon glyphicon-shopping-cart"></span></a></td>
                                            <td><a href="listProperty?category_id=${c.id}"><span class="glyphicon glyphicon-edit"></span></a></td>
                                        </tr>
                                    </c:forEach>
                                    </tbody>
                                </table>
                            </div>

                        </div>
                    </div>
                    <!--End Advanced Tables -->
                </div>
            </div>

        </div>
    </div>
    <!-- /. PAGE WRAPPER  -->
</div>
<!-- /. WRAPPER  -->
<!-- JS Scripts-->
<!-- jQuery Js -->
<script src="../assets/js/jquery-1.10.2.js"></script>
<!-- Bootstrap Js -->
<script src="../assets/js/bootstrap.min.js"></script>
<!-- Metis Menu Js -->
<script src="../assets/js/jquery.metisMenu.js"></script>
<!-- DATA TABLE SCRIPTS -->
<script src="../assets/js/dataTables/jquery.dataTables.js"></script>
<script src="../assets/js/dataTables/dataTables.bootstrap.js"></script>
<script>
    $(document).ready(function () {
        $('#dataTables-example').dataTable();
    });
</script>
<!-- Custom Js -->
<script src="../assets/js/custom-scripts.js"></script>


</body>
</html>
  • editCategory.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
         pageEncoding="UTF-8" isELIgnored="false" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<html>
<head>
    <meta charset="utf-8"/>
    <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
    <title>模仿天貓-後臺</title>
    <!-- Bootstrap Styles-->
    <link href="../assets/css/bootstrap.css" rel="stylesheet"/>
    <!-- FontAwesome Styles-->
    <link href="../assets/css/font-awesome.css" rel="stylesheet"/>
    <!-- Morris Chart Styles-->

    <!-- Custom Styles-->
    <link href="../assets/css/custom-styles.css" rel="stylesheet"/>
    <!-- Google Fonts-->
    <link href='https://fonts.googleapis.com/css?family=Open+Sans' rel='stylesheet' type='text/css'/>
</head>
<body>
<div id="wrapper">
    <nav class="navbar navbar-default top-navbar" role="navigation">
        <div class="navbar-header">
            <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".sidebar-collapse">
                <span class="sr-only">Toggle navigation</span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
            </button>
            <a class="navbar-brand" href="listCategory">Tmall</a>
        </div>
    </nav>

    <!--/. NAV TOP  -->
    <nav class="navbar-default navbar-side" role="navigation">
        <div class="sidebar-collapse">
            <ul class="nav" id="main-menu">

                <li>
                    <a class="active-menu" href="listCategory"><i class="fa fa-bars"></i> 分類管理</a>
                </li>
                <li>
                    <a href="listUser"><i class="fa fa-user"></i> 用戶管理</a>
                </li>
                <li>
                    <a href="listOrder"><i class="fa fa-list-alt"></i> 訂單管理</a>
                </li>
                <li>
                    <a href="listProduct"><i class="fa fa-th-list"></i> 產品管理</a>
                </li>
                <li>
                    <a href="listLink"><i class="fa fa-link"></i> 推薦連接管理</a>
                </li>
            </ul>
        </div>

    </nav>
    <!-- /. NAV SIDE  -->
    <div id="page-wrapper">
        <div id="page-inner">
            <div class="row">
                <div class="col-md-12">
                    <h1 class="page-header">
                        分類管理
                        <small> - id:${category.id} </small>
                    </h1>
                </div>
            </div>

            <div class="row">
                <div class="col-md-6">
                    <!-- Advanced Tables -->
                    <div class="panel panel-default">
                        <div class="panel-heading">
                            編輯分類
                        </div>
                        <div class="panel-body">
                            <div class="row col-lg-12">
                                <form action="updateCategory" role="form">
                                    <div class="form-group">
                                        <%-- 隱藏id屬性,一併提交 --%>
                                        <input type="hidden" name="id" value="${category.id}">
                                        <label>分類名稱:</label>
                                        <input name="name" class="form-control" value="${category.name}"> <br/>
                                        <div class="pull-right">
                                            <input type="submit" class="btn btn-default">
                                        </div>
                                    </div>
                                </form>
                            </div>

                        </div>
                    </div>
                    <!--End Advanced Tables -->
                </div>
            </div>

        </div>
    </div>
    <!-- /. PAGE WRAPPER  -->
</div>
<!-- /. WRAPPER  -->
<!-- JS Scripts-->
<!-- jQuery Js -->
<script src="../assets/js/jquery-1.10.2.js"></script>
<!-- Bootstrap Js -->
<script src="../assets/js/bootstrap.min.js"></script>
</body>
</html>

這樣就完成了 Category 的後臺管理模塊

其餘模塊的思路跟 Category 一模一樣,就比較偏向於體力勞動了...

  • 注意: 全部本類的 id 屬性均爲 id ,全部外鍵的 id 都是 屬性名_id 這樣的格式,保持統一!

Example 條件查詢

MyBatis 逆向工程自動生成文件的時候自動生成了 Example 條件查詢類,咱們到底應該怎麼使用它呢,這裏簡要的說明一下。

不得不說這個東西還挺神奇,也很方便,好比咱們須要查詢 category_id 對應下的屬性表,咱們能夠這樣寫:

public List<Property> list(Integer category_id) {
    PropertyExample example = new PropertyExample();
    example.or().andCategory_idEqualTo(category_id);
    List<Property> properties = propertyMapper.selectByExample(example);
    return properties;
}

經過方法名其實也很容易看懂這些是什麼意思,咱們首先建立了一個 PropertyExample 實例對象,而後經過 .or() 方法開啓條件查詢,.andCategory_idEqualTo() 匹配對應的 category_id ,自動生成的 sql 語句就像這樣:

更多詳情戳這裏 - 引用其餘博客的詳細說明


IDEA 快速重構

當我編寫好了 PropertyService 、PropertyServiceImpl、 PropertyController 以後再想要去編寫 Product 的這一系列文件的時候,發現其實不少代碼都是重複的,只是不多一部分的代碼須要改動,暫時不考慮設計模式的話,咱們可使用 IDEA 來完成快速重構:

  • 直接複製 PropertyController 的代碼到 ProductController 中,而後【Ctrl + F】搜索 Property :

咱們能夠發現全部的 Property 都高亮了,而後咱們怎麼批量修改呢?

而後繼續瘋狂碼代碼...


開發過程當中遇到的一些問題

PropertyValue 遇到的麻煩

PropertyValue 屬性值表,這個表關聯了兩個外鍵,一個指向 Product ,另外一個指向 Property ,當我按照以前的設計把 listProduct.jsp 設計成下面這個樣子的時候,點擊【編輯屬性】,Property 的信息應該怎麼傳遞?

  • 也就是說,如何處理從 listProduct 跳轉到 listPropertyValue 頁面時憑空跳出來的 Property 的相關信息?

解決方案:

在 PropertyValueServiceImpl 中增長:

@Autowired
PropertyService propertyService;

咱們如今有 category_id 和 product_id ,咱們能夠利用 Property 和 Category 之間的聯繫,經過 category_id 查詢出全部對應的 Property ,而後再篩選出同時匹配 property_id 和 product_id 的 PropertyValue:

public List<PropertyValue> list(Integer product_id, Integer category_id) {
    PropertyValueExample example = new PropertyValueExample();
    List<PropertyValue> propertyValues = new ArrayList<PropertyValue>();
    List<Property> properties = propertyService.list(category_id);
    for (Property property : properties) {
        // 篩選出同時匹配 property_id 和 product_id 的值
        example.or().andProperti_idEqualTo(property.getId()).andProduct_idEqualTo(product_id);
        propertyValues.addAll(propertyValueMapper.selectByExample(example));
    }
    return propertyValues;
}

emmm...這樣的思路出來以後,對應的 Controller 就清晰了:

@RequestMapping("/listPropertyValue")
public String list(Model model, Integer product_id, Integer category_id) {
    List<PropertyValue> propertyValues = propertyValueService.list(product_id, category_id);
    model.addAttribute("propertyValues", propertyValues);
    Product product = productService.get(product_id);
    model.addAttribute("product", product);
    return "admin/listPropertyValue";
}

加入一條數據測試:

  • bingo!

另外一個問題是添加屬性值:

添加的屬性值必須是當前 Category 下有的屬性值,因此咱們能夠在 Controller 上自動注入一個 PropertyService 經過 category_id 查詢到當前分類下全部的 Property 而後傳遞給 listPropertyValue :

@Autowired
PropertyService propertyService;

@RequestMapping("/listPropertyValue")
public String list(Model model, Integer product_id, Integer category_id) {
    List<PropertyValue> propertyValues = propertyValueService.list(product_id, category_id);
    model.addAttribute("propertyValues", propertyValues);
    Product product = productService.get(product_id);
    model.addAttribute("product", product);
    List<Property> properties = propertyService.list(category_id);
    model.addAttribute("properties", properties);
    return "admin/listPropertyValue";
}

期間發現一個 BUG,PropertyValue 表裏的 property_id 竟然寫成了 properti_id,嚇得我趕忙檢查了一下全部表的字段,其餘的沒問題,從新生成一下逆向工程

而後獲取屬性名稱:

  • 完善以後大概是這樣:

產品圖片管理

產品圖片的管理須要涉及到文件的上傳操做,咱們須要先提供必要的 jar 包依賴:

  • commons-fileupload
  • commons-io

一樣的搜索 maven 庫添加依賴到 pom.xml中:

<!-- 上傳文件fileupload -->
<dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.3.3</version>
</dependency>
<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.6</version>
</dependency>

產品圖片如何管理?

  • 規定一:
    全部的產品圖片均保存在【img/product/】對應的 product_id 目錄下,而且默認的文件名爲 1,2,3,4,5 ,例如 product_id 爲 1 的產品的產品圖片 1 保存於:【img/product/1/1.jpg】
  • 規定二:
    每個產品對應五張圖片,文件名分別爲 1.jpg ,2.jpg 以此類推,不能少也不能多,刪除也只是將對應目錄下的圖片刪除,id 並不改變
  • 規定三:
    默認產品打開的大圖即爲該產品圖片目錄中的 1.jpg
  • 界面大概設計成了這樣:

  • 莫名其妙一個 BUG:

我把表單設計成了這樣,隱藏了兩個屬性,一個 product_id,一個 id:

爲了方便操做,我想要直接申明兩個參數用來接收上面的兩個屬性,大概是這樣:

可是上面兩種方法都不行,我還查了一些資料在 @RequestParam 註解裏設置了 required 屬性,仍然獲取不到,可是我改爲用 ProductImage 來接收就行了..Why?

後來寫着寫着,又必需要使用上面兩種方法了....

  • 根據咱們的規定來完成代碼

ProductImageService 層仍是跟以前的沒有多大的區別,可是值得注意的是,根據咱們的規定,咱們的刪除須要作一些改動(根據 product_id 批量刪除):

package cn.wmyskxz.service;

import cn.wmyskxz.mapper.PropertyValueMapper;
import cn.wmyskxz.pojo.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

/**
 * cn.wmyskxz.pojo.PropertyValueValueService 實現類
 *
 * @author: @我沒有三顆心臟
 * @create: 2018-04-28-上午 7:47
 */
@Service
public class PropertyValueServiceImpl implements PropertyValueService {

    @Autowired
    PropertyValueMapper propertyValueMapper;

    @Autowired
    PropertyService propertyService;

    @Autowired
    ProductService productService;

    public void add(PropertyValue propertyValue) {
        propertyValueMapper.insert(propertyValue);
    }

    public void delete(Integer id) {
        propertyValueMapper.deleteByPrimaryKey(id);
    }

    public void deleteByProductId(Integer product_id) {
        // 按條件查詢出須要刪除的列表
        PropertyValueExample example = new PropertyValueExample();
        example.or().andProduct_idEqualTo(product_id);
        Integer category_id = productService.get(product_id).getCategory_id();
        List<PropertyValue> propertyValues = list(product_id, category_id);
        // 循環刪除
        for (int i = 0; i < propertyValues.size(); i++) {
            propertyValueMapper.deleteByPrimaryKey(propertyValues.get(i).getId());
        }
    }
    public void update(PropertyValue propertyValue) {
        propertyValueMapper.updateByPrimaryKey(propertyValue);
    }

    public List<PropertyValue> list(Integer product_id, Integer category_id) {
        PropertyValueExample example = new PropertyValueExample();
        List<PropertyValue> propertyValues = new ArrayList<PropertyValue>();
        List<Property> properties = propertyService.list(category_id);
        for (Property property : properties) {
            // 篩選出同時匹配 property_id 和 product_id 的值
            example.or().andProperty_idEqualTo(property.getId()).andProduct_idEqualTo(product_id);
            propertyValues.addAll(propertyValueMapper.selectByExample(example));
        }
        return propertyValues;
    }

    public PropertyValue get(Integer id) {
        return propertyValueMapper.selectByPrimaryKey(id);
    }
}
  • 首先在 ProductController 中 add 和 delete 方法中增長如下代碼:
@Autowired
ProductImageService productImageService;

@RequestMapping("/addProduct")
public String add(Product product) {
    productService.add(product);

    // 建立新的 Product 時默認建立 5 個對應的 ProductImage 數據
    ProductImage productImage = new ProductImage();
    productImage.setProduct_id(product.getId());
    for (int i = 1; i <= 5; i++) {
        productImage.setId(i);
        productImageService.add(productImage);
    }

    return "redirect:listProduct?category_id=" + product.getCategory_id();
}

@RequestMapping("/deleteProduct")
public String delete(Integer id, HttpServletRequest request) {

    // 在刪除產品的時候將對應的 5 個 ProductImage 數據也刪除了
    productImageService.deleteByProductId(id);
    // 同時刪除目錄下的相關文件
    String path = request.getSession().getServletContext().getRealPath("" + id);
    deleteDir(new File(path));

    // 刪除外鍵對應的數據
    propertyValueService.deleteByProductId(id);

    int category_id = productService.get(id).getCategory_id();
    productService.delete(id);

    return "redirect:listProduct?category_id=" + category_id;
}

/**
 * 遞歸刪除目錄下的全部文件及子目錄下全部文件
 *
 * @param dir 將要刪除的文件目錄
 * @return boolean Returns "true" if all deletions were successful.
 * If a deletion fails, the method stops attempting to
 * delete and returns "false".
 */
private static boolean deleteDir(File dir) {
    if (dir.isDirectory()) {
        String[] children = dir.list();
        //遞歸刪除目錄中的子目錄下
        for (int i = 0; i < children.length; i++) {
            boolean success = deleteDir(new File(dir, children[i]));
            if (!success) {
                return false;
            }
        }
    }
    // 目錄此時爲空,能夠刪除
    return dir.delete();
}

而後編寫咱們的 ProductImageController :

package cn.wmyskxz.controller;

import cn.wmyskxz.pojo.Product;
import cn.wmyskxz.pojo.ProductImage;
import cn.wmyskxz.service.ProductImageService;
import cn.wmyskxz.service.ProductService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.util.List;

/**
 * ProductImage 的控制器
 *
 * @author: @我沒有三顆心臟
 * @create: 2018-04-28-下午 14:10
 */
@Controller
@RequestMapping("/admin")
public class ProductImageController {

    @Autowired
    ProductImageService productImageService;

    @Autowired
    ProductService productService;

    @RequestMapping("/editProductImage")
    public String edit(Model model, Integer product_id) {
        List<ProductImage> productImages = productImageService.list(product_id);
        model.addAttribute("productImages", productImages);
        Product product = productService.get(product_id);
        model.addAttribute("product", product);
        return "admin/editProductImage";
    }

    @RequestMapping(value = "/updateProductImage", method = RequestMethod.POST)
    public String update(HttpServletRequest request,
//                       @RequestParam("productImage") ProductImage productImage,
                         Integer product_id, 
                         Integer id,
                         @RequestParam("picture") MultipartFile picture) {

        // 上傳文件到指定位置
        String filePath = request.getSession().getServletContext()
                .getRealPath("img/product/" + product_id);
        // 由於 id 是自增加鍵,因此須要 % 5 來做爲文件名
        String fileName = (id % 5 == 0 ? 5 : id % 5) + ".jpg";
        File uploadPicture = new File(filePath, fileName);
        if (!uploadPicture.exists()) {
            uploadPicture.mkdirs();
        }
        // 保存
        try {
            picture.transferTo(uploadPicture);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "redirect:editProductImage?product_id=" + product_id;
    }

    @RequestMapping("/deleteProductImage")
    public String delete(Integer id, Integer product_id, HttpServletRequest request) {
        // 不刪除表中的數據(在 ProductController 中統一刪除),刪除對應文件
        String filePath = request.getSession().getServletContext()
                .getRealPath("img/product/" + product_id);
        String fileName = id + ".jpg";
        new File(filePath, fileName).delete();

        return "redirect:editProductImage?product_id=" + product_id;
    }
}
  • 再優化一下界面的東西,增長沒有圖片顯示的 error 圖片,大概就是這個樣子:

這裏就只貼一下 table 的代碼吧:

<c:forEach items="${productImages}" var="pi">
    <tr>
        <td>${pi.product_id}</td>
        <td>${pi.id}</td>
        <td><img class="col-md-8"
                 src="../img/product/${pi.product_id}/${pi.id%5==0?5:pi.id%5}.jpg"
                 onerror="this.src='../img/product/error.png'"></td>
        <td class="col-md-5">
            <form action="updateProductImage" method="post"
                  enctype="multipart/form-data">
                <input type="hidden" name="id" value="${pi.id}">
                <input type="hidden" name="product_id"
                       value="${pi.product_id}">
                <input type="file" name="picture" class="pull-left">
                <input type="submit" class="btn btn-primary pull-right" value="上傳">
            </form>
        </td>
        <td>
            <a href="deleteProductImage?product_id=${pi.product_id}&id=${pi.id}"><span
                    class="glyphicon glyphicon-trash"></span></a></td>
    </tr>
</c:forEach>

在寫圖片管理的時候又遇到一個坑

在刪除頂層數據庫數據的時候,要注意刪除其下的有外鍵關聯的數據,特別是 product_id 這個東西,是不少表的外鍵,刪除 product 以前須要先清空有關聯的其餘表的數據....

總之坑是不少啦..不過項目在進展總歸是好事...耐心耐心...

接着碼代碼....

還剩下一些體力活的東西,就先結博文啦...(心累.jpg)

有一些催更的朋友,但願能別催啦...天天都在碼啦,並且自己也是很low的東西,寫完以後我會上傳 github 的。


總結

當我給本身埋了一個大坑說要模仿天貓,而且陷進去的時候,一方面痛苦着一方面也察覺了本身不少不足的地方,就以爲仍是很值得,如今來作一下簡短的總結。

  • 進度比想象中慢了不少,雖然一步一步按照以前的分析圖來編寫代碼整體是順暢的,可是有那種寫着寫着忽然發現以前的設計有問題的感受,中途也改了幾回,發現本身分析問題不夠全面。
  • 項目中有許多相似的代碼,而且在 Controller 和 Impl 中不斷有其餘的東西加入,總以爲是糟糕的代碼,可是又不知道應該進一步如何改進。
  • 方向永遠比努力重要,在行動以前思考清楚,我一直以爲是很重要的一點,我以爲經過對項目的分析,對我項目的進展有一個總體的構思,各個模塊該有什麼功能都比較清晰,特別在編寫 JSP 文件的時候能明顯感受不會很迷茫,這是比較好的一點
  • 發現本身閱讀代碼量不多,這種感受體如今不少地方,一是寫代碼時感受到本身思想的侷限性,二是以爲本身寫的代碼有不少的類似性,雖然這個項目是本身突發奇想的想要去作的,可是有不少細節的地方,是本身沒有去注意到的,好比類型要求、邊界判斷、事務處理等等等...

歡迎轉載,轉載請註明出處!
簡書ID:@我沒有三顆心臟
github:wmyskxz 歡迎關注公衆微信號:wmyskxz_javaweb 分享本身的Java Web學習之路以及各類Java學習資料

相關文章
相關標籤/搜索