一 项目介绍

项目整体架构

项目微服务化 微服务工程搭建_spring

技术架构

项目微服务化 微服务工程搭建_项目微服务化_02

项目结构

项目微服务化 微服务工程搭建_maven_03


结构说明:

changgou_gateway
网关模块,根据网站的规模和需要,可以将综合逻辑相关的服务用网关路由组合到一起。在这里还可以做鉴权和限流相关操作。

changgou_service
微服务模块,该模块用于存放所有独立的微服务工程。

changgou_service_api
对应工程的JavaBean、Feign、以及Hystrix配置,该工程主要对外提供依赖。

changgou_transaction_fescar
分布式事务模块,将分布式事务抽取到该工程中,任何工程如需要使用分布式事务,只需依赖该工程即可。

changgou_web
web服务工程,对应功能模块如需要调用多个微服务,可以将他们写入到该模块中,例如网站后台、网站前台等

二 框架搭建

2.1 父工程搭建

2.1.1 一级父工程搭建

从上边可以看出来,有很多微服务项目,所有我们需要为这些微服务搭建一个父工程;创建父工程 changgou_parent ,pom.xml文件中增加配置

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.changgou</groupId>
    <artifactId>changgou_parent</artifactId>
    <packaging>pom</packaging>
    <version>1.0-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.4.RELEASE</version>
    </parent>

    <properties>
        <skipTests>true</skipTests>
    </properties>

    <!--依赖包-->
    <dependencies>
        <!--测试包-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Greenwich.SR1</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
</project>

删除父工程里的src文件夹(因为是父工程,不写代码,只提供依赖,所以删除src目录)

2.1.2 二级父工程模块搭建

创建changgou_gateway、changgou_service、changgou_service_api、changgou_web工程,工程全部为pom工程,同样,将所有工程的src文件删除。

2.2 Eureka微服务搭建

创建模块changgou_eureka

2.2.1 pom.xml引入依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>changgou_parent</artifactId>
        <groupId>com.changgou</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>changgou_eureka</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
    </dependencies>
</project>

2.2.2 appliation.yml配置

server:
  port: 6868
eureka:
  client:
    register-with-eureka: false #是否将自己注册到eureka中
    fetch-registry: false #是否从eureka中获取信息
    service-url:
      defaultZone: http://127.0.0.1:${server.port}/eureka/

2.2.3 启动类配置

创建包com.changgou.eureka 包下创建启动类

@SpringBootApplication
@EnableEurekaServer
public class EurekaApplication {
    public static void main(String[] args) {
        SpringApplication.run(EurekaApplication.class);
    }
}

2.3 公共模块搭建

2.3.1 全局公共模块

  1. 创建公共子模块changgou_common,pom.xml引入依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>changgou_parent</artifactId>
        <groupId>com.changgou</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>changgou_common</artifactId>
    <dependencies>
        <!--web起步依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- redis 使用-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.51</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
    </dependencies>
</project>

公共子模块引入这些依赖后,其他微服务引入changgou_common后也自动引入了这些依赖

  1. 常用对象
    创建com.changgou.entity包 ,包下建立类Result用于微服务返回结果给前端
/**
 * 返回结果实体类
 */
public class Result {

    private boolean flag;//是否成功
    private Integer code;//返回码
    private String message;//返回消息

    private Object data;//返回数据

    public Result(boolean flag, Integer code, String message, Object data) {
        this.flag = flag;
        this.code = code;
        this.message = message;
        this.data = data;
    }

    public Result(boolean flag, Integer code, String message) {
        this.flag = flag;
        this.code = code;
        this.message = message;
    }

    public Result() {
        this.flag = true;
        this.code = StatusCode.OK;
        this.message = "执行成功";
    }

    // getter and setter.....
}

建立类用于承载分页的数据结果(该项目不使用这个分页,只做了解)

/**
 * 分页结果类
 */
public class PageResult<T> {

    private Long total;//总记录数
    private List<T> rows;//记录

    public PageResult(Long total, List<T> rows) {
        this.total = total;
        this.rows = rows;
    }

    public PageResult() {
    
    }

    //getter and setter ......
}

创建返回状态码实体类

/**
 * 返回码
 */
public class StatusCode {

