springboot电脑商城项目 3.用户登录

当用户输入用户名和密码将数据提交给后台数据库进行查询,如果存在对应的用户名和密码则表示登录成功,登录成功之后跳转到系统的主页index.html页面。跳转在前端使用jquery来完成

1.登录-持久层

1.1规划需要执行的sql语句

依据用户提交的用户名和密码作select查询。密码的比较放在业务层执行。

select * from t_user where username = ?

说明:如果在分析过程中,发现某个功能模块已经被开发完成,所以就可以省略当前的开发步骤,这个分析过程不能省略。

1.2接口设计和抽象方法

不用重复开发。单元测试也是无需单独执行了

2.登录-业务层

2.1规划异常

  1. 用户名对应的密码错误,密码匹配失败:PasswordNotMatchExecption异常,运行时异常,业务异常。
  2. 用户名没有被找到,抛出异常:UsernameNotFountException
  3. 异常编写:
    • 业务层异常需要继承ServiceException异常类
    • 在具体的异常类中定义构造方法(可以使用快捷键来生成,五个构造方法)。

2.2设计业务层接口和抽象方法

1.直接在IUserService接口中编写抽象方法,login(String username,String password)。将当前登录成功的用户数据以当前的用户对象的形式返回。状态管理:可以将数据保存在cookie或session中,可以避免多次频繁操作数据库(用户名、用户id-存放在session中,用户头像-cookie中)。

2.需要在实现类中实现父接口中抽象方法。

3.在测试类中测试业务层登录的方法是否可以执行通过。

2.3抽象方法的实现

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

        //检测用户的密码是否匹配
        //1.先获取到数据库中加密后的密码
        String oldPassword = result.getPassword();
        //2.和用户传递过来的密码进行比较
        //2.1先获取盐值,上一次在注册时自动生成的盐值
        String salt = result.getSalt();
        //2.2将用户的密码按照相同的md5算法规则进行加密
        String newMd5Password = getMD5Password(password, salt);
        if (!oldPassword.equals(newMd5Password)){
            throw new PasswordNotMatchExecption("密码错误");
        }

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

        User user = new User();
        user.setUid(result.getUid());
        user.setUsername(result.getUsername());
        user.setAvatar(result.getAvatar());
        return user;
    }

3.登录-控制层

3.1 处理异常

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

else if (e instanceof UserNotFoundException){
    result.setState(5001);
    result.setMessage("用户数据不存在异常");
} else if (e instanceof PasswordNotMatchExecption){
    result.setState(5002);
    result.setMessage("用户名密码错误");
}

3.2 设计请求

 请求路径:/user/login
请求方式:POST
请求数据:String username,String password,HttpSession session
响应结果:JsonResult<User>

3.3 处理请求

在UserController类中编写处理请求的方法。

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

4.登录-前端

1.在login.html页面中依据前面所设置的请求来发送ajax请求。

2.访问页面进行用户的登录操作

用户登录会话session

session对象主要是存储在服务器端,可以用于保存服务器的临时数据的对象,所保存的数据在整个项目中都可以通过访问来获取,把session的数据看成一个共享数据。首次登陆的时候所获取的用户数据,转移到session对象即可。session.getAttrbute("key")可以将获取session中的数据这种行为进行封装,封装在BaseController类中。

1.session对象中的数据获取(封装在父类中)、数据的设置(当用户登录成功后进行数据的设置,设置全局的session对象)

2.在父类中封装两个数据:uid和username。两个方法对应获取两个数据。用户头像暂时不考虑,将来封装在cookie中使用。

/**
     * 获取session对象中用户的值
     * @param httpSession session对象
     * @return  当前登录的用户uid的值
     */
protected final Integer getUidFromSession(HttpSession httpSession){
    return Integer.valueOf(httpSession.getAttribute("uid").toString());
}

/**
     * 获取当前登录用户的username
     * @param httpSession session对象
     * @return 当前登录用户的用户名
     * 在实现类中重写父类中的toString,不是句柄信息输出
     */
protected final String getUsernameFormSession(HttpSession httpSession){
    return httpSession.getAttribute("username").toString();
}

3.在登录的方法中将数据封装在session对象中。服务器本身自动创建有session对象,已经是一个全局的session对象。springboot直接使用session对象,直接将Httpsession类型的对象作为请求处理方法的参数,会自动将全局的session对象注入到请求处理方法的session形参上

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

    // 向session对象中完成数据的绑定(session全局的)
    session.setAttribute("uid",data.getUid());
    session.setAttribute("username",data.getUsername());

    //获取session中绑定的数据
    System.out.println(getUidFromSession(session));
    System.out.println(getUsernameFormSession(session));

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

拦截器

拦截器:首先将所有的请求统一拦截到拦截器中,在拦截器中来定义过滤的规则,如果不满足系统的这值得过滤规则,统一的处理是重新去打开login.html页面(重定向和转发),推荐使用重定向。

在SpringBoot项目中拦截器的定义和使用。springBoot是依靠springMvc来实现的,springMVC提供了一个HandlerInterceptor接口,用于表示一个拦截器。首先自定义一个类,然后让这个类实现这个接口

1.首先自定义一个类,在这类中实现HanderInterceptor接口。

public class LoginInterceptor implements HandlerInterceptor {
    //在调用所有请求的方法之前调用的方法 DispatherServlet之前
    //只有第一个常用
    /**
     * 检测全局session对象中是否有uid数据,如果有则放行,如果没有重定向到登陆页面
     * @param request 请求对象
     * @param response 响应对象
     * @param handler 处理器:url + Controller : 映射
     * @return 如果返回值为true表示放行当前的请求,如果返回false则表示拦截当前请求
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request,
                             HttpServletResponse response,
                             Object handler) throws Exception {
        //HttpServletRequest对象来获取session
        Object obj = request.getSession().getAttribute("uid");
        if (obj == null){
            //说明用户没有登陆过系统,则重定向回login.html页面
            response.sendRedirect("/web/login.html");
            //结束后续的调用
            return false;
        }

        //请求放行
        return true;
    }
    //在ModelAndView对象返回之后被调用的方法
    @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 {

    }
}

源码解析

public class LoginInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        return false;
    }

    @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.注册过滤器:添加黑名单(在用户登录的情况下在可以访问的页面资源),添加白名单(哪些资源可以在不登陆的情况下访问:login)。

3.注册过滤器的技术:借助WebMvcConfoigure接口,可以将用户定义的拦截器进行注册。注册后才能保证拦截器能生效和使用。定义一个类,然后让这个类实现WebMvcConfigurer接口,配置信息,建议存放在项目的config包结构下。

@Configuration//加载当前拦截器并进行注册
public class LoginInterceptorConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //创建自定义拦截器对象
        HandlerInterceptor interceptor = new LoginInterceptor();
        //配置白名单,存放在一个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/index.html");
        patterns.add("/web/product.html");
        patterns.add("/web/login.html");
        patterns.add("/users/reg");
        patterns.add("/users/login");

        //完成拦截器的注册
        registry.addInterceptor(interceptor).
                addPathPatterns("/**").//设置黑名单
                excludePathPatterns(patterns);//将白名单List集合设置进拦截器。
    }
}

4.提示重定向次数过多,login.html页面会打不开。将浏览器中Cookie删除,再将浏览器设置为初始化

posted @ 2022-02-02 00:37  贾博文  阅读(201)  评论(0)    收藏  举报