今日目标:
理解前端分层开发
实现控制器继承
能够使用mybatis逆向工程生成dao层代码
完成规格管理功能
一、js代码重构
首先介绍javaee的三层架构: 最重要的目的就是解耦
web 接收请求,处理响应
service 处理业务逻辑
dao 数据处理
前端开发我们也可以进行分层开发,分为controller层,service层
controller:控制器,封装和处理数据
service:服务层,与后端进行请求交互。
好处:代码逻辑职责更明确,代码复用性更强
这样做的好处是代码分离了,代码的复用性也提高了。
java种代码抽取的方案如下:
1、工具类 2、继承 3、AOP面向切面编程
在前端开发有控制器继承
伪继承:实现思路是,共享$scope变量
前端代码的抽取过程如下:
1、自定义服务,将之前所有请求后台的代码抽取出来
自定义一个brandService模块抽取方法如下:
//自定义服务
app.service('brandService',function ($http) {
定义查询所有品牌列表的方法
this.findAll=function () {
return $http.get("../brand/findAll.do");
}
//条件查询和分页展示
this.reloadList=function (pageNum,pageSize,searchEntity) {
return $http.post("../brand/search.do?pageNum="+pageNum+"&pageSize="+pageSize,
searchEntity);
}
//添加和修改
this.add=function (entity) {
return $http.post("../brand/add.do",entity);
}
//修改
this.update=function (entity) {
return $http.post("../brand/update.do",entity);
}
//通过id查找
this.findOne=function (id) {
return $http.get("../brand/findOne.do?id="+id);
}
//删除
this.delete=function (selectIds) {
return $http.get("../brand/delete.do?ids="+selectIds);
}
})
2、创建controller层和service层,baseController.js 对js代码进行抽取,这样做的好处是,后期维护方便,便于维护
代码抽取完成如图所示;
二、mybatis逆向工程
逆向工程生成代码分析
生成的DAO层接口中有:根据主键查询、修改、删除等,根据条件进行增删改查操作
XXXExample 封装条件的对象 查询、删除、更新
三、规格管理
1.分页显示+条件查询(通过规格的specName)通过
分析:这个功能和上次的品牌表的设计是一样的
后台实现:
通过search方法传递三个参数(TbSpecification pageNum pageSize),通过mybatis生成自动生成的方法,进行封装,通过查询的结果分装给pageResult()
前台实现:定义search方法,通过angularjs的内置服务,实现发送请求
后台核心代码:
public PageResult findPage(TbSpecification specification, Integer pageNum, Integer pageSize) {
//分页的实现
PageHelper.startPage(pageNum,pageSize);
TbSpecificationExample example = new TbSpecificationExample();
TbSpecificationExample.Criteria criteria = example.createCriteria();
//判断
if(specification!=null){
String specName = specification.getSpecName();
if(specName!=null&&!"".equals(specName)){
//模糊查询
criteria.andSpecNameLike("%"+specName+"%");
}
}
Page<TbSpecification> pageResult = (Page) specificationMapper.selectByExample(example);
return new PageResult(pageResult.getTotal(),pageResult.getResult());
}
前台核心代码:
controller层
//条件查询和分页展示
$scope.searchEntity={};//解决初始化参数为空的情况
$scope.search=function (pageNum,pageSize) {
specificationService.search($scope.searchEntity,pageNum,pageSize).success(function (response) {
$scope.paginationConf.totalItems=response.total;
$scope.list=response.rows;
})
}
service层
//条件查询和分页展示
this.search=function (searchEntity,pageNum,pageSize) {
return $http.post("../specification/search.do?pageNum="+pageNum+"&pageSize="+pageSize,searchEntity);
}
//specification.html
<tbody>
<tr ng-repeat="pojo in list">
<td><input type="checkbox" ></td>
<td>{{pojo.id}}</td>
<td>{{pojo.specName}}</td>
<td class="text-center">
<button type="button" class="btn bg-olive btn-xs" data-toggle="modal" data-target="#editModal">修改</button>
</td>
</tr>
</tbody>
2.添加功能的实现(注意关联规格选项表)
分析:我们要把两个表的数据一起提交到数据库,那么有两种方法,第一种就是在specification表中添加一个规格选项表的list集合,第二种是,自定义一个组合实体类,用于封装两个表的数据,用户保存我们传过来的两个对象.
我们采用第二种方法进行封装数据.
后台:组装数据,并保存,注意,我们通过规格插入数据,必须返回插入的id值,此时我们通过获取的id值,去关联插入规格选项表中.
前台:在保存上添加点击事件,获得保存,注意新增选项格和删除选项格的实现?
后台代码实现:
//controlelr层
//添加
@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,"添加失败");
}
}
service层
//添加的实现
@Override
public void add(Specification specification) {
//获取specification对象
TbSpecification specification1 = specification.getSpecification();
specificationMapper.insert(specification1);
//获取specification的id 值
Long id = specification1.getId();
//循环添加
List<TbSpecificationOption> specificationOptions = specification.getSpecificationOptions();
for (TbSpecificationOption specificationOption : specificationOptions) {
//关联id
specificationOption.setSpecId(specification1.getId());
specificationOptionMapper.insert(specificationOption);
}
}
//注意我们要在插入specification表的时候,返回插入的id值,这样我们就可通过id值,关联插入规格选项表
<insert id="insert" parameterType="com.pinyougou.pojo.TbSpecification" >
/*添加插入返回的id值*/
<selectKey resultType="java.lang.Long" order="AFTER" keyProperty="id">
select last_insert_id() as id
</selectKey>
insert into tb_specification (id, spec_name)
values (#{id,jdbcType=BIGINT}, #{specName,jdbcType=VARCHAR})
</insert>
前台代码实现:
//controller层
//初始化对象
$scope.entity={specificationOptions:[]};
//添加行
$scope.addRow=function () {
$scope.entity.specificationOptions.push({});
}
//删除规格选项
$scope.deleRow=function (index) {
$scope.entity.specificationOptions.splice(index,1);
}
//注意在这有个非常重要操作,就是初始化对象,如果不出初始化对象
//添加是我们实体类是一个组装的
//添加
$scope.save=function () {
//定义一个变量
var method=null;
if($scope.entity.specification.id!=null){
//修改
method=specificationService.update($scope.entity);
}else{
//新增
method=specificationService.add($scope.entity);
}
method.success(function (response) {
if (response.success){
//添加成功
$scope.reloadList();
}else{
//不成功
alert(response.message);
}
})
}
//页面
<body class="hold-transition skin-red sidebar-mini" ng-app="pinyougou" ng-controller="specificationController">
<!-- .box-body -->
<div class="box-header with-border">
<h3 class="box-title">规格管理</h3>
</div>
<div class="box-body">
<!-- 数据表格 -->
<div class="table-box">
<!--工具栏-->
<div class="pull-left">
<div class="form-group form-inline">
<div class="btn-group">
<button type="button" ng-click="entity={specificationOptions:[]}" class="btn btn-default" title="新建" data-toggle="modal" data-target="#editModal" ><i class="fa fa-file-o"></i> 新建</button>
<button type="button" class="btn btn-default" title="删除" ><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.specName">
<button class="btn btn-default" ng-click="reloadList()" >查询</button>
</div>
</div>
<!--工具栏/-->
<!--数据列表-->
<table id="dataList" class="table table-bordered table-striped table-hover dataTable">
<thead>
<tr>
<th class="" style="padding-right:0px">
<input id="selall" type="checkbox" class="icheckbox_square-blue">
</th>
<th class="sorting_asc">规格ID</th>
<th class="sorting">规格名称</th>
<th class="text-center">操作</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="pojo in list">
<td><input type="checkbox" ></td>
<td>{{pojo.id}}</td>
<td>{{pojo.specName}}</td>
<td class="text-center">
<button type="button" class="btn bg-olive btn-xs" data-toggle="modal" data-target="#editModal">修改</button>
</td>
</tr>
</tbody>
</table>
<!--数据列表/-->
<!--分页工具条展示-->
<tm-pagination conf="paginationConf"></tm-pagination>
</div>
<!-- 数据表格 /-->
</div>
<!-- /.box-body -->
<!-- 编辑窗口 -->
<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" ng-model="entity.specification.specName" placeholder="规格名称" > </td>
</tr>
</table>
<!-- 规格选项 -->
<div class="btn-group">
<button type="button" ng-click="addRow()" class="btn btn-default" title="新建" ><i class="fa fa-file-o"></i> 新增规格选项</button>
</div>
<table class="table table-bordered table-striped table-hover dataTable">
<thead>
<tr>
<th class="sorting">规格选项</th>
<th class="sorting">排序</th>
<th class="sorting">操作</th>
</thead>
<tbody>
<tr ng-repeat="option in entity.specificationOptions">
<td>
<input ng-model="option.optionName" class="form-control" placeholder="规格选项">
</td>
<td>
<input ng-model="option.orders" class="form-control" placeholder="排序">
</td>
<td>
<button type="button" ng-click="deleRow($index)" class="btn btn-default" title="删除" ><i class="fa fa-trash-o"></i> 删除</button>
</td>
</tr>
</tbody>
</table>
</div>
<div class="modal-footer">
<button class="btn btn-success" ng-click="save()" data-dismiss="modal" aria-hidden="true">保存</button>
<button class="btn btn-default" data-dismiss="modal" aria-hidden="true">关闭</button>
</div>
</div>
</div>
</div>
</body>
</html>
删除选项格子时,我们通过一个内置对象获取当前index
ng-click="deleRow($index)"
注意:在添加时,我们先要获取tb_specification表的添加的id,然后返回id,我们通过设置tb_specificationOptions
的specificationOption.setSpecId(spe.getId());*******特别注意
注意的问题:后端实现的时候,记得返回插入的id值,要在mapper文件中添加<selectkey>标签返回id值
前台:我们组装信息的时候,注意实体类的初始化
2.修改功能的实现
分析:修改我们实现两个功能,第一个功能:页面回显的问题,第二个问题:修改的时候,我们如何把修改的规格选项保存,原因是这样的,因为可能有添加了行,或者删除了行,所以解决的方法就是删除以前所有的,然后从新添加
后台:通过findOne(id) 返回前天需要显示的信息 修改的时候,我们在service层,删除以前该id的规格选项,然后在添加
前台:页面的回显,绑定数据,
后台核心代码:
@Override
public Specification findOne(Long id) {
//首先获取组合实体类
Specification specification = new Specification();
//获取规格数据
TbSpecification tbSpecification = specificationMapper.selectByPrimaryKey(id);
specification.setSpecification(tbSpecification);
//获取规格id
Long id1 = tbSpecification.getId();
TbSpecificationOptionExample example = new TbSpecificationOptionExample();
TbSpecificationOptionExample.Criteria criteria = example.createCriteria();
criteria.andSpecIdEqualTo(id1);
List<TbSpecificationOption> specificationOptions = specificationOptionMapper.selectByExample(example);
specification.setSpecificationOptions(specificationOptions);
return specification;
}
@Override
public void update(Specification specification) {
//修改规格名称
TbSpecification spec = specification.getSpecification();
specificationMapper.updateByPrimaryKey(spec);
Long id = spec.getId();
//获取规格选项
List<TbSpecificationOption> specificationOptions = specification.getSpecificationOptions();
//先删除出,后提交数据
TbSpecificationOptionExample example = new TbSpecificationOptionExample();
TbSpecificationOptionExample.Criteria criteria = example.createCriteria();
criteria.andIdEqualTo(id);
specificationOptionMapper.deleteByExample(example);
for (TbSpecificationOption specificationOption : specificationOptions) {
//设置id
specificationOption.setSpecId(id);
//添加
specificationOptionMapper.insert(specificationOption);
}
}
前台代码:
//通过id查找
@RequestMapping("/findOne")
public Specification findOne(Long id){
return specificationService.findOne(id);
}
//修改
@RequestMapping("/update")
public Result update(@RequestBody Specification specification){
try {
specificationService.update(specification);
return new Result(true,"修改成功");
} catch (Exception e) {
e.printStackTrace();
return new Result(false,"修改失败");
}
}
//传入id值,返回specification组合实体类
<button type="button" ng-click="findOne(pojo.id)" class="btn bg-olive btn-xs" data-toggle="modal" data-target="#editModal">修改</button>
3.批量删除的实现
分析:技术难点,如何通过点击复选框,改变复选框的状态 ,我们通过前台封装ids数组,送到后台,然后通过循环删除规格选项表
后台:通过ids循环删除
前台:数组的组装,还有复选框的添加和删除,要通过angularjs的内置对象传递参数
后台代码:
@Override
public void delete(Long[] ids) {
for (Long id : ids) {
specificationOptionMapper.deleteByPrimaryKey(id);
TbSpecificationOptionExample example = new TbSpecificationOptionExample();
TbSpecificationOptionExample.Criteria criteria = example.createCriteria();
criteria.andSpecIdEqualTo(id);
specificationOptionMapper.deleteByExample(example);
}
}
前台代码:
//注意当我们点击复选框时,我们需要跟新复选框的状态
//定义复选框ids数组值
$scope.selectIds=[];
//跟新复选框状态
$scope.updateSelection=function ($event,id) {
//判断 选中的状态
if($event.target.checked){
//选中状态
$scope.selectIds.push(id);
}else{
//取消勾选,移除当前的id值,//参数一:移除当前位置的索引值,参数二:从该处移除几个值
var index = $scope.selectIds.indexOf(id);
$scope.selectIds.splice(index,1);
}
}
//controller层
//删除
$scope.delete=function () {
if (confirm("您确定要删除吗")){
specificationService.delete($scope.selectIds).success(function (response) {
if (response.success){
//删除成功
$scope.reloadList();
}else{
//删除失败
//给提示消息
alert(response.message);
}
})
}
}
//service层
//删除
this.delete=function (selectIds) {
return $http.get("../specification/delete.do?ids="+selectIds);
}
//页面
<tr ng-repeat="pojo in list">
<td><input type="checkbox" ng-click="updateSelection($event,pojo.id)"></td>
<td>{{pojo.id}}</td>
<td>{{pojo.specName}}</td>
<td class="text-center">
<button type="button" ng-click="findOne(pojo.id)" class="btn bg-olive btn-xs" data-toggle="modal" data-target="#editModal">修改</button>
</td>
</tr>
注意:一定细心,思路清晰
四、常见错误
1.添加出现的问题
这个问题是我们未初始化实体变量 解决方法;
//初始化对象 $scope.entity={specificationOptions:[]};
原因是这个:
解决方法:进行初始化
ng-click="entity={specificationOptions:[]}"
一定要注意变量的初始化
五、总结
添加过程中,出现两张表的添加,我们要封装一个实体类,进行存,注意存的时候返回插入的规格的id,以便于我们根据id插入规格选项表
前端主要是$(index) 这个是angularjs的内置服务 传入当前index值
($(event),pojo)传入的事件,通过这个实现复选框的添加和删除
非常重要:
//初始化对象 $scope.entity={specificationOptions:[]}; //添加行 $scope.addRow=function () { $scope.entity.specificationOptions.push({}); } //删除规格选项 $scope.deleRow=function (index) { $scope.entity.specificationOptions.splice(index,1); }