Java项目【尚庭公寓】从0开始Java项目实战(二)
1. 房间支付方式管理接口实现
房间支付方式管理共有三个接口,分别是:
查询全部支付方式列表
保存或更新支付方式
根据ID删除支付方式
首先在PaymentTypeController
中注入PaymentTypeService
依赖,如下
@Tag(name = "支付方式管理")
@RequestMapping("/admin/payment")
@RestController
public class PaymentTypeController {
@Autowired
private PaymentTypeService service;
}
1.1 查询全部支付方式列表
查看接口,运行项目后,访问localhost:8080/doc.html
点击支付方式管理
再点击查询全部支付方式列表接口
//响应实例
{
"code": 0,
"message": "",
"data": [
{
"id": 0,
"name": "",
"payMonthCount": "",
"additionalInfo": ""
}
]
}
进行开发
1、在com/atguigu/lease/web/admin/controller/apartment/PaymentTypeController.java创建listPaymentType()方法
@Operation(summary = "查询全部支付方式列表")
@GetMapping("list")
public Result<List<PaymentType>> listPaymentType() {
List<PaymentType> list = service.list();
return Result.ok(list);
}
2、查看service层
/**
* @author Matthew
* @description 针对表【payment_type(支付方式表)】的数据库操作Service
* @createDate 2023-07-24 15:48:00
*/
public interface PaymentTypeService extends IService<PaymentType> {
}
3、查看service实现类
/**
* @author Matthew
* @description 针对表【payment_type(支付方式表)】的数据库操作Service实现
* @createDate 2023-07-24 15:48:00
*/
@Service
public class PaymentTypeServiceImpl extends ServiceImpl<PaymentTypeMapper, PaymentType>
implements PaymentTypeService{
}
4、查看Mapper
/**
* @author Matthew
* @description 针对表【payment_type(支付方式表)】的数据库操作Mapper
* @createDate 2023-07-24 15:48:00
* @Entity com.atguigu.lease.model.PaymentType
*/
public interface PaymentTypeMapper extends BaseMapper<PaymentType> {
}
因为使用的是mybatisplus,这意味着它将拥有BaseMapper
接口中定义的所有通用CRUD方法,这些方法可以直接用于对PaymentType
实体对应的数据库表进行操作,service层也同理。
知识点:
-
逻辑删除功能
由于数据库中所有表均采用逻辑删除策略,所以查询数据时均需要增加过滤条件
is_deleted=0
。上述操作虽不难实现,但是每个查询接口都要考虑到,也显得有些繁琐。为简化上述操作,可以使用Mybatis-Plus提供的逻辑删除功能,它可以自动为查询操作增加
is_deleted=0
过滤条件,并将删除操作转为更新语句。具体配置如下,详细信息可参考官方文档。-
步骤一:在
application.yml
中增加如下内容mybatis-plus: global-config: db-config: logic-delete-field: flag # 全局逻辑删除的实体字段名(配置后可以忽略不配置步骤二) logic-delete-value: 1 # 逻辑已删除值(默认为 1) logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
-
步骤二:在实体类中的删除标识字段上增加
@TableLogic
注解@Data public class BaseEntity { @Schema(description = "主键") @TableId(value = "id", type = IdType.AUTO) private Long id; @Schema(description = "创建时间") @JsonIgnore private Date createTime; @Schema(description = "更新时间") @JsonIgnore private Date updateTime; @Schema(description = "逻辑删除") @JsonIgnore @TableLogic @TableField("is_deleted") private Byte isDeleted; }
注意:
逻辑删除功能只对Mybatis-Plus自动注入的sql起效,也就是说,对于手动在
Mapper.xml
文件配置的sql不会生效,需要单独考虑。
-
1.2 保存或更新支付方式
查看接口,运行项目后,访问localhost:8080/doc.html
点击支付方式管理
再点击保存或更新支付方式
//请求示例
{
"id": 0,
"name": "",
"payMonthCount": "",
"additionalInfo": ""
}
//响应示例
{
"code": 0,
"message": "",
"data": {}
}
进行开发
在PaymentTypeController
中增加如下内容
@Operation(summary = "保存或更新支付方式")
@PostMapping("saveOrUpdate")
public Result saveOrUpdatePaymentType(@RequestBody PaymentType paymentType) {
service.saveOrUpdate(paymentType);
return Result.ok();
}
知识点:
保存或更新数据时,前端通常不会传入isDeleted
、createTime
、updateTime
这三个字段,因此我们需要手动赋值。但是数据库中几乎每张表都有上述字段,所以手动去赋值就显得有些繁琐。为简化上述操作,我们可采取以下措施。
-
is_deleted
字段:可将数据库中该字段的默认值设置为0。 -
create_time
和update_time
:可使用mybatis-plus的自动填充功能,所谓自动填充,就是通过统一配置,在插入或更新数据时,自动为某些字段赋值,具体配置如下,详细信息可参考官方文档。-
为相关字段配置触发填充的时机,例如
create_time
需要在插入数据时填充,而update_time
需要在更新数据时填充。具体配置如下,观察@TableField
注解中的fill
属性。@Data public class BaseEntity { @Schema(description = "主键") @TableId(value = "id", type = IdType.AUTO) private Long id; @Schema(description = "创建时间") @JsonIgnore @TableField(value = "create_time", fill = FieldFill.INSERT) private Date createTime; @Schema(description = "更新时间") @JsonIgnore @TableField(value = "update_time", fill = FieldFill.UPDATE) private Date updateTime; @Schema(description = "逻辑删除") @JsonIgnore @TableLogic @TableField("is_deleted") private Byte isDeleted; }
-
配置自动填充的内容,具体配置如下
-
-
在common模块下创建
com.atguigu.lease.common.mybatisplus.MybatisMetaObjectHandler
类,内容如下:import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; import org.apache.ibatis.reflection.MetaObject; import org.springframework.stereotype.Component; import java.util.Date; @Component public class MybatisMetaObjectHandler implements MetaObjectHandler { @Override public void insertFill(MetaObject metaObject) { this.strictInsertFill(metaObject, "createTime", Date.class, new Date()); } @Override public void updateFill(MetaObject metaObject) { this.strictUpdateFill(metaObject, "updateTime", Date.class, new Date()); } }
在做完上述配置后,当写入数据时,Mybatis-Plus会自动将实体对象的create_time
字段填充为当前时间,当更新数据时,则会自动将实体对象的update_time
字段填充为当前时间。
1.3 根据ID删除支付方式
查看接口,运行项目后,访问localhost:8080/doc.html
点击支付方式管理
再点击根据ID删除支付方式
//响应示例
{
"code": 0,
"message": "",
"data": {}
}
进行开发
在PaymentTypeController
中增加如下方法
@Operation(summary = "根据ID删除支付方式")
@DeleteMapping("deleteById")
public Result deletePaymentById(@RequestParam Long id) {
service.removeById(id);
return Result.ok();
}
知识点:
MybatisPlus逻辑删除功能的使用。
2. 租期管理接口实现
租期管理共有三个接口,分别是
保存或更新租期信息
查询全部租期列表
根据ID根据ID删除租期
首先需要在FacilityController
中注入FacilityInfoService
@Tag(name = "租期管理")
@RequestMapping("/admin/term")
@RestController
public class LeaseTermController {
@Autowired
private LeaseTermService leaseTermService;
}
2.1 查询全部租期列表
查看接口,运行项目后,访问localhost:8080/doc.html
点击租期管理
再点击查询全部租期列表接口
{
"code": 0,
"message": "",
"data": [
{
"id": 0,
"monthCount": 0,
"unit": ""
}
]
}
进行开发
1、在LeaseTermController 中添加方法,根据接口给的信息定义
@GetMapping("list")
@Operation(summary = "查询全部租期列表")
public Result<List<LeaseTerm>> listLeaseTerm() {
List<LeaseTerm> list = leaseTermService.list();
return Result.ok(list);
}
2、查看service层
/**
* @author Matthew
* @description 针对表【lease_term(租期)】的数据库操作Service
* @createDate 2023-07-24 15:48:00
*/
public interface LeaseTermService extends IService<LeaseTerm> {
}
因为使用的是mybatisplus,这意味着它将拥有接口中定义的所有通用CRUD方法,这些方法可以直接用于对LeaseTerm实体对应的数据库表进行操作。
调试测试,点击调试,发送
//响应内容成功
{
"code": 200,
"message": "成功",
"data": [
{
"id": 1,
"monthCount": 1,
"unit": "月"
},
{
"id": 3,
"monthCount": 3,
"unit": "月"
},
{
"id": 4,
"monthCount": 6,
"unit": "月"
},
{
"id": 6,
"monthCount": 12,
"unit": "月"
}
]
}
知识点:
-
逻辑删除功能
由于数据库中所有表均采用逻辑删除策略,所以查询数据时均需要增加过滤条件
is_deleted=0
。上述操作虽不难实现,但是每个查询接口都要考虑到,也显得有些繁琐。为简化上述操作,可以使用Mybatis-Plus提供的逻辑删除功能,它可以自动为查询操作增加
is_deleted=0
过滤条件,并将删除操作转为更新语句。具体配置如下,详细信息可参考官方文档。 -
由于在前篇的房间支付方式已经实现,而实体类都继承BaseEntity,所以这里不需要做任何操作
/** * @TableName lease_term */ @TableName(value = "lease_term") @Data @Schema(description = "租期信息") public class LeaseTerm extends BaseEntity { private static final long serialVersionUID = 1L; @Schema(description = "租期月数") @TableField("month_count") private Integer monthCount; @Schema(description = "租期单位:月") @TableField("unit") private String unit; }
2.2 保存或更新租期信息
查看接口,运行项目后,访问localhost:8080/doc.html
点击租期管理
再点击保存或更新租期信息
进行开发
在LeaseTermController 中添加方法,根据接口给的信息定义
@PostMapping("saveOrUpdate")
@Operation(summary = "保存或更新租期信息")
public Result saveOrUpdate(@RequestBody LeaseTerm leaseTerm) {
leaseTermService.saveOrUpdate(leaseTerm);
return Result.ok();
}
进行测试,发送请求
{
"monthCount": 24,
"unit": "月"
}
知识点:
保存或更新数据时,前端通常不会传入isDeleted
、createTime
、updateTime
这三个字段,因此我们需要手动赋值。但是数据库中几乎每张表都有上述字段,所以手动去赋值就显得有些繁琐。为简化上述操作,我们可采取以下措施。
-
is_deleted
字段:可将数据库中该字段的默认值设置为0。 -
create_time
和update_time
:可使用mybatis-plus的自动填充功能,所谓自动填充,就是通过统一配置,在插入或更新数据时,自动为某些字段赋值,具体配置如下,详细信息可参考官方文档。-
为相关字段配置触发填充的时机,例如
create_time
需要在插入数据时填充,而update_time
需要在更新数据时填充。具体配置如下,观察@TableField
注解中的fill
属性。@Data public class BaseEntity { @Schema(description = "主键") @TableId(value = "id", type = IdType.AUTO) private Long id; @Schema(description = "创建时间") @JsonIgnore @TableField(value = "create_time", fill = FieldFill.INSERT) private Date createTime; @Schema(description = "更新时间") @JsonIgnore @TableField(value = "update_time", fill = FieldFill.UPDATE) private Date updateTime; @Schema(description = "逻辑删除") @JsonIgnore @TableLogic @TableField("is_deleted") private Byte isDeleted; }
-
配置自动填充的内容,具体配置如下
-
-
在common模块下创建
com.atguigu.lease.common.mybatisplus.MybatisMetaObjectHandler
类,内容如下:@Component public class MybatisMetaObjectHandler implements MetaObjectHandler { @Override public void insertFill(MetaObject metaObject) { this.strictInsertFill(metaObject, "createTime", Date.class, new Date()); } @Override public void updateFill(MetaObject metaObject) { this.strictUpdateFill(metaObject, "updateTime", Date.class, new Date()); } }
注意:由于上篇已经实现过了。这里也不需要做任何操作
2.3 根据ID删除租期
查看接口,运行项目后,访问localhost:8080/doc.html
点击租期管理
再点击根据ID删除租期
进行开发
@DeleteMapping("deleteById")
@Operation(summary = "根据ID删除租期")
public Result deleteLeaseTermById(@RequestParam Long id) {
leaseTermService.removeById(id);
return Result.ok();
}
测试
3. 根据类型查询标签列表接口实现(🔴重点:枚举类型转化问题)
3.1 查看接口
启动项目
访问:http://localhost:8080/doc.html
点击标签管理
点击根据查询标签列表
3.2 进行开发
首先在LabelController
中注入LabelInfoService
依赖,如下
@Tag(name = "标签管理")
@RestController
@RequestMapping("/admin/label")
public class LabelController {
@Autowired
private LabelInfoService service;
}
在LabelController
中增加如下内容
@Operation(summary = "(根据类型)查询标签列表")
@GetMapping("list")
public Result<List<LabelInfo>> labelList(@RequestParam(required = false) ItemType type) {
LambdaQueryWrapper<LabelInfo> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(type != null, LabelInfo::getType, type);
List<LabelInfo> list = service.list(queryWrapper);
return Result.ok(list);
}
知识点:
上述接口的功能是根据type(公寓/房间),查询标签列表。由于这个type字段在数据库、实体类、前后端交互的过程中有多种不同的形式,因此在请求和响应的过程中,type字段会涉及到多次类型转换。
首先明确一下type字段的各种形式:
-
数据库中
数据库中的type字段为
tinyint
类型+-------------+--------------+ | Field | Type | +-------------+--------------+ | id | bigint | | type | tinyint | | name | varchar(255) | | create_time | timestamp | | update_time | timestamp | | is_deleted | tinyint | +-------------+--------------+
-
实体类
实体类中的type字段为
ItemType
枚举类型LabelInfo
实体类如下@Schema(description = "标签信息表") @TableName(value = "label_info") @Data public class LabelInfo extends BaseEntity { private static final long serialVersionUID = 1L; @Schema(description = "类型") @TableField(value = "type") private ItemType type; @Schema(description = "标签名称") @TableField(value = "name") private String name; }
ItemType
枚举类如下public enum ItemType { APARTMENT(1, "公寓"), ROOM(2, "房间"); private Integer code; private String name; ItemType(Integer code, String name) { this.code = code; this.name = name; } }
-
前后端交互中
前后端交互所传递的数据中type字段为数字(1/2)。
具体转换过程如下图所示:
-
请求流程
说明
- SpringMVC中的
WebDataBinder
组件负责将HTTP的请求参数绑定到Controller方法的参数,并实现参数类型的转换。 - Mybatis中的
TypeHandler
用于处理Java中的实体对象与数据库之间的数据类型转换。
- SpringMVC中的
-
响应流程
说明
- SpringMVC中的
HTTPMessageConverter
组件负责将Controller方法的返回值(Java对象)转换为HTTP响应体中的JSON字符串,或者将请求体中的JSON字符串转换为Controller方法中的参数(Java对象),例如下一个接口保存或更新标签信息
- SpringMVC中的
下面介绍一下每个环节的类型转换原理
-
WebDataBinder枚举类型转换
WebDataBinder
依赖于Converter
实现类型转换,若Controller方法声明的@RequestParam
参数的类型不是String
,WebDataBinder
就会自动进行数据类型转换。SpringMVC提供了常用类型的转换器,例如String
到Integer
、String
到Date
,String
到Boolean
等等,其中也包括String
到枚举类型,但是String
到枚举类型的默认转换规则是根据实例名称(“APARTMENT”)转换为枚举对象实例(ItemType.APARTMENT)。若想实现code
属性到枚举对象实例的转换,需要自定义Converter
,代码如下,具体内容可参考官方文档。-
在web-admin模块自定义
com.atguigu.lease.web.admin.custom.converter.StringToItemTypeConverter
@Component public class StringToItemTypeConverter implements Converter<String, ItemType> { @Override public ItemType convert(String code) { for (ItemType value : ItemType.values()) { if (value.getCode().equals(Integer.valueOf(code))) { return value; } } throw new IllegalArgumentException("code非法"); } }
-
注册上述的
StringToItemTypeConverter
,在web-admin模块创建com.atguigu.lease.web.admin.custom.config.WebMvcConfiguration
,内容如下:@Configuration public class WebMvcConfiguration implements WebMvcConfigurer { @Autowired private StringToItemTypeConverter stringToItemTypeConverter; @Override public void addFormatters(FormatterRegistry registry) { registry.addConverter(this.stringToItemTypeConverter); } }
但是我们有很多的枚举类型都需要考虑类型转换这个问题,按照上述思路,我们需要为每个枚举类型都定义一个Converter,并且每个Converter的转换逻辑都完全相同,针对这种情况,我们使用
ConverterFactory
接口更为合适,这个接口可以将同一个转换逻辑应用到一个接口的所有实现类,因此我们可以定义一个BaseEnum
接口,然后另所有的枚举类都实现该接口,然后就可以自定义ConverterFactory
,集中编写各枚举类的转换逻辑了。具体实现如下:-
在model模块定义
com.atguigu.lease.model.enums.BaseEnum
接口public interface BaseEnum { Integer getCode(); String getName(); }
-
令所有
com.atguigu.lease.model.enums
包下的枚举类都实现BaseEnun
接口 -
在web-admin模块自定义
com.atguigu.lease.web.admin.custom.converter.StringToBaseEnumConverterFactory
@Component public class StringToBaseEnumConverterFactory implements ConverterFactory<String, BaseEnum> { @Override public <T extends BaseEnum> Converter<String, T> getConverter(Class<T> targetType) { return new Converter<String, T>() { @Override public T convert(String source) { for (T enumConstant : targetType.getEnumConstants()) { if (enumConstant.getCode().equals(Integer.valueOf(source))) { return enumConstant; } } throw new IllegalArgumentException("非法的枚举值:" + source); } }; } }
-
注册上述的
ConverterFactory
,在web-admin模块创建com.atguigu.lease.web.admin.custom.config.WebMvcConfiguration
,内容如下:@Configuration public class WebMvcConfiguration implements WebMvcConfigurer { @Autowired private StringToBaseEnumConverterFactory stringToBaseEnumConverterFactory; @Override public void addFormatters(FormatterRegistry registry) { registry.addConverterFactory(this.stringToBaseEnumConverterFactory); } }
注意:
最终采用的是
ConverterFactory
方案,因此StringToItemTypeConverter
相关代码可以直接删除。
-
-
TypeHandler枚举类型转换
Mybatis预置的
TypeHandler
可以处理常用的数据类型转换,例如String
、Integer
、Date
等等,其中也包含枚举类型,但是枚举类型的默认转换规则是枚举对象实例(ItemType.APARTMENT)和实例名称(“APARTMENT”)相互映射。若想实现code
属性到枚举对象实例的相互映射,需要自定义TypeHandler
。不过MybatisPlus提供了一个通用的处理枚举类型的TypeHandler。其使用十分简单,只需在
ItemType
枚举类的code
属性上增加一个注解@EnumValue
,Mybatis-Plus便可完成从ItemType
对象到code
属性之间的相互映射,具体配置如下。public enum ItemType { APARTMENT(1, "公寓"), ROOM(2, "房间"); @EnumValue private Integer code; private String name; ItemType(Integer code, String name) { this.code = code; this.name = name; } }
-
HTTPMessageConverter枚举类型转换
HttpMessageConverter
依赖于Json序列化框架(默认使用Jackson)。其对枚举类型的默认处理规则也是枚举对象实例(ItemType.APARTMENT)和实例名称(“APARTMENT”)相互映射。不过其提供了一个注解@JsonValue
,同样只需在ItemType
枚举类的code
属性上增加一个注解@JsonValue
,Jackson便可完成从ItemType
对象到code
属性之间的互相映射。具体配置如下,详细信息可参考Jackson官方文档。@Getter public enum ItemType { APARTMENT(1, "公寓"), ROOM(2, "房间"); @EnumValue @JsonValue private Integer code; private String name; ItemType(Integer code, String name) { this.code = code; this.name = name; } }
4. 标签和配套管理接口实现接口实现
4.1 保存或更新标签信息
查看接口
访问http://localhost:8080/doc.html
点击标签管理查看接口
点击新增或修改标签信息
进行开发
在LabelController
中增加如下内容
@Operation(summary = "保存或更新标签信息")
@PostMapping("saveOrUpdate")
public Result saveOrUpdateFacility(@RequestBody LabelInfo labelInfo) {
service.saveOrUpdate(labelInfo);
return Result.ok();
}
解释
@Operation: 这是用于Swagger UI生成接口文档的注解,它提供了此API操作的简要描述。
@PostMapping: 将此方法映射到POST请求的"/saveOrUpdate"路径,用于处理来自客户端的POST请求。
Result: 此方法的返回类型,使用泛型封装API的返回结果。Result.ok()用于生成一个标准的成功响应。
@RequestBody: 指明此参数应从请求的正文(Body)中获取,并自动由Spring框架的HTTP消息转换器将JSON数据映射到LabelInfo对象。
service.saveOrUpdate(labelInfo): 这一行调用了业务层的saveOrUpdate方法,这个方法通常检查传入的labelInfo对象是否包含id。如果包含id,则为更新操作;如果不包含,认为是新的记录,执行插入操作。
Result.ok(): 这通常是一个静态方法,用来创建一个表示操作成功的响应对象。在这个场景中,它没有返回具体的数据,只是一个成功的状态,告诉客户端操作已成功完成。
4.2 根据id删除标签信息
查看接口
访问http://localhost:8080/doc.html
点击标签管理查看接口
点击根据id删除标签信息
进行开发
在LabelController
中增加如下内容
@Operation(summary = "根据id删除标签信息")
@DeleteMapping("deleteById")
public Result deleteLabelById(@RequestParam Long id) {
labelInfoService.removeById(id);
return Result.ok();
}
解释
@Operation: 这个Swagger注解用于生成API文档,描述了这个API端点的主要功能,即根据ID删除标签信息。
@DeleteMapping(“deleteById”): 此注解将方法映射到对应的HTTP
DELETE请求上,路径为"/deleteById"。DELETE请求通常用于表示删除资源的操作。
public Result deleteLabelById(@RequestParam Long id):
这是方法的签名,返回一个Result类型的对象,这是一个自定义响应类,通常用于API的标准化输出。@RequestParam注解用于从请求的URL查询参数中接收名为id的参数,此处没有设置required为false,因此它是必需的。
labelInfoService.removeById(id):
在此行,labelInfoService的removeById方法被调用,传入的参数是id。这个方法负责在数据存储层(如数据库)中删除指定ID的记录。
return Result.ok():
方法返回一个Result.ok()调用的结果,这通常是一个工厂方法,用来创建一个成功的响应对象,表明删除操作已成功执行,没有返回数据,只是一个操作成功的确认。
4.3 根据类型查询配套列表
查看接口
访问http://localhost:8080/doc.html
点击配套管理
点击[根据类型]查询配套信息列表
进行开发
在FacilityController
中增加如下内容
@Tag(name = "标签管理")
@RestController
@RequestMapping("/admin/label")
public class LabelController {
@Autowired
private LabelInfoService labelInfoService;
@Operation(summary = "(根据类型)查询标签列表")
@GetMapping("list")
public Result<List<LabelInfo>> labelList(@RequestParam(required = false) ItemType type) {
LambdaQueryWrapper<LabelInfo> labelInfoLambdaQueryWrapper = new LambdaQueryWrapper<>();
labelInfoLambdaQueryWrapper.eq(type!=null,LabelInfo::getType,type);
List<LabelInfo> list = labelInfoService.list(labelInfoLambdaQueryWrapper);
return Result.ok(list);
}
}
解释
@Operation: 这是用于为Swagger UI生成接口文档的描述信息。
@GetMapping: 将此方法映射到GET请求的"/list"路径,用于处理来自客户端的GET请求。
Result: 指定方法的返回类型,这里使用泛型包装了标签信息的列表,并使用自定义的Result类型标准化响应结构。
@RequestParam: 允许通过请求的查询参数(URL中的参数)传递信息到方法中。required = false表示这个参数不是必须的,请求中可以不包含它。
LambdaQueryWrapper: MyBatis Plus提供的一个工具类,用于构建SQL语句的条件部分。
labelInfoLambdaQueryWrapper.eq(…): 添加一个条件到查询中。这里使用Java 8的方法引用来指定字段名,保证了类型安全。
labelInfoService.list(…): 调用业务逻辑层的方法,执行数据库查询操作,并获取结果。
Result.ok(list): 创建一个表示操作成功的结果,包含查询到的数据,这通常用于统一API的响应结构。
4.4 新增或修改配套信息
查看接口
访问http://localhost:8080/doc.html
点击配套管理
点击新增或修改配套信息
进行开发
在FacilityController
中增加如下内容
@Tag(name = "标签管理")
@RestController
@RequestMapping("/admin/label")
public class LabelController {
@Autowired
private LabelInfoService labelInfoService;
@Operation(summary = "新增或修改标签信息")
@PostMapping("saveOrUpdate")
public Result saveOrUpdateLabel(@RequestBody LabelInfo labelInfo) {
labelInfoService.saveOrUpdate(labelInfo);
return Result.ok();
}
}
4.5 根据id删除配套信息
查看接口
访问http://localhost:8080/doc.html
点击配套管理
点击根据id删除配套信息
进行开发
在FacilityController
中增加如下内容
@Tag(name = "标签管理")
@RestController
@RequestMapping("/admin/label")
public class LabelController {
@Autowired
private LabelInfoService labelInfoService;
@Operation(summary = "根据id删除标签信息")
@DeleteMapping("deleteById")
public Result deleteLabelById(@RequestParam Long id) {
labelInfoService.removeById(id);
return Result.ok();
}
}
5. 基本属性接口实现(🔴重点:自定义SQL)
房间基本属性管理共有五个接口,分别是
1、保存或更新属性名称
2、保存或更新属性值
3、查询全部属性名称和属性值列表
4、根据ID删除属性名称
5、根据ID删除属性值
下面逐一是实现
首先在AttrController
中注入AttrKeyService
和AttrValueService
,如下:
@Tag(name = "房间属性管理")
@RestController
@RequestMapping("/admin/attr")
public class AttrController {
@Autowired
private AttrKeyService attrKeyService;
@Autowired
private AttrValueService attrValueService;
}
5.1 保存或更新属性名称
查看接口
从接口信息可以看出来:
-
POST请求,请求地址为/admin/attr/value/saveOrUpdate
-
请求包含id、name、attrKeyId,是AttrValue对象
@Schema(description = "房间基本属性表") @TableName(value = "attr_key") @Data public class AttrKey extends BaseEntity { private static final long serialVersionUID = 1L; @Schema(description = "属性key") @TableField(value = "name") private String name; }
进行代码开发
因为是单表查询,可以直接使用MyBatisPlus提供的方法实现。在AttrController
中增加如下内容:
@Operation(summary = "新增或更新属性值")
@PostMapping("value/saveOrUpdate")
public Result saveOrUpdateAttrValue(@RequestBody AttrValue attrValue) {
attrValueService.saveOrUpdate(attrValue);
return Result.ok();
}
5.2 保存或更新属性值
查看接口
从接口信息可以看出来:
-
POST请求,请求地址为/admin/attr/key/saveOrUpdate
-
请求包含id、name,是AttrKey对象
@Schema(description = "房间基本属性表") @TableName(value = "attr_key") @Data public class AttrKey extends BaseEntity { private static final long serialVersionUID = 1L; @Schema(description = "属性key") @TableField(value = "name") private String name; }
进行开发
同为单表,直接使用MyBatisPlus即可,在AttrController
中增加如下内容:
@Operation(summary = "新增或更新属性名称")
@PostMapping("key/saveOrUpdate")
public Result saveOrUpdateAttrKey(@RequestBody AttrKey attrKey) {
attrKeyService.saveOrUpdate(attrKey);
return Result.ok();
}
5.3 查询全部属性名称和属性值列表
查看接口
从接口信息可以看出来:
-
Get请求,请求地址为/admin/attr/list
-
不需要传任何参数,无请求体
-
响应数据为AttrKeyVo对象
//响应数据示例 { "code": 0, "message": "", "data": [ { "id": 0, "name": "", "attrValueList": [ { "id": 0, "name": "", "attrKeyId": 0 } ] } ] }
查看web-admin模块下的
com.atguigu.lease.web.admin.vo.attr.AttrKeyVo
,内容如下:@Data public class AttrKeyVo extends AttrKey { @Schema(description = "属性value列表") private List<AttrValue> attrValueList; }
进行开发
查询全部属性名称和属性值列表,包含了两个表,因为MyBatis-Plus本身不支持连表查询,所以需要采用自己手写sql的方式
1、首先在AttrController
中添加如下内容
@Operation(summary = "查询全部属性名称和属性值列表")
@GetMapping("list")
public Result<List<AttrKeyVo>> listAttrInfo() {
//因为MyBatisPlus里面不能进行联表查询,所以这边调用业务层方法自己写sql
List<AttrKeyVo> attrKeyVos = attrKeyService.listAttrInfo();
return Result.ok(attrKeyVos);
}
2、编写Service层逻辑,在AttrKeyService
创建接口
List<AttrKeyVo> listAttrInfo();
3、编写Service层实现类,在AttrKeyServiceImpl
中调用Mapper层方法
/**
* @author Matthew
* @description 针对表【attr_key(房间基本属性表)】的数据库操作Service实现
* @createDate 2023-07-24 15:48:00
*/
@Service
public class AttrKeyServiceImpl extends ServiceImpl<AttrKeyMapper, AttrKey>
implements AttrKeyService{
@Autowired
private AttrKeyMapper attrKeyMapper;
/**
* 查询全部属性名称和属性值列表
*
* @return
*/
@Override
public List<AttrKeyVo> listAttrInfo() {
List<AttrKeyVo> attrKeyVos = attrKeyMapper.listAttrInfo();
return attrKeyVos;
}
}
4、编写Mapper层逻辑
在AttrKeyMapper
中增加如下内容
List<AttrKeyVo> listAttrInfo();
对应的在AttrKeyMapper.xml
编写sql语句,具体思路如下
通过attrKey的id跟attrValue的attr_key_id进行匹配,需要注意的是,再进行关联时,我们需要进行左连接,同时在判断k.id = v.attr_key_id 需要再加上v.is_deleted = 0,where只做判断k.is_deleted = 0,因为用的是逻辑删除,这样避免k值存在,而v值不存在却查询出来,具体代码如下:
<resultMap id="BaseResultMap" type="com.atguigu.lease.web.admin.vo.attr.AttrKeyVo">
<id property="id" column="id"/>
<result property="name" column="key_name"/>
<collection property="attrValueList" ofType="com.atguigu.lease.model.entity.AttrValue">
<id column="value_id" property="id"/>
<result column="value_name" property="name"/>
<result column="key_id" property="attrKeyId"/>
</collection>
</resultMap>
<select id="listAttrInfo" resultMap="BaseResultMap">
select k.id,
k.name key_name,
v.id value_id,
v.name value_name,
v.attr_key_id key_id
from attr_key k
left join attr_value v on k.id = v.attr_key_id and v.is_deleted = 0
where k.is_deleted = 0
</select>
5.4 根据ID删除属性名称
查看接口
从接口信息可以看出来:
- DELETE请求,请求地址为/admin/attr/key/deleteById
- 请求参数为attrKeyId
进行开发
删除属性名称时,需要去删除,对应的属性值,因为作为key不存在了,那么值,也没有存在的意义,所以可以通过``LambdaQueryWrapper`进行条件筛选,删除
在AttrController
中增加如下内容
@Operation(summary = "根据id删除属性名称")
@DeleteMapping("key/deleteById")
@Transactional
public Result removeAttrKeyById(@RequestParam Long attrKeyId) {
//删除属性名称
attrKeyService.removeById(attrKeyId);
//删除属性值
LambdaQueryWrapper<AttrValue> attrValueLambdaQueryWrapper = new LambdaQueryWrapper<>();
attrValueLambdaQueryWrapper.eq(AttrValue::getAttrKeyId,attrKeyId);
attrValueService.remove(attrValueLambdaQueryWrapper);
return Result.ok();
}
5.5 根据ID删除属性值
在AttrController
中增加如下内容
@Operation(summary = "根据id删除属性值")
@DeleteMapping("value/deleteById")
public Result removeAttrValueById(@RequestParam Long id) {
attrValueService.removeById(id);
return Result.ok();
}