全部开发者教程

企业级在线办公系统

这节课我们要动手开发用户登陆程序,只要我们参照时序图的设计,实现后端项目的登陆程序并不难。

图片描述

一、编写持久层

TbUserDao.xml文件中添加用于登陆的SQL语句,原理并不复杂。根据登陆页面提交的用户名和密钥,到数据库中查找是否有匹配的数据。因为数据库中的密码是加密过的,所以我们要把登陆的密码加密之后,再跟数据库中的记录做比对。

<select id="login" parameterType="HashMap" resultType="Integer">
    SELECT id
    FROM tb_user
    WHERE username = #{username} 
    AND password = HEX(AES_ENCRYPT(#{password}, #{username}))
    LIMIT 1;
</select>

SQL语句中为什么要出现LIMIT 1这样的语法?其实我们心里清楚,数据库中能匹配到的登陆信息最多只有一条(用户名是唯一的),所以当数据库查询到第一个符合条件的记录之后,没必要再继续查询下去了,节省查询时间。LIMIT 1可以让数据库只查询符合条件的第一条记录。

大家请注意,SELECT子句中返回的是主键id值。如果没查询到匹配的用户记录,数据库会返回null值,所以resultType属性值必须是Integer,而不能是int,因为int无法保存null值。

TbUserDao.java接口中定义抽象的Dao方法,与SQL语句对应。

@Mapper
public interface TbUserDao {
    ……
    public Integer login(HashMap param);
}

二、编写业务层

UserService.java接口中声明抽象的的登陆方法。

public interface UserService {
    ……
    public Integer login(HashMap param);
}

UserServiceImpl.java中实现登陆方法,就是把查询到用户ID返回。

@Service
public class UserServiceImpl implements UserService {
    ……
    @Override
    public Integer login(HashMap param) {
        Integer userId = userDao.login(param);
        return userId;
    }
}

三、编写Web层

我们首先需要创建一个Form类保存HTTP请求提交的数据,使用Form类的好处是可以为变量设置注解,自动完成后端验证。在com.example.emos.api.controller.form包中创建LoginForm.java类。

@Data
@Schema(description = "登陆表单类")
public class LoginForm {
    @NotBlank(message = "username不能为空")
    @Pattern(regexp = "^[a-zA-Z0-9]{5,20}$", message = "username内容不正确")
    @Schema(description = "用户名")
    private String username;

    @NotBlank(message = "password不能为空")
    @Pattern(regexp = "^[a-zA-Z0-9]{6,20}$", message = "password内容不正确")
    @Schema(description = "密码")
    private String password;
}

UserController.java类中定义Web方法用于处理登陆请求。

@RestController
@RequestMapping("/user")
@Tag(name = "UserController", description = "用户Web接口")
public class UserController {
    ……
    @PostMapping("/login")
    @Operation(summary = "登陆系统")
    public R login(@Valid @RequestBody LoginForm form) {
        HashMap param = JSONUtil.parse(form).toBean(HashMap.class);
        Integer userId = userService.login(param);
        R r = R.ok().put("result", userId != null ? true : false);
        if (userId != null) {
            StpUtil.setLoginId(userId);
            Set<String> permissions = userService.searchUserPermissions(userId);
            /*
             * 因为新版的Chrome浏览器不支持前端Ajax的withCredentials,
             * 导致Ajax无法提交Cookie,所以我们要取出生成的Token返回给前端,
             * 让前端保存在Storage中,然后每次在Ajax的Header上提交Token
             */
            String token=StpUtil.getTokenInfo().getTokenValue();
            r.put("permissions",permissions).put("token",token);
        }
        return r;
    }
}

用Swagger测试的时候,打开浏览器输入http://localhost:8090/emos-api/swagger-ui.html,然后找到Web方法执行测试,这种做法做简单。

如果你访问的是http://localhost:8090/emos-api/swagger-ui/index.html,则需要在页面上设置参数,才能看到要测试的Web方法。

图片描述

Sa-Token框架要求我们用户登陆成功之后,必须在Web方法中执行StpUtil.setLoginId(userId),Sa-Token框架会根据UserId自动生成Token令牌,缓存到Redis里,然后把Token以Cookie的形式存储到浏览器上面。

图片描述
浏览器再提交什么请求,都会带上Cookie(含有Token),这样Sa-Token拦截请求,检查Cookie是否含有合法的Token(与Redis缓存的Token比对),就能判断出用户是否登陆了系统。如果没登陆系统,就跳转到登陆画面。

图片描述