在之前的文章中我们实现了用户注册和验证功能,接下来我们继续实现它的登录,以及登录成功之后要在页面上显示的信息。
接下来,我们来编写代码。
在com.liferunner.service.IUserService接口中添加用户登录方法:
public interface IUserService { ... /** * 用户登录 * @param userRequestDTO 请求dto * @return 登录用户信息 * @throws Exception */ Users userLogin(UserRequestDTO userRequestDTO) throws Exception; }然后,在com.liferunner.service.impl.UserServiceImpl实现类中实现:
@Service @Slf4j public class UserServiceImpl implements IUserService { ... @Override public Users userLogin(UserRequestDTO userRequestDTO) throws Exception { log.info("======用户登录请求:{}", userRequestDTO); Example example = new Example(Users.class); val condition = example.createCriteria(); condition.andEqualTo("username", userRequestDTO.getUsername()); condition.andEqualTo("password", MD5GeneratorTools.getMD5Str(userRequestDTO.getPassword())); val user = this.usersMapper.selectOneByExample(example); log.info("======用户登录处理结果:{}", user); return user; } }Error Tips:
这里有一个小小的坑点,大家一定要注意,在使用selectOneByExample()查询的时候,该方法传入的参数一定注意是tk.mybatis.mapper.entity.Example实例,而不是tk.mybatis.mapper.entity.Example.Criteria,否则会报动态SQL生成查询错误,信息如下:
新人在写代码的时候,特别容易在上一行写了查询变量,下一行就直接开用了,越是简单的错误越是让人无从下手。
实现Controller @RestController @RequestMapping(value = "/users") @Slf4j @Api(tags = "用户管理") public class UserController { ... @ApiOperation(value = "用户登录", notes = "用户登录接口") @PostMapping("/login") public JsonResponse userLogin(@RequestBody UserRequestDTO userRequestDTO, HttpServletRequest request, HttpServletResponse response) { try { if (StringUtils.isBlank(userRequestDTO.getUsername())) return JsonResponse.errorMsg("用户名不能为空"); if (StringUtils.isBlank(userRequestDTO.getPassword()) || userRequestDTO.getPassword().length() < 8) { return JsonResponse.errorMsg("密码为空或长度小于8位"); } val user = this.userService.userLogin(userRequestDTO); UserResponseDTO userResponseDTO = new UserResponseDTO(); BeanUtils.copyProperties(user, userResponseDTO); log.info("BeanUtils copy object {}", userResponseDTO); if (null != userResponseDTO) { // 设置前端存储的cookie信息 CookieTools.setCookie(request, response, "user", JSON.toJSONString(userResponseDTO), true); return JsonResponse.ok(userResponseDTO); } } catch (Exception e) { e.printStackTrace(); log.error("用户登录失败,{},exception = {}", userRequestDTO, e.getMessage()); } return JsonResponse.errorMsg("用户登录失败"); } }在上面的代码中,基本校验问题就不再赘述,我们主要关注几点新的特性信息:
com.liferunner.dto.UserResponseDTO 将我们需要展示给前端的数据封装为一个新的返回对象,我们从数据库中查询出来的Userspojo包含用户的所有数据,比如其中的password、mobile等等一些用户私密的数据是不应该展示给前端的,即便要展示,那也是需要经过脱敏以及加密。因此,常见的做法就是封装一个新的返回对象,其中只需要包含前端需要的数据字段就可以了。
@Data @AllArgsConstructor @NoArgsConstructor @Builder @ApiModel(value = "用户信息返回DTO", description = "用户登录成功后需要的返回对象") public class UserResponseDTO { /** * 主键id */ private String id; /** * 用户名 */ private String username; /** * 昵称 昵称 */ private String nickname; /** * 头像 */ private String face; /** * 性别 1:男 0:女 2:保密 */ private Integer sex; }在这里建议大家使用Ctrl+C我们的com.liferunner.pojo.Users对象,然后删除掉我们不需要的字段就可以了,为什么这么建议呢,是因为下一个好处啦。
org.springframework.beans.BeanUtils.copyProperties(user, userResponseDTO);
大家可以看到,这里直接使用的是Spring BeanUtils工具类进行的值拷贝,就减少了我们循环遍历每一个字段去挨个赋值(SetValue)的工作。(也是一种偷懒小技巧哦,这样是不对的~)