第一部分:angularJs前端项目搭建
前端搭建 angular.js
angularjs的特征
特征一:mvc模式
Model:数据,其实就是angular变量($scope.XX);
View: 数据的呈现,Html+Directive(指令);
Controller:操作数据,就是function,数据的增删改查;
特征二:双向绑定
框架采用并扩展了传统HTML,通过双向的数据绑定来适应动态内容,双向的数据绑定允许模型和视图之间的自动同步
特征三:依赖注入
依赖注入(Dependency Injection,简称DI)是一种设计模式, 指某个对象依赖的其他对象无需手工创建
特征四:模块化设计
高内聚低耦合法则
1)官方提供的模块 ng、ngRoute、ngAnimate
2)用户自定义的模块 angular.module('模块名',[ ])
当网页加载完毕,AngularJS 自动开启。
ng-app 指令告诉 AngularJS,<div> 元素是 AngularJS 应用程序 的"所有者"。
ng-model 指令把输入域的值绑定到应用程序变量 name。
ng-bind 指令把应用程序变量 name 绑定到某个段落的 innerHTML。
ng-init 初始化
第二部分 angular入门:
a.ng-app声明容器
<html>
<head>
<title>angularJs入門</title>
<script src="angular.min.js"></script>
</head>
<body ng-app>
{{100+100}}
</body>
</html>
b.双向绑定
<html>
<head>
<title>angularJs入門</title>
<script src="angular.min.js"></script>
</head>
<body ng-app>
请输入您的姓名:<input ng-model="name">
{{name}}
</body>
</html>
c.初始化变量值
<html>
<head>
<title>angularJs入門 初始化</title>
<script src="angular.min.js"></script>
</head>
<body ng-app ng-init="name='朱世明'">
请输入您的姓名:
<input ng-model="name">
<input ng-model="name">
{{name}}
</body>
</html>
d.事件指令 ng-click -- 指定$scope.z在计算后显示出来
<html>
<head>
<title>angularJs入門 事件指令</title>
<script src="angular.min.js"></script>
<script>
// 建立模块
var myapp = angular.module("myApp",[]);
// 创建控制器 $scope相当于public
myapp.controller("myController",function($scope){
$scope.add = function(){
$scope.z = parseInt($scope.x) + parseInt($scope.y);
};
}
);
</script>
</head>
<body ng-app="myApp" ng-controller="myController">
请输入第一个数:
<input ng-model="x">
请输入第二个数:
<input ng-model="y">
<button ng-click="add()">运算</button>
{{z}}
</body>
</html>
e.数组循环 ng-repeat $scope.list
<html>
<head>
<title>angularJs入門 循环数组</title>
<script src="angular.min.js"></script>
<script>
// 建立模块
var myapp = angular.module("myApp",[]);
// 创建控制器 $scope相当于public
myapp.controller("myController",function($scope){
$scope.list = [110,221,331,2221,666];
});
</script>
</head>
<body ng-app="myApp" ng-controller="myController">
<table>
<tr ng-repeat="x in list">
<td>{{x}}</td>
</tr>
</table>
</body>
</html>
f.循环对象数组
<html>
<head>
<title>angularJs入門 循环对象数组</title>
<script src="angular.min.js"></script>
<script>
// 建立模块
var myapp = angular.module("myApp",[]);
// 创建控制器 $scope相当于public
myapp.controller("myController",function($scope){
$scope.list = [
{name:'张三',age:10,score:100,subjectname:'语文'},
{name:'李四',age:11,score:101,subjectname:'语文1'},
{name:'王五',age:12,score:102,subjectname:'语文2'},
{name:'赵柳',age:13,score:103,subjectname:'语文3'}
];
});
</script>
</head>
<body ng-app="myApp" ng-controller="myController">
<table>
<tr>
<td>姓名</td>
<td>年龄</td>
<td>成绩</td>
<td>科目</td>
</tr>
<tr ng-repeat="entity in list">
<td>{{entity.name}}</td>
<td>{{entity.age}}</td>
<td>{{entity.score}}</td>
<td>{{entity.subjectname}}</td>
</tr>
</table>
</body>
</html>
g.$http的使用
$http服务
angular内置的$http服务简单的封装了浏览器原生的XMLHttpRequest对象,可以直接同外部进行通信。
$http服务只能接受一个参数,且该参数是一个对象,这个对象主要包含一些http请求的配置内容。如:
var req = {
method: 'POST',
url: 'http://example.com',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
data: { test: 'test' }
}$http(req).success(function(data,header,config,status){
//响应成功
}).error(function(data,header,config,status){
//处理响应失败
});
假数据测试
新建data.json
[
{name:'张三',age:10,score:100,subjectname:'语文'},
{name:'李四',age:11,score:101,subjectname:'语文1'},
{name:'王五',age:12,score:102,subjectname:'语文2'},
{name:'赵柳',age:13,score:103,subjectname:'语文3'}
]
<html>
<head>
<title>angularJs入門 循环对象数组</title>
<script src="angular.min.js"></script>
<script>
// 建立模块
var myapp = angular.module("myApp",[]);
// 创建控制器 $scope相当于public
myapp.controller("myController",function($scope){
$scope.findList = function(){
$http.get("data.json").success(
function(response){
$scope.list=response;
}
);
};
});
</script>
</head>
<body ng-app="myApp" ng-controller="myController" ng-init="findList()">
<table>
<tr>
<td>姓名</td>
<td>年龄</td>
<td>成绩</td>
<td>科目</td>
</tr>
<tr ng-repeat="entity in list">
<td>{{entity.name}}</td>
<td>{{entity.age}}</td>
<td>{{entity.score}}</td>
<td>{{entity.subjectname}}</td>
</tr>
</table>
</body>
</html>
访问获取品牌列表 9101/brand/findAll.do
获取成功后通过angularJs进行分页处理
<script type="text/javascript">
var myApp = angular.module("pinyougou",['pagination']);
// 创建控制器 $scope相当于public
myApp.controller("brandController",function($scope,$http){
$scope.findList = function(){
$http.get("../brand/findAll.do").success(
function(response){
$scope.list=response;
}
);
};
// 分页控件配置 itemsPerPage每页的条数
$scope.paginationConf = {
currentPage: 1,
totalItems: 10,
itemsPerPage: 10,
perPageOptions: [10, 20, 30, 40, 50],
onChange: function(){
$scope.reloadList();//重新加载
}
};
// 重新加载列表 数据
$scope.reloadList=function(){
// 切换页码
$scope.findPage( $scope.paginationConf.currentPage, $scope.paginationConf.itemsPerPage);
}
$scope.findPage = function (page,size) {
$http.get('../brand/findPage.do?pageNum='+page+'&pageSize='+size).success(
function(response){
$scope.list=response.rows;
$scope.paginationConf.totalItems=response.total;//更新总记录数
}
);
}
});
</script>
再表格下面添加如下语句
<!--分页--> <tm-pagination conf="paginationConf"></tm-pagination>
后台控制器添加如下的接口:
@RequestMapping("/findPage") public PageResult findPage(int pageNum, int pageSize){ return brandService.findPage(pageNum,pageSize); }
数据访问层:
public PageResult findPage(int pageNum, int pageSize) { PageHelper.startPage(pageNum,pageSize); Page<TbBrand> page = (Page) tbBrandMapper.selectByExample(null); return new PageResult(page.getTotal(),page.getResult()); }
品牌新建
// 新增操作
$scope.save = function () {
var methodType = "add";
if ($scope.entity.id > 0) {
methodType = "update";
}
$http.post('../brand/'+ methodType +'.do',$scope.entity).success(
function (response) {
if (response.success == true) {
// 重新加载分页信息
$scope.reloadList();
} else {
alert(response.message);
}
}
);
}
表单处用ng-model进行值的绑定
新增完成后,下次点击清空文本的内容 ng-click="entity={}"
后端代码:
@RequestMapping("/add")
public Result add(@RequestBody TbBrand tbBrand){
try {
brandService.add(tbBrand);
return new Result(true,"创建成功");
} catch (Exception e){
log.info("BrandController.add",e);
e.printStackTrace();
return new Result(false,"创建失败");
}
}
品牌的修改
需要先实现品牌的查询和显示
$scope.findOne = function (id){
$http.get("../brand/findOne.do?id="+id).success(
function (response) {
$scope.entity = response;
}
);
}
品牌的删除操作
需要确定当前的操作对象用$event监控,如果选中push,未选中计算取消勾选的那个元素的下表,然后剔除出数组
// 删除操作
$scope.selectIdLists = [];
$scope.updateSelection = function ($event,id) {
if ($event.target.checked) {
$scope.selectIdLists.push(id);
} else {
// 取消勾选时,提出选中的元素
var index = $scope.selectIdLists.indexOf(id);
$scope.selectIdLists.splice(index,1);
}
}
$scope.deleteBatch = function (){
$http.get("../brand/delete.do?ids="+$scope.selectIdLists).success(
function (response) {
if (response.success == true) {
$scope.reloadList();
} else {
alert(response.message);
}
}
);
}
后台实现代码的删除
/**
* 批量删除
* @Description:
* @Author: smileTimLi
* @Date: 2018/12/22
*/
@RequestMapping("/delete")
public Result DeleteBatch(Long[] ids){
try {
brandService.deleteBatch(ids);
return new Result(true,"删除成功");
} catch (Exception e) {
e.printStackTrace();
return new Result(false,"删除失败");
}
}
第三部分 angularJs实现业务层代码 (service)
引入背景:
使用$angular.controller进行后台服务的调用,如果调用页面比较多,需要写多个重复的调用,引入service调用,将路径抽象出来
抽象angularJs的控制器
$controller('baseController',{$scope:$scope});//伪继承
第一步:基础js:
base.js和base_pagination.js
var app = angular.module("pinyougou",[]); -- 没有分页的页面引入这个js
var app = angular.module("pinyougou",['pagination']); -- 有分页的页面引入这个js
第二步:基础js:
baseController.js 中第一行要引入$scope
//品牌控制层
app.controller('baseController' ,function($scope){
//重新加载列表 数据
$scope.reloadList=function(){
//切换页码
$scope.search( $scope.paginationConf.currentPage, $scope.paginationConf.itemsPerPage);
}
//分页控件配置
$scope.paginationConf = {
currentPage: 1,
totalItems: 10,
itemsPerPage: 10,
perPageOptions: [10, 20, 30, 40, 50],
onChange: function(){
$scope.reloadList();//重新加载
}
};
$scope.selectIds=[];//选中的ID集合
//更新复选
$scope.updateSelection = function($event, id) {
if($event.target.checked){//如果是被选中,则增加到数组
$scope.selectIds.push( id);
}else{
var idx = $scope.selectIds.indexOf(id);
$scope.selectIds.splice(idx, 1);//删除
}
}
$scope.jsonToString=function(jsonString,key){
var json= JSON.parse(jsonString);
var value="";
for(var i=0;i<json.length;i++){
if(i>0){
value+=",";
}
value +=json[i][key];
}
return value;
}
});
第三步:根据业务区分业务代码
此处实现controller控制器之间的相互集成的关系 【伪继承】实质就是$controller的传递和共用$scope
//控制层
app.controller('brandController' ,function($scope,$controller ,brandService){
$controller('baseController',{$scope:$scope});//继承
//读取列表数据绑定到表单中
$scope.findAll=function(){
brandService.findAll().success(
function(response){
$scope.list=response;
}
);
}
//分页
$scope.findPage=function(page,rows){
brandService.findPage(page,rows).success(
function(response){
$scope.list=response.rows;
$scope.paginationConf.totalItems=response.total;//更新总记录数
}
);
}
//查询实体
$scope.findOne=function(id){
brandService.findOne(id).success(
function(response){
$scope.entity= response;
}
);
}
//保存
$scope.save=function(){
var serviceObject;//服务层对象
if($scope.entity.id!=null){//如果有ID
serviceObject=brandService.update( $scope.entity ); //修改
}else{
serviceObject=brandService.add( $scope.entity );//增加
}
serviceObject.success(
function(response){
if(response.success){
//重新查询
$scope.reloadList();//重新加载
}else{
alert(response.message);
}
}
);
}
//批量删除
$scope.dele=function(){
//获取选中的复选框
brandService.dele( $scope.selectIds ).success(
function(response){
if(response.success){
$scope.reloadList();//刷新列表
$scope.selectIds=[];
}
}
);
}
$scope.searchEntity={};//定义搜索对象
//搜索
$scope.search=function(page,rows){
brandService.search(page,rows,$scope.searchEntity).success(
function(response){
$scope.list=response.rows;
$scope.paginationConf.totalItems=response.total;//更新总记录数
}
);
}
});
第四步:抽取公共的service.js
//服务层
app.service('brandService',function($http){
//读取列表数据绑定到表单中
this.findAll=function(){
return $http.get('../brand/findAll.do');
}
//分页
this.findPage=function(page,rows){
return $http.get('../brand/findPage.do?page='+page+'&rows='+rows);
}
//查询实体
this.findOne=function(id){
return $http.get('../brand/findOne.do?id='+id);
}
//增加
this.add=function(entity){
return $http.post('../brand/add.do',entity );
}
//修改
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,rows,searchEntity){
return $http.post('../brand/search.do?page='+page+"&rows="+rows, searchEntity);
}
//下拉列表数据
this.selectOptionList=function(){
return $http.get('../brand/selectOptionList.do');
}
});
模糊查询的实现
<div class="has-feedback"> 品牌名称:<input ng-model="searchEntity.name"> 品牌首字母:<input ng-model="searchEntity.firstChar"> <button class="btn btn-default" ng-click="reloadList()">查询</button> </div>
searchEntity的实例化
java代码的实现以及业务层的模糊查询
@RequestMapping("/search")
public PageResult search(@RequestBody TbBrand brand,int page,int size){
return brandService.findPage(brand, page, size);
}
@Override
public PageResult findPage(TbBrand brand, int pageNum, int pageSize) {
PageHelper.startPage(pageNum,pageSize);
TbBrandExample example = new TbBrandExample();
Criteria criteria = example.createCriteria();
if(brand!=null){
if(brand.getName()!=null && brand.getName().length()>0){
criteria.andNameLike("%"+brand.getName()+"%");
}
if(brand.getFirstChar()!=null && brand.getFirstChar().length()>0){
criteria.andFirstCharLike("%"+brand.getFirstChar()+"%");
}
}
Page<TbBrand> page = (Page) tbBrandMapper.selectByExample(example);
return new PageResult(page.getTotal(),page.getResult());
}
规格模板的使用
/**
* @program: pinyougou_parent
* @description: 规格和规格内容组合实体类
* @author: smileTimLi
* @create: 2018-12-23 12:34
**/
@Data
@EqualsAndHashCode(callSuper = false)
public class Specification implements Serializable {
private static final long serialVersionUID = -2404762998490659524L;
private TbSpecification specification;
private List<TbSpecificationOption> specificationOptionList;
}
/**
* 组合增加
* @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, "增加失败");
}
}
specification.html
<!-- 编辑窗口 --> <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.specification.specName"> </td> </tr> </table> <!-- 规格选项 --> <div class="btn-group"> <button type="button" class="btn btn-default" title="新建" ng-click="addTableRow()"><i class="fa fa-file-o"></i> 新增规格选项 </button> </div> <table class="table table-bordered table-striped table-hover dataTable"> <thead> <th class="sorting">规格选项</th> <th class="sorting">排序</th> <th class="sorting">操作</th> </thead> <tbody> <tr ng-repeat="pojo in entity.specificationOptionList"> <td> <input class="form-control" placeholder="规格选项" ng-model="pojo.optionName"> </td> <td> <input class="form-control" placeholder="排序" ng-model="pojo.orders"> </td> <td> <button type="button" class="btn btn-default" title="删除" ng-click="delOption($index)"><i class="fa fa-trash-o"></i> 删除 </button> </td> </tr> </tbody> </table> </div> <div class="modal-footer"> <button class="btn btn-success" data-dismiss="modal" aria-hidden="true" ng-click="save()">保存</button> <button class="btn btn-default" data-dismiss="modal" aria-hidden="true">关闭</button> </div> </div> </div> </div>
specificationController.js
// 选项添加新的一行
$scope.addTableRow = function(){
$scope.entity.specificationOptionList.push({});
}
$scope.delOption = function(id) {
var index = $scope.entity.specificationOptionList.indexOf(id);
$scope.entity.specificationOptionList.splice(index,1);
}
新增方法中需要注意
//保存
$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);
}
}
);
}
select2的使用 -- 添加后自动排重
引入select2.js
<script type="text/javascript" src="../js/angular-select2.js"></script>
<body class="hold-transition skin-red sidebar-mini" ng-app="pinyougou" ng-controller="typeTemplateController" ng-init="findBrandList();findSpecificationList()">
弹框中需要注意的
<!-- 编辑窗口 --> <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 select2 select2-model="entity.brandIds" config="brandList" multiple placeholder="选择品牌(多选)" class="form-control" type="text"/> </td> </tr> <tr> <td>关联规格</td> <td> <input select2 select2-model="entity.specIds" config="specificationList" multiple placeholder="选择规格(多选)" class="form-control" type="text"/> </td> </tr> <tr> <td>扩展属性</td> <td> <div class="btn-group"> <button type="button" class="btn btn-default" title="新增扩展属性" ng-click="addTableRow()"> <i class="fa fa-file-o"></i> 新增扩展属性 </button> </div> <table class="table table-bordered table-striped" width="800px"> <thead> <tr> <td><input type="checkbox" class="icheckbox_square-blue"></td> <td>属性名称</td> <td>操作</td> </tr> </thead> <tbody> <tr ng-repeat="pojo in entity.customAttributeItems"> <td><input type="checkbox" class="icheckbox_square-blue" ng-model="pojo.id" ></td> <td><input class="form-control" placeholder="属性名称" ng-model="pojo.text"></td> <td><button type="button" class="btn btn-default" title="删除" ng-click="delOption($index)"><i class="fa fa-trash-o"></i> 删除</button></td> </tr> </tbody> </table> </td> </tr> </table> </div> <div class="modal-footer"> <button class="btn btn-success" data-dismiss="modal" aria-hidden="true" ng-click="save()">保存</button> <button class="btn btn-default" data-dismiss="modal" aria-hidden="true">关闭</button> </div> </div> </div> </div>
控制层头部需要引入其他的service
app.controller('typeTemplateController' ,function($scope,$controller,typeTemplateService,brandService,specificationService)
$scope.brandList = {data: []}; -- 对应config,是数据源,因为加载慢,必须进行初始化
$scope.specificationList = {data: []};
$scope.findBrandList = function(){
brandService.selectBrandList().success(
function (response) {
$scope.brandList={data: response};
}
);
}
$scope.findSpecificationList = function(){
specificationService.selectSpecificationList().success(
function(response){
$scope.specificationList = {data: response};;
});
}
json数据在前台列表中的显示
$scope.jsonToString=function(jsonString,key){
var json= JSON.parse(jsonString);
var value="";
for(var i=0;i<json.length;i++){
if(i>0){
value+=",";
}
value +=json[i][key];
}
return value;
}
html中引用
{{jsonToString(entity.specIds,"text")}}
页面就可以正常显示