The introduction

Hello, this is Anyin.

I was going to write down some simple uses of MQTT this week because I’ve been working with hardware for a while, and it’s kind of a summary. But today when I was writing a user add, delete, change and check of Anyin Cloud project, I suddenly felt that there are some small ways in writing a CRUD.

Today we are going to talk about some simple CRUD tricks that are part of daily development work.

Data entity Conversion

In our normal three-tier architecture, we have Controller, Service, and Dao layers, whose dependencies are top-down. As follows:

When we subcontract code, we generally stipulate that the upper layer cannot depend on the lower layer; Data interaction is required between layers, so three types of basic data entities are generated: VO, DTO and DO. They subcontract corresponding Controller layer, Service layer and Dao layer, and the conversion sequence is as follows:

You will find that this process requires four transformations. For example, if a query returns a result, the sequence of its conversions is as follows:

ReqVO  =>  ReqDTO  =>  ReqDO
                         |
RespVO <=  RespDTO <=  RespDO
Copy the code

This would be particularly annoying in a real development project, where a single query would operate on six entity classes and four transformation methods. So, I made a subtraction:

  1. To get rid ofRespVO.RespDTOandRespDOCan be returned directly to the front end,But do not expose the table structure.
  2. mergeReqDOandRespDOThat is they areDO.
  3. Merge in some scenariosReqDTOandRespDTO.

In this case, I am left with VO, DTO, and DO, which are usually converted 2 times. For example, in user list query, VO is transferred to DTO, DTO is transferred to DO, and the query result DO is directly returned to the front end. As follows:

Ext can be a single table query result or a join table query result. Note that Ext cannot inherit data mapping DO directly, otherwise it risks exposing the table structure

This way, the entire data entity transformation is at least a lot easier to write, albeit a mindless CURD

Method naming and method signing

Method commands and method signatures refer to CRUD method names and signatures, and the Controller layer and Service layer remain corresponding. I usually use the following five forms:

new

// --------- added ---------
/ / Controlelr layer
public ApiResponse create(@Valid  @RequestBody SysUserSaveForm form)
/ / Service layer
public void create(SysUserSaveDTO info);

// --------- edit ---------
public ApiResponse modify(@PathVariable("id") Long id, @Valid  @RequestBody SysUserSaveForm form)
public void modify(Long id, SysUserSaveDTO info);

// --------- query ---------
public ApiResponse<SysUserInfoDTO> info(@PathVariable("id") Long id)
public SysUserInfoDTO info(Long id);

// --------- delete ---------
public ApiResponse delete(@PathVariable("id") Long id)
public void delete(Long id);

// --------- page ---------
public ApiResponse<Page<SysUserExt>> page(@RequestBody SysUserPageForm form)
public Page<SysUserExt> page(SysUserPageDTO query);
Copy the code

These five basic methods are available for controllers and services of business object or entity type, but not for associated objects or non-business objects or entities. For example, users and roles belong to business objects and will have these five basic methods, while the association table between users and roles will not have these five basic methods and will not have corresponding Controller and Service classes.

The create and modify methods generally have the same data entities, but one has an ID and the other has no ID, so either the Controller or the Service layer will display the ID and pass it, This ensures that the fields of the SysUserSaveForm and SysUserSaveDTO data entities are one-to-one.

There are only two things you can do in the Controller layer:

  1. Data validation, this all goes through the data entityFormOn the annotation match@ValidAnnotation for processing.
  2. Data transformation is recommended heremapsturctComponent data conversion, which saves a lot of effort.

The aggregation ofServicelayer

In my understanding of the Service layer it should handle a small amount of simple business logic; If a complex Service is involved, add a separate ServiceA class for the complex Service. The current Service holds a reference to ServiceA and provides the corresponding GET method. Other business services that reference ServiceA cannot be injected directly through @AutoWired, but must get it from getXXXService of their main business Service.

To summarize, in the current business, only one Service class provides services, and its subclass is obtained through getXXXService. Is there that DDD thing about polymeric roots?

The Service layer also holds a reference to multiple Repositories. At the Service layer, complex business logic is stripped away to other sub-services, while database-related operations are stripped away to Repository. Here’s an example:

SysUserService holds a reference to SysUserRepository and provides the getRepository method to get an instance of SysUserRepository. In addition to the five basic methods in the previous section, all simple and complex database operations involving getByUsername should be stored in SysUserRepository. In addition, SysUserService may hold a Repository of its associated tables, such as SysUserRoleRepository, the associated table of users and roles.

A Service is an aggregation of its subservice and associated Repository. It provides the corresponding getXXX method. Services of other services cannot directly reference their subservice and associated Repository.

With some of the specifications described above, our Service is no longer bloated, but simply a scheduler or choreographer.

The last

Those are some simple thoughts for today’s simple CRUD. If you have any suggestions, please correct them.

Anyin Cloud