文章目录
- 前言
- 一、实体类的注解
- 二、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 {
@Resource
private 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 {
@Autowired
private ActivityMapper activityMapper;
@Override
public 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的一些总结