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
     */
    @Override
    public 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
     */
    @Override
    public 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查询
    @Override
    public TbBrand findOne(Long id) {
        return brandMapper.selectByPrimaryKey(id);
    }

    //修改
    @Override
    public 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 {

    //删除
    @Override
    public 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 {
    //条件查询
    @Override
    public 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
    @Override
    public 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
	@Override
	public 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){//如果有ID
			serviceObject=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

	/**
	 * 批量删除
	 */
	@Override
	public 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.mfbz.cn/a/198650.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

使用 watch+$nextTick 解决Vue引入组件无法使用问题

问题描述&#xff1a; 很多时候我们都需要使用第三方组件库&#xff0c;比如Element-UI&#xff0c;Swiper 等等。 如果我们想要在这些结构中传入自己从服务器请求中获取的数据就会出现无法显示的问题。 比如我们在下面的Swiper例子中&#xff0c;我们需要new Swiper 才能让…

福州大学《嵌入式系统综合设计》 实验八:FFMPEG视频编码

一、实验目的 掌握使用算能平台进行视频编码的流程&#xff0c;包括开发主机环境与云平台的配置&#xff0c;视频编码程序的编写与理解&#xff0c;代码的编译、运行以及学习使用码流分析工具分析视频压缩码流等。 二、实验内容 搭建实验开发环境&#xff0c;编译并运行编码…

软著项目推荐 深度学习动物识别 - 卷积神经网络 机器视觉 图像识别

文章目录 0 前言1 背景2 算法原理2.1 动物识别方法概况2.2 常用的网络模型2.2.1 B-CNN2.2.2 SSD 3 SSD动物目标检测流程4 实现效果5 部分相关代码5.1 数据预处理5.2 构建卷积神经网络5.3 tensorflow计算图可视化5.4 网络模型训练5.5 对猫狗图像进行2分类 6 最后 0 前言 &#…

图数据库HugeGraph:HugeGraph-Hubble基于Web的可视化图管理初体验

原创/朱季谦 一、HugeGraph-Hubble简介 关于HugeGraph&#xff0c;官方资料是这样介绍的&#xff0c;它是一款易用、高效、通用的开源图数据库系统&#xff08;Graph Database&#xff09;&#xff0c; 实现了 Apache TinkerPop3 框架及完全兼容 Gremlin 查询语言&#xff0c…

Pod控制器简介,ReplicaSet、Deployment、HPA三种处理无状态pod应用的控制器介绍

目录 一.Pod控制器简介 二.ReplicaSet&#xff08;简写rs&#xff09; 1.简介 &#xff08;1&#xff09;主要功能 &#xff08;2&#xff09;rs较完整参数解释 2.创建和删除 &#xff08;1&#xff09;创建 &#xff08;2&#xff09;删除 3.扩容和缩容 &#xff08…

【Python】torch.exp()和 torch.sigmoid()函数详解和示例

本文对torch.exp&#xff08;&#xff09;和 torch.sigmoid&#xff08;&#xff09;函数进行原理和示例讲解&#xff0c;以帮助大家理解和使用。 目录 torch.exp函数原理运行示例 torch.sigmoid&#xff08;&#xff09;函数原理运行示例torch.sigmoid相关知识 结合运行 torc…

Leetcode 380. O(1) 时间插入、删除和获取随机元素

文章目录 题目代码&#xff08;11.28 首刷看解析&#xff09; 题目 Leetcode 380. O(1) 时间插入、删除和获取随机元素 代码&#xff08;11.28 首刷看解析&#xff09; 1.length:表示的是数组的长度 数组 2.length():表示的是字符串的长度 字符串 3.size():表示的是集合中有多…

Re55:读论文 Entities as Experts: Sparse Memory Access with Entity Supervision

诸神缄默不语-个人CSDN博文目录 诸神缄默不语的论文阅读笔记和分类 论文名称&#xff1a;Entities as Experts: Sparse Memory Access with Entity Supervision 模型名称&#xff1a;Entities as Experts (EaE) ArXiv网址&#xff1a;https://arxiv.org/abs/2004.07202 本文…

看懂YOLOv7混淆矩阵的含义,正确计算召回率、精确率、误检率、漏检率

文章目录 1、准确率、精确率、召回率、误报率、漏报率概念及公式1.1 准确率 Accuracy1.2 精确率 Precision1.3 召回率 Recall1.4 F1-Score1.5 误检率 false rate1.6 漏检率 miss rate 2、YOLOv7混淆矩阵分析 1、准确率、精确率、召回率、误报率、漏报率概念及公式 重点参考博文…

基于Eclipse+Mysql+Tomcat开发的挖掘机配件营销系统

基于EclipseMysqlTomcat开发的挖掘机配件营销系统 项目介绍&#x1f481;&#x1f3fb; 大家都有目共睹&#xff0c;现在的科学技术发展很迅速。而如今&#xff0c;计算机应用已经完全融入到人们的生产和生活当中&#xff0c;特别是企业&#xff0c;现在的企业几乎都是离不开计…

LLM大语言模型

大语言模型的定义 大语言模型&#xff08;英文&#xff1a;Large Language Model&#xff0c;缩写LLM&#xff09;&#xff0c;也称大型语言模型&#xff0c;是一种人工智能模型&#xff0c;旨在理解和生成人类语言。它们在大量的文本数据上进行训练&#xff0c;可以执行广泛的…

数据结构与算法之美学习笔记:27 | 递归树:如何借助树来求解递归算法的时间复杂度?

目录 前言递归树与时间复杂度分析实战一&#xff1a;分析快速排序的时间复杂度实战二&#xff1a;分析斐波那契数列的时间复杂度实战三&#xff1a;分析全排列的时间复杂度内容小结 前言 本节课程思维导图&#xff1a; 今天&#xff0c;我们来讲这种数据结构的一种特殊应用&am…

vue找依赖包的网址

https://www.npmjs.com/ 浅收藏一下

Flask教程入门

1.学习Flask之前&#xff0c;首先需要对URL进行一定的了解。 URL的一些知识&#xff1a; 1.URL只能包含ASCII码里面一些可显示的字符&#xff0c;如A-Z&#xff0c;a-z&#xff0c;0-9&#xff0c;&&#xff0c;#&#xff0c;%&#xff0c;&#xff1f;&#xff0c;/等字符…

Android控件全解手册 - 任意View缩放平移工具-实现思路和讲解

Unity3D特效百例案例项目实战源码Android-Unity实战问题汇总游戏脚本-辅助自动化Android控件全解手册再战Android系列Scratch编程案例软考全系列Unity3D学习专栏蓝桥系列ChatGPT和AIGC &#x1f449;关于作者 专注于Android/Unity和各种游戏开发技巧&#xff0c;以及各种资源分…

day64 django中间件的复习使用

django中间件 django中间件是django的门户 1.请求来的时候需要先经过中间件才能达到真正的django后端 2.响应走的时候也需要经过中间件 ​ djangp自带七个中间件MIDDLEWARE [django.middleware.security.SecurityMiddleware,django.contrib.sessions.middleware.SessionMiddle…

java三大集合类--List

List Set Map 一、List 几个小问题&#xff1a; 1、接口可以被继承吗&#xff1f;&#xff08;可以&#xff09; 2、接口可以被多个类实现吗&#xff1f;&#xff08;可以&#xff09; 3、以下两种写法有什么区别&#xff1f; //List list1new List();是错误的因为List()…

【axios封装】万字长文,TypeScript实战,封装一个axios - 基础封装篇

目录 前言版本环境变量配置引入的类型1、AxiosIntance: axios实例类型2、InternalAxiosRequestConfig: 高版本下AxiosRequestConfig的拓展类型3、AxiosRequestConfig: 请求体配置参数类型4、AxiosError: 错误对象类型5、AxiosResponse: 完整原始响应体类型 目标效果开始封装骨架…

C#文件流FileStream类

目录 一、文件流类 1.FileStream类的常用属性 2.FileStream类的常用方法 3.使用FileStream类操作文件 二、文本文件的写入与读取 1.StreamWriter类 2.StreamReader类 3.示例及源码 三、二进制文件的写入与读取 1.BinaryWriter类 2.BinaryReader类 3.示例源码 数据流…

【数据结构/C++】栈和队列_链栈

链头 栈顶。 #include<iostream> using namespace std; // 链栈 typedef int ElemType; typedef struct Linknode {ElemType data;struct Linknode *next; } *LiStack; // 初始化 void InitLiStack(LiStack &S) {S (LiStack)malloc(sizeof(struct Linknode));S->…