本文目录如下:
- Spring Cloud (Hoxton.SR8) 开发笔记
- 1、业务模块实现步骤
- 使用 Mybatis-Plus-Generator 自动生成代码
- Application 启动类添加 @MapperScan() 扫描注解
- 自动生成的 实体类 注解的问题(@JsonProperty()、@TableField())?
- 修改 Mapper 接口的实现类
- 注册 config/MyBatisPlusConfig 扫描 mapper 接口
- 定义 ITESysDepartmentService 接口, 并定义 接口实现类
- 根据请求接口定义 入参对象
- 定义出参对象, 接收数据库查询结果:
- 注入 Service, 并编写Controller请求处理器
- Post请求 入参要添加 @RequestBody 注解, 否则不会注入
- 使用 postman 进行测试
- 2、Mybatis-Plus & Mybatis-Plus-Join 注意事项
- 动态SQL 实现案例1 - Mybatis-Plus-Join
- 动态SQL 实现案例2 - Mybatis-Plus-Join
- 如何选择 MPJLambdaWrapper 还是 MPJQueryWrapper?
- Mybatis-Plus 使用 Lambda 表达式
- BaseMapper 和 MPJBaseMapper 的区别?
- MPJBaseMapper + MPJLambdaWrapper 实现案例?
- MPJBaseMapper + MPJQueryWrapper实现案例?
- MyBatis-Plus 实现 单表分页?
- MyBatis-Plus 实现 多表分页?
- Mybatis-Plus不依赖实体执行 原生SQL?
- Mybatis-Plus 中使用 UPDATE 和 DELETE?
- Mybatis-Plus中 like 属性在后的用法?
- Mybatis-Plus中 like 使用注意事项?
- 3、Redis - 请求鉴权
Spring Cloud (Hoxton.SR8) 开发笔记
1、业务模块实现步骤
使用 Mybatis-Plus-Generator 自动生成代码
- 设计 模块 中需要用到的 数据库表
根据 数据库表名, 使用
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
Application 启动类添加 @MapperScan() 扫描注解
@SpringBootApplication
@MapperScan("com.tencent.wechat.user.mapper") // 参考 Spring Cloud 教学
public class TencentWechatUserApplication {
public static void main(String[] args) {
SpringApplication.run(TencentWechatUserApplication.class, args);
}
}
自动生成的 实体类 注解的问题(@JsonProperty()、@TableField())?
- 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 接口的实现类
Mapper 有两种类 可以继承:
BaseMapper
: mabatis-plus 单表查询 (默认使用这种)MPJBaseMapper
: mabatis-plus-join 多表连接查询 (建议全部使用这种)
public interface TESysDepartmentMapper extends MPJBaseMapper<TESysDepartment> {
// 不用写任何实现, Mybatis-Plus已经默认写好了
}
注册 config/MyBatisPlusConfig 扫描 mapper 接口
@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);
}
}
定义 ITESysDepartmentService 接口, 并定义 接口实现类
- ITESysDepartmentService .java
public interface ITESysUserService extends IService<TESysUser> {
ResultData Insert();
ResultData InsertLove(InsertLoveIn info);
}
- ITESysDepartmentServiceImpl .java
@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;
// ......
}
注入 Service, 并编写Controller请求处理器
DeptUserController.java
@RestController
@RequestMapping("/User")
public class UserController {
@Autowired
ITESysUserService iteSysUserService;
@PostMapping("/InsertLove")
public ResultData InsertLove(@RequestBody InsertLoveIn info) {
return iteSysUserService.InsertLove(info);
}
// ......
}
Post请求 入参要添加 @RequestBody 注解, 否则不会注入
@PostMapping("/InsertLove")
public ResultData InsertLove(@RequestBody InsertLoveIn info) {
return iteSysUserService.InsertLove(info);
}
Get
请求 不能加@RequestBody
注解, 否则会报错。
使用 postman 进行测试
- 新建
- 新建
User
目录- 新建请求:
InsertLove
- POST :
localhost:8190/user/User/InsertLove
- 参数放入
Body
中:
2、Mybatis-Plus & Mybatis-Plus-Join 注意事项
动态SQL 实现案例1 - Mybatis-Plus-Join
MPJQueryWrapper<TESysUser> wrapper = new MPJQueryWrapper<TESysUser>()
.select("t.UserName", "t.IsOnLine");
if (!"".equals(info.getZhiorli())) {
wrapper.leftJoin("T_E_Sys_DeptEmployee C on B.EmployeeID=C.EmployeeID and C.DeptEmployeeType = " + info.getZhiorli());
}
wrapper.like("true".equals(info.getSelflag()), "D.DeptWBS", str_deptwbs + "%");
}
IPage<FunGetDeptUserListOut> page = baseMapper.selectJoinPage(new Page<>(info.getCurrent(), info.getSize()), FunGetDeptUserListOut.class, wrapper);
动态SQL 实现案例2 - Mybatis-Plus-Join
MPJQueryWrapper<TEAppPublishinfo> wrapper = new MPJQueryWrapper<TEAppPublishinfo>()
.select("t.autoid", "t.publish_type", "t.publish_title")
.innerJoin("T_E_Sys_Employee B on t.publish_user = B.EmployeeID")
.or(i -> i.eq("t.stateflag", 2).like("t.user_id", info.getEmployeeid() + "%"))
.eq(StringUtils.isNotEmpty(info.getQuery_type()), "t.publish_type", info.getQuery_type())
if (StringUtils.isNotEmpty(info.getOrderfieldname())) {
wrapper.orderByDesc("t..autoid");
}
}
如何选择 MPJLambdaWrapper 还是 MPJQueryWrapper?
- 一般情况下: 默认使用
MPJLambdaWrapper
。- 当 SQL语句 涉及
[自连接]
、[动态字段]
的功能时, 则只能使用MPJQueryWrapper
。
Mybatis-Plus 使用 Lambda 表达式
点击查看: Mybatis-Plus 使用 Lambda 表达式
- 普通 Wrapper:
QueryWrapper
(查询)、UpdateWrapper
(更新) 【都继承了AbstractWrapper
】- Lambda Wrapper:
LambdaQueryWrapper
、LambdaUpdateWrapper
BaseMapper 和 MPJBaseMapper 的区别?
BaseMapper
是MPJBaseMapper
的 顶层父类。
MPJBaseMapper
包含BaseMapper
中实现的 所有方法, 还包括自己另外添加的方法。(只做增强, 不做修改)。
MPJBaseMapper + MPJLambdaWrapper 实现案例?
MPJLambdaWrapper<TESysDepartment> wrapper = new MPJLambdaWrapper<TESysDepartment>()
.select(TESysDepartment::getDeptID, TESysDepartment::getDeptCode)
.innerJoin(TESysDepartmenttype.class, TESysDepartmenttype::getTypeID, TESysDepartmenttype::getTypeID)
.eq(TESysDepartment::getDeptWBS, str_deptwbs);
List<FunGetDeptListOut> list = baseMapper.selectJoinList(FunGetDeptListOut.class, wrapper);
// 注意区分 TESysDepartment 和 FunGetDeptListOut。
MPJBaseMapper + MPJQueryWrapper实现案例?
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);
MyBatis-Plus 实现 单表分页?
单表分页:
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<FunGetDeptUserListOut>
@Data
@AllArgsConstructor
@NoArgsConstructor
public class FunGetDeptUserListIn extends BaseRequest<FunGetDeptUserListOut> implements Serializable {
@JsonProperty("deptid")
private String deptid;
// ...
}
MyBatis-Plus 实现 多表分页?
多表分页:
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()), FunOut.class, wrapper
);
for (int i=0; i<page.getRecords().size(); i++) {
System.out.println(page.getRecords().get(i).toString());
};
Mybatis-Plus不依赖实体执行 原生SQL?
- Mapper 文件中添加:
@Select("${sqlStr}")
List<HashMap<String, Object>> ExecuteReaderDataTable(@Param("sqlStr")String sql);
- 调用执行:
// sql_str: 动态组成的 复杂的 sql 字符串
dt_mainpage02 = baseMapper.ExecuteReaderDataTable(sql_str);
Mybatis-Plus 中使用 UPDATE 和 DELETE?
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);
Mybatis-Plus中 like 属性在后的用法?
MPJQueryWrapper<TESysFunnode> wrapper = new MPJQueryWrapper<TESysFunnode>()
.select("FunWBS", "FunName")
.eq("WebID", str_webid)
.apply("{0} like CONCAT(funWBS, '%')", treeNo); // {0}: 用于匹配 treeNo
Mybatis-Plus中 like 使用注意事项?
like默认在匹配字符串前后都添加百分号,例如:
wrapper.like("FunID", "0190")
等同于:
FunID like '%0190%'
3、Redis - 请求鉴权
Redis鉴权中的关键文件
其实就是一个 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());
}
}
项目中使用 Redis鉴权
@Autowired
private IRedisUtil redisUtil;
@Override
public ResultData GetSysInfo() {
RedisUserInfo user = redisUtil.getAllSession();
if(user==null){
return ResultData.error("系统已经过期,请重新登录");
}
// ... 其它业务逻辑
// 从redis获取人员id
String employeeid = user.getEmployeeid();
}
更新 Redis 中存储的 实体
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);
}