项目(SpringBoot+MyBatis)-- 登录功能实现

用户登录功能

先分析一下思路:当用户输入用户名和密码将数据提交给后台数据库进行查询,如果存在对应的用户名和密码则表示登录成功,登录成功之后跳转到系统的主页。

1.登录-持久层

规划需要执行的SQL语句

依据用户提交的用户名来做select查询

select * from t_user where username=? and password=?这种不太好,这种相当于在查询用户名时直接判断了用户和密码是否一致了,如果持久层把判断做了那业务层就没事干了,所以这里我们只查询用户名,判断用户名和密码是否一致交给业务层做。
这个功能模块已经被开发完成(UserMapper接口的findByUsername方法),省略。

2.登录-业务层

2.1规划异常
1.用户名对应的密码错误,即密码匹配的异常,起名PasswordNotMatchException,这个是运行时异常
2.用户名没有被找到的异常,起名UsernameNotFoundException,这个也是运行时异常
继承ServiceException 类,并重写里面的方法

2.2设计接口和抽象方法及实现
1.在IUserService接口中编写抽象方法login(String username,String password)login(User user)也是可以的.

    /**
     * 用户登录功能
     * @param username 用户名
     * @param password 用户密码
     * @return 当前匹配的用户数据,如果没有则返回null
     */
    User login(String username,String password);

2.在抽象类UserServiceImpl中实现该抽象方法

    @Override
    public User login(String username, String password) {
        //根据用户名称来查询用户的数据是否存在,不存在则抛出异常
        User result = userMapper.findByUsername(username);
        if (result == null) {
            throw new UsernameNotFoundException("用户数据不存在");
        }

        /**
         * 检测用户的密码是否匹配:
         * 1.先获取数据库中加密之后的密码
         * 2.和用户传递过来的密码进行比较
         *  2.1先获取盐值
         *  2.2将获取的用户密码按照相同的md5算法加密
         */
        String oldPassword = result.getPassword();
        String salt = result.getSalt();
        String newMd5Password = getMD5Password(password, salt);
        if (!newMd5Password.equals(oldPassword)) {
            throw new PasswordNotMatchException("用户密码错误");
        }

        //判断is_delete字段的值是否为1,为1表示被标记为删除
        if (result.getIsDelete() == 1) {
            throw new UsernameNotFoundException("用户数据不存在");
        }

        //方法login返回的用户数据是为了辅助其他页面做数据展示使用(只会用到uid,username,avatar)
        //所以可以new一个新的user只赋这三个变量的值,这样使层与层之间传输时数据体量变小,后台层与
        // 层之间传输时数据量越小性能越高,前端也是的,数据量小了前端响应速度就变快了
        User user = new User();
        user.setUid(result.getUid());
        user.setUsername(result.getUsername());
        user.setAvatar(result.getAvatar());
        return user;
    }

3.登录-控制层

3.1处理异常
在BaseController 层统一进行异常处理。业务层抛出的异常需要在统一异常处理类中进行统一的捕获和处理,如果该异常类型已经在统一异常类中曾经处理过则不需要重复添加。

else if (e instanceof UsernameNotFoundException) {
    result.setState(4001);
    result.setMessage("用户数据不存在的异常");
} else if (e instanceof PasswordNotMatchException) {
    result.setState(4002);
    result.setMessage("用户名密码错误的异常");
}

3.2处理请求
在UserController类中编写处理请求的方法.编写完成后启动主服务验证一下

    @RequestMapping("login")
    public JsonResult<User> login(String username,String password) {
        User data = userService.login(username, password);
        return new JsonResult<User>(OK,data);
    }

5.优化

5.1 用session存储和获取用户数据
1.在父类中封装两个方法:获取uid和获取username对应的两个方法(用户头像暂不考虑,将来封装到cookie中来使用)

    /**
     * 获取session对象中的uid
     * @param session session对象
     * @return 当前登录的用户uid的值
     */
    public final Integer getUidFromSession(HttpSession session) {
        //getAttribute返回的是Object对象,需要转换为字符串再转换为包装类
        return Integer.valueOf(session.getAttribute("uid").toString());
    }

    public final String getUsernameFromSession(HttpSession session) {
        return session.getAttribute("username").toString();
    }

