基于宠物商店项目的重构,将原先项目进行前后盾分离,文末附上项目代码
RESTful API的设计
springboot工程
ORM我们用到mybatis-plus,引入各种依赖,对配置文件进行配置,没什么特别之处,此处便省略。
新建实体类
实体类注解配置
详情请参照mybaits-plus官网教程
项目数据库表:
@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;
}
编写Mapper类
继承BaseMapper
public interface CategoryMapper extends BaseMapper<Category> {
}
启动类添加@MapperScan注解
编写测试类,进行测试
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>)]
成功
通用响应的设计
此处的controller以及service层实现我就不再赘述了
编写CommonResponse类,此类的设计依据原先RESTful API的设计实现
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;
}
}
这是原先的设计,但这样设计有一个问题,在传参时传整形与字符串型的话只能调用第二个构造函数。
测试如下:
改进如下:
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(){
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);
}
}
将构造方法设置为私有,通过下面的静态方法进行赋值
这样通用响应就设计完成了
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("没有找到种类信息");//没查到但此时的状态仍然为成功的
}
else{
return CommonResponse.creatForSuccess(categoryList);
}
}
}
上述代码即为service层,最后运行时出现了下面的报错:
No converter found for return value of type: class com.xiesuper.common.CommonResponse]
调试时数据都已经得到,但在postman上访问时就出现上述报错,最后发现CommonResponse类中没添加@Getter注解(引入了lambook依赖)。
最后得到的JSON数据如下:
{
"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>"
}
]
}
此处我们没有对msg赋值,但最终得到了msg的数据,解决方法:在CommonResponse类上添加注解
//Json序列化时空的数据不会被包含
@JsonInclude(JsonInclude.Include.NON_NULL)
实体类中的信息不是来自于一张表该周么办??
我们看原来宠物商店Item类中变量:
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;
其信息来自于三个表:
item表:
inventory表:
product表:
其中一个解决方法就是SQL语句的连接查询,但mybatis-plus是不推荐这种用法的
下面我们来解决这种问题:
首先我们需要学习一下VO,BO,DTO,DO几个对象的概念: 浅析VO,BO,DTO,DO
VO即view object 也就是我们页面中要展示的对象,此时查询Item信息我们便用到vo 这里以查询某个productId下的所有Items为例
新建Item,Product,ItemInventory实体类,以及Itemmapper,Productmapper,ItemInventoryMapper具体代码就不再这展示了。 新建ItemVo:
对ItemVo信息进行填充:
@Data
public class ItemVo {
//item表中字段
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所属product属性
private String categoryId;
private String name;
private String description;
//item的库存
private int quantity;
}
下面我们理一下思路,首先,我们要根据productId获取到数据库中Item表中的items,然后获得product信息,然后获得库存信息,那么问题来了,我们如何根据productId获取到items呢?
此时我们便用到mybatis-plus中条件构造器
关键代码实现如下
QueryWrapper<Item> queryWrapper = new QueryWrapper<>();//条件构造器
queryWrapper.eq("productId",productId);//参数为字段名与传入的value值
List<Item> itemList = itemMapper.selectList(queryWrapper);
然后就是将分别查到的数据填充到ItemVo中便可:实现代码如下:
@Override
public CommonResponse<List<ItemVo>> getItemsByProductId(String productId) {
QueryWrapper<Item> queryWrapper = new QueryWrapper<>();//条件构造器
queryWrapper.eq("productId",productId);//参数为字段名与传入的value值
List<Item> itemList = itemMapper.selectList(queryWrapper);
if(itemList.isEmpty()){
return CommonResponse.creatForSuccessMessage("对应ProductId没有items信息");
}
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;
}