品优购电商系统 2 - 品牌管理
本文部分内容来自黑马49期项目实战-品优购电商系统开发
课程目标
- 运用AngularJS前端框架的常用命令
- 完成品牌管理的列表功能
- 完成品牌管理的分页列表功能
- 完成品牌管理的增加功能
- 完成品牌管理的修改功能
- 完成品牌管理的删除功能
- 完成品牌管理的条件查询功能
前端框架AngularJS入门
AngularJS简介
AngularJS 诞生于2009年,由Misko Hevery 等人创建,后为Google所收购。是一款优秀的前端JS框架,已经被用于Google的多款产品当中。AngularJS有着诸多特性,最为核心的是:MVC、模块化、自动化双向数据绑定、依赖注入等等。
AngularJS四大特征
MVC模式
- Angular遵循软件工程的MVC模式,并鼓励展现,数据,和逻辑组件之间的松耦合。
通过依赖注入(dependency injection),Angular为客户端的Web应用带来了传统服务端的服务,例如独立于视图的控制。 因此,后端减少了许多负担,产生了更轻的Web应用。
-
MVC
- Model:数据
- View:视图页面,呈现数据
- Controller:操作数据,数据的增删改查
双向绑定
- AngularJS是建立在这样的信念上的:即声明式编程应该用于构建用户界面以及编写软件构建,而指令式编程非常适合来表示业务逻辑。
-
框架采用并扩展了传统HTML,通过双向的数据绑定来适应动态内容,双向的数据绑定允许模型和视图之间的自动同步。因此,AngularJS使得对DOM的操作不再重要并提升了可测试性。
依赖注入
- 依赖注入(Dependency Injection,简称DI)是一种设计模式, 指某个对象依赖的其他对象无需手工创建,只需要“吼一嗓子”,则此对象在创建时,其依赖的对象由框架来自动创建并注入进来,其实就是最少知识法则;模块中所有的service和provider两类对象,都可以根据形参名称实现DI.
模块化设计
- 高内聚低耦合法则
- 官方提供的模块:ng、ngRoute、ngAnimate
- 用户自定义模块 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>
- 表达式的格式是 {{ 表达式 }}
- ng-app指令初始化一个AngularJS应用程序
- ng-init指令初始化应用程序数据
- ng-model指令把元素值绑定到应用程序
- ng-controller=”myController”定义一个控制器
-
$scope
的使用贯穿整个 AngularJS App 应用,它与数据模型相关联,同时也是表达式执行的上下文.有了$scope
就在视图和控制器之间建立了一个通道,基于作用域视图在修改数据时会立刻更新$scope
,同样的$scope
发生改变时也会立刻重新渲染视图
品牌列表的实现
需求分析
-
实现品牌列表的查询(不用分页和条件查询)
前端代码
-
在pinyougou-manager-web下webapp中加入静态文件
-
引入JS
- 修改brand.html,引入JS
<script src="../plugins/angularjs/angular.min.js"></script>
-
指定模块和控制器
<body class="hold-transition skin-red sidebar-mini" ng-app="pinyougou" ng-controller="brandController">
- ng-app指令中定义的就是模块的名称
- ng-controller指令添加控制器
- 在controller中,编写函数和变量,用scope对象访问
-
获取数据
-
在中添加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>
-
在中初始化调用方法
<body class="hold-transition skin-red sidebar-mini" ng-app="pinyougou" ng-controller="brandController" ng-init="findAll()">
-
-
循环列表显示数据
<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>
-
结果
品牌列表分页的实现
需求分析
-
在品牌管理下方放置分页栏,实现分页功能
后端代码
分页结果封装实体
-
在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; } }
服务接口层
-
在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); }
服务实现层
-
在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()); } }
控制层
-
在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); } }
测试
前端代码
-
在brand.html引入分页组件
<!-- 分页组件开始 --> <script src="../plugins/angularjs/pagination.js"></script> <link rel="stylesheet" href="../plugins/angularjs/pagination.css"> <!-- 分页组件结束 -->
-
构建app模块时,引入pageination模块
var app = angular.module('pinyougou', ['pagination']);
-
在页面表格下放置分页组件
<!-- 分页 --> <tm-pagination conf="paginationConf"></tm-pagination>
-
修改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>
-
去掉ng-init初始化
<body class="hold-transition skin-red sidebar-mini" ng-app="pinyougou" ng-controller="brandController">
测试
-
查看效果
增加品牌
需求分析
-
实现品牌增加功能
后端代码
服务接口层
-
在pinyougou-sellergoods-interface工程的BrandService.java新增方法
/** * 增加品牌 * * @param brand the brand */ void add(TbBrand brand);
服务实现层
-
在pinyougou-sellergoods-service工程的BrandServiceImpl.java新增方法
@Override public void add(TbBrand brand) { // 增加品牌 brandMapper.insert(brand); }
封装返回结果实体
-
在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; } }
控制层
-
在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, "增加失败"); }
前端代码
-
在app.controller中新增函数
// 新增产品 $scope.add = function () { $http.post("../brand/add.do", $scope.entity).success( function (response) { if (response.success) { // 重新加载数据 $scope.reloadBrandList(); } else { alert(response.message); } } ); }
-
使用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>
-
防止每次打开新建品牌窗口遗留上次的数据,使用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>
测试
-
新增格力品牌
-
查看品牌列表
修改品牌
需求分析
-
点击列表的修改按钮,弹出窗口,修改数据后点击“保存”
后端代码
服务接口层
-
在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);
服务实现层
-
在pinyougou-sellergoods-service工程的BrandServiceImpl.java新增方法
@Override public void update(TbBrand brand) { brandMapper.updateByPrimaryKey(brand); } @Override public TbBrand findOne(Long id) { return brandMapper.selectByPrimaryKey(id); }
控制层
-
在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); }
前端代码
-
在app.controller中新增函数
// 查询品牌实体 $scope.findOne = function (id) { $http.get("../brand/findOne.do?id="+id).success( function (response) { $scope.entity = response; } ); };
-
修改列表中“修改”按钮,点击此按钮执行查询实体信息,使用ng-click绑定
<button type="button" class="btn bg-olive btn-xs" data-toggle="modal" data-target="#editModal" ng-click="findOne(entity.id)">修改</button>
-
将
$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); } } ); };
测试
-
点击修改,弹出对应品牌信息
-
将苹果首字母改为“A”,列表中,苹果品牌的首字母显示为A
删除品牌
需求分析
-
勾选列表的复选框,点击删除按钮,删除选中品牌
后端代码
服务接口层
-
在pinyougou-sellergoods-interface工程的BrandService.java新增方法
/** * 批量删除 * * @param ids the ids */ void delete(Long[] ids);
服务实现层
-
在pinyougou-sellergoods-service工程的BrandServiceImpl.java新增方法
@Override public void delete(Long[] ids) { for (Long id: ids) { brandMapper.deleteByPrimaryKey(id); } }
控制层
-
在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, "删除失败"); }
前端代码
-
主要思路: 需要定义一个用于存储选中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(); } ); }
-
修改列表复选框和删除按钮
<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>
测试
-
选中格力复选框
-
点击删除,刷新列表,列表中没有格力选项
品牌条件查询
需求分析
- 实现品牌条件查询功能,输入品牌名称、首字母后查询,并分页
后端代码
服务接口层
-
在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);
服务实现层
-
在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()); }
控制层
-
在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); }
前端代码
-
修改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; } ); }
-
修改reloadBrandList方法
// 重新加载数据列表 $scope.reloadBrandList = function() { // 切换页码 $scope.search($scope.paginationConf.currentPage, $scope.paginationConf.itemsPerPage); };
-
添加工具栏中添加搜索输入框
<!--工具栏--> <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> <!--工具栏/-->
测试
-
刷新品牌列表页,正常显示
-
品牌名称输入“中”,显示“中兴”
-
品牌首字母输入”L”,点击查询
上一篇: 基于FPGA的图像中值滤波原理与实现
下一篇: 基于OpenCV的中值滤波代码仿真
推荐阅读
-
品优购电商系统开发第 2 章 品牌管理 四
-
品优购电商系统开发第 3 章规格及模板管理 七
-
品优购电商系统 2 - 品牌管理
-
品优购电商系统开发第 3 章规格及模板管理 四
-
品优购电商系统开发 第 6 章 五
-
day01_品优购电商项目_01_走进电商 + 分布式框架-Dubbox + 品优购-框架搭建 + 逆向工程 + 品牌列表展示 + 常见错误_用心笔记
-
跨境B2B电商市场血雨腥风,供应链管理系统成争夺焦点
-
day02_品优购电商项目_02_前端框架AngularJS入门 + 品牌列表的实现 + 品牌列表分页的实现 + 增加/修改/删除品牌的实现 + 品牌分页条件查询的实现_用心笔记
-
趣哪优品社交社群分享电商网购平台上线
-
电商红利见顶?零食品牌为啥都学良品铺子做O2O