    public static final int OK=20000;//成功
    public static final int ERROR =20001;//失败
    public static final int LOGINERROR =20002;//用户名或密码错误
    public static final int ACCESSERROR =20003;//权限不足
    public static final int REMOTEERROR =20004;//远程调用失败
    public static final int REPERROR =20005;//重复操作
}
  1. 生成id工具类(推特的工具,每秒可以生成26万个不重复的ID)
package com.changgou.util;

import java.lang.management.ManagementFactory;
import java.net.InetAddress;
import java.net.NetworkInterface;

/**
 * <p>名称:IdWorker.java</p>
 * <p>描述:分布式自增长ID</p>
 * <pre>
 *     Twitter的 Snowflake JAVA实现方案  每秒可以生成26万个不重复的ID
 * </pre>
 * 核心代码为其IdWorker这个类实现,其原理结构如下,我分别用一个0表示一位,用—分割开部分的作用:
 * 1||0---0000000000 0000000000 0000000000 0000000000 0 --- 00000 ---00000 ---000000000000
 * 在上面的字符串中,第一位为未使用(实际上也可作为long的符号位),接下来的41位为毫秒级时间,
 * 然后5位datacenter标识位,5位机器ID(并不算标识符,实际是为线程标识),
 * 然后12位该毫秒内的当前毫秒内的计数,加起来刚好64位,为一个Long型。
 * 这样的好处是,整体上按照时间自增排序,并且整个分布式系统内不会产生ID碰撞(由datacenter和机器ID作区分),
 * 并且效率较高,经测试,snowflake每秒能够产生26万ID左右,完全满足需要。
 * <p>
 * 64位ID (42(毫秒)+5(机器ID)+5(业务编码)+12(重复累加))
 *
 * @author Polim
 */
public class IdWorker {
    // 时间起始标记点,作为基准,一般取系统的最近时间(一旦确定不能变动)
    private final static long twepoch = 1288834974657L;
    // 机器标识位数
    private final static long workerIdBits = 5L;
    // 数据中心标识位数
    private final static long datacenterIdBits = 5L;
    // 机器ID最大值
    private final static long maxWorkerId = -1L ^ (-1L << workerIdBits);
    // 数据中心ID最大值
    private final static long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
    // 毫秒内自增位
    private final static long sequenceBits = 12L;
    // 机器ID偏左移12位
    private final static long workerIdShift = sequenceBits;
    // 数据中心ID左移17位
    private final static long datacenterIdShift = sequenceBits + workerIdBits;
    // 时间毫秒左移22位
    private final static long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;

    private final static long sequenceMask = -1L ^ (-1L << sequenceBits);
    /* 上次生产id时间戳 */
    private static long lastTimestamp = -1L;
    // 0,并发控制
    private long sequence = 0L;

    private final long workerId;
    // 数据标识id部分
    private final long datacenterId;

