Project (SpringBoot+MyBatis) -- login function implementation

User login function

First analyze the idea: when the user enters the user name and password to submit the data to the background database for query, if there is a corresponding user name and password, it means that the login is successful, and after successful login, it will jump to the home page of the system.

1. Login - persistence layer

Plan the SQL statement to be executed

Do a select query based on the user name submitted by the user

select * from t_user where username=? and password=? This is not very good. This is equivalent to directly judging whether the user and password are consistent when querying the username. If the persistence layer makes the judgment, the business layer will have nothing to do , so here we only query the user name, and judge whether the user name and password are consistent and hand it over to the business layer.
This function module has been developed (the findByUsername method of the UserMapper interface), so it is omitted.

2. Login - business layer

2.1 Planning anomalies
1. The password corresponding to the user name is wrong, that is, the abnormality of password matching, named PasswordNotMatchException, this is a runtime exception
2. The exception that the username is not found is named UsernameNotFoundException, which is also a runtime exception
Inherit the ServiceException class and override the methods inside

2.2 Design interface and abstract method and implementation
1. It is also possible to write the abstract method login(String username,String password)login(User user) in the IUserService interface.

    /**
     * User login function
     * @param username username
     * @param password user password
     * @return The currently matched user data, or null if none
     */
    User login(String username,String password);

2. Implement the abstract method in the abstract class UserServiceImpl

    @Override
    public User login(String username, String password) {
        //Query whether the user's data exists according to the user name, and throw an exception if it does not exist
        User result = userMapper.findByUsername(username);
        if (result == null) {
            throw new UsernameNotFoundException("user data does not exist");
        }

        /**
         * Check if the user's password matches:
         * 1.Get the encrypted password in the database first
         * 2.Compare with the password passed by the user
         *  2.1 Get the salt value first
         *  2.2 Encrypt the obtained user password according to the same md5 algorithm
         */
        String oldPassword = result.getPassword();
        String salt = result.getSalt();
        String newMd5Password = getMD5Password(password, salt);
        if (!newMd5Password.equals(oldPassword)) {
            throw new PasswordNotMatchException("wrong user password");
        }

        //Determine whether the value of the is_delete field is 1, which means it is marked as deleted
        if (result.getIsDelete() == 1) {
            throw new UsernameNotFoundException("user data does not exist");
        }

        //The user data returned by the method login is used to assist other pages in data display (only uid, username, avatar will be used)
        //Therefore, a new user can be assigned only the values ​​of these three variables, so that the data volume during transmission between layers becomes smaller, and the background layer and
        // When transferring between layers, the smaller the amount of data, the higher the performance. The same is true for the front end. The smaller the amount of data, the faster the response speed of the front end.
        User user = new User();
        user.setUid(result.getUid());
        user.setUsername(result.getUsername());
        user.setAvatar(result.getAvatar());
        return user;
    }

3. Login-control layer

3.1 Handling exceptions
Exception handling is performed uniformly at the BaseController layer. The exception thrown by the business layer needs to be captured and processed uniformly in the unified exception handling class. If the exception type has been handled in the unified exception class, there is no need to add it repeatedly.

else if (e instanceof UsernameNotFoundException) {
    result.setState(4001);
    result.setMessage("User data does not exist exception");
} else if (e instanceof PasswordNotMatchException) {
    result.setState(4002);
    result.setMessage("Exception for wrong username and password");
}

3.2 Processing requests
Write the method of processing the request in the UserController class. After writing, start the main service to verify

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

5. Optimization

5.1 Use session to store and get user data
1. Encapsulate two methods in the parent class: two methods corresponding to obtaining uid and obtaining username (the user avatar is not considered for the time being, and will be encapsulated into a cookie for use in the future)

    /**
     * Get the uid in the session object
     * @param session session object
     * @return The value of the uid of the currently logged in user
     */
    public final Integer getUidFromSession(HttpSession session) {
        //getAttribute returns an Object object, which needs to be converted to a string and then converted to a wrapper class
        return Integer.valueOf(session.getAttribute("uid").toString());
    }

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

2. Transfer the user data acquired for the first login to the session object:

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

        //Complete data binding to the session object (this session is global and can be accessed anywhere in the project)
        session.setAttribute("uid",data.getUid());
        session.setAttribute("username",data.getUsername());

        //Test whether the data stored in the session can be obtained normally
        System.out.println(getUidFromSession(session));
        System.out.println(getUsernameFromSession(session));

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

5.2 Interceptors
1. So if you want to use an interceptor, you need to define a class and make it implement the HandlerInterceptor interface, build a package interceptor under the store, create a class LoginInterceptor under the package and write code:

/**define an interceptor*/
public class LoginInterceptor implements HandlerInterceptor {
    /**
     *Detect whether there is uid data in the global session object, if there is, it will be released, if not redirected to the login page
     * @param request request object
     * @param response response object
     * @param handler Processor (map url and Controller together)
     * @return The return value is true to release the current request, otherwise intercept the current request
     * @throws Exception
     */
    @Override
    //The method that is automatically called and executed before DispatcherServlet calls all methods for processing requests
    //springboot will automatically give the request object to request, the response object to response, and the adapter to handler
    public boolean preHandle(HttpServletRequest request, 
                             HttpServletResponse response, 
                             Object handler) throws Exception {
        //Get the session object through the HttpServletRequest object
        Object obj = request.getSession().getAttribute("uid");
        if (obj == null) { //Indicates that the user has not logged in to the system, then redirects to the login.html page
            //Relative paths cannot be used, because this is to tell the front-end which directory the new page is located in
            //page, but the previous localhost:8080 can be omitted, because it is under the same project
            response.sendRedirect("/web/login.html");
            //end subsequent call
            return false;
        }
        //allow this request
        return true;
    }
    //The method that is called automatically after the ModelAndView object is returned to the DispatcherServlet
//    @Override
//    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
//    }
    //The method to be executed after all associated resources of the entire request have been executed
//    @Override
//    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
//    }
}

2. Register filter:

Register filter technology: register user-defined interceptors with the help of the WebMvcConfigure interface. So if you want to register a filter, you need to define a class to implement the WebMvcConfigure interface and add a blacklist inside it (accessible only when the user is logged in page resources) and whitelist (which resources can be accessed without logging in: ①register.html②login.html③index.html④/users/reg⑤/users/login⑥static resources):

/**Registration of interceptors*/
@Configuration //Automatically load the current class and register the interceptor. If there is no @Configuration, it is equivalent to not writing the class LoginInterceptorConfigure
public class LoginInterceptorConfigure implements WebMvcConfigurer {
    @Override
    //Configure interceptors
    public void addInterceptors(InterceptorRegistry registry) {
        //1. Create a custom interceptor object
        HandlerInterceptor interceptor =  new LoginInterceptor();
        //2. Configure the whitelist and store it in a List collection
        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); complete interception
        // The registration of the server, the latter addPathPatterns indicates which url s are intercepted
        //The parameter /** here represents all requests, followed by the excludePathPatterns table
        // Indicates which ones are whitelisted, and the parameter is a list
        registry.addInterceptor(interceptor)
                .addPathPatterns("/**")
                .excludePathPatterns(patterns);
    }
}

Tags: Java Mybatis Spring Boot Project

Posted by Kulak on Thu, 22 Dec 2022 10:38:36 +0300