目录
1. 顺序图
2. 参数要求
3. 创建 Service 接口
4. 实现 Service 接口
5. 单体测试
6. 实现 Controller
7. 实现前端
在用户登录部分特别注意的是需要进行密码校验:
1. MD5(MD5(用户提交的原密码)+数据库查出来的用户的盐)= 密码的密文
2. 用上面的生成的密码的密文和数据库中用户的 password 字段的密码作比较,如果相等,则校验通过,否则失败。
1. 顺序图

2. 参数要求
登录时需要用户提交的参数列表:
| 参数名 | 描述 | 类型 | 默认值 | 条件 | 
|---|---|---|---|---|
| username | 用户名 | String | 必须 | |
| password | 密码 | String | 必须 | 
3. 创建 Service 接口
根据用户名查询用户信息:
public interface IUserService {
    /**
     * 根据用户名查询用户信息
     * @param username 用户名
     * @return
     */
    User selectByName(String username);
    /**
     * 创建普通用户
     *
     * @param user 用户名
     */
    void createNormalUser(User user);
    /**
     * ⽤⼾登录
     * @param username ⽤⼾名
     * @param password 密码
     * @return
     */
    User login(String username, String password);
} 
4. 实现 Service 接口
@Slf4j // 日志
@Service // 交给 Spring 管理
public class UserServiceImpl implements IUserService {
    @Resource
    private UserMapper userMapper;
    @Override
    public User selectByName(String username) {
        // 非空校验
        if(StringUtils.isEmpty(username)){
            // 打印日志
            log.warn(ResultCode.FAILED_PARAMS_VALIDATE.toString());
            // 抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_PARAMS_VALIDATE));
        }
        // 根据用户名查询用户信息
        User user = userMapper.selectByName(username);
        // 返回结果
        return user;
    }
    @Override
    public void createNormalUser(User user) {
        // 非空校验
        if(user == null || StringUtils.isEmpty(user.getUsername())
                || StringUtils.isEmpty(user.getNickname())
                || StringUtils.isEmpty(user.getPassword())
                || StringUtils.isEmpty(user.getSalt())){
            // 打印日志
            log.warn(ResultCode.FAILED_PARAMS_VALIDATE.toString());
            // 抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_PARAMS_VALIDATE));
        }
        // 校验用户是否存在
        User existUser = selectByName(user.getUsername());
        if(existUser != null){
            // 打印日志
            log.warn(ResultCode.FAILED_USER_EXISTS.toString() + "username = " + user.getUsername());
            // 抛出异常,用户已存在
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_USER_EXISTS));
        }
        // 为属性设置默认值
        // 性别 0女 1男 2保密
        if(user.getGender() != null){
            if(user.getGender() < 0 || user.getGender() > 2){
                user.setGender((byte)2);
            }
        }else{
            user.setGender((byte)2);
        }
        // 发帖数
        user.setArticleCount(0);
        // 是否管理员
        user.setIsAdmin((byte)0);
        // 状态
        user.setState((byte)0);
        // 时间
        Date date = new Date();
        user.setCreateTime(date); // 创建时间
        user.setUpdateTime(date); // 更新时间
        // 写入数据库
        int row = userMapper.insertSelective(user);
        if(row != 1){
            // 打印日志
            log.warn(ResultCode.FAILED_CREATE.toString() + "注册用户失败,username = " + user.getUsername());
            // 抛出异常,用户已存在
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_CREATE));
        }
    }
    @Override
    public User login(String username, String password) {
        // 非空校验
        if(StringUtils.isEmpty(username) || StringUtils.isEmpty(password)){
            // 打印日志
            log.warn(ResultCode.FAILED_PARAMS_VALIDATE.toString());
            // 抛出异常,用户已存在
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_PARAMS_VALIDATE));
        }
        // 根据用户名查询用户信息
        User user = selectByName(username);
        // 校验用户是否存在
        if (user == null) {
            // 打印日志
            log.info(ResultCode.FAILED_USER_NOT_EXISTS.toString()+",username = " + username);
            // 抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_LOGIN));
        }
        // 校验密码是否正确
        String encryptPassword = MD5Utils.md5Salt(password, user.getSalt());
        if (!encryptPassword.equalsIgnoreCase(user.getPassword())) {
            // 打印日志
            log.info("密码输入错误,username = " + username + ", password = " + password);
            // 密码不正确抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_LOGIN));
        }
        // 校验通过,返回用户信息
        return user;
    }
}
 
5. 单体测试
编写测试代码:
@Test
    void login() throws JsonProcessingException {
        // 正确用户
        User user = userService.login("Danny","123");
        System.out.println(objectMapper.writeValueAsString(user));
        // 错误用户
        user = userService.login("123","123");
        System.out.println(objectMapper.writeValueAsString(user));
    } 
测试结果如下:

6. 实现 Controller
 
 在 UserControlle r中实现登录方法: 
 
 
因此在 Config 包下新建 AppConfig 类,添加全局变量:
public class AppConfig {
    /**
     * 为 session 中存储的 User 对象定义一个全局变量
     */
    public static final String SESSION_USER_KEY = "SESSION_USER_KEY";
} 
继续编写 UserController 类中的方法:
/**
     * 用户登录
     *
     * @param request
     * @param username 用户名
     * @param password 密码
     * @return AppResult
     */
    @ApiOperation("⽤⼾登录")
    @PostMapping("/login")
    public AppResult login (HttpServletRequest request,
                            @ApiParam(value = "用户名") @RequestParam(value = "username") @NonNull String username,
                            @ApiParam(value = "密码") @RequestParam(value = "password") @NonNull String password) {
        // 调用 Service
        User user = userService.login(username, password);
        // 在 session 中保存当前登录的用户信息
        // 1. 获取 session 对象
        HttpSession session = request.getSession(true);
        // 2. 把用户信息保存在 session 中
        session.setAttribute(AppConfig.SESSION_USER_KEY, user);
        // 登录成功响应
        return AppResult.success("登录成功");
    } 
 
 启动程序,访问 API 页面 login 接口,分别提交错误和正确的用户名密码进行测试: 
 
 
 登录失败: 
 

登陆成功:

7. 实现前端
完整的前端代码:forum: 论坛项目 - Gitee.com
// 构造数据
        let postData = {
          username : $('#username').val(),
          password : $('#password').val()
        };
        // 发送AJAX请求,成功后跳转到index.html
        $.ajax({
          // 请求的方法类型
          type : 'POST',
          // API 的 URL
          url : 'user/login',
          //数据格式
          contentType : 'application/x-www-form-urlencoded',
          // 提交的数据
          data : postData,
          // 成功回调
          success : function(respData) {
          // ⽤状态码判断是否成功
            if (respData.code == 0) {
              // 成功
              location.assign('index.html');
            } else {
            // 失败
            $.toast({
              heading : '警告',
              text : respData.message,
              icon : 'Warning'
            });
           }
          },
          // 失败(HTTP)
          error: function() {
            $.toast({
              heading : '错误',
              text : '出错了,请联系管理员',
              icon : 'error'
            });
          }
        });
      }); 
登录后的界面如下:

以上即为登录功能的实现,接下来在下篇博客中我们将实现在上面登录进去的界面中进行退出。



















