電商專案day03(前端分層開發&規格實現)
今日目標:
理解前端分層開發
實現控制器繼承
能夠使用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); }