# 简单示例

本节以一个简单的分页查询演示基本的代码构成。

## 数据对象（实体）

{% code title="Foo.java" %}

```java
package com.example.demo.entity;

import lombok.Data;

import javax.persistence.*;

@Entity
@Data
public class Foo {

    @Id
    @GeneratedValue
    private Long id;

    private String name;

    @ManyToOne
    private Bar bar;
}
```

{% endcode %}

{% code title="Bar.java" %}

```java
package com.example.demo.entity;

import lombok.Data;
import lombok.ToString;

import javax.persistence.*;
import java.util.List;

@Entity
@Data
@ToString(exclude = "fooList")
public class Bar {

    @Id
    @GeneratedValue
    private Long id;

    private String name;

    @OneToMany
    private List<Foo> fooList;
}
```

{% endcode %}

{% hint style="info" %}
除基本的JPA注解之外，使用lombok提供的`@Data`注解简化POJO配置。注意使用`@ToString`注解排除可能造成循环依赖的字段。
{% endhint %}

## 数据传输对象（DTO)

{% code title="FooDto.java" %}

```java
package com.example.demo.dto;

import com.example.demo.entity.Bar;
import com.taocares.commons.beans.annotation.Nested;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

@Data
@ApiModel("Foo数据传输对象")
public class FooDto {

    @ApiModelProperty("唯一标识")
    private Long id;

    @ApiModelProperty("名字")
    private String name;

    @ApiModelProperty("关联的Bar")
    @Nested(thisClass = BarDto.class, thatClass = Bar.class)
    private BarDto bar;
}

```

{% endcode %}

{% code title="BarDto.java" %}

```java
package com.example.demo.dto;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

@Data
@ApiModel("Bar数据传输对象")
public class BarDto {

    @ApiModelProperty("唯一标识")
    private Long id;

    @ApiModelProperty("名字")
    private String name;
}
```

{% endcode %}

{% hint style="info" %}
针对数据传输的需求，配置和实体字段的映射关系，定义Swagger数据模型。使用lombok简化代码。
{% endhint %}

## 数据查询对象（QO）

{% code title="FooQo.java" %}

```java
package com.example.demo.qo;

import com.taocares.commons.jpa.ConditionType;
import com.taocares.commons.jpa.QueryCondition;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

@Data
@ApiModel("Foo查询条件对象")
public class FooQo {

    @ApiModelProperty(value = "Foo的名字", notes = "模糊匹配开始")
    @QueryCondition(type = ConditionType.STARTS_WITH)
    private String name;

    @ApiModelProperty(value = "Bar的名字", notes = "严格匹配")
    @QueryCondition(targetField = "bar.name")
    private String barName;
}
```

{% endcode %}

{% hint style="info" %}
根据查询需求定义数据查询对象，定义Swagger数据模型。使用lombok简化代码。
{% endhint %}

## 数据持久层（Repository）

{% code title="FooRepository.java" %}

```java
package com.example.demo.repository;

import com.example.demo.entity.Foo;
import com.taocares.commons.jpa.RepositoryEnhancer;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;

public interface FooRepository extends JpaRepository<Foo, Long>, JpaSpecificationExecutor<Foo>, RepositoryEnhancer {
}
```

{% endcode %}

{% hint style="info" %}
实现`JpaRepository`和`JpaSpecificationExecutor`接口即可，如果需要自定义查询语句，只需额外实现`RepositoryEnhancer`接口即可。
{% endhint %}

## 业务逻辑层（Service）

{% code title="FooService.java" %}

```java
package com.example.demo.service;

import com.example.*;
import com.taocares.commons.beans.BeanUtils;
import com.taocares.commons.jpa.SpecificationFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.*;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class FooService {

    @Autowired
    private FooRepository fooRepository;

    public Page<FooDto> findAll(FooQo fooQo, Pageable pageable) {
        Specification<Foo> specification = SpecificationFactory.getSpecification(fooQo);
        Page<Foo> page = fooRepository.findAll(specification, pageable);
        List<FooDto> dtoList = BeanUtils.copyProperties(page.getContent(), FooDto.class);
        return new PageImpl<>(dtoList, pageable, page.getTotalElements());
    }
}
```

{% endcode %}

{% hint style="info" %}
进行业务逻辑操作
{% endhint %}

## 请求控制层（Controller）

{% code title="FooController.java" %}

```java
package com.example.demo.controller;

import com.example.demo.*;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.web.*;

@RestController
@RequestMapping("/foos")
@Slf4j
@Api(tags = "Foo CRUD服务")
public class FooController {

    @Autowired
    private FooService fooService;

    @GetMapping("/")
    @ApiOperation("根据条件分页查询结果")
    public Page<FooDto> findAll(FooQo fooQo, Pageable pageable) {
        log.debug("Query Object: {}; pageable: {}", fooQo, pageable);
        return fooService.findAll(fooQo, pageable);
    }
}
```

{% endcode %}

{% hint style="info" %}
映射HTTP请求，使用Swagger定义接口
{% endhint %}
