Java大型电商项目——品优购(一)

  • 视频教程:【黑马程序员】Java大型电商项目—品优购【配套源码+笔记】_哔哩哔哩_bilibili
  • 源码下载:  
    • 链接:https://pan.baidu.com/s/1fECz5In_XCB-aW6ed6ZTbA 
    • 提取码:27xa 

技术选型:

后端框架:Spring+SpringMVC+mybatis+Dubbox

前端:angularJS+Bootstrap

  • 分布式:Dubbox框架
  • 注册中心:Zookeeper

前端出错,先清理一下浏览器的缓存,再刷新一下页面,,还是报错,再去看代码 

第一部分 

运行环境

1、linux虚拟机

  • 运行linux虚拟机
  • 打开linux的终端,不可关闭虚拟机
  • 打开SecureCRT代替linux的终端写命令,更清楚
  • 启动zookeeper
    • cd
    • cd zookeeper-3.4.6
    • cd bin
    • ./zkServer.sh start
    • ./zkServer.sh status 查看zookeeper运行状态,是否开启了
    • 每次重启虚拟机,ip地址会发生变化,所以把虚拟机挂起就行,不用关机
    • 查看ip地址的命令:ifconfig
    • 如果ip地址变化,则相应地修改springmvc.xml文件里的zookeeper信息。2181是zookeeper的默认端口,如果配置文件里没有改动,就不变
    • 后续写代码时,在浏览器访问html文件时,不报错,但就是不显示表格,除了表格什么都正常,很难排错。后来发现是zookeeper的端口发生了变化,但是代码里没有修改过来。

2、mysql数据库

  • mysql如何导入.sql文件:http://t.csdnimg.cn/mhP9M
  • 保持打开状态,才可运行其他代码

后端:在IDEA上搭建工程

1、先建父工程,后建子模块

  •                

2、引入依赖

  • 主要问题:
    • 有些依赖maven的本地仓库里没有,需要手动导入
      • 解决教程:http://t.csdnimg.cn/m4fCs
    • 有些依赖的版本需要修改,比如dubbo的2.8.4版本已经不维护了,要改成2.5.3;还有mysql的版本也要和自己电脑里8.0版本的mysql相对应,不能用5.0版本的。
      • 解决办法:只需对着pom.xml文件里的依赖在maven的本地仓库里逐个寻找,把爆红的依赖版本改成仓库里现有的依赖版本
  • 父工程的pom.xml文件需要手动导入的jar包命令如下
    •         mvn install:install-file-Dfile=D:\各种jar包\fastdfs-client-java-1.29.jar-DgroupId=org.csource-DartifactId=fastdfs-client-java-Dversion=1.29 -Dpackaging=jar
    •         mvn install:install-file-Dfile=D:\各种jar包\spring-security-cas-4.1.0.RELEASE.jar-DgroupId=org.springframework.security-DartifactId=spring-security-cas-Dversion=4.1.0.RELEASE-Dpackaging=jar
    •          mvn install:install-file-Dfile=D:\各种jar包\cas-client-core-3.5.1.jar-DgroupId=org.jasig.cas.client-DartifactId=cas-client-core-Dversion=3.3.3-Dpackaging=jar
    •         mvn install:install-file-Dfile=D:\各种jar包\kaptcha-2.3.2.jar-DgroupId=com.github.penggle-DartifactId=kaptcha-Dversion=2.3.2 -Dpackaging=jar
    •         mvn install:install-file-Dfile=D:\各种jar包\solr-solrj-4.10.3.jar-DgroupId=org.apache.solr-DartifactId=solr-solrj-Dversion=4.10.3-Dpackaging=jar
    •         mvn install:install-file-Dfile=D:\各种jar包\activemq-all-5.11.2.jar-DgroupId=org.apache.activemq-DartifactId=activemq-all-Dversion=5.11.2 -Dpackaging=jar
    •         mvn install:install-file-Dfile=D:\各种jar包\ikanalyzer-2012_u6.jar-DgroupId=com.janeluo-DartifactId=ikanalyzer-Dversion=2012_u6-Dpackaging=jar

3、逆向工程

  • 目的:实现实体类与数据访问层代码的自动生成
  • 老师发的资料里没有逆向工程的最新代码,把旧的代码修改一下,即可用,具体代码已放资源里
  • 修改的地方主要有
    • 1、mapper映射文件的生成位置
              <!-- targetProject:mapper映射文件生成的位置 --><sqlMapGenerator targetPackage="com.pinyougou.mapper" targetProject=".\src\main\resources"><!-- enableSubPackages:是否让schema作为包的后缀 --><property name="enableSubPackages" value="false" /></sqlMapGenerator>
    • 2、数据库的连接密码
  • 逆向代码运行教程:http://t.csdnimg.cn/Qt5ti

  • 没有逆向工程源码也行,直接从老师发的资料里其他源码里拿到pojo包,接口包和mapper映射文件包三个包即可

  • 容易出现的问题:逆向工程的代码生错了,要仔细辨别 

4、编写后端代码

  • 注意@Service和@Refrence(远程调用)注解引入要用dubbo的,否则会注入失败,报空指针异常
    • import com.alibaba.dubbo.config.annotation.Reference;
    • import com.alibaba.dubbo.config.annotation.Service;

5、测试

  • 地址:http://localhost:9101/brand/findAll.do
  • 错误一:
    • 解决办法:http://t.csdnimg.cn/ZnSSP
    • 修改了db.properties文件里的jdbc.url和jdbc.driver
      jdbc.driver=com.mysql.cj.jdbc.Driver
      jdbc.url=jdbc:mysql://localhost:3306/pinyougoudb?serverTimezone=Asia/Shanghai&characterEncoding=utf-8&useSSL=false
      
    • 然后把pinyougou-dao该重新clean和install,真正修改完数据库文件后,再运行
    •  
  • 测试成功后
  • 测试这里出了很多错,无奈之下,把项目又重新做了一遍,发现父工程的依赖无法爆红,无法正常导入;逆向工程代码出错了;zookeeper的ip地址也有变化;数据库的相关配置也没有修改完全,修改后又没有更新到数据库配置文件里……想过很多次放弃,但也没有更好的选择,所以还是坚持下来了,最大的收获还是可以静下心来好好分析报错信息了。

