品优购电商系统 2 - 品牌管理

本文部分内容来自黑马49期项目实战-品优购电商系统开发

课程目标

  1. 运用AngularJS前端框架的常用命令
  2. 完成品牌管理的列表功能
  3. 完成品牌管理的分页列表功能
  4. 完成品牌管理的增加功能
  5. 完成品牌管理的修改功能
  6. 完成品牌管理的删除功能
  7. 完成品牌管理的条件查询功能

前端框架AngularJS入门

AngularJS简介

AngularJS 诞生于2009年,由Misko Hevery 等人创建,后为Google所收购。是一款优秀的前端JS框架,已经被用于Google的多款产品当中。AngularJS有着诸多特性,最为核心的是:MVC、模块化、自动化双向数据绑定、依赖注入等等。

这里写图片描述

AngularJS四大特征

MVC模式

  1. Angular遵循软件工程的MVC模式,并鼓励展现,数据,和逻辑组件之间的松耦合。
  2. 通过依赖注入(dependency injection),Angular为客户端的Web应用带来了传统服务端的服务,例如独立于视图的控制。 因此,后端减少了许多负担,产生了更轻的Web应用。

  3. MVC

    这里写图片描述

    1. Model:数据
    2. View:视图页面,呈现数据
    3. Controller:操作数据,数据的增删改查

双向绑定

  1. AngularJS是建立在这样的信念上的:即声明式编程应该用于构建用户界面以及编写软件构建,而指令式编程非常适合来表示业务逻辑。
  2. 框架采用并扩展了传统HTML,通过双向的数据绑定来适应动态内容,双向的数据绑定允许模型和视图之间的自动同步。因此,AngularJS使得对DOM的操作不再重要并提升了可测试性。

    这里写图片描述

依赖注入

  1. 依赖注入(Dependency Injection,简称DI)是一种设计模式, 指某个对象依赖的其他对象无需手工创建,只需要“吼一嗓子”,则此对象在创建时,其依赖的对象由框架来自动创建并注入进来,其实就是最少知识法则;模块中所有的service和provider两类对象,都可以根据形参名称实现DI.

模块化设计

  1. 高内聚低耦合法则
  2. 官方提供的模块:ng、ngRoute、ngAnimate
  3. 用户自定义模块 angular.module(”)

入门小Demo

表达式

<html>
<head>
    <meta charset="utf-8">
    <title>AngularJS 表达式 Demo</title>
    <script src="http://cdn.static.runoob.com/libs/angular.js/1.4.6/angular.min.js"></script>
</head>

<body ng-app="myApp">
    <div ng-init="name='AngularJS By Google'" ng-controller="myControl">
        <p> 100 * 100 = {{100*100}} </p>
        <p>请输入名字:<input type="text" ng-model="name"></p>
        <p>名字: {{ name }}</p>

        <p>姓: <input type="text" ng-model="lastName"></p>
        <p>名: <input type="text" ng-model="firstName"></p>
        <p>全名:{{ fullName() }}</p>
    </div>
</body>

<script type="text/javascript">
    var app = angular.module('myApp', []);
    app.controller('myControl', function ($scope) {
        // body...
        // $scope.firstName = "";
        // $scope.lastName = "";
        $scope.fullName = function() {
            return $scope.lastName + $scope.firstName;
        };
    });
</script>
</html>

这里写图片描述

扫描二维码关注公众号,回复: 1903227 查看本文章
  1. 表达式的格式是 {{ 表达式 }}
  2. ng-app指令初始化一个AngularJS应用程序
  3. ng-init指令初始化应用程序数据
  4. ng-model指令把元素值绑定到应用程序
  5. ng-controller=”myController”定义一个控制器
  6. $scope 的使用贯穿整个 AngularJS App 应用,它与数据模型相关联,同时也是表达式执行的上下文.有了$scope就在视图和控制器之间建立了一个通道,基于作用域视图在修改数据时会立刻更新 $scope,同样的$scope发生改变时也会立刻重新渲染视图

品牌列表的实现

需求分析

  1. 实现品牌列表的查询(不用分页和条件查询)

    这里写图片描述

