- 用户中心框架搭建
- 开发业务子系统前的准备工作
我们先创建一个通用的工具模块,封装通用的工具在私服上维护。如下图所示:
plugin-common的maven如下:
<groupId>com.ys.plugin.common</groupId>
<artifactId>plugin-common</artifactId>
<version>${common.version}</version>
<packaging>pom</packaging>
<!-- 统一的配置 -->
<properties>
<common.version>1.0.0</common.version>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.16</version>
<scope>provided</scope>
</dependency>
</dependencies>
<modules>
<module>plugin-common-tools</module>
</modules>
这里我们定义了统一的版本管理还java的版本
plugin-common-tools添加统一的返回信息的格式定义。实现如下:
@Data
public class ReturnResult <T>{
private int code;
private String msg;
private T data;
public ReturnResult(){
this.code = 200;
this.msg = "成功";
}
public ReturnResult(int code,String msg){
this.code = code;
this.msg = msg;
}
public ReturnResult(Enum e){
try {
this.code = (Integer) e.getClass().getMethod("getCode").invoke(e);
this.msg = (String) e.getClass().getMethod("getMsg").invoke(e);
} catch (Exception e1) {
throw new RuntimeException("枚举类定义错误");
}
}
public ReturnResult(Enum e,T data){
try {
this.code = (Integer) e.getClass().getMethod("getCode").invoke(e);
this.msg = (String) e.getClass().getMethod("getMsg").invoke(e);
this.data = data;
} catch (Exception e1) {
throw new RuntimeException("枚举类定义错误");
}
}
}
- 新建业务子系统-用户中心
项目的目录结构如下:
我们在open模块中定义对外提供的接口。如下:
@Api(value = "用户中心 用户操作",tags = {"用户中心 用户操作"})
@FeignClient(value = "user", contextId = "cn.com.leimon.user.open.api.user.UserCenterFeign")
@RequestMapping(value = "/user")
public interface UserCenterFeign {
@ApiOperation(value="用户注册(使用用户名密码的方式)")
@PostMapping(value = "/register")
public ReturnResult register();
@ApiOperation(value="用户登录")
@GetMapping(value = "/login")
public ReturnResult<UserResponse> login(
@ApiParam(value = "用户名",required = true)
@RequestParam(required = true)String userName,
@ApiParam(value = "密码",required = true)
@RequestParam(required = true)String password
);
@ApiOperation(value="根据用户id获取用户详情")
@GetMapping(value = "/getUserInfo")
public ReturnResult getUserInfo(
@ApiParam(value = "用户id",required = true,example = "-1")
@RequestParam(required = true)Long id
);
@ApiOperation(value="删除用户")
public ReturnResult removeUserInfo();
@ApiOperation(value="修改密码")
public ReturnResult changePassword();
@ApiOperation(value="获取用户列表")
public ReturnResult getUserList();
@ApiOperation(value="退出登录")
public ReturnResult unLogin();
@ApiOperation(value="封号")
public ReturnResult suspendAccount();
@ApiOperation(value="解封帐号")
public ReturnResult unSuspendAccount();
}
我们暂时提供以上的接口。
- 用户注册功能的实现
我们先在provider模块中添加对接口的实现如下图所示:
@RestController
public class UserCenterController implements UserCenterFeign{
@Override
public ReturnResult register() {
return null;
}
}
我们先分析我们注册需要哪些逻辑然后再去做代码实现
- 注册功能需求分析
用户在没有系统帐号的时候可以通过注册帐号/手机号/邮箱/直接登录的方式进入系统
在用户登录系统之后给一个默认的权限。该权限是该系统的管理人员设定的权限
由于用这个系统做测试,管理后台并未开发我们在无法完成的模块中使用TODO作为预留的功能
这里我们暂时实现一个用户名密码注册的功能
- 用户名密码注册的流程
根据上面的结构新建用户中心的表
判断用户名是否在系统中已经存在
判断密码是否符合既定的规则
入库
返回注册状态
- 用户表
我们暂时新建一个最简单的用户表,在后面的业务中会添加相关的业务字段。表如下:
CREATE TABLE `user` (
`id` bigint(20) NOT NULL COMMENT '主键id',
`parents_id` bigint(20) DEFAULT NULL COMMENT '父id',
`org_id` bigint(20) DEFAULT NULL COMMENT '所属组织',
`username` varchar(100) DEFAULT NULL COMMENT '用户名',
`password` varchar(100) DEFAULT NULL COMMENT '密码',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';
我们在infrastructure模块中新建实体类User.infrastructure模块是和数据库打交道的模块。属于一个基础设施模块。实体类如下:
@Data
public class User {
private Long id;//主键id
private Long parentsId;//父id
private Long orgId;//所属组织id
private String username;//用户名
private String password;//密码
}
查询用户名是否存在
新建一个UserMapper.目录结构如下:
查询用户名是否存在的代码如下:
@Mapper
public interface UserMapper {
/**
* 检查用户名是否存在
* @param userName 用户名
* @return
*/
@Select("select id from user where username=#{userName}")
public User checkUser(@Param("userName")String userName);
}
我们在provider层新增service的代码如下:
@Service
public class UserInfoService {
@Autowired
private UserMapper userMapper;
/**
* 坚持指定的用户名是否在系统中注册过
* @param userName 用户名
* @return 0 未注册 1已注册
*/
public int checkRegisterUser(String userName) throws RuntimeException{
User u = userMapper.checkUser(userName);
if(u==null) {
return 0;
}else {
return 1;
}
}
}
在service代码中抛出RuntimeException
- 统一的返回信息格式
我们在provider中定义统一的返回信息格式
定义一个枚举类如下:
public enum ResultMessage {
LOGIN_SUCCESS(2000,"登录成功"),
LOGIN_ERROR(2001,"用户名密码错误"),
UNDEFINE(500, "未定义异常信息");
private int code;
private String msg;
ResultMessage(int code,String msg){
this.code = code;
this.msg = msg;
}
public static String msg(int code) {
for (ResultMessage m : ResultMessage.values()) {
if (m.getCode() == code) {
return m.getMsg();
}
}
return UNDEFINE.getMsg();
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
我们新建一个工具类的模块提供给其他模块调用,封装通用的工具类。结构如下:
在这里定义统一的返回数据的格式。实现如下:
@Data
public class ReturnResult <T>{
private int code;
private String msg;
private T data;
public ReturnResult(){
this.code = 2000;
this.msg = "成功";
}
public ReturnResult(int code,String msg){
this.code = code;
this.msg = msg;
}
public ReturnResult(Enum e){
try {
this.code = (Integer) e.getClass().getMethod("getCode").invoke(e);
this.msg = (String) e.getClass().getMethod("getMsg").invoke(e);
} catch (Exception e1) {
e1.printStackTrace();
}
}
public ReturnResult(Enum e,T data){
try {
this.code = (Integer) e.getClass().getMethod("getCode").invoke(e);
this.msg = (String) e.getClass().getMethod("getMsg").invoke(e);
this.data = data;
} catch (Exception e1) {
e1.printStackTrace();
}
}
}
- Controller返回注册状态
我们在common模块中添加一个字符校验的工具类并实现一个密码校验的实现方法。我们后面字符校验相关的工具类都可以封装在这里。具体实现如下:
public class StringCheckUtil {
private static final String CHECK_PASSWORD = "^[a-zA-Z0-9]{6,12}$";
public static boolean isLetterDigit(String str) {
boolean isDigit= false;//定义一个boolean值,用来表示是否包含数字
boolean isUpperCase = false;//定义一个boolean值,用来表示是否包含大写字母
boolean isLowerCase = false;//定义一个boolean值,用来表示是否包含小写字母
for (int i = 0; i < str.length(); i++) {
if (Character.isDigit(str.charAt(i))) { //用char包装类中的判断数字的方法判断每一个字符
isDigit = true;
} else if (Character.isUpperCase(str.charAt(i))) { //用char包装类中的判断字母的方法判断每一个字符
isUpperCase = true;
}
else if (Character.isLowerCase(str.charAt(i))) { //用char包装类中的判断字母的方法判断每一个字符
isLowerCase = true;
}
}
boolean isRight = isDigit&& isLowerCase&&isUpperCase && str.matches(CHECK_PASSWORD);
return isRight;
}
}
我们在open模块中添加对外提供的接口
@ApiOperation(value="用户注册(使用用户名密码的方式)")
@PostMapping(value = "/register")
public ReturnResult register(
@ApiParam(value = "用户名",required = true)
@RequestParam(required = true)String userName,
@ApiParam(value = "密码",required = true)
@RequestParam(required = true)String password
);
control的具体实现如下:
@Override
public ReturnResult register(String userName,String password) {
//判断用户是否存在
int num = userInfoService.checkRegisterUser(userName);
if(num==1) {//用户已经注册
return new ReturnResult(ResultMessage.USER_IS_REGISTER);
}
if(!StringCheckUtil.isLetterDigit(password)) {
return new ReturnResult(ResultMessage.PASSWORD_ISNOT_RULE);
}
//TODO 入库操作 并返回操作状态
return null;
}
我们在控制层主要对参数校验的工具。具体的业务逻辑放在service层处理
入库和返回入库状态这些请自行实现。
后面我们每个人分到子服务模块的时候。按照上面的方式新建一个模块即可。