欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

品优购(IDEA版)-第二天

程序员文章站 2023-08-31 12:47:51
品优购 第2天 "学习目标" 目标1:运用AngularJS前端框架的常用指令 目标2:完成品牌管理的列表功能 目标3:完成品牌管理的分页列表功能 目标4:完成品牌管理的增加功能 目标5:完成品牌管理的修改功能 目标6:完成品牌管理的删除功能 目标7:完成品牌管理的条件查询功能 目标N:通用Mapp ......

品优购-第2天

目标1:运用angularjs前端框架的常用指令
目标2:完成品牌管理的列表功能
目标3:完成品牌管理的分页列表功能
目标4:完成品牌管理的增加功能
目标5:完成品牌管理的修改功能
目标6:完成品牌管理的删除功能
目标7:完成品牌管理的条件查询功能
目标n:通用mapper

第1章 前端框架angularjs入门

1.1 angularjs简介rjs

angularjs 诞生于2009年,由misko hevery 等人创建,后为google所收购。是一款优秀的前端js框架,已经被用于google的多款产品当中。angularjs有着诸多特性,最为核心的是:mvc、模块化、自动化双向数据绑定、依赖注入等等。
品优购(IDEA版)-第二天

1.2 angularjs四大特征

1.2.1 mvc模式

angular遵循软件工程的mvc模式,并鼓励展现,数据,和逻辑组件之间的松耦合.通过依赖注入(dependency injection),angular为客户端的web应用带来了传统服务端的服务,例如独立于视图的控制。 因此,后端减少了许多负担,产生了更轻的web应用。
品优购(IDEA版)-第二天
model:数据,其实就是angular变量($scope.xx);

view: 数据的呈现,html+directive(指令);

controller:操作数据,就是function,数据的增删改查;

1.2.2 双向绑定

angularjs是建立在这样的信念上的:即声明式编程应该用于构建用户界面以及编写软件构建,而指令式编程非常适合来表示业务逻辑。框架采用并扩展了传统html,通过双向的数据绑定来适应动态内容,双向的数据绑定允许模型和视图之间的自动同步。因此,angularjs使得对dom的操作不再重要并提升了可测试性。
品优购(IDEA版)-第二天

1.2.3 依赖注入

依赖注入(dependency injection,简称di)是一种设计模式, 指某个对象依赖的其他对象无需手工创建,只需要“吼一嗓子”,则此对象在创建时,其依赖的对象由框架来自动创建并注入进来,其实就是最少知识法则;模块中所有的service和provider两类对象,都可以根据形参名称实现di.

1.2.4 模块化设计

高内聚低耦合法则

1)官方提供的模块 ng、ngroute、nganimate

2)用户自定义的模块 angular.module(‘模块名’,[ ])

1.3 入门小demo

1.3.1 表达式
<html>
<head>
    <title>入门小demo-1</title>
    <script src="angular.min.js"></script>
</head>
<body ng-app>
{{100+100}}
</body>
</html>

执行结果如下:
品优购(IDEA版)-第二天
表达式的写法是{{表达式 }} 表达式可以是变量或是运算式

ng-app 指令 作用是告诉子元素以下的指令是归angularjs的,angularjs会识别的
ng-app 指令定义了angularjs 应用程序的 根元素。
ng-app 指令在网页加载完毕时会自动引导(自动初始化)应用程序。

1.3.2 双向绑定
<html>
<head>
    <title>入门小demo-1  双向绑定</title>
    <script src="angular.min.js"></script>
</head>
<body ng-app>
请输入你的姓名:<input ng-model="myname">
<br>
{{myname}},你好
</body>
</html>

运行效果如下:
品优购(IDEA版)-第二天

ng-model 指令用于绑定变量,这样用户在文本框输入的内容会绑定到变量上,而表达式可以实时地输出变量。

1.3.3 初始化指令

我们如果希望有些变量具有初始值,可以使用ng-init指令来对变量初始化:

<html>
<head>
    <title>入门小demo-3  初始化</title>
    <script src="angular.min.js"></script>