前端:框架AngularJS

  • 四大特性

    • 1、MVC模式
    • 2、双向绑定
    • 3、依赖注入
    • 4、模块化设计
  • 基本内容

    • 表达式
      <html>
      <head><title>angularJS demo 表达式</title><script src="angular.min.js"></script>
      </head>
      <body ng-app>
      {{100+100}}
      </body>
      </html>
    • 双向绑定
      <html>
      <head><title>angularJS demo 双向绑定</title><script src="angular.min.js"></script>
      </head>
      <body ng-app>
      请输入你的名称:<input ng-model="myname">
      {{myname}},你好
      </body>
      </html>
    • 初始化指令
      <html>
      <head><title>angularJS demo 初始化指令</title><script src="angular.min.js"></script>
      </head>
      <body ng-app ng-init="myname='abc'">
      请输入你的名称:<input ng-model="myname">
      {{myname}},你好
      </body>
      </html>
    • 控制器
      <html>
      <head><title>angularJS demo 控制器</title><script src="angular.min.js"></script><script>// 定义一个名为myApp的模块,下面的<body>块内的代码都属于该模块var app=angular.module("myApp",[]);// 定义控制器,可以控制页面的某个功能// $scope在视图和控制器之间建立了一个通道,双向更新app.controller("myController",function($scope){$scope.add=function(){//parseInt把字符串类型转换成数值类型return parseInt($scope.x)+parseInt($scope.y);}});</script>
      </head>
      <body ng-app="myApp" ng-controller="myController">
      <!--输入绑定变量x-->
      x:<input ng-model="x">
      <!--输入绑定变量y-->
      y:<input ng-model="y">
      <!--在页面显示x+y的结果add-->
      {{add()}}
      </body>
      </html>
    • 事件指令
      <html>
      <head><title>angularJS demo 事件指令</title><script src="angular.min.js"></script><script>var app=angular.module("myApp",[]);app.controller("myController",function($scope){$scope.add=function(){$scope.z=parseInt($scope.x)+parseInt($scope.y);}});</script>
      </head>
      <body ng-app="myApp" ng-controller="myController">
      x:<input ng-model="x">
      y:<input ng-model="y">
      <!--点击“运算”按钮后,触发add()方法,输出x+y的结果-->
      <button ng-click="add()">运算</button>
      {{z}}
      </body>
      </html>
    • 循环数组
      <html>
      <head><title>angularJS demo 循环数组</title><script src="angular.min.js"></script><script>var app=angular.module("myApp",[]);app.controller("myController",function($scope){$scope.list=[100,200,300,400];});</script>
      </head>
      <body ng-app="myApp" ng-controller="myController">
      <!--    利用循环把list里的元素打印到表格中--><table><tr ng-repeat="x in list"><td>{{x}}</td></tr></table>
      </body>
      </html>
    • 循环对象数组
      <html>
      <head><title>angularJS demo 循环对象数组</title><script src="angular.min.js"></script><script>var app=angular.module("myApp",[]);app.controller("myController",function($scope){$scope.list=[{name:"张三",chinese:1,math:1},{name:"李四",chinese:2,math:2},{name:"王五",chinese:3,math:3},{name:"赵六",chinese:4,math:4}];});</script>
      </head>
      <body ng-app="myApp" ng-controller="myController"><table><tr ng-repeat="x in list"><td>{{x.name}}</td><td>{{x.chinese}}</td><td>{{x.math}}</td></tr></table>
      </body>
      </html>
    • 内置服务
      <html>
      <head><title>angularJS demo 内置服务</title><meta charset="utf-8"><script src="angular.min.js"></script><script>var app=angular.module("myApp",[]);// $http从后端获取数据,数据修改更灵活app.controller("myController",function($scope,$http){$scope.findList=function(){$http.get("data.json").success(function(response){$scope.list=response;});}});</script>
      </head>
      <!--初始化时,顺便触发findList()方法-->
      <body ng-app="myApp" ng-controller="myController" ng-init="findList()"><table><tr ng-repeat="x in list"><td>{{x.name}}</td><td>{{x.chinese}}</td><td>{{x.math}}</td></tr></table>
      </body>
      </html>
      //json数据
      [
      //  key用双引号括起,value若是字符串也要用双引号括起{"name":"张三","chinese":1,"math":1},{"name":"李四","chinese":2,"math":2},{"name":"王五","chinese":3,"math":3},{"name":"赵六","chinese":4,"math":4}
      ]
  • 常用指令

    • ng-app:定义AngularJS应用程序的根元素
    • ng-model:用于绑定变量(输入端和变量端,双向绑定)
    • ng-init:初始化变量
    • ng-controller:用于指定所用控制器
    • ng-click:单击事件指令,点击时触发控制器的某个方法
    • ng-repeat:用于循环数组变量

第二部分(实现功能)

品牌列表分页

1、后端

PageResult

pinyougou-pojo模块

package entity;import java.io.Serializable;
import java.util.List;/*** 分布结果实体类* 模块:pinyougou-pojo* 路径:src/main/java/entity*/
public class PageResult implements Serializable {private long total;//记录总条数private List rows;//当面页记录//getter,setter方法和构造器省略
}
BrandService

pinyougou-sellergoods-interface模块

package com.pinyougou.sellergoods.service;import com.pinyougou.pojo.TbBrand;
import entity.PageResult;import java.util.List;/*** 品牌业务接口*/
public interface BrandService {/*** 分布查询* @param pageNum* @param pageSize* @return*/public PageResult findPage(int pageNum,int pageSize);
}
 BrandServiceImpl

pinyougou-sellergoods-service模块

package com.pinyougou.sellergoods.service.impl;import com.alibaba.dubbo.config.annotation.Service;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.pinyougou.mapper.TbBrandMapper;
import com.pinyougou.pojo.TbBrand;
import com.pinyougou.sellergoods.service.BrandService;
import entity.PageResult;
import org.springframework.beans.factory.annotation.Autowired;import java.util.List;/*** 品牌服务层实现类*/
@Service
public class BrandServiceImpl implements BrandService {/*** 分页的服务层代码* @param pageNum* @param pageSize* @return*/@Overridepublic 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());}
}
BrandController

pinyougou-manager-web模块

package com.pinyougou.manager.controller;import com.alibaba.dubbo.config.annotation.Reference;
import com.pinyougou.pojo.TbBrand;
import com.pinyougou.sellergoods.service.BrandService;
import entity.PageResult;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.List;/*** 品牌的控制器层*/
public class BrandController {@RequestMapping("/findPage")public PageResult findPage(int page,int rows){return brandService.findPage(page,rows);}
}

 父工程重新install后,运行结果:

2、前端 

<!DOCTYPE html>
<html>
<head><!--导入资源--><script src="../plugins/jQuery/jquery-2.2.3.min.js"></script><script src="../plugins/bootstrap/js/bootstrap.min.js"></script><script src="../plugins/angularjs/angular.min.js"></script><!--分页组件开始--><script src="../plugins/angularjs/pagination.js"></script><link rel="stylesheet" href="../plugins/angularjs/pagination.css"><!--分页组件结束--><script>//定义名为app的模块var app=angular.module("pinyougou",["pagination"]);app.controller("brandController",function ($scope,$http) {//读取列表数据绑定到表单中// $scope.findAll=function () {// 	$http.get("../brand/findAll.do").success(function(response){// 		$scope.list=response;// 	})//// }//分页$scope.findPage=function(page,rows) {$http.get("../brand/findPage.do?page="+page+"&rows="+rows).success(function(response){$scope.list=response.rows;$scope.paginationConf.totalItems=response.total;//定义总记录数})}//定义对象paginationConf,分布的配置$scope.paginationConf={currentPage: 1,//当前页totalItems: 10,//总记录条数itemsPerPage: 10,//每页的记录条数perPageOptions: [10,20,30,40,50],//页码选项,每页10条还是20还是...onChange: function () {//当页码发生变化时自动触发的方法$scope.reloadList();}}//重新加载记录$scope.reloadList=function () {$scope.findPage($scope.paginationConf.currentPage,$scope.paginationConf.itemsPerPage);}})</script></head>
<body class="hold-transition skin-red sidebar-mini" ng-app="pinyougou" ng-controller="brandController" ng-init="findAll()"><!-- .box-body --><!-- 数据表格 --><div class="table-box"><!--数据列表--><table id="dataList" class="table table-bordered table-striped table-hover dataTable"><!--表体--><tbody><!--使用循环填写表格--><tr ng-repeat="entity in list"><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></table><!--数据列表/--><!--在数据表格下放置分页组件,那个分页的小栏--><tm-pagination conf="paginationConf"></tm-pagination>	 </div><!-- 数据表格 /-->                                    </div>
</body>
</html>