2.把首次登录所获取的用户数据转移到session对象:

    @RequestMapping("login")
    public JsonResult<User> login(String username, String password, HttpSession session) {
        User data = userService.login(username, password);

        //向session对象中完成数据的绑定(这个session是全局的,项目的任何位置都可以访问)
        session.setAttribute("uid",data.getUid());
        session.setAttribute("username",data.getUsername());

        //测试能否正常获取session中存储的数据
        System.out.println(getUidFromSession(session));
        System.out.println(getUsernameFromSession(session));

        return new JsonResult<User>(OK,data);
    }

5.2 拦截器
1.所以想要使用拦截器就要定义一个类并使其实现HandlerInterceptor接口,在store下建包interceptor,包下建类LoginInterceptor并编写代码:

/**定义一个拦截器*/
public class LoginInterceptor implements HandlerInterceptor {
    /**
     *检测全局session对象中是否有uid数据,如果有则放行,如果没有重定向到登录页面
     * @param request 请求对象
     * @param response 响应对象
     * @param handler 处理器(把url和Controller映射到一块)
     * @return 返回值为true放行当前请求,反之拦截当前请求
     * @throws Exception
     */
    @Override
    //在DispatcherServlet调用所有处理请求的方法前被自动调用执行的方法
    //springboot会自动把请求对象给到request,响应对象给到response,适配器给到handler
    public boolean preHandle(HttpServletRequest request, 
                             HttpServletResponse response, 
                             Object handler) throws Exception {
        //通过HttpServletRequest对象来获取session对象
        Object obj = request.getSession().getAttribute("uid");
        if (obj == null) { //说明用户没有登录过系统,则重定向到login.html页面
            //不能用相对路径,因为这里是要告诉前端访问的新页面是在哪个目录下的新
            //页面,但前面的localhost:8080可以省略,因为在同一个项目下
            response.sendRedirect("/web/login.html");
            //结束后续的调用
            return false;
        }
        //放行这个请求
        return true;
    }
    //在ModelAndView对象返回给DispatcherServlet之后被自动调用的方法
//    @Override
//    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
//    }
    //在整个请求所有关联的资源被执行完毕后所执行的方法
//    @Override
//    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
//    }
}

2.注册过滤器:

注册过滤器的技术:借助WebMvcConfigure接口将用户定义的拦截器进行注册.所以想要注册过滤器需要定义一个类使其实现WebMvcConfigure接口并在其内部添加黑名单(在用户登录的状态下才可以访问的页面资源)和白名单(哪些资源可以在不登录的情况下访问:①register.html②login.html③index.html④/users/reg⑤/users/login⑥静态资源):

/**拦截器的注册*/
@Configuration //自动加载当前的类并进行拦截器的注册,如果没有@Configuration就相当于没有写类LoginInterceptorConfigure
public class LoginInterceptorConfigure implements WebMvcConfigurer {
    @Override
    //配置拦截器
    public void addInterceptors(InterceptorRegistry registry) {
        //1.创建自定义的拦截器对象
        HandlerInterceptor interceptor =  new LoginInterceptor();
        //2.配置白名单并存放在一个List集合
        List<String> patterns = new ArrayList<>();
        patterns.add("/bootstrap3/**");
        patterns.add("/css/**");
        patterns.add("/images/**");
        patterns.add("/js/**");
        patterns.add("/web/register.html");
        patterns.add("/web/login.html");
        patterns.add("/web/index.html");
        patterns.add("/web/product.html");
        patterns.add("/users/reg");
        patterns.add("/users/login");

        //registry.addInterceptor(interceptor);完成拦截
        // 器的注册,后面的addPathPatterns表示拦截哪些url
        //这里的参数/**表示所有请求,再后面的excludePathPatterns表
        // 示有哪些是白名单,且参数是列表
        registry.addInterceptor(interceptor)
                .addPathPatterns("/**")
                .excludePathPatterns(patterns);
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值