</head>
<body ng-app   ng-init="myname='陈大海'">
请输入你的姓名:<input ng-model="myname">
<br>
{{myname}},你好
</body>
</html>
1.3.4 控制器
<html>
<head>
    <title>入门小demo-3  初始化</title>
    <script src="angular.min.js"></script>
    <script>
        var app=angular.module('myapp',[]); //定义了一个叫myapp的模块
        //定义控制器
        app.controller('mycontroller',function($scope){
            $scope.add=function(){
                return 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()}}
</body>
</html>

运行结果如下:
品优购(IDEA版)-第二天
ng-controller用于指定所使用的控制器。

理解 $scope:

$scope 的使用贯穿整个 angularjs app 应用,它与数据模型相关联,同时也是表达式执行的上下文.有了$scope就在视图和控制器之间建立了一个通道,基于作用域视图在修改数据时会立刻更新 $scope,同样的$scope 发生改变时也会立刻重新渲染视图.

1.3.5 事件指令
<html>
<head>
    <title>入门小demo-5  事件指令</title>
    <script src="angular.min.js"></script>  
    <script>
        var app=angular.module('myapp',[]); //定义了一个叫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" >
<button ng-click="add()">运算</button>
结果:{{z}}
</body>
</html>

运行结果:
品优购(IDEA版)-第二天
ng-click 是最常用的单击事件指令,再点击时触发控制器的某个方法

1.3.6 循环数组
<html>
<head>
    <title>入门小demo-6  循环数据</title>
    <script src="angular.min.js"></script>
    <script>
        var app=angular.module('myapp',[]); //定义了一个叫myapp的模块
        //定义控制器
        app.controller('mycontroller',function($scope){
            $scope.list= [100,192,203,434 ];//定义数组
        });
    </script>
</head>
<body ng-app="myapp" ng-controller="mycontroller">
<table>
<tr ng-repeat="x in list">
    <td>{{x}}</td>
</tr>
</table>
</body>
</html>

这里的ng-repeat指令用于循环数组变量。

运行结果如下:

1.3.7 循环对象数组
<html>
<head>
    <title>入门小demo-7  循环对象数组</title>
    <script src="angular.min.js"></script>  
    <script>
        var app=angular.module('myapp',[]); //定义了一个叫myapp的模块
        //定义控制器
        app.controller('mycontroller',function($scope){     
            $scope.list= [
                {name:'张三',shuxue:100,yuwen:93},
                {name:'李四',shuxue:88,yuwen:87},
                {name:'王五',shuxue:77,yuwen:56}
            ];//定义数组            
        }); 
    </script>   
</head>
<body ng-app="myapp" ng-controller="mycontroller">
<table>
<tr>
    <td>姓名</td>
    <td>数学</td>
    <td>语文</td>
</tr>
<tr ng-repeat="entity in list">
    <td>{{entity.name}}</td>
    <td>{{entity.shuxue}}</td>
    <td>{{entity.yuwen}}</td>
</tr>
</table>
</body>
</html>

运行结果如下:
品优购(IDEA版)-第二天

1.3.8 内置服务

我们的数据一般都是从后端获取的,那么如何获取数据呢?我们一般使用内置服务$http来实现。注意:以下代码需要在tomcat中运行。

<html>
<head>
    <title>入门小demo-8  内置服务</title>
    <meta charset="utf-8" />
    <script src="angular.min.js"></script>  
    <script>
        var app=angular.module('myapp',[]); //定义了一个叫myapp的模块
        //定义控制器
        app.controller('mycontroller',function($scope,$http){       
            $scope.findall=function(){
                $http.get('data.json').success(
                    function(response){
                        $scope.list=response;
                    }                   
                );              
            }           
        }); 
    </script>   
</head>
<body ng-app="myapp" ng-controller="mycontroller" ng-init="findall()">
<table>
<tr>
    <td>姓名</td>
    <td>数学</td>
    <td>语文</td>
</tr>
<tr ng-repeat="entity in list">
    <td>{{entity.name}}</td>
    <td>{{entity.shuxue}}</td>
    <td>{{entity.yuwen}}</td>
</tr>
</table>
</body>
</html>

建立文件 data.json

[
    {"name":"张三","shuxue":100,"yuwen":93},
    {"name":"李四","shuxue":88,"yuwen":87},
    {"name":"王五","shuxue":77,"yuwen":56},
    {"name":"赵六","shuxue":67,"yuwen":86}
]

第2章 通用mapper

2.1 通用mapper介绍

通用 mapper 提供了一些通用的方法,这些通用方法是以接口的形式提供的,它主要简化了我们工作中常做的单表操作问题,让mybatis由面向过程转换成了面向对象的操作方式,当然,mybatis编写sql面向过程操作和通用mapper面向对象操作可以共存。

为了方便测试,我们在parent工程中引入log日志包,版本如下:

<slf4j.version>1.6.6</slf4j.version>
<log4j.version>1.2.12</log4j.version>

包引入如下:

<!-- log start -->
<dependency>
    <groupid>log4j</groupid>
    <artifactid>log4j</artifactid>
    <version>${log4j.version}</version>
</dependency>

<dependency>
    <groupid>org.slf4j</groupid>
    <artifactid>slf4j-api</artifactid>
    <version>${slf4j.version}</version>
</dependency>

<dependency>
    <groupid>org.slf4j</groupid>
    <artifactid>slf4j-log4j12</artifactid>
    <version>${slf4j.version}</version>
</dependency>
<!-- log end -->

log4j.properties

log4j.rootlogger=debug,console
log4j.appender.console=org.apache.log4j.consoleappender
log4j.appender.console.layout=org.apache.log4j.patternlayout
log4j.appender.console.layout.conversionpattern=%d [%t] %-5p [%c] - %m%n
log4j.logger.org.apache=debug

2.2 配置介绍

使用通用通用mapper首先需要引入依赖包。

<!--通用mapper-->
<dependency>
    <groupid>tk.mybatis</groupid>
    <artifactid>mapper</artifactid>
</dependency>

替换mybatis集成spring的包扫描bean,修改pinyougou-mapper项目中spring-mybatis.xml

替换前:

<bean class="org.mybatis.spring.mapper.mapperscannerconfigurer"
   p:basepackage="com.pinyougou.mapper"
     p:sqlsessionfactorybeanname="sqlsessionfactorybean" />

替换后:

<bean class="tk.mybatis.spring.mapper.mapperscannerconfigurer"
     p:basepackage="com.pinyougou.mapper"
     p:sqlsessionfactorybeanname="sqlsessionfactorybean">
   <!--通用接口-->
   <property name="properties">
      <value>
         mappers=tk.mybatis.mapper.common.mapper
      </value>
   </property>
</bean>

2.3 mybatis+通用mapper+spring集成测试

在pinyougou-sellergoods-service编写测试类

package com.pinyougou;
import org.junit.before;
import org.junit.test;
import org.springframework.context.applicationcontext;
import org.springframework.context.support.classpathxmlapplicationcontext;
public class mappertest {
    private applicationcontext act;
    @before
    public void init(){
        act = new classpathxmlapplicationcontext("classpath:spring/spring.xml");
    }
    @test
    public void testspring(){
        string[] names = act.getbeandefinitionnames();

        for (string name : names) {
            system.out.println(name);
        }
    }
}

测试结果

addressmapper
areasmapper
brandmapper
citiesmapper
contentcategorymapper
contentmapper
freighttemplatemapper
goodsdescmapper
goodsmapper
itemcatmapper
itemmapper
orderitemmapper
ordermapper
paylogmapper
provincesmapper
seckillgoodsmapper
seckillordermapper
sellermapper
specificationmapper
specificationoptionmapper
typetemplatemapper
usermapper

这里可以看到每个接口都产生了一个代理对象,并且注入到spring容器中,而每个接口都继承了mapper 接口,所以初步可以断定,继承通用mapper成功,接着我们来使用通用mapper实现增删改查。

2.4通用mapper的使用

2.4.1 增加操作
2.4.1.1 不忽略空值-insert
/***
 * 增加数据
 * 不忽略空值
 */
@test
public void testinsert(){
    brand brand = new brand();
    brand.setname("深圳黑马训练营");
    //brand.setfirstchar("c");
    int acount = brandmapper.insert(brand);
    system.out.println(acount);
}

日志:

当brand的id、firstchar为空的时候,sql语句仍然执行了插入操作。

==>  preparing: insert into tb_brand ( id,name,first_char ) values( ?,?,? ) 
==> parameters: null, 深圳黑马训练营(string), null
1.4.1.2. 忽略空值-insertselective
/***
 * 增加数据
 * 忽略空值
 */
@test
public void testinsertselective(){
    brand brand = new brand();
    brand.setname("传智播客-黑马训练营");
    //brand.setfirstchar("c");
    int acount = brandmapper.insertselective(brand);
    system.out.println(acount);
}

日志:

当brand的id、firstchar为空的时候,sql语句没有执行了插入操作。

==>  preparing: insert into tb_brand ( name ) values( ? ) 
==> parameters: 传智播客-黑马训练营(string)
2.4.2修改操作
2.4.2.1 根据主键修改数据-不忽略空值
/**
 * 需改操作
 * 不忽略空值
 */
@test
public void testupdatebyprimarykey(){
    brand brand = new brand();
    brand.setid(25l);
    //brand.setname("深圳黑马训练营");
    brand.setfirstchar("s");
    //根据主键修改数据
    int mcount = brandmapper.updatebyprimarykey(brand);
    system.out.println(mcount);
}

日志:

当name为空的时候,sql语句仍然执行修改。

==>  preparing: update tb_brand set name = ?,first_char = ? where id = ? 
==> parameters: null, s(string), 25(long)
2.4.2.2. 根据主键修改数据-忽略空值
/**
 * 需改操作
 * 忽略空值
 */
@test
public void testupdatebyprimarykeyselective(){
    brand brand = new brand();
    brand.setid(25l);
    brand.setname("深圳黑马训练营");
    //brand.setfirstchar("s");
    //根据主键修改数据
    int mcount = brandmapper.updatebyprimarykeyselective(brand);
    system.out.println(mcount);
}

日志:

当name为空的时候,sql语句不执行修改。

1
2
3
sql
==>  preparing: update tb_brand set name = ? where id = ? 
==> parameters: 深圳黑马训练营(string), 25(long)
2.4.2.3构造条件修改数据-不忽略空值
/**
 * 构造条件执行修改
 * 不忽略空值
 */
@test
public void testupdatebyexample(){
    //firstchar=s
    brand brand = new brand();
    brand.setname("深圳市黑马训练营");

    //创建example对象
    example example = new example(brand.class);

    //criteria 用来构造约束条件
    example.criteria criteria = example.createcriteria();

    //第一个参数是brand对应的属性,第二个参数是属性约束值   相当于 where firstchar=s
    criteria.andequalto("firstchar","s");

    //条件修改数据
    int mcount = brandmapper.updatebyexample(brand,example);
    system.out.println(mcount);
}

日志:

criteria.andequalto(“firstchar”,“s”); 转换成了这里的sql语句 where(first_char=?),这里firstchart为空,但sql语句仍然执行了修改。

1
2
==>  preparing: update tb_brand set name = ?,first_char = ? where ( first_char = ? ) 
==> parameters: 深圳市黑马训练营(string), null, s(string)
2.4.2.4 构造条件修改数据-忽略空值
/**
 * 构造条件执行修改
 * 忽略空值
 */
@test
public void testupdatebyexampleselective(){
    //firstchar=s
    brand brand = new brand();
    brand.setfirstchar("s");
    //创建example对象
    example example = new example(brand.class);
    //criteria 用来构造约束条件
    example.criteria criteria = example.createcriteria();

    //第一个参数是brand对应的属性,第二个参数是属性约束值   相当于 where name='深圳市黑马训练营'
    criteria.andequalto("name","深圳市黑马训练营");

    //条件修改数据
    int mcount = brandmapper.updatebyexampleselective(brand,example);
    system.out.println(mcount);
}

日志:

这里name为空,sql语句并没有做出修改操作。

==>  preparing: update tb_brand set first_char = ? where ( name = ? ) 
==> parameters: s(string), 深圳市黑马训练营(string)
2.4.3查询操作
1.4.3.1. 根据主键查询
/***
 * 根据主键查询
 */
@test
public void testselectbyprimarykey(){
    long id = 25l;
    brand brand = brandmapper.selectbyprimarykey(id);
    system.out.println(brand);
}

日志:

==>  preparing: select id,name,first_char from tb_brand where id = ? 
==> parameters: 25(long)
brand{id=25, name='深圳市黑马训练营', firstchar='s'}
2.4.3.1查询单条记录
/***
 * 查询单个记录
 */
@test
public void testselectone(){
    brand brand = new brand();
    brand.setid(25l);
    brand.setname("深圳市黑马训练营");
    brand brand1 = brandmapper.selectone(brand);
    system.out.println(brand1);
}

日志:

==>  preparing: select id,name,first_char from tb_brand where id = ? and name = ? 
==> parameters: 25(long), 深圳市黑马训练营(string)
brand{id=25, name='深圳市黑马训练营', firstchar='s'}

注意:

这里需要注意一下,复合该条件的数据,数据库里必须<=1条,如果大于了1条数据,则会报错

toomanyresultsexception: expected one result (or null) to be returned by selectone(), but found: 3
2.4.3.2 根据条件查询-example
/***
 * 根据条件执行查询
 */
@test
public void testexample(){
    example example = new example(brand.class);
    example.criteria criteria = example.createcriteria();
    //id in(1,2,5,6)
    list<long> ids = new arraylist<long>();
    ids.add(1l);
    ids.add(2l);
    ids.add(5l);
    ids.add(6l);

    //第二个参数是个集合对象即可,注意集合对象这里对应的类型虽然是object,不过要和你数据库对应的类型保持一致
    criteria.andin("id",ids);

    //执行查询
    list<brand> brands = brandmapper.selectbyexample(example);

    for (brand brand : brands) {
        system.out.println(brand);
    }
}

日志:

==>  preparing: select id,name,first_char from tb_brand where ( id in ( ? , ? , ? , ? ) ) 
==> parameters: 1(long), 2(long), 5(long), 6(long)
brand{id=1, name='联想', firstchar='l'}
brand{id=2, name='华为', firstchar='h'}
brand{id=5, name='oppo', firstchar='o'}
brand{id=6, name='深圳市黑马训练营', firstchar='s'}
2.4.3.3 根据条件查询-javabean
/***
 * 根据条件查询
 * 入参:javabean
 */
@test
public void testselect(){
    brand brand = new brand();
    brand.setid(25l);
    brand.setname("深圳市黑马训练营");
    //把brand作为查询条件,这里会忽略空值
    list<brand> brands = brandmapper.select(brand);
    for (brand bd : brands) {
        system.out.println(bd);
    }
}

日志:

==>  preparing: select id,name,first_char from tb_brand where id = ? and name = ? 
==> parameters: 25(long), 深圳市黑马训练营(string)
brand{id=25, name='深圳市黑马训练营', firstchar='s'}
2.4.3.4 查询所有
/***
 * 查询所有
 */
@test
public void testselectall(){
    //执行查询
    list<brand> brands = brandmapper.selectall();

    for (brand brand : brands) {
        system.out.println(brand);
    }
}

日志:

==>  preparing: select id,name,first_char from tb_brand 
==> parameters: 
brand{id=1, name='联想', firstchar='l'}
brand{id=2, name='华为', firstchar='h'}
brand{id=3, name='深圳市黑马训练营', firstchar='s'}
...........................................
2.4.3.5 统计查询
/***
 * 统计查询-总记录数
 */
@test
public void testselectcount(){
    //查询总记录数
    int count = brandmapper.selectcount(null);
    system.out.println(count);
}

日志:

==>  preparing: select count(id) from tb_brand 
==> parameters: 
25
2.4.4 删除操作
2.4.4.1 根据主键删除
/***
 * 根据id删除
 */
@test
public void testdeletebyprimarykey(){
    long id = 25;
    int dcount = brandmapper.deletebyprimarykey(id);
    system.out.println(dcount);
}

日志:

==>  preparing: delete from tb_brand where id = ? 
==> parameters: 25(long)
2.4.4.2 条件删除-example
/***
 * 条件删除
 */
@test
public void testdeletebyexample(){
    example example = new example(brand.class);
    example.criteria criteria = example.createcriteria();
    //where id between 23 and 28
    criteria.andbetween("id",23l,28l);
    //根据条件删除
    int dcount = brandmapper.deletebyexample(example);
    system.out.println(dcount);
}

日志:

==>  preparing: delete from tb_brand where ( id between ? and ? ) 
==> parameters: 23(long), 28(long)
2.4.4.3 条件删除-javabean
/***
 * 条件删除
 * 入参:javabean
 */
@test
public void testdelete(){
    brand brand = new brand();
    brand.setname("阿凡达");
    //根据条件删除
    int dcount = brandmapper.delete(brand);
    system.out.println(dcount);
}

日志:

==>  preparing: delete from tb_brand where name = ? 
==> parameters: 阿凡达(string)

第3章 分页工具

在做项目的时候,分页属于很常见的,但通常都有繁琐的封装。这里提供了一个通用分页插件pagehelper,能满足我们工作中的基本需求。

3.1 配置介绍

首先需要引入对应的依赖

<!--分页工具包-->
<dependency>
    <groupid>com.github.pagehelper</groupid>
    <artifactid>pagehelper</artifactid>
</dependency>

然后需要配置一个mybatis拦截器,在pinyougou-mapper项目的mybatis.xml中加入如下插件代码

<plugins>
    <!-- com.github.pagehelper为pageinterceptor类所在包名 -->
    <plugin interceptor="com.github.pagehelper.pageinterceptor">
        <property name="reasonable" value="true"/>
    </plugin>
</plugins>

上述配置也可以不配置在mybatis.xml中,也可以配置在spring-mybatis.xml的sqlsessionfactorybean中,代码如下:

<!-- sqlsessionfactorybean -->
<bean id="sqlsessionfactorybean" class="org.mybatis.spring.sqlsessionfactorybean">
    <property name="configlocation" value="classpath:mybatis/mybatis.xml" />
    <property name="typealiasespackage" value="com.pinyougou.model" />
    <property name="mapperlocations">
        <list>
            <value>classpath:com/pinyougou/mapper/*mapper.xml</value>
        </list>
    </property>
    <property name="datasource" ref="datasource" />

    <!--分页插件配置-->
    <property name="plugins">
        <array>
            <bean class="com.github.pagehelper.pageinterceptor">
                <!--配置分页属性-->
                <property name="properties">
                    <props>
                        <!--指定数据库方言-->
                        <prop key="helperdialect">mysql</prop>
                        <!--合理化分页操作-->
                        <prop key="reasonable">true</prop>
                    </props>
                </property>
            </bean>
        </array>
    </property>
</bean>

3.2 分页类介绍

pageinfo类既包含我们工作中的分页信息,也包含分页查询的集合对象,所以很实用,如下代码:

public class pageinfo<t> implements serializable {
    private static final long serialversionuid = 1l;
    //当前页
    private int pagenum;
    //每页的数量
    private int pagesize;
    //当前页的数量
    private int size;
    //当前页面第一个元素在数据库中的行号
    private int startrow;
    //当前页面最后一个元素在数据库中的行号
    private int endrow;
    //总记录数
    private long total;
    //总页数
    private int pages;
    //结果集
    private list<t> list;
    //前一页
    private int prepage;
    //下一页
    private int nextpage;
    //是否为第一页
    private boolean isfirstpage = false;
    //是否为最后一页
    private boolean islastpage = false;
    //是否有前一页
    private boolean haspreviouspage = false;
    //是否有下一页
    private boolean hasnextpage = false;
    //导航页码数
    private int navigatepages;
    //所有导航页号
    private int[] navigatepagenums;
    //导航条上的第一页
    private int navigatefirstpage;
    //导航条上的最后一页
    private int navigatelastpage;
     //........略
}

3.3 分页插件的使用

分页插件的使用很简单,配置好了后,直接调用pagehelper的静态方法startpage即可实现分页,其他查询正常写就行了,注意一点,调用startpage的方法必须写在执行查询selectall()前面,否则分页无效。

/**
 * 分页测试
 */
@test
public void testpage(){
    //page 当前页    size 每页显示多少条
    int page = 1,size=10;
    //分页处理,只需要调用pagehelper.startpage静态方法即可。s
    pagehelper.startpage(page,size);

    //查询
    list<brand> brands = brandmapper.selectall();

    //获取分页信息,注意这里传入了brands集合对象
    pageinfo<brand> pageinfo = new pageinfo<brand>(brands);
    system.out.println(pageinfo);
}

日志:

==>  preparing: select count(0) from tb_brand 
==> parameters: 
------------------------------------------------------------------------------------------------------------------------------------------------
==>  preparing: select id,name,first_char from tb_brand limit ? 
==> parameters: 10(integer)
------------------------------------------------------------------------------------------------------------------------------------------------
pageinfo{pagenum=1, pagesize=10, size=10, startrow=1, endrow=10, total=22, pages=3, list=page{count=true, pagenum=1, pagesize=10, startrow=0, endrow=10, total=22, pages=3, reasonable=true, pagesizezero=false}, prepage=0, nextpage=2, isfirstpage=true, islastpage=false, haspreviouspage=false, hasnextpage=true, navigatepages=8, navigatefirstpage=1, navigatelastpage=3, navigatepagenums=[1, 2, 3]}

第4章 品牌列表的实现

品牌分页实现,记得再pinyougou-sellergoods-interface中引入分页包

<!--分页工具包-->
<dependency>
    <groupid>com.github.pagehelper</groupid>
    <artifactid>pagehelper</artifactid>
</dependency>

4.1 需求分析

实现品牌列表的查询(不用分页和条件查询)效果如下:

品优购(IDEA版)-第二天

4.2 前端代码

4.2.1 拷贝资源

将“资源/静态原型/运营商管理后台”下的页面资源拷贝到pinyougou-manager-web下

品优购(IDEA版)-第二天

其中plugins文件夹中包括了angularjs 、bootstrap、jquery等常用前端库,我们将在项目中用到

4.2.2 引入js

修改brand.html ,引入js

<script src="/plugins/angularjs/angular.min.js"></script>

指定模块和控制器

<body ng-app="pinyougou" ng-controller="brandcontroller" class="hold-transition skin-red sidebar-mini">

ng-app 指令中定义的就是模块的名称

ng-controller 指令用于为你的应用添加控制器。

在控制器中,你可以编写代码,制作函数和变量,并使用 scope 对象来访问。

4.2.3 编写js代码
<script>
   /******
   * 1、引入angularjs
   * 2、发送请求
   * 3、显示数据
   *****/

   //定义一个模块
   var app = angular.module("pinyougou",[]);

   /*****
    * 定义一个controller
    * 发送http请求从后台获取数据
    ****/
   app.controller("brandcontroller",function($scope,$http){
      //创建一个方法
      //获取所有的品牌信息
      $scope.getpage=function(page,size){
         //发送请求获取数据
         $http.post("/brand/list.shtml?page="+page+"&size="+size).success(function(response){
            //集合数据
            $scope.list = response.list;
         });
      }
   });
</script>
4.3.4 循环显示表格数据
<tbody>
<tr ng-repeat="entity in list">
   <td><input  type="checkbox" ng-model="id" ></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>

4.3.5 初始化调用

<body ng-app="pinyougou" ng-controller="brandcontroller" ng-init="getpage(1,10)" class="hold-transition skin-red sidebar-mini">

5.1 需求分析

在品牌管理下方放置分页栏,实现分页功能

品优购(IDEA版)-第二天

5.2 后端代码

5.2.1 服务接口层

在pinyougou-sellergoods-interface的brandservice.java 增加方法定义

/***
 * 分页返回列表
 * @param pagenum
 * @param pagesize
 * @return
 */
public pageinfo<brand> getall(int pagenum, int pagesize);
5.2.2 服务实现层

在pinyougou-sellergoods-service的brandserviceimpl.java中实现该方法y:

public pageinfo<brand> getall(int pagenum, int pagesize) {
    //执行分页
    pagehelper.startpage(pagenum,pagesize);
    //list<brand> all = brandmapper.getallbrand();
    list<brand> all = brandmapper.selectall();

    pageinfo<brand> pageinfo = new pageinfo<brand>(all);
    return pageinfo;
}

pagehelper为mybatis分页插件

5.2.3 控制层

在pinyougou-manager-web工程的brandcontroller.java新增方法

/***
 * 分页查询数据
 * 获取json数据
 * @return
 */
@requestmapping(value = "/list")
public pageinfo<brand> list(@requestparam(value = "page", required = false, defaultvalue = "1") int page,
                            @requestparam(value = "size", required = false, defaultvalue = "10") int size) {
    return brandservice.getall(page, size);
}

5.3 前端代码控制层

5.3.1 html

在brand.html引入分页组件

<!--分页相关引入-->
<link rel="stylesheet" href="/plugins/angularjs/pagination.css">
<script src="/plugins/angularjs/pagination.js"></script>

构建app模块时引入pagination模块

//定义一个模块
var app = angular.module("pinyougou",["pagination"]); //引入分页模块

页面的表格下放置分页组件

<!--分页-->
<tm-pagination conf="paginationconf"></tm-pagination>
5.3.2 js代码

在brandcontroller中添加如下代码

/***
 * 分页控件配置
 * currentpage:当前页
 * totalitems:共有多少条记录
 * itemsperpage:每页显示多少条
 * perpageoptions:每页多少条选项条
 * onchange:参数发生变化时执行
 * */
$scope.paginationconf = {
   currentpage: 1,
   totalitems: 10,
   itemsperpage: 10,
   perpageoptions: [10, 20, 30, 40, 50],
   onchange: function(){
      $scope.reloadlist();//重新加载
   }
};
//重新加载
$scope.reloadlist=function(){
   $scope.getpage($scope.paginationconf.currentpage,$scope.paginationconf.itemsperpage);
}

在页面的body元素上去掉ng-init指令的调用

<body ng-app="pinyougou" ng-controller="brandcontroller" class="hold-transition skin-red sidebar-mini">
5.3.3 完整代码
<script>
   /******
    * 步骤分析:
    * 1、引入angularjs
    * 2、发送请求
    * 3、显示数据
    *****/
    //定义一个模块
   var app = angular.module("pinyougou",["pagination"]);

   /*****
    * 定义一个controller
    * 发送http请求从后台获取数据
    ****/
   app.controller("brandcontroller",function($scope,$http){
      /***
       * 分页控件配置
       * currentpage:当前页
       * totalitems:共有多少条记录
       * itemsperpage:每页显示多少条
       * perpageoptions:每页多少条选项条
       * onchange:参数发生变化时执行
       * */
      $scope.paginationconf = {
         currentpage: 1,
         totalitems: 10,
         itemsperpage: 10,
         perpageoptions: [10, 20, 30, 40, 50],
         onchange: function(){
            $scope.reloadlist();//重新加载
         }
      };

      //创建一个方法
      //获取所有的品牌信息
      $scope.getpage=function(page,size){
         //发送请求获取数据
         $http.post("/brand/list.shtml?page="+page+"&size="+size).success(function(response){
            //集合数据
            $scope.list = response.list;

            //分页数据
            $scope.paginationconf.totalitems=response.total;
         });
      }
      
      //重新加载
      $scope.reloadlist=function(){
         $scope.getpage($scope.paginationconf.currentpage,$scope.paginationconf.itemsperpage);
      }
   });
</script>
5.3.4 效果

品优购(IDEA版)-第二天

6.1 需求分析

实现品牌增加功能

品优购(IDEA版)-第二天

6.2 后端代码

6.2.1 控制层

在pinyougou-manager-web的brandcontroller中增加add方法,同时相应json数据。

/***
 * 增加品牌数据
 * @param brand
 * 响应数据:success
 *                  true:成功  false:失败
 *           message
 *                  响应的消息
 *
 */
@requestmapping(value = "/add",method = requestmethod.post)
public map<string,object> add(@requestbody brand brand){
    //存放响应消息
    map<string,object> datamap = new hashmap<string,object>();
    
    try {
        //执行增加
        int acount = brandservice.add(brand);

        if(acount>0){
            //增加成功
            datamap.put("success",true);
            datamap.put("message","增加品牌成功");
        }
    } catch (exception e) {
        e.printstacktrace();
        datamap.put("success",false);
        datamap.put("message","增加品牌失败");
    }
    return datamap;
}
6.2.2 服务接口层

在pinyougou-sellergoods-interface的brandservice.java新增方法定义

/***
 * 增加品牌信息
 * @param brand
 * @return
 */
int add(brand brand);
6.2.3 服务实现层

在com.pinyougou.sellergoods.service.impl的brandserviceimpl.java实现该方法

@override
public int add(brand brand) {
    return brandmapper.insertselective(brand);
}

6.3 前端代码

6.3.1 js代码
//添加品牌方法
$scope.save = function(){
   //发送http请求,执行增加
   $http.post("/brand/add.shtml",$scope.entity).success(function(response){
      //判断执行状态
      if(response.success){
         //重新加载新的数据
         $scope.reloadlist();
      }else{
         //打印错误消息
         alert(response.message);
      }
   });
}
6.3.2 html代码

绑定表单元素,我们用ng-model指令,绑定按钮的单击事件我们用ng-click

<!-- 编辑窗口 -->
<div class="modal fade" id="editmodal" tabindex="-1" role="dialog" aria-labelledby="mymodallabel" aria-hidden="true">
   <div class="modal-dialog" >
      <div class="modal-content">
         <div class="modal-header">
            <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
            <h3 id="mymodallabel">品牌编辑</h3>
         </div>
         <div class="modal-body">
            <table class="table table-bordered table-striped"  width="800px">
               <tr>
                  <td>品牌名称</td>
                  <td><input ng-model="entity.name" class="form-control" placeholder="品牌名称" >  </td>
               </tr>
               <tr>
                  <td>首字母</td>
                  <td><input ng-model="entity.firstchar"  class="form-control" placeholder="首字母">  </td>
               </tr>
            </table>
         </div>
         <div class="modal-footer">
            <button ng-click="save()" class="btn btn-success" data-dismiss="modal" aria-hidden="true">保存</button>
            <button class="btn btn-default" data-dismiss="modal" aria-hidden="true">关闭</button>
         </div>
      </div>
   </div>
</div>
6.3.3 效果

品优购(IDEA版)-第二天

6.4 增加缓存解决

为了每次打开窗口没有遗留上次的数据,我们可以修改新建按钮,对entity变量进行清空操作

<button ng-click="entity={}" type="button" class="btn btn-default" title="新建" data-toggle="modal" data-target="#editmodal" ><i class="fa fa-file-o"></i> 新建</button>

效果

品优购(IDEA版)-第二天

6.5 封装响应消息体

6.5.1 封装介绍

响应消息体我们写的是一个map,每次需要用到的时候,都要重复创建这个map对象,并重复给指定的key赋值,存在大量重复代码,而且每次key容易书写错,所以我们可以考虑封装成一个实体bean,名字叫result,每次直接new result()即可。

6.5.2 创建result

由于result可能会在很多项目中都会用到,所以我们可以考虑把它放到pinyougou-common项目中,在pinyougou-common中创建result类

package com.pinyougou.http;
import java.io.serializable;
public class result implements serializable {

    private boolean success;

    private string message;

    public result(boolean success, string message) {
        this.success = success;
        this.message = message;
    }

    public result(boolean success) {
        this.success = success;
    }

    public result(string message) {
        this.message = message;
    }

    public result() {
    }

    //get.. set.. tostring..
}
6.5.3 依赖关系分析

无论是哪个项目都直接或者间接依赖了pinyougou-pojo,所以可以让pojo依赖pinyougou-common,maven有依赖的传递性,则所有项目都会依赖pinyougou-common,而pinyougou-common主要用来写一些常用的工具包,所以任何项目依赖他都合情合理。

在pinyougou-pojo的pom.xml中加入依赖

<!--依赖pinyougou-common-->
<dependency>
    <artifactid>pinyougou-common</artifactid>
    <groupid>com.pinyougou</groupid>
    <version>1.0-snapshot</version>
</dependency>
6.5.4 修改controllerl

修改pinyougou-manager-web中的brandcontroller的add方法:

/***
 * 增加品牌数据
 * @param brand
 * 响应数据:success
 *                  true:成功  false:失败
 *           message
 *                  响应的消息
 *
 */
@requestmapping(value = "/add",method = requestmethod.post)
public result add(@requestbody brand brand){
    try {
        //执行增加
        int acount = brandservice.add(brand);

        if(acount>0){
            //增加成功
           return new result(true,"增加品牌成功");
        }
    } catch (exception e) {
        e.printstacktrace();
    }
    return new result(false,"增加品牌失败");
}

7.1 需求分析

点击列表的修改按钮,弹出窗口,修改数据后点“保存”执行保存操作,大概分为2个步骤。

第一:根据id查询出品牌数据,展示出来。

第二:根据用户修改保存数据。

品优购(IDEA版)-第二天

7.2 后端代码

7.2.1 控制层

在pinyougou-manager-web的brandcontroller中分别加入根据id查询和修改品牌的方法

/***
 * 修改品牌信息
 * @param brand
 * @return
 */
@requestmapping(value = "/update",method = requestmethod.post)
public result modify(@requestbody brand brand){
    try {
        //根据id修改品牌信息
        int mcount = brandservice.updatebrandbyid(brand);
        if(mcount>0){
            return new result(true,"品牌修改成功");
        }
    } catch (exception e) {
        e.printstacktrace();
    }
    return new result(false,"品牌修改失败");
}

/***
 * 根据id查询品牌信息
 * @param id
 * @return
 */
@requestmapping(value = "/{id}",method = requestmethod.get)
public brand getbyid(@pathvariable(value = "id")long id){
    //根据id查询品牌信息
    brand brand = brandservice.getonebyid(id);
    return brand;
}
7.2.2 服务接口层

在pinyougou-sellergoods-interface的brandservice.java新增方法定义

/***
 * 根据id查询品牌信息
 * @param id
 * @return
 */
brand getonebyid(long id);

/***
 * 根据id修改品牌信息
 * @param brand
 * @return
 */
int updatebrandbyid(brand brand);
7.2.3 服务实现层

在pinyougou-sellergoods-service的brandserviceimpl.java新增方法实现

@override
public brand getonebyid(long id) {
    return brandmapper.selectbyprimarykey(id);
}

@override
public int updatebrandbyid(brand brand) {
    return brandmapper.updatebyprimarykeyselective(brand);
}

7.3 前端代码

7.3.1 实现数据查询

增加js代码;

//根据id查询品牌信息
$scope.getbyid=function(id){
   $http.get("/brand/"+id+".shtml").success(function(response){
      //将后台的数据绑定到前台
      $scope.entity=response;
   });
}

修改列表中的“修改”按钮,调用此方法执行查询实体的操作

<button ng-click="getbyid(entity.id)" type="button" class="btn bg-olive btn-xs" data-toggle="modal" data-target="#editmodal">修改</button>
7.3.2 保存数据

修改js的save方法

//添加或者修改品牌方法
$scope.save = function(){
   //发送http请求,执行增加
   var url="/brand/add.shtml";
   if($scope.entity.id!=null){
      //执行修改数据
      url="/brand/update.shtml";
   }
   //执行操作
   $http.post(url,$scope.entity).success(function(response){
      //判断执行状态
      if(response.success){
         //重新加载新的数据
         $scope.reloadlist();
      }else{
         //打印错误消息
         alert(response.message);
      }
   });
}

8.1 需求分析

点击列表前的复选框,点击删除按钮,删除选中的品牌。

品优购(IDEA版)-第二天

8.2 后端代码

8.2.1 控制层

在brandcontroller中加入删除方法

/***
 * 根据id批量删除
 * @param ids
 * @return
 */
@requestmapping(value = "/delete")
public result delete(@requestbody list<long> ids){
    try {
        //根据id删除数据
        int dcount = brandservice.deletebyids(ids);

        if(dcount>0){
            return new result(true,"品牌删除成功");
        }
    } catch (exception e) {
        e.printstacktrace();
    }
    return new result(false,"品牌删除失败");
}
8.2.2 服务接口层

在pinyougou-sellergoods-interface的brandservice.java接口定义方法

/***
 * 根据id批量删除品牌信息
 * @param ids
 * @return
 */
int deletebyids(list<long> ids);
8.2.3 服务实现层

在pinyougou-sellergoods-service的brandserviceimpl.java实现该方法

@override
public int deletebyids(list<long> ids) {
    //创建example,来构建根据id删除数据
    example example = new example(brand.class);
    example.criteria criteria = example.createcriteria();

    //所需的sql语句类似 delete from tb_brand where id in(1,2,5,6)
    criteria.andin("id",ids);
    return brandmapper.deletebyexample(example);
}

8.3 前端代码

8.3.1 js

主要思路:我们需要定义一个用于存储选中id的数组,当我们点击复选框后判断是选择还是取消选择,如果是选择就加到数组中,如果是取消选择就从数组中移除。在点击删除按钮时需要用到这个存储了id的数组。

这里我们补充一下js的关于数组操作的知识

数组的push方法:向数组中添加元素

数组的splice方法:从数组的指定位置移除指定个数的元素 ,参数1为位置 ,参数2位移除的个数

复选框的checked属性:用于判断是否被选中:

//定义一个变量,用于存储要删除的品牌id
$scope.selectids=[];

//判断当前点击是否要删除对应品牌
$scope.updateselection=function($event,id){
   //判断当前操作是否是选中复选框
   if($event.target.checked){
      //如果选中复选框,则将该id增加到数组中去
      $scope.selectids.push(id);
   }else{
      //取消删除,则从数组中移除该id
      var idx = $scope.selectids.indexof(id);   //获取id对应的下标
      $scope.selectids.splice(idx, 1);//删除对应下标的数据,1表示删除的数量
   }
}


//批量删除
$scope.delete=function(){
   $http.post("/brand/delete.shtml",$scope.selectids).success(function(response){
      //判断删除状态
      if(response.success){
         $scope.reloadlist();
      }else{
         alert(response.message);
      }
   });
}
8.3.2 html

修改列表的复选框

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

修改删除按钮

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

9.1 需求分析

实现品牌条件查询功能,输入品牌名称、首字母后查询,并分页。

9.2 后端代码

9.2.1 控制层

修改brandcontroller里面的list方法

/***
 * 分页查询数据
 * 获取json数据
 * @return
 */
@requestmapping(value = "/list")
public pageinfo<brand> list(@requestbody brand brand,@requestparam(value = "page", required = false, defaultvalue = "1") int page,
                            @requestparam(value = "size", required = false, defaultvalue = "10") int size) {
    return brandservice.getall(brand,page, size);
}
9.2.2 服务接口层

在pinyougou-sellergoods-interface工程的brandservice.java方法增加方法定义

/***
 * 分页返回列表
 * @param pagenum
 * @param pagesize
 * @return
 */
public pageinfo<brand> getall(brand brand,int pagenum, int pagesize);
9.2.3 服务实现层

在pinyougou-sellergoods-service工程brandserviceimpl.java实现该方法

public pageinfo<brand> getall(brand brand,int pagenum, int pagesize) {
    //执行分页
    pagehelper.startpage(pagenum,pagesize);

    //条件查询
    example example = new example(brand.class);
    example.criteria criteria = example.createcriteria();

    if(brand!=null){
        //名字模糊搜索
        if(stringutils.isnotblank(brand.getname())){
            criteria.andlike("name","%"+brand.getname()+"%");
        }

        //首字母搜索
        if(stringutils.isnotblank(brand.getfirstchar())){
            criteria.andequalto("firstchar",brand.getfirstchar());
        }
    }
    //执行查询
    list<brand> all = brandmapper.selectbyexample(example);
    pageinfo<brand> pageinfo = new pageinfo<brand>(all);


    //======================================================================
    //list<brand> all = brandmapper.getallbrand();
    /*list<brand> all = brandmapper.selectall();

    pageinfo<brand> pageinfo = new pageinfo<brand>(all);*/
    return pageinfo;
}

9.3 前端代码

修改pinyougou-manager-web的brand.html

9.3.1 增加搜索块

增加搜索代码块,并绑定一个搜索对象。同时增加点击事件,调用搜索方法。

<div class="has-feedback">
   品牌名称:<input ng-model="searchentity.name">
   品牌首字母:<input ng-model="searchentity.firstchar">
   <button ng-click="getpage(1,10)" class="btn btn-default">查询</button>
</div>
9.3.2 js

定义一个搜索对象,和搜索条件那里保持一致,并修改原来搜索方法。

//条件查询对象定义
$scope.searchentity={};

//获取所有的品牌信息
$scope.getpage=function(page,size){
   //发送请求获取数据
   $http.post("/brand/list.shtml?page="+page+"&size="+size,$scope.searchentity).success(function(response){
      //集合数据
      $scope.list = response.list;

      //分页数据
      $scope.paginationconf.totalitems=response.total;
   });
}
9.3.3 效果

品优购(IDEA版)-第二天
第二天需要的资料文件