3.Spring Cloud (Hoxton.SR8) 实战笔记—业务模块实现步骤、Mybatis-Plus & Mybatis-Plus-Join 注意事项

Spring Cloud (Hoxton.SR8) 开发笔记

1、业务模块实现步骤

使用 Mybatis-Plus-Generator 自动生成代码

  • 设计 模块 中需要用到的 数据库表

根据 数据库表名, 使用 mybatis-plus-generator 代码生成器, 自动生成 entitiesControllerServiceMapper 文件夹以及相应的文件, 但不使用 默认生成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 表就是查询主表, 因为默认注入的 baseMapperTESysDepartmentMapper 类型。
  • 如果需要其他 作为 主表, 则需要额外进行注入 (使用 @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 进行测试

  • 新建 WeChat 文件夹
  • 新建 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: LambdaQueryWrapperLambdaUpdateWrapper

BaseMapper 和 MPJBaseMapper 的区别?

  • BaseMapperMPJBaseMapper 顶层父类
    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类 中则不需要再写 pagesize 信息)

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类 中则不需要再写 pagesize 信息)

@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: 使用 MPJQueryWrapperQueryWrapper, 不要用 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);
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

页川叶川

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值