运行结果:

增加品牌

1、后端 

BrandService

pinyougou-sellergoods-interface

package com.pinyougou.sellergoods.service;import com.pinyougou.pojo.TbBrand;
import entity.PageResult;import java.util.List;/*** 品牌业务接口*/
public interface BrandService {/*** 增加品牌* @param brand*/public void add(TbBrand brand);
}
BrandServiceImpl

pinyougou-sellergoods-service

package com.pinyougou.sellergoods.service.impl;import com.alibaba.dubbo.config.annotation.Service;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.pinyougou.mapper.TbBrandMapper;
import com.pinyougou.pojo.TbBrand;
import com.pinyougou.sellergoods.service.BrandService;
import entity.PageResult;
import org.springframework.beans.factory.annotation.Autowired;import java.util.List;/*** 品牌服务层实现类*/
@Service
public class BrandServiceImpl implements BrandService {/*** 增加品牌* @param brand*/@Overridepublic void add(TbBrand brand) {brandMapper.insert(brand);}
}
 BrandController

pinyougou-manager-web

package com.pinyougou.manager.controller;import com.alibaba.dubbo.config.annotation.Reference;
import com.pinyougou.pojo.TbBrand;
import com.pinyougou.sellergoods.service.BrandService;
import entity.PageResult;
import entity.Result;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.List;/*** 品牌的控制器层*/
@RestController
@RequestMapping("/brand")
public class BrandController {//增加品牌@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,"添加失败🙃");}}
}
Result

pinyougou-pojo

package entity;import java.io.Serializable;/*** 增加品牌的返回结果实体类*/
public class Result implements Serializable {private boolean success;private String message;//getter,setter方法,构造器省略
}

2、前端

<!DOCTYPE html>
<html>
<head><script>//定义名为app的模块var app=angular.module("pinyougou",["pagination"]);app.controller("brandController",function ($scope,$http) {//增加品牌$scope.add=function () {$http.post("../brand/add.do",$scope.entity).success(function(response){if(response.success){$scope.reloadList();//刷新数据}else{alert(response.message);//打印信息}})}})</script></head>
<body class="hold-transition skin-red sidebar-mini" ng-app="pinyougou" ng-controller="brandController" ng-init="findAll()"><!-- .box-body --><div class="box-body"><!-- 数据表格 --><div class="table-box"><!--工具栏--><div class="pull-left"><div class="form-group form-inline"><div class="btn-group"><!--添加的ng-click可以让每次打开新建的窗口里,都保持空白页面--><button type="button" class="btn btn-default" title="新建" ng-click="entity={}" data-toggle="modal" data-target="#editModal" ><i class="fa fa-file-o"></i> 新建</button></div></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="sorting">品牌首字母</th>									     				<th class="text-center">操作</th></tr></thead></table>					 </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-body">		<table class="table table-bordered table-striped"  width="800px"><tr><td>品牌名称</td><!--此处的ng-model是将属性name和品牌名称绑定,获取到品牌名称后,绑定后name属性中--><td><input  class="form-control" ng-model="entity.name" placeholder="品牌名称" >  </td></tr>		      	<tr><td>首字母</td><td><input  class="form-control" ng-model="entity.firstChar" placeholder="首字母">  </td></tr>		      	</table>				</div><div class="modal-footer">	<!--此处的ng-click是为了在点击保存时,触发add()方法-->					<button class="btn btn-success" data-dismiss="modal" ng-click="add()" aria-hidden="true">保存</button></div></div></div>
</div></body>
</html>

运行结果:

修改品牌

1、后端 

BrandService

pinyougou-sellergoods-interface

package com.pinyougou.sellergoods.service;import com.pinyougou.pojo.TbBrand;
import entity.PageResult;import java.util.List;/*** 品牌业务接口*/
public interface BrandService {/*** 根据ID查询实体* @param id* @return*/public TbBrand findOne(Long id);/*** 修改* @param brand*/public void update(TbBrand brand);
}
BrandServiceImpl

pinyougou-sellergoods-service

package com.pinyougou.sellergoods.service.impl;import com.alibaba.dubbo.config.annotation.Service;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.pinyougou.mapper.TbBrandMapper;
import com.pinyougou.pojo.TbBrand;
import com.pinyougou.sellergoods.service.BrandService;
import entity.PageResult;
import org.springframework.beans.factory.annotation.Autowired;import java.util.List;/*** 品牌服务层实现类*/
@Service
public class BrandServiceImpl implements BrandService {//根据ID查询@Overridepublic TbBrand findOne(Long id) {return brandMapper.selectByPrimaryKey(id);}//修改@Overridepublic void update(TbBrand brand) {brandMapper.updateByPrimaryKey(brand);}
}
BrandController

pinyougou-manager-web

package com.pinyougou.manager.controller;import com.alibaba.dubbo.config.annotation.Reference;
import com.pinyougou.pojo.TbBrand;
import com.pinyougou.sellergoods.service.BrandService;
import entity.PageResult;
import entity.Result;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.List;/*** 品牌的控制器层*/
public class BrandController {//根据ID查询@RequestMapping("/findOne")public TbBrand findOne(Long id){return brandService.findOne(id);}//修改@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,"修改失败🙃");}}
}

运行结果:

2、前端

