文章目录
- 前言
- 一、实体类的注解
- 二、Req查询条件
- 三、Controller接口
- 四、Service接口
- 五、Service接口实现类
- 六、Mapper接口
- 七、枚举的使用
- 总结
前言
最近的项目是使用mybatis-plus作为持久层框架,前面也记录过mybatis-plus的基本使用,此次记录一下本次项目中的一些使用要点
一、实体类的注解
基本的导入依赖和代码自动生成器,可以去看以前的文章,本次不再赘述。
以项目中的一个实体类为例
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.IdType;import java.util.Date;import com.baomidou.mybatisplus.annotation.TableId;import java.io.Serializable;
import java.util.List;import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;@Data
@EqualsAndHashCode(callSuper = false)
@TableName("co_activity")
@ApiModel(value = "Activity对象", description = "绿色活动")
public class Activity implements Serializable {private static final long serialVersionUID = 1L;@TableId(value = "id", type = IdType.ASSIGN_ID)private String id;@ApiModelProperty(value = "关联EMP活动ID")private String empId;@ApiModelProperty(value = "活动小图")private String image;@ApiModelProperty(value = "活动名称")private String name;@ApiModelProperty(value = "活动副标题")private String subTitle;@ApiModelProperty(value = "活动日期")@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")private Date activityDate;@ApiModelProperty(value = "活动城市")private String city;@ApiModelProperty(value = "排序")private Integer sort;@ApiModelProperty(value = "签到奖励能量")private Integer sigInEnergy;@ApiModelProperty(value = "预约奖励能量")private Integer reservationEnergy;@ApiModelProperty(value = "关联绿色场景")private String sceneRuleId;@ApiModelProperty(value = "推荐(1:是,0:否)")private Integer recommend;@ApiModelProperty(value = "删除标记")private Integer delFlag;}
实体类上mybatis-plus的注解有两个,
- @TableName(“co_activity”)指定表名
- @TableId(value = “id”, type = IdType.ASSIGN_ID) 指定主键
实体类还应该实现序列化接口,方便后续对数据进行流操作
其余的注解是lombok注解和swagger文档注解
二、Req查询条件
req查询条件是mybatis-plus封装自己为我们封装的查询条件,需要我们继承一个BaseRequest< T >类(其中T是我们的实体类),也支持我们对其进行自定义修改加入我们需要的查询条件,默认的查询条件如下:
mybatis-plus帮我们自动实现了分页的查询条件,当然在实际的开发中只有一个分页条件是远远不够的,下边是我的自定义查询条件:
三、Controller接口
这里我以一个条件查询的方法演示
@Api(tags = "绿色活动")
@RestController
@RequestMapping("/activity")
@Slf4j
public class ActivityController {@Resourceprivate IActivityService iActivityService;@ApiOperation("分页查询")@PostMapping("/admin/page")public Result page(@RequestBody ActivityReq req) {log.info("分页查询活动列表:{}", JSON.toJSONString(req));Map<String, Object> page = iActivityService.pageQuery(req);log.info("分页查询活动列表到的数据:{}", JSON.toJSONString(page));return Result.ok(page);}
}
也就是说,我们后端接口接收的查询条件就是req,它以json的数据格式进行传输
传入的数据格式如下
{"id":"","empId":"","activityName":"","city":"","sceneRuleId":""
}
四、Service接口
service接口需要我们去实现一个mybatis-plus的接口IService< T >
public interface IActivityService extends IService<Activity> {/*** 分页查询** @param req 查询条件* @return map*/Map<String, Object> pageQuery(ActivityReq req);
}
其中实现了一些基础的CRUD方法,如果只是简单不带业务逻辑的基本功能,mybatis-plus都给我们进行了封装,拿来即用,此处不再展示
五、Service接口实现类
这里除了我们需要去实现一个我们自定义的接口外,还需要我们去继承一个mybatis-plus的类ServiceImpl<Mapper, Model> 代码如下:
@Service
@Slf4j
public class ActivityServiceImpl extends ServiceImpl<ActivityMapper, Activity>
implements IActivityService {@Autowiredprivate ActivityMapper activityMapper;@Overridepublic Map<String, Object> pageQuery(ActivityReq req) {log.info("分页查询活动列表到的数据:{}", JSON.toJSONString(req));List<SceneRule> sceneRules = sceneRuleMapper.selectList(new QueryWrapper<>());Map<String, String> sceneRuleMap = new HashMap<>(sceneRules.size());for (SceneRule sceneRule : sceneRules) {sceneRuleMap.put(sceneRule.getId(), sceneRule.getName());}QueryWrapper<Activity> queryWrapper = new QueryWrapper<>();/*活动id模糊查询*/queryWrapper.like(StringUtils.isNotBlank(req.getId()), "id", req.getId());/*emp活动id模糊查询*/queryWrapper.like(StringUtils.isNotBlank(req.getEmpId()), "emp_id", req.getEmpId());/*活动名称模糊查询*/queryWrapper.like(StringUtils.isNotBlank(req.getActivityName()), "name", req.getActivityName());/*城市*/CityEnum eumByCode = CityEnum.getEumByCode(req.getCityCode());if (eumByCode != null) {String city = eumByCode.getDesc();queryWrapper.eq("city", city);}/*未删除的*/queryWrapper.eq("del_flag", DelFlagEnum.NO_DEL.getCode());/*不查全国的*/queryWrapper.ne("city", CityEnum.QUANGUO.getDesc());/*场景*/queryWrapper.eq(StringUtils.isNotBlank(req.getSceneRuleId()), "scene_rule_id", req.getSceneRuleId());/*日期降序*/queryWrapper.orderByDesc("activity_date");IPage<Activity> page = baseMapper.selectPage(req.getPage(), queryWrapper);List<Activity> activityList = page.getRecords();List<String> empIds = new ArrayList<>(activityList.size());for (Activity activity : activityList) {if (StringUtils.isNotBlank(activity.getEmpId()) && !empIds.contains(activity.getEmpId())) {empIds.add(activity.getEmpId());}}List<EmpVo> empVoList = empVoList(empIds);Map<String, EmpVo> empVoMap = new HashMap<>(empVoList.size());for (EmpVo empVo : empVoList) {empVoMap.put(empVo.getEventId(), empVo);}/*将结果封装为VO返回前端*/List<ActivityVo> list = page.getRecords().stream().map(activity -> {ActivityVo vo = new ActivityVo();BeanUtils.copyProperties(activity, vo);if (sceneRuleMap.get(activity.getSceneRuleId()) == null) {vo.setSceneRuleName("无");} else {vo.setSceneRuleName(sceneRuleMap.get(activity.getSceneRuleId()));}EmpVo empVo = empVoMap.get(activity.getEmpId());if (empVo != null) {String image = null;vo.setName(empVo.getTitle());vo.setSubTitle(empVo.getType());vo.setActivityDate(empVo.getHoldingEndTime());vo.setCityName(empVo.getCity());if ("0".equals(empVo.getEventScene())) {image = empVo.getAppCoverImage();} else if ("1".equals(empVo.getEventScene())) {List<String> eventImageList = empVo.getEventImageList();if (CollectionUtils.isNotEmpty(eventImageList)) {image = eventImageList.get(0);}}vo.setImage(image);}log.info("vo封装结束");return vo;}).collect(Collectors.toList());Map<String, Object> map = new HashMap<>(3);map.put("total", page.getTotal());map.put("list", list);map.put("page", page.getCurrent());return map;}
}
此处需要注意的是,我们需要使用一个StringUtils.isNotBlank(查询条件) 方法去判断我们的查询条件是否为空,不为空再进行拼接,其次这里还使用了一个stream流去处理查询出来的结果,因为mybatis-plus只支持单表查询,但是对于复杂的显示来说,我们不得不去另外一张表中取数据,所以,这里对查询结果使用stream流进行数据处理,将我们需要的数据进行处理,然后返回
六、Mapper接口
有些时候我们自带的查询方法,极有可能不满足我们的业务需求,所以我们需要使用mybatis的xml映射文件去编写sql,和mybatis基本一致,需要注意的是我们的mapper也要继承一个类BaseMapper< T > 其中封装了一些基本的持久层的CRUD方法供我们使用
@Repository
public interface ActivityMapper extends BaseMapper<Activity> {/*** 获取已经关联的empId* @return*/List<String> getEmpIds();
}
七、枚举的使用
开发规范中,不允许魔法值的出现,所以在真实的开发中需要我们使用枚举去完成一些类目的判断,下面以城市为例:
@Getter
@AllArgsConstructor
public enum CityEnum {BEIJING("110000", "北京市"),SHANGHAI("310000", "上海市"),GUANGZHOU("440100", "广州市"),SHENZHEN("440300", "深圳市"),HANGZHOU("330100", "杭州市"),FOSHAN("440600", "佛山市"),QUANGUO("000000", "全国");private String code;private String desc;public static CityEnum getEumByCode(String code) {if (code == null) {return null;}for (CityEnum type : CityEnum.values()) {if (type.getCode().equals(code)) {return type;}}return null;}
}
以上就是一个城市的枚举类
在使用的时候如下:
/*城市*/CityEnum eumByCode = CityEnum.getEumByCode(req.getCityCode());if (eumByCode != null) {String city = eumByCode.getDesc();queryWrapper.eq("city", city);}
这样就避免的魔法值的出现
常用的枚举还有逻辑删除
@Getter
@AllArgsConstructor
public enum DelFlagEnum {NO_DEL(0, "未删除"),DEL(1, "已删除");private Integer code;private String desc;
}
我们也可以在VO类中添加枚举处理,例如我们需要在活动VO中获取城市名,(假设model中是没有城市名的,只存了一个code码)
public String setCityName() {String name = "";CityEnum eumByCode = CityEnum.getEumByCode(this.city);if (eumByCode != null) {name = eumByCode.getDesc();}return name;}
可以在VO中添加上边的代码,
总结
以上就是最近在使用mybatis-plus的一些总结