前端代码

  1. 在pinyougou-manager-web下webapp中加入静态文件

    这里写图片描述

  2. 引入JS

    1. 修改brand.html,引入JS
    <script src="../plugins/angularjs/angular.min.js"></script>
  3. 指定模块和控制器

    <body class="hold-transition skin-red sidebar-mini" ng-app="pinyougou" ng-controller="brandController">
    1. ng-app指令中定义的就是模块的名称
    2. ng-controller指令添加控制器
    3. 在controller中,编写函数和变量,用scope对象访问
  4. 获取数据

    1. 在中添加js代码

      <script type="text/javascript">
              var app = angular.module('pinyougou', []);
              app.controller('brandController', function ($scope, $http) {
      
                  // 查询品牌列表
                  $scope.findAll = function () {
                      $http.get("../brand/findAll.do").success(
                          function (response) {
                              $scope.brandList = response;
                          }
                      );
                  }
              });
      </script>
    2. 在中初始化调用方法

      <body class="hold-transition skin-red sidebar-mini" ng-app="pinyougou" ng-controller="brandController" ng-init="findAll()">
  5. 循环列表显示数据

    <tbody>
      <tr ng-repeat="entity in brandList">
          <td><input  type="checkbox" ></td>                                          
          <td>{{ entity.id }}}</td>
          <td>{{ entity.name }}}</td>
          <td>{{ entity.firstChar }}}</td>
          <td class="text-center">                                           
              <button type="button" class="btn bg-olive btn-xs" data-toggle="modal" data-target="#editModal"  >修改</button>                                           
          </td>
      </tr>
    </tbody>
  6. 结果

    这里写图片描述

品牌列表分页的实现

需求分析

  1. 在品牌管理下方放置分页栏,实现分页功能

    这里写图片描述

后端代码

分页结果封装实体

  1. 在pinyougou-pojo工程中创建entity包,用于存放通用实体类,创建PageResult类

    package com.huangwangxin.entity;
    
    import java.io.Serializable;
    import java.util.List;
    
    /**
     * 分页结果封装对象
     *
     * @author wangxinhuang
     * @date 2018/6/29
     */
    public class PageResult implements Serializable {
    
    
        private long total; // 总记录数
        private List rows;
    
        public PageResult(long total, List rows) {
            this.total = total;
            this.rows = rows;
        }
    
        public long getTotal() {
            return total;
        }
    
        public void setTotal(long total) {
            this.total = total;
        }
    
        public List getRows() {
            return rows;
        }
    
        public void setRows(List rows) {
            this.rows = rows;
        }
    }

服务接口层

  1. 在pinyougou-sellergoods-interface的BrandService.java增加方法定义

    package com.huangwangxin.service;
    
    import com.huangwangxin.entity.PageResult;
    import com.huangwangxin.pojo.TbBrand;
    
    import java.util.List;
    
    /**
     * 品牌服务层接口
     *
     * @author wangxinhuang
     * @date 2018 /6/27
     */
    public interface BrandService {
    
        /**
         * 返回全部列表
         *
         * @return the list
         */
        List<TbBrand> findAll();
    
        /**
         * 返回分页列表.
         *
         * @param pageNum  the page num
         * @param pageSize the page size
         * @return the page result
         */
        PageResult findPage(int pageNum, int pageSize);
    }
    

服务实现层

  1. 在pinyougou-sellergoods-service的BrandServiceImpl.java实现该方法

    package com.huangwangxin.sellergoods.service.impl;
    
    import com.alibaba.dubbo.config.annotation.Service;
    import com.github.pagehelper.Page;
    import com.github.pagehelper.PageHelper;
    import com.huangwangxin.entity.PageResult;
    import com.huangwangxin.mapper.TbBrandMapper;
    import com.huangwangxin.pojo.TbBrand;
    import com.huangwangxin.pojo.TbBrandExample;
    import com.huangwangxin.service.BrandService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * 品牌服务实现
     *
     * @author wangxinhuang
     * @date 2018/6/27
     */
    @Service
    public class BrandServiceImpl implements BrandService {
    
        @Autowired
        private TbBrandMapper brandMapper;
    
        @Override
        public List<TbBrand> findAll() {
    
            return brandMapper.selectByExample(null);
        }
    
        @Override
        public PageResult findPage(int pageNum, int pageSize) {
    
            PageHelper.startPage(pageNum, pageSize);
            Page<TbBrand> page = (Page<TbBrand>) brandMapper.selectByExample(null);;
    
            return new PageResult(page.getTotal(), page.getResult());
        }
    }