<!DOCTYPE html>
<html>
<head><script>//定义名为app的模块var app=angular.module("pinyougou",["pagination"]);app.controller("brandController",function ($scope,$http) {//保存(新增和修改)$scope.save=function () {var methodName="add";//新增时,id为空;但修改时,id不为空if($scope.entity.id!=null){methodName="update";}$http.post("../brand/"+methodName+".do",$scope.entity).success(function(response){if(response.success){$scope.reloadList();//刷新数据}else{alert(response.message);//打印信息}})}//根据ID查询$scope.findOne=function(id){$http.get("../brand/findOne.do?id="+id).success(function (response) {$scope.entity=response;})}})</script></head>
<body class="hold-transition skin-red sidebar-mini" ng-app="pinyougou" ng-controller="brandController" ng-init="findAll()"><!-- .box-body --><div class="box-body"><!-- 数据表格 --><div class="table-box"><!--数据列表--><table id="dataList" class="table table-bordered table-striped table-hover dataTable"><!--表体--><tbody><!--使用循环填写表格--><tr ng-repeat="entity in list"><td><input  type="checkbox" ></td><!--此处要加双花括号,是因为entity.id是表达式--><td>{{entity.id}}</td><td>{{entity.name}}</td><td>{{entity.firstChar}}</td><td class="text-center"><!--此处的findOne()里entity.id不用双括号是因为在这里它是变量--><button type="button" class="btn bg-olive btn-xs" data-toggle="modal" ng-click="findOne(entity.id)" data-target="#editModal"  >修改</button></td></tr></tbody></table>			 </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-footer">						<button class="btn btn-success" data-dismiss="modal" ng-click="save()" aria-hidden="true">保存</button></div></div></div>
</div> 
</body>
</html>

运行结果:

删除品牌

1、后端 

BrandService

pinyougou-sellergoods-interface

package com.pinyougou.sellergoods.service;import com.pinyougou.pojo.TbBrand;
import entity.PageResult;import java.util.List;/*** 品牌业务接口*/
public interface BrandService {/*** 删除* @param ids*/public void delete(Long []ids);
}
BrandServiceImpl

pinyougou-sellergoods-service

package com.pinyougou.sellergoods.service.impl;import com.alibaba.dubbo.config.annotation.Service;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.pinyougou.mapper.TbBrandMapper;
import com.pinyougou.pojo.TbBrand;
import com.pinyougou.sellergoods.service.BrandService;
import entity.PageResult;
import org.springframework.beans.factory.annotation.Autowired;import java.util.List;/*** 品牌服务层实现类*/
@Service
public class BrandServiceImpl implements BrandService {//删除@Overridepublic void delete(Long[] ids) {for(Long id:ids){brandMapper.deleteByPrimaryKey(id);}}
}
BrandController

pinyougou-manager-web

package com.pinyougou.manager.controller;import com.alibaba.dubbo.config.annotation.Reference;
import com.pinyougou.pojo.TbBrand;
import com.pinyougou.sellergoods.service.BrandService;
import entity.PageResult;
import entity.Result;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.List;/*** 品牌的控制器层*/
@RestController
@RequestMapping("/brand")
public class BrandController {//删除@RequestMapping("/delete")public Result delete(Long []ids){try {brandService.delete(ids);return new Result(true,"删除成功☺");} catch (Exception e) {e.printStackTrace();return new Result(false,"删除失败🙃");}}
}

运行结果:

2、前端

<!DOCTYPE html>
<html>
<head><script>//定义名为app的模块var app=angular.module("pinyougou",["pagination"]);app.controller("brandController",function ($scope,$http) {//批量选中$scope.selectIds=[];//选中的ID数组,准备批量删除的数据$scope.updateSelection=function($event,id){if($event.target.checked){//判断是否选中$scope.selectIds.push(id);//向数组中添加数据}else{var idx=$scope.selectIds.indexOf(id);//id在选中数据的数组中的位置$scope.selectIds.splice(idx,1);//从数组中删除数据,重复点复选框,选择和取消选择反复横跳}}//删除$scope.dele=function () {$http.get("../brand/delete.do?ids="+$scope.selectIds).success(function (response) {if(response.success){$scope.reloadList();//刷新列表$scope.selectIds=[];}else{alert(response.message);//打印信息}})}})</script>    
</head>
<body class="hold-transition skin-red sidebar-mini" ng-app="pinyougou" ng-controller="brandController" ng-init="findAll()"><!-- .box-body --><div class="box-body"><!-- 数据表格 --><div class="table-box"><!--工具栏--><div class="pull-left"><div class="form-group form-inline"><button type="button" class="btn btn-default" title="删除" ng-click="dele()"><i class="fa fa-trash-o"></i> 删除</button>                                    </div></div></div><!--工具栏/--><!--在数据表格下放置分页组件,那个分页的小栏--><tm-pagination conf="paginationConf"></tm-pagination>{{selectIds}}							 </div><!-- 数据表格 /-->             </div><!-- /.box-body -->
</body>
</html>

条件查询

1、后端 

BrandService

pinyougou-sellergoods-interface

package com.pinyougou.sellergoods.service;import com.pinyougou.pojo.TbBrand;
import entity.PageResult;import java.util.List;/*** 品牌业务接口*/
public interface BrandService {/*** 条件查询* @param pageNum* @param pageSize* @return*///直接传递一个实体类TbBrand比逐个传递它的属性要更灵活public PageResult findPage(TbBrand brand,int pageNum,int pageSize);
}
BrandServiceImpl

pinyougou-sellergoods-service

package com.pinyougou.sellergoods.service.impl;import com.alibaba.dubbo.config.annotation.Service;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.pinyougou.mapper.TbBrandMapper;
import com.pinyougou.pojo.TbBrand;
import com.pinyougou.pojo.TbBrandExample;
import com.pinyougou.sellergoods.service.BrandService;
import entity.PageResult;
import org.springframework.beans.factory.annotation.Autowired;import java.util.List;/*** 品牌服务层实现类*/
@Service
public class BrandServiceImpl implements BrandService {//条件查询@Overridepublic PageResult findPage(TbBrand brand, int pageNum, int pageSize) {//分页插件PageHelper.startPage(pageNum,pageSize);//封装查询条件TbBrandExample example = new TbBrandExample();//构建查询条件的类TbBrandExample.Criteria criteria = example.createCriteria();if(brand!=null){//如果有名称的条件if(brand.getName()!=null && brand.getName().length() > 0){//where name like %s%criteria.andNameLike("%"+brand.getName()+"%");}//如果有首字母的条件if(brand.getFirstChar()!=null && brand.getFirstChar().length() > 0){criteria.andFirstCharEqualTo(brand.getFirstChar());}}Page<TbBrand> page=(Page<TbBrand>)brandMapper.selectByExample(null);return new PageResult(page.getTotal(),page.getResult());}
}
BrandController

pinyougou-manager-web

package com.pinyougou.manager.controller;import com.alibaba.dubbo.config.annotation.Reference;
import com.pinyougou.pojo.TbBrand;
import com.pinyougou.sellergoods.service.BrandService;
import entity.PageResult;
import entity.Result;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.List;/*** 品牌的控制器层*/
@RestController
@RequestMapping("/brand")
public class BrandController {//条件查询@RequestMapping("/search")public PageResult search(@RequestBody TbBrand brand, int page,int rows){return brandService.findPage(brand,page,rows);}
}

2、前端

