# 快速上手

本教程将通过为如下角色表构建RESTful服务的完整过程，帮助您快速上手DoytoQuery框架。

| id | role\_name | role\_code | valid |
| -- | ---------- | ---------- | ----- |
| 1  | admin      | ADMIN      | true  |
| 2  | vip        | VIP        | true  |
| 3  | vip2       | VIP2       | true  |
| 4  | vip3       | VIP3       | true  |
| 5  | guest      | GUEST      | true  |

示例代码请访问[Github](https://github.com/f0rb/doyto-query-demo)。

### 初始化工程

#### 1. 在 [Spring Initializer](https://start.spring.io) 上初始化工程，添加以下4个依赖：

* Lombok
* Spring Web
* Validation
* HyperSQL Database

#### 2. 引入DoytoQuery

在`pom.xml`中添加如下依赖：

```xml
<dependencies>
    <dependency>
        <groupId>win.doyto</groupId>
        <artifactId>doyto-query-jdbc</artifactId>
        <version>${doyto-query.version}</version>
    </dependency>
    <dependency>
        <groupId>win.doyto</groupId>
        <artifactId>doyto-query-web</artifactId>
        <version>${doyto-query.version}</version>
    </dependency>
    <dependency>
        <groupId>win.doyto</groupId>
        <artifactId>doyto-query-dialect</artifactId>
        <version>${doyto-query.version}</version>
    </dependency>
    ...
</dependencies>
```

#### 3. 添加默认Web配置

DemoApplication需要继承`win.doyto.query.web.WebMvcConfigurerAdapter`

```java
package win.doyto.query.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import win.doyto.query.web.WebMvcConfigurerAdapter;

@SpringBootApplication
public class DemoApplication extends WebMvcConfigurerAdapter {

    public static void main(String[] args) {
        SpringApplication.run(DoytoQueryDemoApplication.class, args);
    }

}
```

#### 4. 配置分页插件

DoytoQuery默认提供的是MySQL的分页插件，而本demo使用的数据库是[HSQLDB](http://hsqldb.org)，所以我们这里需要引入`doyto-query-dialect`，然后在spring的`application.yaml`文件里配置使用。另外这里列名是小写加下划线的格式，这里同时配置一下`map-camel-case-to-underscore`为true，表示将驼峰形式的字段名映射为下划线形式的列名：

```yaml
doyto:
  query:
    config:
      dialect: win.doyto.query.dialect.HSQLDBDialect
      map-camel-case-to-underscore: true
```

### 初始化数据

在`src/main/resources`下创建`schema.sql`:

```sql
SET DATABASE SQL SYNTAX MYS TRUE;

drop table t_role if exists;
create table t_role
(
    id        bigint generated by default as identity (start with 1) primary key,
    role_name VARCHAR(100) not null,
    role_code VARCHAR(100) not null,
    valid     boolean DEFAULT TRUE
);

INSERT INTO t_role (role_name, role_code) VALUES ('admin', 'ADMIN');
INSERT INTO t_role (role_name, role_code) VALUES ('vip', 'VIP');
INSERT INTO t_role (role_name, role_code) VALUES ('vip2', 'VIP2');
INSERT INTO t_role (role_name, role_code) VALUES ('vip3', 'VIP3');
INSERT INTO t_role (role_name, role_code) VALUES ('guest', 'GUEST');

```

### 创建业务类

在package`win.doyto.query.demo.module.role`下，创建以下三个类：

* `RoleEntity`，用于映射表字段

```java
package win.doyto.query.demo.module.role;

import lombok.Getter;
import lombok.Setter;
import win.doyto.query.entity.AbstractPersistable;
import win.doyto.query.validation.CreateGroup;

import javax.persistence.Table;
import javax.validation.constraints.NotNull;

@Getter
@Setter
@Table(name = "t_role")
public class RoleEntity extends AbstractPersistable<Integer> {

    @NotNull(groups = CreateGroup.class)
    private String roleName;

    @NotNull(groups = CreateGroup.class)
    private String roleCode;

    private Boolean valid;
}

```

* `RoleQuery`，用于生成查询语句

```java
package win.doyto.query.demo.module.role;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.SuperBuilder;
import win.doyto.query.core.PageQuery;

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@SuperBuilder
public class RoleQuery extends PageQuery {
    private String roleNameLike;
}

```

* `RoleController`，用于提供CRUD功能和RESTful接口

```java
package win.doyto.query.demo.module.role;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import win.doyto.query.web.controller.AbstractEIQController;

@RestController
@RequestMapping("role")
public class RoleController extends AbstractEIQController<RoleEntity, Integer, RoleQuery> {
}

```

### 测试验证

只需以上三个类就完成了整个RESTful服务的开发，接下来我们一起验证一下效果。

将`org.springframework.web.servlet.mvc.method.annotation`包的日志等级设置为trace，启动DemoApplication，可以看到`/role/`路径下已经有GET, PUT, PATCH等方法了：

```
s.w.s.m.m.a.RequestMappingHandlerMapping : 
	w.d.q.d.m.r.RoleController:
	{POST [/role]}: add(List)
	{PUT [/role/{id}]}: update(Serializable,Object)
	{GET [/role]}: paging(PageQuery)
	{GET [/role/{id}]}: getById(Serializable)
	{DELETE [/role/{id}]}: deleteById(Serializable)
	{PATCH [/role/{id}]}: patch(Serializable,Object)
```

然后通过curl访问一下分页查询接口：

> curl '<http://localhost:8080/role/?roleNameLike=vip\\&pageNumber=2\\&pageSize=2\\&sort=id,desc>'

```json
{
  "code": 0,
  "message": "ok",
  "data": {
    "list": [
      {
        "id": 2,
        "roleName": "vip",
        "roleCode": "VIP",
        "valid": true
      }
    ],
    "total": 3
  },
  "success": true
}
```

可以看到我们使用`roleNameLike=vip`过滤出3条数据`id=[2,3,4]``，再根据id倒序排列并通过`pageNumber=2`和`pageSize=2\`查询出了第二页id为2的记录。

> 更多查询字段的用法请参考[查询对象字段后缀汇总](https://query.doyto.win/manual/suffix-summary)。

再通过单元测试来验证一下：

```java
@Test
@Rollback
void patchRole() throws Exception {
    RequestBuilder requestBuilder = patch("/role/2")
        .content("{\"roleName\":\"new role\"}")
        .contentType(MediaType.APPLICATION_JSON);
    performAndExpectSuccess(requestBuilder);
    performAndExpectSuccess(get("/role/2"))
            .andExpect(jsonPath("$.data.roleName").value("new role"))
    ;
}
```

> 完整的测试用例请查看[这里](https://github.com/f0rb/doyto-query-demo/blob/main/src/test/java/win/doyto/query/demo/module/role/RoleControllerTest.java)。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://query.docs.doyto.win/zh/quickstart.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
