- 设计 模块 中需要用到的 数据库表
根据 数据库表名, 使用
mybatis-plus-generator
代码生成器, 自动生成entities
、Controller
、Service
、Mapper
文件夹以及相应的文件, 但不使用 默认生成 的 Controller 文件, 统一在 DeptUserController 中进行实现。
- 模块名:
deptuser
- 模块Controller:
DeptUserController
- 请求URL:
deptuser/DeptUser/FunGetDeptList
- Controller上的注解:
@RequestMapping("/DeptUser")
自动生成的 类:
- 数据库表:
T_E_Sys_Department
- 实体类:
TESysDepartment
- Mapper接口类:
TESysDepartmentMapper
- Service接口类:
TESysDepartmentService
- ServiceImpl实现类:
TESysDepartmentServiceImpl
@SpringBootApplication
@MapperScan("com.tencent.wechat.user.mapper") // 参考 Spring Cloud 教学
public class TencentWechatUserApplication {
public static void main(String[] args) {
SpringApplication.run(TencentWechatUserApplication.class, args);
}
}
- Mybatis-Plus 自动生成的 实体类 代码 不能修改, 只能在字段上添加
@JsonProperty()
, 并且值与@TableField()
中的值严格一致。- 有
下划线_
的 实体类、入参、出参 一定要标记@JsonProperty()
注解。
// 仅用于参考,自动生成的实体类无需修改
@Data
@EqualsAndHashCode(callSuper = false)
@TableName("T_E_Sys_User")
@ApiModel(value="TESysUser对象", description="")
public class TESysUser implements Serializable {
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "自增id")
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
@ApiModelProperty(value = "用户id")
@TableField("UserID")
private String UserID;
// ......
}
Mapper 有两种类 可以继承:
BaseMapper
: mabatis-plus 单表查询 (默认使用这种)MPJBaseMapper
: mabatis-plus-join 多表连接查询 (建议全部使用这种)
public interface TESysDepartmentMapper extends MPJBaseMapper<TESysDepartment> {
// 不用写任何实现, Mybatis-Plus已经默认写好了
}
@Configuration
@EnableTransactionManagement // 开启事务管理
@MapperScan("com.tencent.wechat.user.mapper") // 扫描mapper接口
public class MyBatisPlusConfig {
/**
* 分页插件
*/
@Bean
public MybatisPlusInterceptor paginationInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor());
return interceptor;
}
}
@MapperScan("com.tencent.wechat.user.mapper")
@SpringBootApplication
public class TencentWechatUserApplication {
public static void main(String[] args) {
SpringApplication.run(BaseApplication.class,args);
}
}
public interface ITESysUserService extends IService<TESysUser> {
ResultData Insert();
ResultData InsertLove(InsertLoveIn info);
}
@Service
public class TESysUserServiceImpl extends ServiceImpl<TESysUserMapper, TESysUser> implements ITESysUserService {
@Override
public ResultData Insert() {
// .. 具体实现逻辑, 主要实现代码的地方
return ResultData.ok();
}
public ResultData InsertLove(InsertLoveIn info) {
// .. 具体实现逻辑, 主要实现代码的地方
return ResultData.ok();
}
}
- 注意: 在
TESysUserServiceImpl
中进行左连接,TESysUser
表就是查询主表, 因为默认注入的baseMapper
是TESysDepartmentMapper
类型。- 如果需要其他 表 作为 主表, 则需要额外进行注入 (使用
@Resource
注解 而不是@Autowired
注解)
@Resource // 不能用 @Autowired
private TESysBlogMapper tESysBlogMapper;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class InsertLoveIn implements Serializable {
// 在 entitiesIn、entitiesOut 中: java 主动和 url 中字段保持一致: 通过 @JsonProperty() 实现
// 在 entities 中: java 主动和 MySQL 数据库 中字段保持一致, 通过 @TableField()
@JsonProperty("FormID")
private String FormID;
@JsonProperty("FormName")
private String FormName;
}
注1: 一定要实现
Serializable
接口, 否接无法接收入参数据。
@Data
@NoArgsConstructor
@AllArgsConstructor
public class InsertLoveOut implements Serializable {
@JsonProperty("FormName")
private String FormName;
// ......
}
DeptUserController.java
@RestController
@RequestMapping("/User")
public class UserController {
@Autowired
ITESysUserService iteSysUserService;
@PostMapping("/InsertLove")
public ResultData InsertLove(@RequestBody InsertLoveIn info) {
return iteSysUserService.InsertLove(info);
}
// ......
}
@PostMapping("/InsertLove")
public ResultData InsertLove(@RequestBody InsertLoveIn info) {
return iteSysUserService.InsertLove(info);
}
Get
请求 不能加@RequestBody
注解, 否则会报错。
- 简化代码: 例如有一个 99个字段 的 Java类, 使用普通 CRUD SQL语句 将会非常 冗余繁杂, 使用
Mybatis-Plus
则非常简洁。- 动态 SQL (语句不是固定的,
运行时
才能确定最终组成的SQL语句
)- 支持多种数据库
- 代码自动生成: 输入 数据库表名, 自动生成与之对应的 实体类、Mapper类(已实现常用的CRUD)、Service类、ServiceImpl类。
MPJQueryWrapper<TESysUser> wrapper = new MPJQueryWrapper<TESysUser>()
.select("t.UserName", "t.IsOnLine", "t.IsLock", "t.LoginType", "B.EmployeeID", "B.EmployeeName", "B.Officephone2", "D.DeptID", "D.DeptName", "B.OrderID", "C.DeptEmployeeType")
.select("E.DeptName as P_DeptName")
.innerJoin("T_E_Sys_Employee B on t.EmployeeID = B.EmployeeID");
if (!"".equals(info.getZhiorli())) {
wrapper.leftJoin("T_E_Sys_DeptEmployee C on B.EmployeeID=C.EmployeeID and C.DeptEmployeeType = " + info.getZhiorli());
} else {
wrapper.leftJoin("T_E_Sys_DeptEmployee C on B.EmployeeID=C.EmployeeID");
}
wrapper.leftJoin("T_E_Sys_Department D on C.DeptID=D.DeptID")
.leftJoin("T_E_Sys_Department E on D.DeptPWBS=E.DeptWBS");
wrapper.like("true".equals(info.getSelflag()), "D.DeptWBS", str_deptwbs + "%");
wrapper..like(!"true".equals(info.getSelflag()), "D.DeptWBS", str_deptwbs);
}
IPage<FunGetDeptUserListOut> page = baseMapper.selectJoinPage(new Page<>(info.getCurrent(), info.getSize()), FunGetDeptUserListOut.class, wrapper);
MPJQueryWrapper<TEAppPublishinfo> wrapper = new MPJQueryWrapper<TEAppPublishinfo>()
.select("t.autoid", "t.publish_type", "t.publish_title", "t.publish_date", "t.stateflag", "t.linkfile", "t.tablename", "t.rsautoid", "t.filename", "t.filepath")
.select("B.EmployeeID,B.EmployeeName")
.innerJoin("T_E_Sys_Employee B on t.publish_user = B.EmployeeID")
.eq("t.stateflag", 1)
.or(i -> i.eq("t.stateflag", 2).like("t.user_id", info.getEmployeeid() + "%"))
.like(StringUtils.isNotEmpty(info.getQuery_title()), "t.publish_title", info.getQuery_title() + "%")
.eq(StringUtils.isNotEmpty(info.getQuery_type()), "t.publish_type", info.getQuery_type())
.ge(StringUtils.isNotEmpty(info.getQuery_date_b()), "t.A.publish_date", info.getQuery_date_b())
.le(StringUtils.isNotEmpty(info.getQuery_date_e()), "t.A.publish_date", info.getQuery_date_e());
if (StringUtils.isNotEmpty(info.getOrderfieldname())) {
if ("employeename".equals(info.getOrderfieldname().toLowerCase()) || "employeeid".equals(info.getOrderfieldname().toLowerCase())) {
wrapper.orderByAsc("B." + info.getOrderfieldname());
} else {
wrapper.orderByAsc("t." + info.getOrderfieldname());
}
} else {
wrapper.orderByDesc("t..autoid");
}
- 一般情况下: 默认使用
MPJLambdaWrapper
。- 当 SQL语句 涉及
[自连接]
、[动态字段]
的功能时, 则只能使用MPJQueryWrapper
。
点击查看: Mybatis Plus select 实现只查询部分字段
Mybatis-Plus 中的 select语句 默认查询 所有字段,如需要指定字段查询,则需使用
MPJQueryWrapper
或MPJLambdaWrapper
。
点击查看: Mybatis-Plus 使用 Lambda 表达式
- 普通 Wrapper:
QueryWrapper
(查询)、UpdateWrapper
(更新) 【都继承了AbstractWrapper
】- Lambda Wrapper:
LambdaQueryWrapper
、LambdaUpdateWrapper
建议直接使用 Mybatis-Plus-Join 提供的
MPJLambdaWrapper
BaseMapper
是MPJBaseMapper
的 顶层父类。
MPJBaseMapper
包含BaseMapper
中实现的 所有方法, 还包括自己另外添加的方法。(只做增强, 不做修改)。
MPJLambdaWrapper<TESysDepartment> wrapper = new MPJLambdaWrapper<TESysDepartment>()
.select(TESysDepartment::getDeptID, TESysDepartment::getDeptCode, TESysDepartment::getDeptName, TESysDepartment::getDeptWBS, TESysDepartment::getDeptPWBS, TESysDepartment::getTypeID)
.select(TESysDepartmenttype::getTypeName, TESysDepartmenttype::getIsBizAreaType)
.select(TESysDepartment::getOrderID)
.innerJoin(TESysDepartmenttype.class, TESysDepartmenttype::getTypeID, TESysDepartmenttype::getTypeID)
.eq(TESysDepartment::getDeptWBS, str_deptwbs)
.orderByAsc(TESysDepartment::getOrderID, TESysDepartment::getDeptWBS);
List<FunGetDeptListOut> list = baseMapper.selectJoinList(FunGetDeptListOut.class, wrapper);
// 注意区分 TESysDepartment 和 FunGetDeptListOut。
MPJQueryWrapper<TESysDepartment> wrapper1 = new MPJQueryWrapper<TESysDepartment>()
.select("DeptPWBS,count(DeptID) as ChildNum")
.in("DeptPWBS", tmpList)
.groupBy("DeptPWBS");
List<FunGetDeptList2Out> list2 = baseMapper.selectJoinList(FunGetDeptList2Out.class, wrapper1);
leftJoin("(select * from user_address) addr on t.id = addr.user_id")
对应sql:
LEFT JOIN (select * from user_address) addr ON t.id = addr.user_id
单表分页:
In类
继承BaseRequest
对象。(In类
中则不需要再写page
、size
信息)
BaseRequest.java
@Accessors(chain = true)
@Data
public class BaseRequest<T> implements Serializable {
@ApiModelProperty(value = "页码", required = true)
private long current;
@ApiModelProperty(value = "每页显示多少条", required = true)
private long size;
// 封装分页对象
@ApiModelProperty(hidden = true) // 不在swagger接口文档中显示
public IPage<T> getPage() {
return new Page<T>().setCurrent(this.current).setSize(this.size);
}
}
FunGetDeptUserListIn
继承 BaseRequest
@Data
@AllArgsConstructor
@NoArgsConstructor
public class FunGetDeptUserListIn extends BaseRequestCurrentSize<FunGetDeptUserListOut> implements Serializable {
@JsonProperty("deptid")
private String deptid;
// ...
}
多表分页:
In类
直接 继承BaseRequestCurrentSize
对象。(In类
中则不需要再写page
、size
信息)
@Data
@AllArgsConstructor
@NoArgsConstructor
public class FunGetDeptUserListIn extends BaseRequestCurrentSize implements Serializable {
@JsonProperty("deptid")
private String deptid;
// ...
}
baseMapper.selectJoinPage()
进行查询IPage<FunGetDeptUserListOut> page = baseMapper.selectJoinPage(
new Page<>(info.getCurrent(), info.getSize()), FunGetDeptUserListOut.class,wrapper
);
for (int i=0; i<page.getRecords().size(); i++) {
page.getRecords().get(i).setXuHao((int)((page.getCurrent()-1)*page.getSize()) + i + 1);
if (page.getRecords().get(i).getOrderID() == null) {
page.getRecords().get(i).setOrderID(0);
}
page.getRecords().get(i).setDeptEmployeeType(page.getRecords().get(i).getDeptEmployeeType().equals("1") ? "直属" : "隶属");
};
点击查看
mapper中添加:
@Select("${sqlStr}")
List<HashMap<String, Object>> ExecuteReaderDataTable(@Param("sqlStr")String sql);
调用执行:
// sql_str: 动态组成的 复杂的 sql 字符串
dt_mainpage02 = baseMapper.ExecuteReaderDataTable(sql_str);
UPDATE
: 使用 UpdateWrapper
UpdateWrapper wrapper = new UpdateWrapper<TEWfSealinfo>()
.eq("autoid", str_autoid);
baseMapper.update(teWfSealinfo, wrapper);
DELETE
: 使用 MPJQueryWrapper
或 QueryWrapper
, 不要用 MPJLambdaWrapper
MPJQueryWrapper<TEAppCarouselpic> wrapper = new MPJQueryWrapper<TEAppCarouselpic>()
.eq("autoid", info.getAutoid());
int num = baseMapper.delete(wrapper);
解决办法: 把字段用 `` 包起来。
SELECT FunID,`Limit`
FROM T_E_Sys_DeptLimit t
WHERE (FunID IN ('016a7b6a-7785-4e40-837d-dff009077090','1d8135ba-dcd6-4919-ad3f-330204b10234') AND DeptID IN (
select DeptID
FROM T_E_Sys_DeptEmployee
WHERE EmployeeID='CEA52225-D79E-42B1-A006-474629638C99'))
也可以使用
MPJQueryWrapper
、MPJLambdaWrapper
, 会自动在字段前加上 别名, 所以不会出现上述问题。
''
?# 错误写法
wrapper.inSql("age", "select name from T_E_Sys_User WHERE id=" + info.getId());
# 正确写法
wrapper.inSql("age", "select name from T_E_Sys_User WHERE id='" + info.getId() + "'");
.inSql
需要添加.in
不需要添加.eq
不需要添加- 总结: 自己写的 sql语句 中才需要添加
''
, Mybatis-Plus 组成的sql会自动添加''
- 正确方法:
selectAs(TESysFunnode::getFunSIco, "FunIcon")
- 错误方法:
selectAs(TESysFunnode::getFunSIco, GetFunInfo2Out::getFunIcon)
原因: 第二种书写方式, GetFunInfo2Out::getFunIcon 有可能返回的是
funIcon
, 而不是FunIcon
, 会导致往 出参 中写入数据时报错。
在方法上添加
@Transactional
注解即可。
@Transactional
public ResultData SaveSignData(SaveSignDataIn info) {
// ...
}
MPJQueryWrapper<TESysFunnode> wrapper = new MPJQueryWrapper<TESysFunnode>()
.select("FunWBS", "FunName")
.eq("WebID", str_webid)
.apply("{0} like CONCAT(funWBS, '%')", treeNo); // {0}: 用于匹配 treeNo
其实就是一个 service, 和一个 serviceImpl, 所有有关 Redis 的操作都在 service接口 中定义, 并在 serviceImpl 中具体实现。
public interface IRedisUtil {
RedisUserInfo getAllSession();
}
@Service
public class RedisUtilImpl implements IRedisUtil {
@Autowired
private RedisUtils redisUtils;
public RedisUserInfo getAllSession() {
return (RedisUserInfo) redisUtils.getString(AuthUtil.geTokenId());
}
}
@Autowired
private IRedisUtil redisUtil;
@Override
public ResultData GetSysInfo() {
RedisUserInfo user = redisUtil.getAllSession();
if(user==null){
return ResultData.error("系统已经过期,请重新登录");
}
// ... 其它业务逻辑
// 从redis获取人员id
String employeeid = user.getEmployeeid();
}
RedisUserInfo user = redisUtil.getAllSession();
if(user==null || StringUtils.isEmpty(user.getUsername())){
return ResultData.error("Session数据已失效!");
}
String accessToken = AuthUtil.geTokenId();
if (StringUtils.isEmpty(user.getWebid())) {
user.setWebid("1");
redisUtils.setString(accessToken, user);
}