<!DOCTYPE html>
<html>
<head><script>//定义名为app的模块var app=angular.module("pinyougou",["pagination"]);app.controller("brandController",function ($scope,$http) {//定义搜索对象$scope.searchEntity={};//条件查询+分页$scope.search=function(page,rows){$http.post("../brand/search.do?page="+page+"&rows="+rows,$scope.searchEntity).success(function (response) {$scope.list=response.rows;//给列表变量赋值$scope.paginationConf.totalItems=response.total;//定义总记录数})}//重新加载记录$scope.reloadList=function () {$scope.search($scope.paginationConf.currentPage,$scope.paginationConf.itemsPerPage);}})</script></head>
<body class="hold-transition skin-red sidebar-mini" ng-app="pinyougou" ng-controller="brandController" ng-init="findAll()"><!-- .box-body --><div class="box-body"><!-- 数据表格 --><div class="table-box"><!--工具栏--><div class="box-tools pull-right"><div class="has-feedback">名称: <input ng-model="searchEntity.name">首字母: <input ng-model="searchEntity.firstChar"><button ng-click="reloadList()">查询</button></div></div><!--工具栏/-->						 </div><!-- 数据表格 /-->     </div><!-- /.box-body -->
</body>
</html>

运行结果:


第三部分(简化开发)

前端分层开发(后端MVC的分层思想)

brand.html

<!DOCTYPE html>
<html>
<head><script src="../js/base_pagination.js"></script><script src="../js/service/brandService.js"></script><script src="../js/controller/brandController.js"></script>
</body>
</html>

base_pagination.js

//使用分页插件时,引入该资源
var app=angular.module("pinyougou",["pagination"]);

base.js

//不使用分页插件时,引入该资源
var app=angular.module("pinyougou",[]);

brandService.js

//构建前端服务层
//和后端打交道的代码写在服务层
app.service("brandService",function($http){//$get:传递属性,变量; $post:传递对象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.search=function (page,rows,searchEntity) {return $http.post("../brand/search.do?page="+page+"&rows="+rows,searchEntity);}this.add=function (entity) {return $http.post("../brand/add.do?",entity);}this.update=function (entity) {return $http.post("../brand/update.do?",entity);}this.findOne=function (id) {return $http.get("../brand/findOne.do?id="+id);}this.dele=function (ids) {return $http.get("../brand/delete.do?ids="+ids);}
})

brandController.js 

//构建前端的控制层
//和页面打交道的代码写在控制层
app.controller("brandController",function ($scope,brandService) {//读取列表数据绑定到表单中$scope.findAll=function () {brandService.findAll().success(function(response){$scope.list=response;})}//定义搜索对象$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;//定义总记录数})}//分页$scope.findPage=function(page,rows) {brandService.findPage(page,rows).success(function(response){$scope.list=response.rows;$scope.paginationConf.totalItems=response.total;//定义总记录数})}//定义对象paginationConf,分布的配置$scope.paginationConf={currentPage: 1,//当前页totalItems: 10,//总记录条数itemsPerPage: 10,//每页的记录条数perPageOptions: [10,20,30,40,50],//页码选项,每页10条还是20还是...onChange: function () {//当页码发生变化时自动触发的方法$scope.reloadList();}}//重新加载记录$scope.reloadList=function () {$scope.search($scope.paginationConf.currentPage,$scope.paginationConf.itemsPerPage);}//保存(新增和修改)$scope.save=function () {var object=null;//新增时,id为空;但修改时,id不为空if($scope.entity.id!=null){object=brandService.update($scope.entity);}else{object=brandService.add($scope.entity);}object.success(function(response){if(response.success){$scope.reloadList();//刷新数据}else{alert(response.message);//打印信息}})}//根据ID查询$scope.findOne=function(id){brandService.findOne(id).success(function (response) {$scope.entity=response;})}//批量选中$scope.selectIds=[];//选中的ID数组,准备批量删除的数据$scope.updateSelection=function($event,id){if($event.target.checked){//判断是否选中$scope.selectIds.push(id);//向数组中添加数据}else{var idx=$scope.selectIds.indexOf(id);//id在选中数据的数组中的位置$scope.selectIds.splice(idx,1);//从数组中删除数据,重复点复选框,选择和取消选择反复横跳}}//删除$scope.dele=function () {brandService.dele($scope.selectIds).success(function (response) {if(response.success){$scope.reloadList();//刷新列表$scope.selectIds=[];}else{alert(response.message);//打印信息}})}
})

 控制器继承(提高代码复用率)

brand.html

<!DOCTYPE html>
<html>
<head><script src="../js/controller/baseController.js"></script><script src="../js/controller/brandController.js"></script> 
</body>
</html>

baseController.js