    public IdWorker(){
        this.datacenterId = getDatacenterId(maxDatacenterId);
        this.workerId = getMaxWorkerId(datacenterId, maxWorkerId);
    }
    /**
     * @param workerId
     *            工作机器ID
     * @param datacenterId
     *            序列号
     */
    public IdWorker(long workerId, long datacenterId) {
        if (workerId > maxWorkerId || workerId < 0) {
            throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));
        }
        if (datacenterId > maxDatacenterId || datacenterId < 0) {
            throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId));
        }
        this.workerId = workerId;
        this.datacenterId = datacenterId;
    }
    /**
     * 获取下一个ID
     *
     * @return
     */
    public synchronized long nextId() {
        long timestamp = timeGen();
        if (timestamp < lastTimestamp) {
            throw new RuntimeException(String.format("Clock moved backwards.  Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
        }

        if (lastTimestamp == timestamp) {
            // 当前毫秒内,则+1
            sequence = (sequence + 1) & sequenceMask;
            if (sequence == 0) {
                // 当前毫秒内计数满了,则等待下一秒
                timestamp = tilNextMillis(lastTimestamp);
            }
        } else {
            sequence = 0L;
        }
        lastTimestamp = timestamp;
        // ID偏移组合生成最终的ID,并返回ID
        long nextId = ((timestamp - twepoch) << timestampLeftShift)
                | (datacenterId << datacenterIdShift)
                | (workerId << workerIdShift) | sequence;

        return nextId;
    }

    private long tilNextMillis(final long lastTimestamp) {
        long timestamp = this.timeGen();
        while (timestamp <= lastTimestamp) {
            timestamp = this.timeGen();
        }
        return timestamp;
    }

    private long timeGen() {
        return System.currentTimeMillis();
    }

    /**
     * <p>
     * 获取 maxWorkerId
     * </p>
     */
    protected static long getMaxWorkerId(long datacenterId, long maxWorkerId) {
        StringBuffer mpid = new StringBuffer();
        mpid.append(datacenterId);
        String name = ManagementFactory.getRuntimeMXBean().getName();
        if (!name.isEmpty()) {
            /*
             * GET jvmPid
             */
            mpid.append(name.split("@")[0]);
        }
        /*
         * MAC + PID 的 hashcode 获取16个低位
         */
        return (mpid.toString().hashCode() & 0xffff) % (maxWorkerId + 1);
    }

    /**
     * <p>
     * 数据标识id部分
     * </p>
     */
    protected static long getDatacenterId(long maxDatacenterId) {
        long id = 0L;
        try {
            InetAddress ip = InetAddress.getLocalHost();
            NetworkInterface network = NetworkInterface.getByInetAddress(ip);
            if (network == null) {
                id = 1L;
            } else {
                byte[] mac = network.getHardwareAddress();
                id = ((0x000000FF & (long) mac[mac.length - 1])
                        | (0x0000FF00 & (((long) mac[mac.length - 2]) << 8))) >> 6;
                id = id % (maxDatacenterId + 1);
            }
        } catch (Exception e) {
            System.out.println(" getDatacenterId: " + e.getMessage());
        }
        return id;
    }


    public static void main(String[] args) {

        IdWorker idWorker=new IdWorker(0,0);

        for(int i=0;i<10000;i++){
            long nextId = idWorker.nextId();
            System.out.println(nextId);
        }
    }
}

2.3.2 数据访问层公共模块搭建

创建公共模块changgou_common_db ,删除src文件夹,pom文件引入依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>changgou_parent</artifactId>
        <groupId>com.changgou</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>changgou_common_db</artifactId>
    <dependencies>
        <dependency>
            <groupId>com.changgou</groupId>
            <artifactId>changgou_common</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <!--通用mapper起步依赖,以后不需要写任何sql了-->
        <dependency>
            <groupId>tk.mybatis</groupId>
            <artifactId>mapper-spring-boot-starter</artifactId>
            <version>2.0.4</version>
        </dependency>
        <!--MySQL数据库驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <!--mybatis分页插件-->
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper-spring-boot-starter</artifactId>
            <version>1.2.3</version>
        </dependency>
    </dependencies>
</project>

这个公共模块是连接mysql数据库的公共微服务模块,所以需要连接mysql的微服务都继承自此工程。

2.4 商品微服务搭建

2.4.1 商品微服务API工程搭建

  1. changgou_service_api 引入依赖
<dependency>
     <groupId>org.springframework.cloud</groupId>
     <artifactId>spring-cloud-starter-openfeign</artifactId>
     <scope>provided</scope>
</dependency>
<dependency>
     <groupId>javax.persistence</groupId>
     <artifactId>persistence-api</artifactId>
     <version>1.0</version>
     <scope>compile</scope>
</dependency>
  1. changgou_service_api 下创建changgou_service_goods_api 子模块

2.4.2 Service层微服务工程搭建

  1. changgou_service下创建changgou_service_goods子模块 ,pom.xml引入依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>changgou_service</artifactId>
        <groupId>com.changgou</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>changgou_service_goods</artifactId>

    <dependencies>
        <dependency>
            <groupId>com.changgou</groupId>
            <artifactId>changgou_common_db</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
		<dependency>
            <groupId>com.changgou</groupId>
            <artifactId>changgou_service_goods_api</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
     </dependencies>
</project>
  1. 创建配置文件application.yml
server:
  port: 9011
spring:
  application:
    name: goods
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://192.168.200.128:3306/changgou_goods?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
    username: root
    password: admin
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:6868/eureka
  instance:
    prefer-ip-address: true
feign:
  hystrix:
    enabled: true
    
#hystrix 配置
hystrix:
  command:
    default:
      execution:
        timeout:
        #如果enabled设置为false,则请求超时交给ribbon控制
          enabled: true
        isolation:
          strategy: SEMAPHORE
# 由于使用MyBatis通用Mapper,实现了0sql,所以这里不写MyBatis配置了
  1. 创建包com.changgou 包下创建启动类
@SpringBootApplication
//开启Eureka客户端
@EnableEurekaClient
//开启通用Mapper包扫描,注意导入的包是tk下的包
@MapperScan(basePackages = {"com.changgou.goods.dao"})
public class GoodsApplication {
    public static void main(String[] args) {
        SpringApplication.run(GoodsApplication.class);
    }
}

三 商品微服务-品牌增删改查

3.1 需求分析

创建商品微服务,实现对品牌表的增删改查功能。具体包括

(1)查询全部列表数据

(2)根据ID查询实体数据

(3)增加

(4)修改

(5)删除

(6)条件查询

(7)分页查询

(8)分页+条件查询

(9)公共异常处理

3.2 表结构分析

字段名称

字段含义

字段类型

字段长度

备注

id

品牌id

INT

name

品牌名称

VARCHAR

image

品牌图片地址

VARCHAR

letter

品牌的首字母

CHAR

seq

排序

INT

3.3 代码实现

3.3.1 品牌列表

  1. (1)在changgou_service_goods_api创建com.changgou.pojo包,包下创建Brand实体类
@Table(name="tb_brand")
public class Brand implements Serializable{
	@Id
	private Integer id;//品牌id
	private String name;//品牌名称
	private String image;//品牌图片地址
	private String letter;//品牌的首字母
	private Integer seq;//排序
	
	// getter and setter  .....(省略)
}

@Table和@Id都是JPA注解,@Table用于配置表与实体类的映射关系,@Id用于标识主键属性。

  1. Dao创建
    在changgou_service_goods微服务下创建com.changgou.goods.dao.BrandMapper接口,代码如下:
public interface BrandMapper extends Mapper<Brand> {
}

使用通用Mapper,不需要写sql语句;继承了Mapper接口,就自动实现了增删改查的常用方法,注意,Mapper接口导入的包是tk下的包(记的在启动类上加@MapperScan注解)

项目微服务化 微服务工程搭建_maven_04

  1. 业务层
    创建com.changgou.goods.service.BrandService接口,代码如下:
public interface BrandService {

    /***
     * 查询所有品牌
     * @return
     */
  public  List<Brand> findAll();
}

创建com.changgou.goods.service.impl包,包下创建服务实现类 BrandServiceImpl,代码如下:

@Service
public class BrandServiceImpl implements BrandService {
    
    @Autowired
    private BrandMapper brandMapper;
    
    @Override
    public List<Brand> findAll() {
        return brandMapper.selectAll();
    }   
}
  1. 控制层

控制层 com.changgou.goods包下创建controller包 ,包下创建类

@RestController
@RequestMapping("/brand")
/**
*跨域:A域名访问B域名的数据
*  域名或者请求端口或者协议不一致的时候,就是跨域了
*  域名不一致:www.baidu.com下的html,访问www.souhu.com下的任何资源
*  协议不一样:https://www.baidu.com 访问 http://www.baidu.com
*  端口不一样:www.baidu.com:8081 访问 www.baidu.com:8082
*  如果不加这个注解的话,跨域是访问不了的
**/
@CrossOrigin
public class BrandController {

    @Autowired
    private BrandService brandService;

    @GetMapping
    public Result findAll(){
        List<Brand> brandList = brandService.findAll();
        return new Result(true, StatusCode.OK,"查询成功",brandList) ;
    }
}

3.3.2 根据ID查询品牌

  1. 业务层接口

修改com.changgou.goods.service.BrandService接口,添加根据ID查询品牌数据方法,代码如下:

/**
 * 根据ID查询
 * @param id
 * @return
 */
public Brand findById(Integer id);
  1. 业务层实现
    修改com.changgou.goods.service.impl.BrandServiceImpl新增方法,代码如下:
/**
 * 根据ID查询
 * @param id
 * @return
 */
@Override
public Brand findById(Integer id){
    return  brandMapper.selectByPrimaryKey(id);
}
  1. 控制层
    BrandController新增方法
/***
 * 根据ID查询品牌数据
 * @param id
 * @return
 */
@GetMapping("/{id}")
public Result findById(@PathVariable Integer id){
    Brand brand = brandService.findById(id);
    return new Result(true,StatusCode.OK,"查询成功",brand);
}

3.3.3 新增品牌

  1. 业务层接口 修改com.changgou.goods.service.BrandService,新增方法
/***
 * 新增品牌
 * @param brand
 */
public void add(Brand brand);
  1. 业务层实现 修改com.changgou.goods.service.impl.BrandServiceImpl,新增增加品牌方法代码如下:
/**
 * 增加
 * @param brand
 */
@Override
public void add(Brand brand){
   //注意:使用insertSelective方法,不使用insert方法,因为insertSelective会忽略实体类里的空值属性(哪些属性有值就插入哪些属性值),而insert会将没有值的属性置为null后插入数据库里
    brandMapper.insertSelective(brand);
}
  1. 控制层 BrandController新增方法
/***
 * 新增品牌数据
 * @param brand
 * @return
 */
@PostMapping
public Result add(@RequestBody Brand brand){
    brandService.add(brand);
    return new Result(true,StatusCode.OK,"添加成功");
}

3.3.4 修改品牌

  1. 业务层接口
    需改com.changgou.goods.service.BrandService,添加修改品牌方法,代码如下:
/***
 * 修改品牌数据
 * @param brand
 */
public void update(Brand brand);
  1. 业务层实现 修改com.changgou.goods.service.impl.BrandServiceImpl,添加修改品牌方法,代码如下:
/**
 * 修改
 * @param brand
 */
@Override
public void update(Brand brand){
    brandMapper.updateByPrimaryKeySelective(brand);
}
  1. 控制层
    BrandController新增方法
/***
 * 修改品牌数据
 * @param brand
 * @param id
 * @return
 */
@PutMapping(value="/{id}")
public Result update(@RequestBody Brand brand,@PathVariable Integer id){
    brand.setId(id);
    brandService.update(brand);
    return new Result(true,StatusCode.OK,"修改成功");
}

3.3.5 删除品牌

  1. 业务层接口
    修改com.changgou.goods.service.BrandService,添加删除品牌方法,代码如下:
/***
 * 删除品牌
 * @param id
 */
public void delete(Integer id);
  1. 业务层实现 修改com.changgou.goods.service.impl.BrandServiceImpl,新增删除品牌方法,代码如下:
/**
 * 删除
 * @param id
 */
@Override
public void delete(Integer id){
    brandMapper.deleteByPrimaryKey(id);
}
  1. 控制层 BrandController新增方法
/***
 * 根据ID删除品牌数据
 * @param id
 * @return
 */
@DeleteMapping(value = "/{id}" )
public Result delete(@PathVariable Integer id){
    brandService.delete(id);
    return new Result(true,StatusCode.OK,"删除成功");
}

3.3.6 品牌列表条件查询

  1. 业务层接口
    修改com.changgou.goods.service.BrandService,增加根据条件搜索品牌方法,代码如下:
/***
 * 多条件搜索品牌方法
 * @param searchMap
 * @return
 */
public List<Brand> findList(Map<String, Object> searchMap);
  1. 业务层实现
    修改com.changgou.goods.service.impl.BrandServiceImpl,添加根据多条件搜索品牌方法的实现,代码如下:
/**
 * 条件查询
 * @param searchMap
 * @return
 */
@Override
public List<Brand> findList(Map<String, Object> searchMap){
	Example example = createExample(searchMap);
	return brandMapper.selectByExample(example);
}

/**
 * 构建查询对象
 * @param searchMap
 * @return
 */
private Example createExample(Map<String, Object> searchMap){
	Example example=new Example(Brand.class);
	//条件构造器
	Example.Criteria criteria = example.createCriteria();
	if(searchMap!=null){
		// 品牌名称
		if(searchMap.get("name")!=null && !"".equals(searchMap.get("name"))){
			criteria.andLike("name","%"+searchMap.get("name")+"%");
		}
		// 品牌的首字母
		if(searchMap.get("letter")!=null && !"".equals(searchMap.get("letter"))){
			criteria.andEqualTo("letter",searchMap.get("letter"));
		}
	}
	return example;
}
  1. 控制层 BrandController新增方法
/***
 * 多条件搜索品牌数据
 * @param searchMap
 * @return
 */
@GetMapping(value = "/search" )
public Result findList(@RequestParam Map searchMap){
	List<Brand> list = brandService.findList(searchMap);
	return new Result(true,StatusCode.OK,"查询成功",list);
}

3.3.7 品牌列表分页查询

  1. 业务层接口
    修改com.changgou.goods.service.BrandService添加分页方法,代码如下:
/***
 * 分页查询
 * @param page 当前页
 * @param size 每页显示的条数
 * @return
 */
public PageInfo<Brand> findPage(int page, int size);
  1. 业务层实现
    修改com.changgou.goods.service.impl.BrandServiceImpl添加分页方法实现,代码如下:
@Override
public PageInfo<Brand> findPage(int page, int size){
   PageHelper.startPage(page,size);
   //由于上边使用了PageHelper分页,所以下边必须是一个集合类型的数
   List<Brand> brands = brandMapper.selectAll();
   return  new PageInfo<Brand>(brands);
}
  1. 控制层 BrandController新增方法
/***
 * 分页搜索实现
 * @param searchMap
 * @param page
 * @param size
 * @return
 */
@GetMapping(value = "/search/{page}/{size}" )
public Result findPage(@PathVariable  int page, @PathVariable  int size){
	PageInfo<Brand> pageList = brandService.findPage( page, size);
      
    return new Result<PageInfo<Brand>>(true,StatusCode.OK,"分页查询成功",pageList);
}

其中,PageResult如下

package com.changgou.entity;
import java.util.List;
public class PageResult<T> {

    private Long total;//总记录数
    private List<T> rows;//记录

    public PageResult(Long total, List<T> rows) {
        this.total = total;
        this.rows = rows;
    }

    public PageResult() {
    }

    public Long getTotal() {
        return total;
    }

    public void setTotal(Long total) {
        this.total = total;
    }

    public List<T> getRows() {
        return rows;
    }

    public void setRows(List<T> rows) {
        this.rows = rows;
    }
}

3.3.8 品牌列表条件+分页查询

  1. 业务层接口
    修改com.changgou.goods.service.BrandService,增加多条件分页查询方法,代码如下:
/***
 * 多条件分页查询
 * @param searchMap
 * @param page
 * @param size
 * @return
 */
Page<Brand> findPage(Map<String, Object> searchMap, int page, int size);
  1. 业务层实现
    修改com.changgou.goods.service.impl.BrandServiceImpl,添加多条件分页查询方法代码如下:
/**
 * 条件+分页查询
 * @param searchMap 查询条件
 * @param page 页码
 * @param size 页大小
 * @return 分页结果
 */
@Override
public Page<Brand> findPage(Map<String,Object> searchMap, int page, int size){
    PageHelper.startPage(page,size);
    Example example = createExample(searchMap);
    return (Page<Brand>)brandMapper.selectByExample(example);
}
  1. 控制层
    BrandController新增方法
/***
 * 分页搜索实现
 * @param searchMap
 * @param page
 * @param size
 * @return
 */
@PostMapping(value = "/search/{page}/{size}" )
public Result findPage(@RequestParam Map searchMap, @PathVariable  int page, @PathVariable  int size){
	Page<Brand> pageList = brandService.findPage(searchMap, page, size);
	PageResult pageResult=new PageResult(pageList.getTotal(),pageList.getResult());
	return new Result(true,StatusCode.OK,"查询成功",pageResult);
}

3.3.9 公共异常处理

为了使我们的代码更容易维护,我们创建一个类集中处理异常

在com.changgou.goods.controller包下创建公共异常处理类BaseExceptionHandler

/**
 * 统一异常处理类
 */
@ControllerAdvice
public class BaseExceptionHandler {
	
    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    public Result error( Exception e) {
        e.printStackTrace();        
        return new Result(false, StatusCode.ERROR, e.getMessage());
    }
}

此时,controller层报错的时候,就会返回json格式的错误信息数据给前台;