SpringBoot - 后台开发规约/问题
- 一:Controller用什么参数接收值?
- 二:一行代码太长,换行问题
- 三:@RequestParam相关问题
- 四:Service层注意事项
- 五:VO和DTO该如何使用?
- 六:封装数据返回格式 R
- 七:约定Controller对外提供的基本接口
一:Controller用什么参数接收值?
1> 形参名和传入参数名保持一致
2> 使用Map<String,Object>接收(开发一时爽,维护火葬场)
3> 同时使用Map<String,Object>和基本类型接收
4> 使用DTO:为CRUD分别创建四种DTO,传入的参数使用相应DTO接收
- 四种DTO
- XxxAddDTO
- XxxDeleteDTO
- XxxUpdateDTO
- XxxQueryDTO
- 重新划分项目后由于DTO与实体处于同一层级,代码包结构需要更新
- domain
- entity
- dto
- vo
- domain
- 重新划分使用上述包结构后,为了方便维护,建议后台按照业务模块分类
- course(课程)
- domain
- entity
- dto
- vo
- mapper/dao
- service
- controller
- domain
- file(文件)
- domain
- entity
- dto
- vo
- mapper/dao
- service
- controller
- domain
- course(课程)
5> 同时使用Map<String, Object>和DTO
二:一行代码太长,换行问题
-
函数参数:逗号后换行(
参考三
) -
对象方法:点前换行
三:@RequestParam相关问题
1> 介绍
2> 使用
3> @RequestBody是做什么用的?
前端可以通过参数/表单的方式提交数据,此时我们可以能够使用@RequestParam注解,也可以不使用注解,都可以直接被Spring解析到参数中去。
但是如果前端传给后台的数据格式为application/json(JSON字符串),后台再使用@RequestParam或不使用注解
就拿不到值了。
此时需要使用@RequestBody解析application/json格式数据:
-
使用String接收
-
使用Map接收
-
使用DTO接收
-
@RequestParam都可以使用多个,@RequestBody可以使用多个吗?
不可以!会报错400
四:Service层注意事项
1> 包结构
- service
- 接口.java
- impl
- 接口实现类.java
2> 方法注释
- 方法注释写在接口上
- 实现类中方法注释只按需写非@Override方法注释
五:VO和DTO该如何使用?
1> VO(ValueObject)
-
实体Entity的最初功能是为了满足封装从数据库中获取的数据,但是随着业务的拓展,前台需求的数据并不是单单一个实体能满足的。
-
于是我们可以在entity中添加虚拟字段,来表示这些属性没有与数据库字段绑定,这种方法可以解决问题,但是业务层的部分逻辑划分已经渗透到实体层了。这种耦合趋势是不被接收的。
-
于是我们在Entity层再次抽象了一层VO,VO用于从封装从数据库中拿到的数据(
这意味着继承Entity
),同时VO携带者业务层需要的其他属性数据(以前在Entity中耦合的虚拟字段
),Controller层所有数据均需要被VO封装后返回。 -
这是一种
-
规范,不是一种强制。
-
实例
-
数据库中存储的类型type为:“0”/“1”/“2”/“3”,前端需要的是对应用于显示的数据,如何操作?
-
定义枚举类,手动解析将其放入VO虚拟字段中;
-
SQL语句中直接解析(使用CASE/WHEN/THEN/END + AS)
-
-
2> DTO(Data Transfer Object)
-
数据库中主键是唯一的,当我们根据ID查询时可以查询到唯一的数据,这是肯定的,但是如果前台传入其他列属性作为查询参数,我们将会查询到一个List。
-
多个非ID字段同时作为插叙条件时,后台一个Controller该如何接收这些数据?
-
使用Map?
- 是的,MyBatisPlus中就是使用Map来接收参数的,而且还有很多快捷操作。
- 但是如果前后端分离
- 后端开发者B去维护A写的接口时,嗯?Map?查询条件都有哪些?除非运行时Debug。语法简洁带来成就感的背后,是维护成本的大大提升。
- 前端开发者在编辑查询条件时,直接需要知道后台数据库中的字段名称,而且大小写还不能错误。对于部分前端开发者来说,数据库可能并不能像后端开发者一样得心应手。
- 前后端分离后,如果不能让双端开发者专注于业务,这种分离是没有意义的。
-
使用DTO
-
返回给前台的数据上方说道需要被封装到VO中,同样,前台传入的数据我们再次将其封装DTO,DTO预示着前端传输到后台的数据对象。
-
QueryDTO
- 多条件查询时,这里封装了所有查询条件(
不需要继承实体Entity,面向前端
)
- 多条件查询时,这里封装了所有查询条件(
-
UpdateDTO(
更新/保存
)- 多表更新时,前端一个保存功能需要在数据库DB(DataBase)中存储多条数据,在前台发两个请求到后端是不被允许的(一旦一条成功,一条失败,数据不完全存储是个大问题),一个请求到后台,就需要一个类去封装前台传来的数据,这就是UpdateDTO。
- 1:N更新,UpdateDTO中存储1的属性,N的List,Service层解析。
-
-
六:封装数据返回格式 R
- R
- IResultCode接口
- ResultCode枚举
七:约定Controller对外提供的基本接口
1> 所有请求使用Post发送
2> 约定提供的基本接口
-
getById
-
queryList
-
queryListByPage
-
save
-
update
-
remove
3> 对应Mapper
@Mapper
public interface PaymentMapper extends BaseMapper<Payment> {
/**
* 多条件查询
*
* @param page
* @param queryDTO
* @return
*/
List<PaymentVO> queryList(@Param("queryDTO") PaymentQueryDTO queryDTO);
/**
* 多条件查询(分页)
*
* @param page
* @param queryDTO
* @return
*/
IPage<PaymentVO> queryListByPage(Page<PaymentVO> page, @Param("queryDTO") PaymentQueryDTO queryDTO);
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.x.demo.mapper.PaymentMapper">
<select id="queryList" resultType="com.x.demo.vo.PaymentVO">
SELECT
*
FROM
payment
<where>
1=1
<if test="queryDTO.name != null and queryDTO.name != ''">
AND name=#{queryDTO.name}
</if>
</where>
</select>
<select id="queryListByPage" resultType="com.x.demo.vo.PaymentVO">
SELECT
*
FROM
payment
<where>
1=1
<if test="queryDTO.name != null and queryDTO.name != ''">
AND name=#{queryDTO.name}
</if>
</where>
</select>
</mapper>