//父控制器
app.controller("baseController",function ($scope) {//定义搜索对象$scope.searchEntity={};//定义对象paginationConf,分布的配置$scope.paginationConf={currentPage: 1,//当前页totalItems: 10,//总记录条数itemsPerPage: 10,//每页的记录条数perPageOptions: [10,20,30,40,50],//页码选项,每页10条还是20还是...onChange: function () {//当页码发生变化时自动触发的方法$scope.reloadList();}}//重新加载记录$scope.reloadList=function () {$scope.search($scope.paginationConf.currentPage,$scope.paginationConf.itemsPerPage);}//批量选中$scope.selectIds=[];//选中的ID数组,准备批量删除的数据$scope.updateSelection=function($event,id){if($event.target.checked){//判断是否选中$scope.selectIds.push(id);//向数组中添加数据}else{var idx=$scope.selectIds.indexOf(id);//id在选中数据的数组中的位置$scope.selectIds.splice(idx,1);//从数组中删除数据,重复点复选框,选择和取消选择反复横跳}}})

brandController.js

//构建前端的控制层
//和页面打交道的代码写在控制层
app.controller("brandController",function ($scope,$controller,brandService) {//把baseController的$scope传递给brandController的$scope,伪继承$controller("baseController",{$scope:$scope});//读取列表数据绑定到表单中$scope.findAll=function () {brandService.findAll().success(function(response){$scope.list=response;})}//条件查询+分页$scope.search=function(page,rows){brandService.search(page,rows,$scope.searchEntity).success(function (response) {$scope.list=response.rows;//给列表变量赋值$scope.paginationConf.totalItems=response.total;//定义总记录数})}//分页$scope.findPage=function(page,rows) {brandService.findPage(page,rows).success(function(response){$scope.list=response.rows;$scope.paginationConf.totalItems=response.total;//定义总记录数})}//保存(新增和修改)$scope.save=function () {var object=null;//新增时,id为空;但修改时,id不为空if($scope.entity.id!=null){object=brandService.update($scope.entity);}else{object=brandService.add($scope.entity);}object.success(function(response){if(response.success){$scope.reloadList();//刷新数据}else{alert(response.message);//打印信息}})}//根据ID查询$scope.findOne=function(id){brandService.findOne(id).success(function (response) {$scope.entity=response;})}//删除$scope.dele=function () {brandService.dele($scope.selectIds).success(function (response) {if(response.success){$scope.reloadList();//刷新列表$scope.selectIds=[];}else{alert(response.message);//打印信息}})}
})

规格管理(深入理解和使用双向绑定)

代码较散,前后端不断切换写代码,调试


第四部分

模板管理

一、品牌下拉列表(使用select2实现下拉列表功能

写代码的思路、逻辑、顺序基本如下

后端

TbBrandMapper.xml
  <select id="selectOptionList" resultType="java.util.Map">select id,name as text from tb_brand</select>
TbBrandMapper
    /*** 下拉列表数据* @return*/List<Map> selectOptionList();
 BrandService
    public List<Map> selectOptionList();
BrandServiceImpl
    @Overridepublic List<Map> selectOptionList() {return brandMapper.selectOptionList();}
 BrandController
    @RequestMapping("/selectOptionList")public List<Map> selectOptionList(){return brandService.selectOptionList();}

运行结果:

 前端

 brandService.js
    this.selectOptionList=function () {return $http.get("../brand/selectOptionList.do")}
typeTemplateController.js 
 //控制层 
app.controller('typeTemplateController' ,function($scope,$controller,typeTemplateService,brandService,specificationService){$controller('baseController',{$scope:$scope});//继承//搜索$scope.search=function(page,rows){			typeTemplateService.search(page,rows,$scope.searchEntity).success(function(response){$scope.list=response.rows;	$scope.paginationConf.totalItems=response.total;//更新总记录数}			);}$scope.brandList={data:[]};//品牌列表//查询品牌列表$scope.findBrandList=function(){brandService.selectOptionList().success(function(response){$scope.brandList={data:response};});		}	
});	
typeTemplate.html
<!DOCTYPE html>
<html><head><script src="../plugins/angularjs/angular.min.js"></script><!--分页组件开始--><script src="../plugins/angularjs/pagination.js"></script><link rel="stylesheet" href="../plugins/angularjs/pagination.css"><!--分页组件结束--><script src="../js/base_pagination.js"></script><script src="../js/angular-select2.js"></script><script src="../js/service/typeTemplateService.js"></script><script src="../js/service/brandService.js"></script><script src="../js/service/specificationService.js"></script><script src="../js/controller/baseController.js"></script><script src="../js/controller/typeTemplateController.js"></script>
</head><body class="hold-transition skin-red sidebar-mini" ng-app="pinyougou" ng-controller="typeTemplateController" ng-init="findAll();findBrandList()"><!-- .box-body --><div class="box-body"><!--工具栏/--><!--数据列表--><table id="dataList" class="table table-bordered table-striped table-hover dataTable"><tbody><tr ng-repeat="entity in list"><td><input  type="checkbox"></td><td>{{entity.id}}</td><td>{{entity.name}}</td><td>{{entity.brandIds}}</td><td>{{entity.specIds}}</td><td>{{entity.customAttributeItems}}</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><!--multiple表示可多选config用于配置数据来源select2-model用于指定用户选择后提交的变量--><input select2 select2-model="entity.brandIds" config="brandList" multiple placeholder="支持多选" class="form-control" type="text"/></td></tr><tr></tr>	<tr><td>扩展属性</td><td><div class="btn-group">                                                                    </div>         </td></tr>	</table>				</div></div></div>
</div></body></html>

运行结果:

规格下拉列表(同上)

注意事项:

typeTemplate.html文件里的ng-init必须带上findAll()方法,用浏览器访问时才会正常显示表格

<body class="hold-transition skin-red sidebar-mini" ng-app="pinyougou" ng-controller="typeTemplateController" ng-init="findAll();findBrandList();findSpecList()">

二、扩展属性(增加、删除行)

typeTemplateController.js

	//增加扩展属性行$scope.addTableRow=function(){$scope.entity.customAttributeItems.push({});}//删除扩展属性行$scope.deleTableRow=function(index){$scope.entity.customAttributeItems.splice(index,1);}

typeTemplate.html

<!DOCTYPE html>
<html>
<body class="hold-transition skin-red sidebar-mini" ng-app="pinyougou" ng-controller="typeTemplateController" ng-init="findAll();findBrandList();findSpecList()"><!-- .box-body --><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" class="btn btn-default" title="新建" data-toggle="modal" data-target="#editModal" ng-click="entity={customAttributeItems:[]}"><i class="fa fa-file-o"></i> 新建</button></div></div></div><!--工具栏/--></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><tr><td>关联规格</td><td><input select2 select2-model="entity.specIds" config="specList" 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"><tbody><tr ng-repeat="pojo in entity.customAttributeItems"><td><input type="checkbox" class="icheckbox_square-blue" ></td><td><input class="form-control" ng-model="pojo.text" placeholder="属性名称" ></td><td><button type="button" class="btn btn-default" title="删除" ng-click="deleTableRow($index)"><i class="fa fa-trash-o"></i> 删除</button></td></tr></tbody></table>	</td></tr>	</table>				</div></div></div>
</div></body></html>

 运行结果:

三、新增模板

typeTemplate.html

1、绑定文本框

							<tbody><tr ng-repeat="pojo in entity.customAttributeItems"><td><input type="checkbox" class="icheckbox_square-blue" ></td><td><input class="form-control" ng-model="pojo.text" placeholder="属性名称" ></td><td><button type="button" class="btn btn-default" title="删除" ng-click="deleTableRow($index)"><i class="fa fa-trash-o"></i> 删除</button></td></tr></tbody>

2、保存按钮

		<div class="modal-footer">						<button class="btn btn-success" data-dismiss="modal" aria-hidden="true" ng-click="save()">保存</button></div>

 运行结果:

四、修改模板

typeTemplateController.js

	//查询实体 $scope.findOne=function(id){				typeTemplateService.findOne(id).success(function(response){$scope.entity= response;		//转换字符串为json对象(集合)$scope.entity.brandIds=  JSON.parse( $scope.entity.brandIds);//品牌$scope.entity.specIds= JSON.parse($scope.entity.specIds);//规格$scope.entity.customAttributeItems = JSON.parse($scope.entity.customAttributeItems);//自定义属性// JSON.parse(string): 将字符串转成对象// JSON.stringify(object): 将对象转成字符串});				}

typeTemplate.html

修改按钮

		                                  <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>

运行结果: 

 五、删除模板

typeTemplate.html

1、复选框勾选

		                          <tr ng-repeat="entity in list"><td><input  type="checkbox" ng-click="updateSelection($event,entity.id)"></td><td>{{entity.id}}</td><td>{{entity.name}}</td><td>{{entity.brandIds}}</td><td>{{entity.specIds}}</td><td>{{entity.customAttributeItems}}</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>

2、删除按钮

                                    <div class="btn-group"><button type="button" class="btn btn-default" title="删除" ng-click="dele()"><i class="fa fa-trash-o"></i> 删除</button>                                  </div>

 运行结果:

六、优化页面

baseController.js

    //提取json字符串数据中某个属性,返回拼接字符串,逗号分隔// 让浏览器访问的html文件上的数据更通俗易懂$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];//key是json[i]的某个属性}return value;}

typeTemplate.html

			                      <tbody><tr ng-repeat="entity in list"><td><input  type="checkbox" ng-click="updateSelection($event,entity.id)"></td><td>{{entity.id}}</td><td>{{entity.name}}</td><td>{{ jsonToString(entity.brandIds,"text") }}</td><td>{{ jsonToString(entity.specIds,"text") }}</td><td>{{ jsonToString(entity.customAttributeItems,"text") }}</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>

优化前:

 优化后:

经常出现的问题:

        如果出现更改了前端代码,前端代码没有问题,但前端页面显示不正常(一般是规定的数据不显示),就清除一下浏览器的数据(另外去百度),再刷新一下页面

 商品分类

一、商品列表

后端

ItemCatService
	public List<TbItemCat> findByParentId(Long parentId);
ItemCatServiceImpl
	@Overridepublic List<TbItemCat> findByParentId(Long parentId) {TbItemCatExample example = new TbItemCatExample();TbItemCatExample.Criteria criteria = example.createCriteria();criteria.andParentIdEqualTo(parentId);return tbItemCatMapper.selectByExample(example);}
ItemCatController
	/*** 根据上级ID查询商品分类* @param parentId* @return*/@RequestMapping("/findByParentId")public List<TbItemCat> findByParentId(Long parentId){return itemCatService.findByParentId(parentId);}

运行结果:

前端

itemCatService.js
	//根据上级ID查询列表this.findByParentId=function (parentId) {return $http.get('../itemCat/findByParentId.do?parentId='+parentId);}
itemCatController.js
	//根据上级ID查询列表$scope.findByParentId=function (parentId) {itemCatService.findByParentId(parentId).success(function (response) {$scope.list=response;});}
item_cat.html
<!DOCTYPE html>
<html>
<head><script src="../plugins/angularjs/angular.min.js"></script><script src="../js/base.js"></script><script src="../js/service/itemCatService.js"></script><script src="../js/controller/baseController.js"></script><script src="../js/controller/itemCatController.js"></script>
</head>
<body class="hold-transition skin-red sidebar-mini" ng-app="pinyougou" ng-controller="itemCatController" ng-init="findAll();findByParentId()"><tbody><tr ng-repeat="entity in list"><td><input  type="checkbox" ></td>			                              <td>{{entity.id}}</td><td>{{entity.name}}</td><td>{{entity.typeId}}</td><td class="text-center">		                                     <button type="button" class="btn bg-olive btn-xs" ng-click="findByParentId(entity.id)">查询下级</button><button type="button" class="btn bg-olive btn-xs" data-toggle="modal" data-target="#editModal" >修改</button>                                           </td></tr></tbody>
</body>

 运行结果:

二、面包屑导航(Breadcrumb Navigation)

面包屑导航(Breadcrumb Navigation)这个概念来自童话故事“汉赛尔和格莱特”,当汉赛尔和格莱特穿过森林时,不小心迷路了,但是他们发现沿途走过的地方都撒下了面包屑,让这些面包屑来帮助他们找到回家的路。 

itemCatController.js

	//定义面包屑$scope.breadcrumb=[{id:0,name:"顶级分类列表"}];$scope.search=function (id,name) {//添加面包屑$scope.breadcrumb.push({id:id,name:name});$scope.findByParentId(id);}$scope.showList=function (index,id) {//截断面包屑//index+1: 表示从当前索引的后一个索引开始截断(从面包屑中去除)//2: 表示截断的个数,在此最大是3级,所以写2,写100也没关系$scope.breadcrumb.splice(index+1,2);$scope.findByParentId(id);}

item_cat.html

1、查询下级按钮

<button ng-if="breadcrumb.length<3" type="button" class="btn bg-olive btn-xs" ng-click="search(entity.id,entity.name)">查询下级</button>

2、绑定面包屑

                      	    <ol class="breadcrumb"><!--绑定面包屑--><li ng-repeat="pojo in breadcrumb"><a href="#" ng-click="showList($index,pojo.id)">{{pojo.name}}</a></li></ol>

 运行结果:

三、新增商品分类

在哪一级新增商品分类,那新增数据就应该显示在哪一级,而不是全部显示在顶级。

关键在于查询时记录下当前级parentId

itemCatController.js

	//保存 $scope.save=function(){				var serviceObject;//服务层对象  				if($scope.entity.id!=null){//如果有IDserviceObject=itemCatService.update( $scope.entity ); //修改  }else{serviceObject=itemCatService.add( $scope.entity  );//增加 }				serviceObject.success(function(response){if(response.success){//重新查询$scope.findByParentId($scope.entity.parentId);}else{alert(response.message);}}		);				}$scope.searchEntity={};//定义搜索对象//定义变量parentId,记录本级的ID//entity是表单所绑定的实体// $socpe.entity={parentId:0};//根据上级ID查询列表$scope.findByParentId=function (parentId) {//查询时记录上级ID$scope.entity={parentId:parentId};itemCatService.findByParentId(parentId).success(function (response) {$scope.list=response;});}

item_cat.html

<div class="modal-body">							<table class="table table-bordered table-striped"  width="800px"><tr><td>上级商品分类</td><td><!--绑定面包屑--><span ng-repeat="pojo in breadcrumb">{{pojo.name}}</span></td></tr><tr><td>商品分类名称</td><td><input  ng-model="entity.name" class="form-control" placeholder="商品分类名称" >  </td></tr>			  <tr><td>类型模板</td><td>	      		<input ng-model="entity.typeId" placeholder="商品类型模板" class="form-control" type="text"/></td>		      		      		</tr>		      	</table>				</div><div class="modal-footer">						<button class="btn btn-success" data-dismiss="modal" aria-hidden="true" ng-click="save()">保存</button></div>

注意:

itemCatController.js文件去除了  $socpe.entity={parentId:0}; 这句给parentId赋初值的语句,因为parentId后续在function函数中再次被修改,这两个操作会发生冲突,导致前端引用$scope.entity对象时出错,如果要修改,最好使用深拷贝,而非直接赋值

 运行结果:

四、模板下拉列表

itemCatController.js

	//查询模板列表 (下拉框显示模板)$scope.findTypeTemplateList=function () {typeTemplateService.findAll().success(function (response) {$scope.typeTemplateList=response;//模板列表})}

item_cat.html

      	        <tr><td>类型模板</td><td><select ng-model="entity.typeId" ng-options="item.id as item.name for item in typeTemplateList"></select></td></tr>	

运行结果:

五、修改商品分类

item_cat.html

 <button type="button" class="btn bg-olive btn-xs" data-toggle="modal" data-target="#editModal" ng-click="findOne(entity.id)">修改</button>

六、删除商品分类

itemCatServiceImpl

	/*** 批量删除*/@Overridepublic void delete(Long[] ids) {for(Long id:ids){List<TbItemCat> list=findByParentId(id);if(list.size()>0){//要删除的商品有下级商品分类,抛出运行时异常throw new RuntimeException("不能删除有下级分类的商品分类!");}else{//删除tbItemCatMapper.deleteByPrimaryKey(id);}}}

itemCatController

	@RequestMapping("/delete")public Result delete(Long [] ids){try {itemCatService.delete(ids);return new Result(true, "删除成功"); } catch(RuntimeException e){//把抛出的运行时异常信息打印出来e.printStackTrace();return new Result(false,e.getMessage());} catch (Exception e) {e.printStackTrace();return new Result(false, "删除失败");}}

itemCatController.js

	//批量删除 $scope.dele=function(){			//获取选中的复选框			itemCatService.dele( $scope.selectIds ).success(function(response){if(response.success) {$scope.findByParentId($scope.entity.parentId);$scope.selectIds = [];}else{alert(response.message);//把异常信息显示在前端页面}}		);				}

item_cat.html

1、复选框,实现多选

<td><input  type="checkbox" ng-click="updateSelection($event,entity.id)"></td>

2、删除按钮

<button type="button" class="btn btn-default" title="删除" ng-click="dele()"><i class="fa fa-trash-o" ></i> 删除</button>

 七、显示模板名称

itemCatController.js

//定义一个变量$scope.typeTemplateMap=[];//查询模板列表 (下拉框显示模板)$scope.findTypeTemplateList=function () {typeTemplateService.findAll().success(function (response) {$scope.typeTemplateList=response;//模板列表//构建模板数据,用于列表显示名称for(var i=0;i<$scope.typeTemplateList.length;i++){//得到一个对象var typeTemplate=$scope.typeTemplateList[i];//把对象的id值修改成name$scope.typeTemplateMap[typeTemplate.id]=typeTemplate.name;}})}

item_cat.html

                                    <tr ng-repeat="entity in list"><!--ng-click是勾选复选框,实现多选--><td><input  type="checkbox" ng-click="updateSelection($event,entity.id)"></td><td>{{entity.id}}</td><td>{{entity.name}}</td><td>{{typeTemplateMap[entity.typeId]}}</td><td class="text-center">		                                     <button ng-if="breadcrumb.length<3" type="button" class="btn bg-olive btn-xs" ng-click="search(entity.id,entity.name)">查询下级</button><button type="button" class="btn bg-olive btn-xs" data-toggle="modal" data-target="#editModal" ng-click="findOne(entity.id)">修改</button></td></tr>

 运行结果:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/209935.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

spring-boot-admin-starter-server监控springboot项目

文章目录 场景实现具体操作展示 场景 监控三件套Prometheus、Grafana、Alertmanager 部署起来太复杂,如果公司没有运维而且项目很小就可以使用spring-boot-admin-starter-server替代。这个包使用起来还是很简单的, 下面就实现一个对springCloud项目的监控 实现 参考 项目 具体操…

redis-cluster集群(目的:高可用)

1、特点 集群由多个node节点组成&#xff0c;redis数据分布在这些节点中&#xff0c;在集群中分为主节点和从节点&#xff0c;一个主对应一个从&#xff0c;所有组的主从形成一个集群&#xff0c;每组的数据是独立的&#xff0c;并且集群自带哨兵模式 2、工作原理 集群模式中…

【SpringBoot篇】Spring_Task定时任务框架

文章目录 &#x1f339;概述&#x1f33a;应用场景&#x1f384;cron表达式&#x1f6f8;入门案例&#x1f38d;实际应用 &#x1f339;概述 Spring Task 是 Spring 框架提供的一种任务调度和异步处理的解决方案。可以按照约定的时间自动执行某个代码逻辑它可以帮助开发者在 S…

电脑开机显示器没反应?5个方法轻松解决!

“各位朋友们&#xff0c;我想问问&#xff0c;电脑开机显示器没反应是为啥呢&#xff1f;有什么方法可以解决这个问题吗&#xff1f;感谢感谢&#xff01;” 在使用电脑时&#xff0c;用户可能会遇到各种各样的情况。电脑开机显示器没反应也是一个比较常见的电脑问题。遇到这种…

c语言:回文字符串

题目&#xff1a; 思路&#xff1a; 创建一个字符数组&#xff0c;然后判断字符串长度&#xff0c;用循环&#xff0c;看对应字符是否相等&#xff0c;相等则输出&#xff0c;不相等则将对应字符ascll较大的改成ascll较小的&#xff08;题目要求字典最小的情况&#xff09;。…

【Vue入门篇】基础篇—Vue指令,Vue生命周期

&#x1f38a;专栏【JavaSE】 &#x1f354;喜欢的诗句&#xff1a;更喜岷山千里雪 三军过后尽开颜。 &#x1f386;音乐分享【如愿】 &#x1f384;欢迎并且感谢大家指出小吉的问题&#x1f970; 文章目录 &#x1f354;Vue概述&#x1f384;快速入门&#x1f33a;Vue指令⭐v-…

【深度学习】学习率及多种选择策略

学习率是最影响性能的超参数之一&#xff0c;如果我们只能调整一个超参数&#xff0c;那么最好的选择就是它。相比于其它超参数学习率以一种更加复杂的方式控制着模型的有效容量&#xff0c;当学习率最优时&#xff0c;模型的有效容量最大。本文从手动选择学习率到使用预热机制…

P8599 [蓝桥杯 2013 省 B] 带分数(dfs+全排列+断点判断)

思路&#xff1a;1.深度枚举所有排列情况 2.设置为每个排列设置两个断点&#xff0c;分为三部分&#xff1a;a,b,c 3.转换为乘法判断条件&#xff0c;满足加一 代码如下&#xff1a;&#xff08;可用next_permutation全排列函数代替dfs&#xff09; #include<iostream>…

122.买卖股票的最佳时机II(不限次数)

题目 题解 labuladong的状态图解 class Solution:def maxProfit(self, prices: List[int]) -> int:N len(prices)# 定义状态&#xff1a;dp[i][j]表示在第i天持有或卖出时的最大利润&#xff0c;j1代表持有&#xff0c;j0代表卖出dp [[0 for j in range(2)] for i in ra…

PC8223(CC/CV控制)高耐压输入5V/3.4A同步降压电路内建补偿带恒流恒压输出

概述 PC8233&#xff08;替代CX8853&#xff09;是一款同步降压调节器,输出电流高达3.4A,操作范围从8V到32V的宽电源电压。内部补偿要求最低数量现成的标准外部组件。PC8233在CC&#xff08;恒定输出电流&#xff09;模式或CV&#xff08;恒定输出电压&#xff09;模式&#x…

超详细 | 实验室linux服务器非root账号 | 安装pip | 安装conda

登录实验室公用服务器&#xff0c;个人账号下&#xff08;非root&#xff09;是空的&#xff0c;啥也没有&#xff0c;想安装下pip和conda。 转了一圈&#xff0c;好像没太有针对这个需求写具体博客的&#xff0c;但有挺多讲直接在root下安的&#xff08;用的应该是个人虚拟机&…

CSGO搬砖项目全面讲解 ,CSGO搬砖注意事项

Steam/CSGO游戏搬砖全套操作流程之如何选品&#xff08;第二课&#xff09; 一个游戏只要能搬&#xff0c;只要体量不够大&#xff0c;很快就会货币价格暴跌&#xff0c;直接凉凉。市面上的能稳定手动搬砖的游戏越来越少。所以对于兼职赚点外快的散人搬砖党来说&#xff0c;找一…