今日目标:
(1)理解和运用 angular js 的 service
(2)理解好运用控制器继承
(3)掌握代码生成器的使用
(4)实现规格管理
(5)实现模板管理
1、前段分层开发
1.1 JS 代码改造
// 自定义模块,引入分页模块
var app = angular.module('pinyougou', ['pagination']);
//自定义服务
app.service('brandService', function ($http) {
// 分页查询品牌列表
this.findByPage = function (page, size) {
return $http.get('../brand/findByPage.do?page=' + page + '&size=' + size);
};
// 新增品牌
this.add = function (entity) {
return $http.post('../brand/add.do', entity);
};
// 按id查询品牌
this.findOne = function (id) {
return $http.get('../brand/findOne.do?id=' + id);
};
// 修改品牌
this.update = function (entity) {
return $http.post('../brand/update.do', entity);
};
// 删除品牌
this.dele = function (ids) {
return $http.get('../brand/delete.do?ids=' + ids);
}
this.search = function (page,size,queryParam) {
return $http.post('../brand/search.do?page=' + page + '&size=' + size, queryParam);
}
});
//自定义控制器
app.controller('brandController', function ($scope, brandService) {
//分页控件配置
$scope.paginationConf = {
//当前页
currentPage: 1,
//总记录数
totalItems: 10,
//每页记录数
itemsPerPage: 10,
//可以选择的每页记录数
perPageOptions: [10, 20, 30, 40, 50],
//选择每页记录数事件
onChange: function () {
$scope.reloadList();
}
};
//重新加载
$scope.reloadList = function () {
$scope.search($scope.paginationConf.currentPage, $scope.paginationConf.itemsPerPage);
};
/*
分页查询品牌列表
*/
$scope.findByPage = function (page, size) {
brandService.findByPage(page, size).success(
function (rtn) {
//显示当前页的数据
$scope.list = rtn.rows;
//修改总记录数
$scope.paginationConf.totalItems = rtn.total;
}
);
};
/*
新增品牌、修改品牌
*/
$scope.save = function () {
var object = null;
if ($scope.entity.id != null) {
object = brandService.update($scope.entity);
} else {
object = brandService.add($scope.entity);
}
object.success(
function (rtn) {
alert(rtn.message);
if (rtn.success) {
//重新加载数据
$scope.reloadList();
}
}
);
};
/*
加载要修改的品牌到编辑品牌表单
*/
$scope.findOne = function (id) {
brandService.findOne(id).success(
function (rtn) {
$scope.entity = rtn;
}
);
};
//记录被勾选的id值
$scope.selectIds = [];
/*
更新被勾选的id值
*/
$scope.updateSelection = function ($event, id) {
if ($event.target.checked) {//选中状态
//将id值加入selectIds
$scope.selectIds.push(id);
} else {//取消选中
//获取id值的下标
var index = $scope.selectIds.indexOf(id);
//移除id
$scope.selectIds.splice(index, 1);
}
};
/*
删除操作
*/
$scope.dele = function () {
brandService.dele($scope.selectIds).success(
function (rtn) {
alert(rtn.message);
if (rtn.success) {
//重新加载数据
$scope.reloadList();
}
}
);
};
/*
条件查询
*/
//初始化queryParam
$scope.queryParam = {};
$scope.search = function (page, size) {
brandService.search(page, size, $scope.queryParam).success(
function (rtn) {
//显示当前页的数据
$scope.list = rtn.rows;
//修改总记录数
$scope.paginationConf.totalItems = rtn.total;
}
);
};
});
1.2 将改造后的 JS 分层,即将放入不同的 JS 文件中
(1)base_pagination.js
// 自定义模块,引入分页模块
var app = angular.module('pinyougou', ['pagination']);
(2)brandService.js
//自定义服务
app.service('brandService', function ($http) {
// 分页查询品牌列表
this.findByPage = function (page, size) {
return $http.get('../brand/findByPage.do?page=' + page + '&size=' + size);
};
// 新增品牌
this.add = function (entity) {
return $http.post('../brand/add.do', entity);
};
// 按id查询品牌
this.findOne = function (id) {
return $http.get('../brand/findOne.do?id=' + id);
};
// 修改品牌
this.update = function (entity) {
return $http.post('../brand/update.do', entity);
};
// 删除品牌
this.dele = function (ids) {
return $http.get('../brand/delete.do?ids=' + ids);
}
this.search = function (page,size,queryParam) {
return $http.post('../brand/search.do?page=' + page + '&size=' + size, queryParam);
}
});
(3)brandController.js
//自定义控制器
app.controller('brandController', function ($scope, brandService) {
//分页控件配置
$scope.paginationConf = {
//当前页
currentPage: 1,
//总记录数
totalItems: 10,
//每页记录数
itemsPerPage: 10,
//可以选择的每页记录数
perPageOptions: [10, 20, 30, 40, 50],
//选择每页记录数事件
onChange: function () {
$scope.reloadList();
}
};
//重新加载
$scope.reloadList = function () {
$scope.search($scope.paginationConf.currentPage, $scope.paginationConf.itemsPerPage);
};
/*
分页查询品牌列表
*/
$scope.findByPage = function (page, size) {
brandService.findByPage(page, size).success(
function (rtn) {
//显示当前页的数据
$scope.list = rtn.rows;
//修改总记录数
$scope.paginationConf.totalItems = rtn.total;
}
);
};
/*
新增品牌、修改品牌
*/
$scope.save = function () {
var object = null;
if ($scope.entity.id != null) {
object = brandService.update($scope.entity);
} else {
object = brandService.add($scope.entity);
}
object.success(
function (rtn) {
alert(rtn.message);
if (rtn.success) {
//重新加载数据
$scope.reloadList();
}
}
);
};
/*
加载要修改的品牌到编辑品牌表单
*/
$scope.findOne = function (id) {
brandService.findOne(id).success(
function (rtn) {
$scope.entity = rtn;
}
);
};
//记录被勾选的id值
$scope.selectIds = [];
/*
更新被勾选的id值
*/
$scope.updateSelection = function ($event, id) {
if ($event.target.checked) {//选中状态
//将id值加入selectIds
$scope.selectIds.push(id);
} else {//取消选中
//获取id值的下标
var index = $scope.selectIds.indexOf(id);
//移除id
$scope.selectIds.splice(index, 1);
}
};
/*
删除操作
*/
$scope.dele = function () {
brandService.dele($scope.selectIds).success(
function (rtn) {
alert(rtn.message);
if (rtn.success) {
//重新加载数据
$scope.reloadList();
}
}
);
};
/*
条件查询
*/
//初始化queryParam
$scope.queryParam = {};
$scope.search = function (page, size) {
brandService.search(page, size, $scope.queryParam).success(
function (rtn) {
//显示当前页的数据
$scope.list = rtn.rows;
//修改总记录数
$scope.paginationConf.totalItems = rtn.total;
}
);
};
});
(4)在品牌管理页面中引入这些 JS
1.3 控制器继承
(1)抽取出控制器中公共代码到baseController.js中
app.controller('baseController',function ($scope) {
//分页控件配置
$scope.paginationConf = {
//当前页
currentPage: 1,
//总记录数
totalItems: 10,
//每页记录数
itemsPerPage: 10,
//可以选择的每页记录数
perPageOptions: [10, 20, 30, 40, 50],
//选择每页记录数事件
onChange: function () {
$scope.reloadList();
}
};
//重新加载
$scope.reloadList = function () {
$scope.search($scope.paginationConf.currentPage, $scope.paginationConf.itemsPerPage);
};
//记录被勾选的id值
$scope.selectIds = [];
/*
更新被勾选的id值
*/
$scope.updateSelection = function ($event, id) {
if ($event.target.checked) {//选中状态
//将id值加入selectIds
$scope.selectIds.push(id);
} else {//取消选中
//获取id值的下标
var index = $scope.selectIds.indexOf(id);
//移除id
$scope.selectIds.splice(index, 1);
}
};
});
(2)使用 brandController 继承 baseController
// 继承baseController
$controller('baseController', {$scope: $scope});
注意:要使用继承,必须先将$controller 服务注入到brandController,并且要在引入brandController.js之前引入baseController.js
2、规格管理
2.1 规格列表显示,后端代码与JS代码使用生成器生成,只需修改页面
(1)引入 JS 文件
(2)引入 angular JS
(3)循环获取值
2.2 新增规格
需求1:点击新增规格选项,在表格中新增一行
(1)点击新建按钮时,初始化绑定的变量
(2)编写 JS 代码(specificationController.js)
//新增规格选项
$scope.addTableRow = function () {
$scope.entity.specificationOptionList.push({});
}
(3)为新增规格选项按钮绑定事件
需求2:点击删除按钮,删除当前表格行
(1)编写 JS 代码(specificationController.js)
//删除规格选项
$scope.deleTableRow = function (index) {
$scope.entity.specificationOptionList.splice(index,1);
}
(2)为删除按钮绑定事件,index参数可以使用 $index 直接获取
需求3:点击保存按钮,提交到后端进行保存
(1)后端代码
a、pinyougou-dao,修改TbSpecificationMapper.xml中的insert映射,加入代码,为了在插入规格后获取其ID,用于后续操作
<selectKey resultType="java.lang.Long" order="AFTER" keyProperty="id">
SELECT LAST_INSERT_ID() AS id
</selectKey>
b、创建一个实体类,用于接受前端传过来的参数
package com.pinyougou.pojogroup;
import com.pinyougou.pojo.TbSpecification;
import com.pinyougou.pojo.TbSpecificationOption;
import java.util.List;
/**
* 规格和规格选项组合实体类
* Author xushuai
* Description
*/
public class Specification {
/** 品牌规格 */
private TbSpecification specification;
/** 规格选项 */
private List<TbSpecificationOption> specificationOptionList;
public TbSpecification getSpecification() {
return specification;
}
public void setSpecification(TbSpecification specification) {
this.specification = specification;
}
public List<TbSpecificationOption> getSpecificationOptionList() {
return specificationOptionList;
}
public void setSpecificationOptionList(List<TbSpecificationOption> specificationOptionList) {
this.specificationOptionList = specificationOptionList;
}
}
c、服务层接口(sellergoods-interface),重载add方法
/**
* 新增
*
* @param specification 规格组合实体
*/
void add(Specification specification);
d、服务层实现(sellergoods-service),新增实现
@Override
public void add(Specification specification) {
//从组合实体中获取规格对象
TbSpecification tbSpecification = specification.getSpecification();
//执行保存
specificationMapper.insert(tbSpecification);
//从组合试题中获取规格选项
List<TbSpecificationOption> tbSpecificationOptionList = specification.getSpecificationOptionList();
//循环保存
for (TbSpecificationOption option : tbSpecificationOptionList) {
//设置规格id
option.setSpecId(tbSpecification.getId());
//保存规格选项
specificationOptionMapper.insert(option);
}
}
d、控制层(manager-web)
/**
* 增加
* @param specification
* @return
*/
@RequestMapping("/add")
public Result add(@RequestBody Specification specification){
try {
specificationService.add(specification);
return new Result(true, "增加成功");
} catch (Exception e) {
e.printStackTrace();
return new Result(false, "增加失败");
}
}
(2)后端代码
a、为规格名称绑定变量
b、为保存按钮添加事件
//保存
$scope.save=function(){
var serviceObject;//服务层对象
if($scope.entity.specification.id!=null){//如果有ID
serviceObject=specificationService.update( $scope.entity ); //修改
}else{
serviceObject=specificationService.add( $scope.entity );//增加
}
serviceObject.success(
function(response){
if(response.success){
//重新查询
$scope.reloadList();//重新加载
}else{
alert(response.message);
}
}
);
}
2.3 修改规格
(1)后端代码
a、服务层接口(sellergoods-interface)
/**
* 根据ID获取实体
*
* @param id
* @return
*/
Specification findOne(Long id);
b、服务层实现(sellergoods-service)
/**
* 根据ID获取实体
*
* @param id
* @return
*/
@Override
public Specification findOne(Long id) {
//查询规格
TbSpecification tbSpecification = specificationMapper.selectByPrimaryKey(id);
//封装规格选项查询条件
TbSpecificationOptionExample specificationOptionExample = new TbSpecificationOptionExample();
specificationOptionExample.createCriteria().andSpecIdEqualTo(id);
//查询规格选项
List<TbSpecificationOption> tbSpecificationOptions = specificationOptionMapper.selectByExample(specificationOptionExample);
//创建规格组合实体类
Specification specification = new Specification();
specification.setSpecification(tbSpecification);
specification.setSpecificationOptionList(tbSpecificationOptions);
return specification;
}
c、控制层
/**
* 获取实体
* @param id
* @return
*/
@RequestMapping("/findOne")
public Specification findOne(Long id){
return specificationService.findOne(id);
}
(2)前端无需修改
2.4 删除规格
(1)后端代码,只需要修改服务层实现中的delete方法
/**
* 批量删除
*/
@Override
public void delete(Long[] ids) {
for (Long id : ids) {
//删除规格数据
specificationMapper.deleteByPrimaryKey(id);
//删除规格选项数据
TbSpecificationOptionExample specificationOptionExample = new TbSpecificationOptionExample();
specificationOptionExample.createCriteria().andSpecIdEqualTo(id);
//删除规格选项
specificationOptionMapper.deleteByExample(specificationOptionExample);
}
}
(2)前端
a、为复选框加入单击事件
b、为删除按钮绑定事件
3、模板管理
3.1 模板列表和规格列表几乎一样,参考规格列表
3.2 品牌下拉列表(select2组件)
(1)引入select2的js和css文件
<link rel="stylesheet" href="../plugins/select2/select2.css" />
<link rel="stylesheet" href="../plugins/select2/select2-bootstrap.css" />
<script src="../plugins/select2/select2.min.js" type="text/javascript"></script>
<script type="text/javascript" src="../js/angular-select2.js"> </script>
注意:angular-select2.js 必须放在自定义模块的js文件后面引入,因为angular-select2中会使用到app
(2)在controller中新增变量,即下拉菜单中的数据
(3)在页面中添加select2组件
(4)效果
3.3 品牌下拉列表从后端获取数据集
(1)新增mapper映射(TbBrandMapper.xml)
<!-- 查询品牌列表,并封装为Map返回 -->
<select id="selectOptionList" resultType="java.util.Map">
select id,name as text
from tb_brand
</select>
(2)BrandMapper接口,新增对应方法
List<Map> selectOptionList();
(3)服务层接口(BrandService)
/**
* 返回品牌下拉列表数据
*
* @return java.util.List<java.util.Map>
*/
List<Map> selectOptionList();
(4)服务层实现(BrandServiceImpl)
@Override
public List<Map> selectOptionList() {
return brandMapper.selectOptionList();
}
(5)控制层(BrandController)
/**
* 获取品牌下拉列表需要的品牌列表数据格式
*
* @return java.util.List<java.util.Map>
*/
@RequestMapping("/selectOptionList")
public List<Map> selectOptionList() {
return brandService.selectOptionList();
}
(6)在前端 brandService.js 中,添加方法
// 获取品牌下拉列表需要的数据集
this.selectOptionList = function () {
return $http.get('../brand/selectOptionList.do');
}
(7)在 typeTemplateController.js 中注入 brandService 服务
注意:需要在页面引入 brandService.js 文件
(8)在 typeTemplateController.js 中定义加载品牌列表数据的方法
//获取品牌列表下拉列表需要的数据集
$scope.findBrandList = function () {
brandService.selectOptionList().success(
function (rtn) {
$scope.brandList = {data:rtn};
}
);
}
(9)在 angular js 初始化调用指令,调用该方法
(10)测试
3.4 规格下拉列表和品牌下拉列表做法一致,参考品牌下拉列表
3.5 增加和删除扩展属性表格行
(1)在点击新建按钮时,初始化扩展属性的数组
(2)编写新增行方法
//新增扩展属性行
$scope.addTableRow = function () {
$scope.entity.customAttributeItems.push({});
}
(3)为新增扩展属性按钮绑定单击事件
(4)绑定扩展属性数组到表格行
(5)编写删除行方法
//删除扩展属性行
$scope.deleTableRow = function (index) {
$scope.entity.customAttributeItems.splice(index,1);
}
(6)为删除按钮绑定单击事件
3.6 点击保存,保存模板信息
(1)为商品类型绑定变量
(2)为保存按钮绑定单击事件
3.7 修改模板信息
(1)为修改按钮绑定单击事件
(2)修改 findOne 方法
效果:
3.8 删除模板,只需要为复选框绑定单击事件,并给删除按钮绑定单击事件
3.9 优化模板列表显示
我们需要将信息以更友好的方式展现出来,如下图形式
(1)提交一个转换方法到baseController.js中
/*
json数据转换方法
*/
$scope.jsonToString = function (jsonString, key) {
//将jsonString转换为json对象
var json = JSON.parse(jsonString);
//存放转换后的值
var value = '';
//遍历json进行转换
for(var i = 0; i < json.length; i++) {
if(i>0) {
value += ',';
}
value += json[i][key];
}
return value;
}