控制层

  1. 在pinyougou-manager-web工程的BrandController.java中新增方法

    package com.huangwangxin.manager.controller;
    
    import com.alibaba.dubbo.config.annotation.Reference;
    import com.huangwangxin.entity.PageResult;
    import com.huangwangxin.pojo.TbBrand;
    import com.huangwangxin.service.BrandService;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    import java.util.List;
    
    /**
     * 品牌
     *
     * @author wangxinhuang
     * @date 2018/6/27
     */
    @RestController
    @RequestMapping("/brand")
    public class BrandController {
    
        @Reference
        private BrandService brandService;
    
        /**
         * 返回品牌全部列表 all list.
         *
         * @return the list
         */
        @RequestMapping("/findAll")
        public List<TbBrand> findAll() {
    
            return brandService.findAll();
        }
    
        /**
         * 分页列表.
         *
         * @param page the page
         * @param pageSize  the page size
         * @return the page result
         */
        @RequestMapping("/findPage")
        public PageResult findPage(int page, int pageSize) {
    
            return brandService.findPage(page, pageSize);
        }
    }
    

测试

  1. 访问http://localhost:9101/brand/findPage.do?page=1&pageSize=10

    这里写图片描述

前端代码

  1. 在brand.html引入分页组件

    <!-- 分页组件开始 -->
    <script src="../plugins/angularjs/pagination.js"></script>
    <link rel="stylesheet" href="../plugins/angularjs/pagination.css">
    <!-- 分页组件结束 -->
  2. 构建app模块时,引入pageination模块

    var app = angular.module('pinyougou', ['pagination']); 
  3. 在页面表格下放置分页组件

    <!-- 分页 -->
    <tm-pagination conf="paginationConf"></tm-pagination>
  4. 修改JS

    <script type="text/javascript">
        var app = angular.module('pinyougou', ['pagination']);
        app.controller('brandController', function ($scope, $http) {
    
            // 查询品牌列表
            $scope.findPage = function (page, rows) {
                $http.get("../brand/findPage.do?page="+page+"&pageSize="+rows).success(
                    function (response) {
                        $scope.brandList = response.rows;
                        $scope.paginationConf.totalItems = response.total;
                    }
                );
            };
    
            // 重新加载数据列表
            $scope.reloadBrandList = function() {
    
                // 切换页码
                $scope.findPage($scope.paginationConf.currentPage, $scope.paginationConf.itemsPerPage);
            };
    
    
    
            // 分页
            $scope.paginationConf = {
                // 当前页码
                currentPage: 1,
                // 总条数
                totalItems: 10,
                // 每页数量
                itemsPerPage: 10,
                // 页码选项
                perPageOptions: [10, 20, 30, 40, 50],
                // 更改页面时触发事件
                onChange: function () {
                    // 重新加载
                    $scope.reloadBrandList();
                }
            }
        });
    </script>
  5. 去掉ng-init初始化

    <body class="hold-transition skin-red sidebar-mini" ng-app="pinyougou" ng-controller="brandController">

测试

  1. 查看效果

    这里写图片描述

增加品牌

需求分析

  1. 实现品牌增加功能

    这里写图片描述

后端代码

服务接口层

  1. 在pinyougou-sellergoods-interface工程的BrandService.java新增方法

    /**
     * 增加品牌
     *
     * @param brand the brand
     */
    void add(TbBrand brand);

服务实现层

  1. 在pinyougou-sellergoods-service工程的BrandServiceImpl.java新增方法

    @Override
    public void add(TbBrand brand) {
    
        // 增加品牌
        brandMapper.insert(brand);
    }

