实现 Mybatis >、< 等多表联合的动态 sql 拼接
前端页面
前端页面的条件查询,通过点赞数或反对数,或者两者都有的条件进行一个多表查询(联合评论表和用户表):
操作符可以是:大于、大于等于、等于、小于、小于等于。
后端 Controller
我设置的是 Get 请求,由于这个请求被用到的地方很多,我设置了 6 个非必填的参数(其实建议 Post 请求,并通过 Map 接收数据)。
@GetMapping("/query")
public R<List<BuchComment>> query(@RequestParam(required = false) String buchType,
@RequestParam(required = false) Integer buchId,
@RequestParam(required = false) String diggOp,
@RequestParam(required = false) String buryOp,
@RequestParam(required = false) Integer digg,
@RequestParam(required = false) Integer bury) {
ParamsMap<String, Object> paramsMap = new ParamsMap<>();
paramsMap.set("buchType", buchType)
.set("buchId", buchId)
.set("diggOp", diggOp)
.set("buryOp", buryOp)
.set("bury", bury)
.set("digg", digg);
return service.query(paramsMap.getMap());
}
这个请求函数写的有点啰嗦了,不过并无大碍。
后端 Mapper
SQL 分段1
这是联合查询的 SQL 分段,有可能多处用到这个 SQL,就复用起来。
<sql id="frg1">
SELECT bc.*,
u.username u_username,
u.level u_level,
u.id u_id,
u.profile_photo u_profile_photo
FROM buch_comments bc
INNER JOIN buchs b ON b.id = bc.buch_id
INNER JOIN users u ON u.id = bc.user_id
</sql>
resultMap 标签
查询出来的结果是一个集合,其一个元素中的关系是一个评论对应一个用户。
<resultMap id="queryCommsResultMap" type="BuchComment" autoMapping="true">
<id property="id" column="id"/>
<association property="user" javaType="com.buchstadt.pojo.BuchComment$User" autoMapping="true"
columnPrefix="u_">
<id property="id" column="id"/>
</association>
</resultMap>
SQL 分段2
这个 SQL 分段是一个操作符的判断,选择到底使用哪一个 SQL 条件,由于这里被用到的两次,所以写到 SQL 分段中以复用。
<sql id="frg2">
<choose>
<!-- > 大于-->
<when test="${operName} == 'gt'">
AND ${colFiled} > #{${proFiled}}
</when>
<!-- >= 大于等于-->
<when test="${operName} == 'gteq'">
AND ${colFiled} >= #{${proFiled}}
</when>
<!-- < 小于-->
<when test="${operName} == 'lt'">
AND ${colFiled} < #{${proFiled}}
</when>
<!-- <= 小于等于-->
<when test="${operName} == 'lteq'">
AND ${colFiled} <= #{${proFiled}}
</when>
<!-- eq 等于-->
<when test="${operName} == 'eq'">
AND ${colFiled} = #{${proFiled}}
</when>
</choose>
</sql>
这个标签中有一个重要的注意事项,${}
是取出 property 标签传入的值,作为表中的可能存在的字段。而,#{}
是取出值,作为一个变量,如数字、字符串等,不是表中的字段。
我解释一下 #{${proFiled}}
的用法。因为 property 传递过来的值只能通过 ${}
获取,而又因可能将其作为一个 SQL 变量使用,所以外面包裹一个 #{}
。
select 查询标签
select 查询标签中最重要的是 if 标签了。首先通过 trim 标签去除多余的 AND 关键字,以及给第一个添加一个 WHERE 关键字。
接着就取出一个个 Map 中的元素,判断其值是否空或者 null 等。
<select id="query" resultMap="queryCommsResultMap">
<include refid="frg1"/>
<trim prefix="WHERE" prefixOverrides="AND">
<if test="buchType != null and buchType != '' and buchType != 'all'">
AND bc.type = #{buchType}
</if>
<if test="buchId != null and buchId != 0">
AND bc.buch_id = #{buchId}
</if>
<if test="bury != null and operator != ''">
<include refid="frg2">
<property name="colFiled" value="bc.bury"/>
<property name="operName" value="buryOp"/>
<property name="proFiled" value="bury"/>
</include>
</if>
<if test="digg != null and operator != ''">
<include refid="frg2">
<property name="colFiled" value="bc.digg"/>
<property name="operName" value="diggOp"/>
<property name="proFiled" value="digg"/>
</include>
</if>
</trim>
</select>
这里有一个细节,bc.digg
意思是,选取多表查询中被重命名的表 bc
,得到其字段 digg 。