Based on the reconstruction of the pet store project, the original project was separated from the backing, and the project code was attached at the end of the article

RESTful API design

API design demo

Springboot engineering

ORM we use Mybatis -plus, introduce a variety of dependencies, configuration file configuration, nothing special, omitted here.

Creating a New Entity Class

Entity class annotation configuration

Please refer to mybaitS-Plus website for details

Project database table:

@TableName(value = "category")
public class Category {

    @TableId(value = "catid", type = IdType.INPUT)
    private String categoryId;
    @TableField(value = "name")
    private String name;
    @TableField(value = "descn")
    private String description;

}
Copy the code

Write the Mapper class

Inheritance BaseMapper

public interface CategoryMapper extends BaseMapper<Category> {}Copy the code

Start the class with the @mapperscan annotation

Write test classes and perform tests

6
[Category(categoryId=, name=, description=<image src='/images/birds_icon.gif'><font size='5' color='blue'> Birds</font>), Category(categoryId=BIRDS, name=Birds, description=<image src="./images/birds_icon.gif"><font size="5" color="blue"> Birds</font>), Category(categoryId=CATS, name=Cats, description=<image src="/images/cats_icon.gif"><font size="5" color="blue"> Cats</font>), Category(categoryId=DOGS, name=Dogs, description=<image src="/images/dogs_icon.gif"><font size="5" color="blue"> Dogs</font>), Category(categoryId=FISH, name=Fish, description=<image src="/images/fish_icon.gif"><font size="5" color="blue"> Fish</font>), Category(categoryId=REPTILES, name=Reptiles, description=<image src="/images/reptiles_icon.gif"><font size="5" color="blue"> Reptiles</font>)]
Copy the code

successful

Design of common response

I won’t go into the Controller and service layer implementations here

Write CommonResponse class, this kind of design according to the original RESTful API design implementation

public class CommonResponse<T> implements Serializable {

    private int status;
    private String msg;
    private T data;


    public CommonResponse(int status){
        this.status=status;
    }
    public CommonResponse(int status,String msg){
        this.status = status;
        this.msg=msg;

    }
    public CommonResponse(int status,String msg,T data){
        this.status = status;
        this.msg=msg;
        this.data=data;
    }
    public CommonResponse(int status,T data){
        this.status = status;
        this.data=data; }}Copy the code

This is the original design, but one problem with this design is that only the second constructor can be called when passing integers and strings as parameters.

The tests are as follows:

The improvements are as follows:

public class CommonResponse<T> implements Serializable {

    private int status;
    private String msg;
    private T data;


    private CommonResponse(int status){
        this.status=status;
    }
    private CommonResponse(int status,String msg){
        this.status = status;
        this.msg=msg;

    }
    private CommonResponse(int status,String msg,T data){
        this.status = status;
        this.msg=msg;
        this.data=data;
    }
    private CommonResponse(int status,T data){
        this.status = status;
        this.data=data;
    }

    public static <T> CommonResponse<T> creatForSuccess(a){
        return new CommonResponse<T>(0);
    }
    public static <T> CommonResponse<T> creatForSuccess(T date){
        return new CommonResponse<T>(0,date);
    }
    
     public static <T> CommonResponse<T> creatForSuccess(String msg,T date){
        return new CommonResponse<T>(0,msg,date);
    }
    public static <T> CommonResponse<T> creatForSuccessMessage(String msg){
        return new CommonResponse<T>(0,msg);
    }
   
    public static <T> CommonResponse<T> creatForError(String msg){
        return new CommonResponse<T>(1,msg); }}Copy the code

Make the constructor private and assign through the static method below

This completes the design of the universal response

public class CatalogServiceImpl implements CatalogService {

    @Autowired
    private CategoryMapper categoryMapper;

    @Override
    public CommonResponse<List<Category>> getCategoryList() {
        List<Category> categoryList = categoryMapper.selectList(null);
        if (categoryList.isEmpty()){
            return CommonResponse.creatForSuccessMessage("No species information found.");// Not found but still in successful state
        }
        else{
            returnCommonResponse.creatForSuccess(categoryList); }}}Copy the code

The above code is the service layer, and the following error occurs at runtime:

No converter found for return value of type: class com.xiesuper.common.CommonResponse] 
Copy the code

The CommonResponse class did not add the @getter annotation (which introduced the lambook dependency).

The resulting JSON data is as follows:

{
   "status": 0."msg": null."data": [{"categoryId": "BIRDS"."name": "Birds"."description": "<image src=\"./images/birds_icon.gif\"><font size=\"5\" color=\"blue\"> Birds</font>"
       },
       {
           "categoryId": "CATS"."name": "Cats"."description": "<image src=\"/images/cats_icon.gif\"><font size=\"5\" color=\"blue\"> Cats</font>"
       },
       {
           "categoryId": "DOGS"."name": "Dogs"."description": "<image src=\"/images/dogs_icon.gif\"><font size=\"5\" color=\"blue\"> Dogs</font>"
       },
       {
           "categoryId": "FISH"."name": "Fish"."description": "<image src=\"/images/fish_icon.gif\"><font size=\"5\" color=\"blue\"> Fish</font>"
       },
       {
           "categoryId": "REPTILES"."name": "Reptiles"."description": "<image src=\"/images/reptiles_icon.gif\"><font size=\"5\" color=\"blue\"> Reptiles</font>"}}]Copy the code

Here we don’t assign to MSG, but eventually get the MSG data. Solution: add annotations to the CommonResponse class

//Json serialized spacetime data will not be included
@JsonInclude(JsonInclude.Include.NON_NULL)
Copy the code

What if the information in the entity class doesn’t come from a table?

Let’s look at the variable in the original pet store Item class:

private String itemId;
  private String productId;
  private BigDecimal listPrice;
  private BigDecimal unitCost;
  private int supplierId;
  private String status;
  private String attribute1;
  private String attribute2;
  private String attribute3;
  private String attribute4;
  private String attribute5;
  private Product product;
  private int quantity;
Copy the code

The information comes from three tables:

The item list:

The inventory table:The product table:

One solution is join queries for SQL statements, but this is not recommended by Mybatis – Plus

Let’s solve this problem:

First of all, we need to learn the concepts of VO, BO, DTO and DO: brief analysis of VO, BO, DTO and DO

VO is view object, which is also the object to be displayed in our page. At this time, we use VO to query Item information. Here, we use VO to query all Items under a productId as an example

New Item, Product, ItemInventory entity class, as well as Itemmapper Productmapper, ItemInventoryMapper specific code is no longer the shows. New ItemVo:

Fill in ItemVo information:

@Data
public class ItemVo {
    //item specifies the fields in the table
    private String itemId;
    private String productId;
    private BigDecimal listPrice;
    private BigDecimal unitCost;
    private int supplierId;
    private String status;
    private String attribute1;
    private String attribute2;
    private String attribute3;
    private String attribute4;
    private String attribute5;


    // Item belongs to the product property
    private String categoryId;
    private String name;
    private String description;

    / / item inventory
    private int quantity;

}
Copy the code

First, we need to obtain the items from the Item table in the database according to productId, then obtain the product information, then obtain the inventory information, so the question is how to obtain the items from the productId table?

At this point we use the conditional constructor in Mybatis – Plus

Conditional constructor

The key code implementation is as follows


QueryWrapper<Item> queryWrapper = new QueryWrapper<>();// Conditional constructor
 queryWrapper.eq("productId",productId);// The parameters are the field name and the value passed in
 List<Item> itemList = itemMapper.selectList(queryWrapper);
Copy the code

ItemVo = ItemVo = ItemVo = ItemVo

 @Override
    public CommonResponse<List<ItemVo>> getItemsByProductId(String productId) {

        QueryWrapper<Item> queryWrapper = new QueryWrapper<>();// Conditional constructor
        queryWrapper.eq("productId",productId);// The parameters are the field name and the value passed in
        List<Item> itemList = itemMapper.selectList(queryWrapper);

        if(itemList.isEmpty()){
            return CommonResponse.creatForSuccessMessage("Corresponding ProductId has no items information");
        }
        Product product =productMapper.selectById(productId);

        List<ItemVo> itemVoList = new ArrayList<>();
        for(Item item:itemList){
            ItemVo itemVo = itemToItemVo(item,product);
            itemVoList.add(itemVo);
        }


        return CommonResponse.creatForSuccess(itemVoList);


    }

    private ItemVo itemToItemVo(Item item,Product product){
        ItemVo itemVo =new ItemVo();
        itemVo.setItemId(item.getItemId());
        itemVo.setProductId(item.getProductId());
        itemVo.setUnitCost(item.getUnitCost());
        itemVo.setListPrice(item.getListPrice());
        itemVo.setSupplierId(item.getSupplierId());
        itemVo.setStatus(item.getStatus());
        item.setAttribute1(item.getAttribute1());
        item.setAttribute2(item.getAttribute2());
        item.setAttribute3(item.getAttribute3());
        item.setAttribute4(item.getAttribute4());
        item.setAttribute5(item.getAttribute5());

        itemVo.setDescription(product.getDescription());
        itemVo.setCategoryId(product.getCategoryId());
        itemVo.setName(product.getName());

        ItemInventory itemInventory = itemInventoryMapper.selectById(item.getItemId());
        itemVo.setQuantity(itemInventory.getQuantity());

        return itemVo;

    }
Copy the code

Project source link