封装返回结果实体

  1. 在pinyougou-pojo的entity包下新增Result.java

    package com.huangwangxin.entity;
    
    import java.io.Serializable;
    
    /**
     * 返回结果封装
     *
     * @author wangxinhuang
     * @date 2018/6/29
     */
    public class Result implements Serializable {
    
        private boolean success;
    
        private String message;
    
        public Result(boolean success, String message) {
            this.success = success;
            this.message = message;
        }
    
        public boolean isSuccess() {
            return success;
        }
    
        public void setSuccess(boolean success) {
            this.success = success;
        }
    
        public String getMessage() {
            return message;
        }
    
        public void setMessage(String message) {
            this.message = message;
        }
    }
    

控制层

  1. 在pinyougou-manager-web的BrandController.java新增方法

    /**
     * 增加品牌
     *
     * @param brand the brand
     * @return the result
     */
    @RequestMapping("/add")
    public Result add(@RequestBody TbBrand brand) {
    
        try {
            brandService.add(brand);
            return new Result(true, "增加成功");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return new Result(false, "增加失败");
    }

前端代码

  1. 在app.controller中新增函数

    // 新增产品
    $scope.add = function () {
        $http.post("../brand/add.do", $scope.entity).success(
            function (response) {
                if (response.success) {
    
                    // 重新加载数据
                    $scope.reloadBrandList();
                } else {
                    alert(response.message);
                }
            }
        );
    }
  2. 使用ng-model指令绑定entity,使用ng-click绑定保存按钮

    <!-- 编辑窗口 -->
    <div class="modal fade" id="editModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
      <div class="modal-dialog" >
        <div class="modal-content">
            <div class="modal-header">
                <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
                <h3 id="myModalLabel">品牌编辑</h3>
            </div>
            <div class="modal-body">        
                <table class="table table-bordered table-striped"  width="800px">
                    <tr>
                        <td>品牌名称</td>
                        <td><input  class="form-control" placeholder="品牌名称" ng-model="entity.name">  </td>
                    </tr>               
                    <tr>
                        <td>首字母</td>
                        <td><input  class="form-control" placeholder="首字母" ng-model="entity.firstChar">  </td>
                    </tr>               
                 </table>               
            </div>
            <div class="modal-footer">                      
                <button class="btn btn-success" data-dismiss="modal" aria-hidden="true" ng-click="add()">保存</button>
                <button class="btn btn-default" data-dismiss="modal" aria-hidden="true">关闭</button>
            </div>
          </div>
        </div>
    </div>
  3. 防止每次打开新建品牌窗口遗留上次的数据,使用ng-click对entity变量进行清空操作

     <button type="button" class="btn btn-default" title="新建" data-toggle="modal" data-target="#editModal" ng-click="entity={}"><i class="fa fa-file-o"></i> 新建</button>

测试

  1. 新增格力品牌

    这里写图片描述

  2. 查看品牌列表

    这里写图片描述

修改品牌

需求分析

  1. 点击列表的修改按钮,弹出窗口,修改数据后点击“保存”

    这里写图片描述

后端代码

服务接口层

  1. 在pinyougou-sellergoods-interface工程的BrandService.java新增方法

    /**
     * 修改品牌.
     *
     * @param brand the brand
     */
    void update(TbBrand brand);
    
    /**
     * 根据ID获取品牌实体
     *
     * @param id the id
     * @return the tb brand
     */
    TbBrand findOne(Long id);

服务实现层

  1. 在pinyougou-sellergoods-service工程的BrandServiceImpl.java新增方法

    @Override
    public void update(TbBrand brand) {
        brandMapper.updateByPrimaryKey(brand);
    }
    
    @Override
    public TbBrand findOne(Long id) {
        return brandMapper.selectByPrimaryKey(id);
    }

控制层

  1. 在pinyougou-manager-web的BrandController.java新增方法

    /**
     * 更新品牌信息.
     *
     * @param brand the brand
     * @return the result
     */
    @RequestMapping("/update")
    public Result update(@RequestBody TbBrand brand) {
        try {
            brandService.update(brand);
            return new Result(true, "修改成功");
        } catch (Exception e) {
            e.printStackTrace();
        }
    
        return new Result(false, "修改失败");
    }
    
    /**
     * 根据品牌Id查找品牌.
     *
     * @param id the id
     * @return the tb brand
     */
    @RequestMapping("/findOne")
    public TbBrand findOne(Long id) {
        return brandService.findOne(id);
    }

前端代码

  1. 在app.controller中新增函数

    // 查询品牌实体
    $scope.findOne = function (id) {
        $http.get("../brand/findOne.do?id="+id).success(
            function (response) {
                $scope.entity = response;
            }
        );
    };
  2. 修改列表中“修改”按钮,点击此按钮执行查询实体信息,使用ng-click绑定

    <button type="button" class="btn bg-olive btn-xs" data-toggle="modal" data-target="#editModal" ng-click="findOne(entity.id)">修改</button>
  3. $scope.add改为$scope.save

    // 新增产品
    $scope.save = function () {
    
        var methodName = "add";
    
        // 如果有实体id,则调用更新方法
        if ($scope.entity.id != null) {
            methodName = "update";
        } 
    
        $http.post("../brand/" + methodName +".do", $scope.entity).success(
            function (response) {
                if (response.success) {
    
                    // 重新加载数据
                    $scope.reloadBrandList();
                } else {
                    alert(response.message);
                }
            }
        );
    };

测试

  1. 点击修改,弹出对应品牌信息

    这里写图片描述

  2. 将苹果首字母改为“A”,列表中,苹果品牌的首字母显示为A

    这里写图片描述

删除品牌

需求分析

  1. 勾选列表的复选框,点击删除按钮,删除选中品牌

    这里写图片描述

后端代码

服务接口层

  1. 在pinyougou-sellergoods-interface工程的BrandService.java新增方法

    /**
     * 批量删除
     *
     * @param ids the ids
     */
    void delete(Long[] ids);

服务实现层

  1. 在pinyougou-sellergoods-service工程的BrandServiceImpl.java新增方法

    @Override
    public void delete(Long[] ids) {
        for (Long id: ids) {
            brandMapper.deleteByPrimaryKey(id);
        }
    }

控制层

  1. 在pinyougou-manager-web的BrandController.java新增方法

    /**
     * 批量删除.
     *
     * @param ids the ids
     * @return the result
     */
    @RequestMapping("/delete")
    public Result delete(Long[] ids) {
    
        try {
            brandService.delete(ids);
            return new Result(true, "删除成功");
        } catch (Exception e) {
            e.printStackTrace();
        }
    
        return new Result(false, "删除失败");
    }

前端代码

  1. 主要思路: 需要定义一个用于存储选中ID的数组,当我们点击复选框后判断是选择还是取消选择,如果是选择就加到数组中,如果是取消选择就从数组中移除。在点击删除按钮时需要用到这个存储了ID的数组。

    // 选中的Id集合
    $scope.selectIds = [];
    
    // 更新复选
    $scope.updateSelection =function ($event, id) {
    
        // 如果选中,添加到数组中
        if ($event.target.checked) {
            $scope.selectIds.push(id);
        } else {
            // splice方法,从数组的指定位置移除指定个数的元素,第一个参数为位置,第二个参数是移除的个数
            var index = $scope.selectIds.indexOf(id);
            $scope.selectIds.splice(index, 1);
        }
    }
    
    // 批量删除
    $scope.deleteBrands = function () {
    
        $http.get("../brand/delete.do?ids=" + $scope.selectIds).success(
            function (response) {
                // 重新加载数据
                $scope.reloadBrandList();
            }
        );
    }
  2. 修改列表复选框和删除按钮

    <tbody>
      <tr ng-repeat="entity in brandList">
          <td><input type="checkbox" ng-click="updateSelection($event, entity.id)"></td>
          <td>{{ entity.id }}</td>
          <td>{{ entity.name }}</td>
          <td>{{ entity.firstChar }}</td>
          <td class="text-center">                                           
              <button type="button" class="btn bg-olive btn-xs" data-toggle="modal" data-target="#editModal" ng-click="findOne(entity.id)">修改</button>
          </td>
      </tr>
    </tbody>
    <button type="button" class="btn btn-default" title="删除" ng-click="deleteBrands()"><i class="fa fa-trash-o"></i> 删除</button>

测试

  1. 选中格力复选框

    这里写图片描述

  2. 点击删除,刷新列表,列表中没有格力选项

    这里写图片描述

品牌条件查询

需求分析

  1. 实现品牌条件查询功能,输入品牌名称、首字母后查询,并分页

后端代码

服务接口层

  1. 在pinyougou-sellergoods-interface工程的BrandService.java新增方法

    /**
     * 品牌查询
     *
     * @param brand    品牌
     * @param pageNum  the page num
     * @param pageSize the page size
     * @return the page result
     */
    PageResult findBrand(TbBrand brand, int pageNum, int pageSize);

服务实现层

  1. 在pinyougou-sellergoods-service工程的BrandServiceImpl.java新增方法

    @Override
    public PageResult findBrand(TbBrand brand, int pageNum, int pageSize) {
    
        PageHelper.startPage(pageNum, pageSize);
    
        TbBrandExample example = new TbBrandExample();
        TbBrandExample.Criteria criteria = example.createCriteria();
        if (brand != null) {
            if (!StringUtils.isEmpty(brand.getName())) {
                // 品牌名称
                criteria.andNameLike("%" + brand.getName() + "%");
            }
    
            if (!StringUtils.isEmpty(brand.getFirstChar())) {
                // 品牌首字母
                criteria.andFirstCharEqualTo(brand.getFirstChar());
            }
        }
    
        Page<TbBrand> page = (Page<TbBrand>) brandMapper.selectByExample(example);
    
        return new PageResult(page.getTotal(), page.getResult());
    }

控制层

  1. 在pinyougou-manager-web的BrandController.java新增方法

    /**
     * 查询品牌 + 分页
     *
     * @param brand    the brand
     * @param page     the page
     * @param pageSize the page size
     * @return the page result
     */
    @RequestMapping("/search")
    public PageResult search(@RequestBody TbBrand brand, int page, int pageSize) {
    
        return brandService.findBrand(brand, page, pageSize);
    }

前端代码

  1. 修改brand.html文件,在app.controller中添加

    // 定义搜索对象
    $scope.searchEntity = {};
    
    // 条件查询
    $scope.search = function (page, rows) {
    
        $http.post("../brand/search.do?page=" + page + "&pageSize=" + rows, $scope.searchEntity).success(
            function (response) {
                $scope.brandList = response.rows;
                $scope.paginationConf.totalItems = response.total;
            }
        );
    }
  2. 修改reloadBrandList方法

    // 重新加载数据列表
    $scope.reloadBrandList = function() {
    
        // 切换页码
        $scope.search($scope.paginationConf.currentPage, $scope.paginationConf.itemsPerPage);
    };
  3. 添加工具栏中添加搜索输入框

    <!--工具栏-->
    <div class="pull-left">
        <div class="form-group form-inline">
            <div class="btn-group">
                <button type="button" class="btn btn-default" title="新建" data-toggle="modal" data-target="#editModal" ng-click="entity={}"><i class="fa fa-file-o"></i> 新建</button>
                <button type="button" class="btn btn-default" title="删除" ng-click="deleteBrands()"><i class="fa fa-trash-o"></i> 删除</button>
                <button type="button" class="btn btn-default" title="刷新" onclick="window.location.reload();"><i class="fa fa-refresh"></i> 刷新</button>
            </div>
        </div>
    </div>
    <div class="box-tools pull-right">
        <div class="has-feedback">
            品牌名称:<input ng-model="searchEntity.name"> 品牌首字母:<input ng-model="searchEntity.firstChar"> <button type="button" class="btn btn-default" ng-click="reloadBrandList()">查询</button>
        </div>
    </div>
    <!--工具栏/-->

测试

  1. 刷新品牌列表页,正常显示

    这里写图片描述

  2. 品牌名称输入“中”,显示“中兴”

    这里写图片描述

  3. 品牌首字母输入”L”,点击查询

    这里写图片描述

猜你喜欢

转载自blog.csdn.net/h1101723183/article/details/80881664