SpringBoot + mybatis-plus + Redis实现同一时间只有一个相同用户名的人登录功能

我们可以按照以下步骤进行实现:

配置Spring Boot项目:

首先,确保你已经创建了一个Spring Boot项目,并且已经添加了以下依赖:

xml

<!-- Spring Boot Starter Web -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>


<!-- Spring Boot Starter Data Redis -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>


<!-- Spring Boot Starter JDBC -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>


<!-- MyBatis Plus -->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.5.3.1</version>
</dependency>


<!-- Lombok -->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
</dependency>


<!-- MySQL Connector Java -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>


<!-- BCrypt Password Encoder -->
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-crypto</artifactId>
</dependency>

创建SessionContext类用于管理HttpSession对象:


package com.icoderoad.example.demo.util;


import javax.servlet.http.HttpSession;
import java.util.HashMap;
import java.util.Map;


public class SessionContext {
    private static final Map<String, HttpSession> sessionMap = new HashMap<>();


    public static synchronized void addSession(HttpSession session) {
        if (session != null) {
            sessionMap.put(session.getId(), session);
        }
    }


    public static synchronized void removeSession(HttpSession session) {
        if (session != null) {
            sessionMap.remove(session.getId());
        }
    }


    public static synchronized HttpSession getSession(String sessionId) {
        return sessionMap.get(sessionId);
    }
}


//创建SessionListener类实现HttpSessionListener接口:


package com.icoderoad.example.demo.listener;


import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;


import com.icoderoad.example.demo.util.SessionContext;


public class SessionListener implements HttpSessionListener {


    @Override
    public void sessionCreated(HttpSessionEvent se) {
        HttpSession session = se.getSession();
        SessionContext.addSession(session);
    }


    @Override
    public void sessionDestroyed(HttpSessionEvent se) {
        HttpSession session = se.getSession();
        SessionContext.removeSession(session);
    }
}

项目启动类


package com.icoderoad.example.demo;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
import org.springframework.context.annotation.Bean;


import com.icoderoad.example.demo.listener.SessionListener;


@SpringBootApplication
@MapperScan("com.icoderoad.example.demo.mapper")
public class DemoApplication {


public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}



@Bean
    public ServletListenerRegistrationBean<SessionListener> sessionListener() {
        ServletListenerRegistrationBean<SessionListener> listenerBean =
                new ServletListenerRegistrationBean<>();
        listenerBean.setListener(new SessionListener());
        return listenerBean;
    }
}

用户实体类

java


package com.icoderoad.example.demo.entity;

import java.time.LocalDateTime;

import lombok.Data;

@Data
public class User {
    private Long id;
    private String userName;
    private String name;
    private String phone;
    private String email;
    private LocalDateTime createTime;
}

创建用户服务层:

编写用户服务层UserService,处理用户登录、保存用户信息到Session等逻辑。

java

package com.icoderoad.example.demo.service;


import javax.servlet.http.HttpSession;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;


import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.icoderoad.example.demo.entity.User;
import com.icoderoad.example.demo.mapper.UserMapper;
import com.icoderoad.example.demo.util.SessionContext;


@Service
public class UserService {
    private final UserMapper userMapper;
    private final RedisTemplate<String, String> redisTemplate;
    private final BCryptPasswordEncoder passwordEncoder;


    @Autowired
    public UserService(UserMapper userMapper, RedisTemplate<String, String> redisTemplate) {
        this.userMapper = userMapper;
        this.redisTemplate = redisTemplate;
        this.passwordEncoder = new BCryptPasswordEncoder();
    }


    public boolean login(String userName, String password, HttpSession session) {


        // 验证用户名和密码是否匹配
        boolean loginSuccess = this.validateUser(userName, password);




        // 在登录成功后,判断是否已经有用户登录了
        if( loginSuccess ){
        String previousSessionId = redisTemplate.opsForValue().get(userName);
        if (previousSessionId != null) {
            // 如果存在已登录用户,使其Session失效,实现踢出功能
            HttpSession previousSession = SessionContext.getSession(previousSessionId);
            if (previousSession != null) {
                previousSession.invalidate();
            }
        }


         User user = getUserByUsername(userName);
        session.setAttribute("loggedInUser", user);
        // 更新Redis中的用户Session信息
        redisTemplate.opsForValue().set(userName, session.getId());
      }


        return true;
    }


    public boolean validateUser(String userName, String password) {
        // 根据用户名查询用户
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_name", userName);
        User user = userMapper.selectOne(queryWrapper);


        // 判断用户是否存在并且密码是否匹配
        if (user != null && passwordEncoder.matches(password, user.getPassword())) {
            return true; // 用户名和密码匹配
        }


        return false; // 用户名或密码错误
    }


   public User getUserByUsername(String userName) {
        // 根据用户名查询用户
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_name", userName);
        return userMapper.selectOne(queryWrapper);
    }


    public void registerUser(User user) {
        // 对密码进行BCrypt哈希加密
        String hashedPassword = passwordEncoder.encode(user.getPassword());
        user.setPassword(hashedPassword);


        // 插入用户信息到数据库
        userMapper.insert(user);
    }
}

控制器层:

创建控制器层UserController,处理用户登录请求。

java

package com.icoderoad.example.demo.controller;

import java.util.Objects;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;


import com.icoderoad.example.demo.entity.User;
import com.icoderoad.example.demo.service.UserService;




@RestController
@RequestMapping("/user")
public class UserController {


    private final UserService userService;


    @Autowired
    public UserController(UserService userService) {
        this.userService = userService;
    }


    @GetMapping("/login")
    public String login(@RequestParam String userName,
                        @RequestParam String password,
                        HttpServletRequest request) {
        HttpSession session = request.getSession(true);


        // 验证登录并处理踢出逻辑
        boolean loginSuccess = userService.login(userName, password, session);


        if (loginSuccess) {
            // 登录成功,根据业务需求跳转到相应页面
            return "登陆成功";
        } else {
            // 登录失败,返回登录页或错误提示页
            return "登陆失败";
        }
    }


    @PostMapping("/register")
    public String register(@RequestBody User user) {
        // 注册用户
        userService.registerUser(user);


        return "注册成功";
    }
    
    @GetMapping("validate")
    public String validate(HttpServletRequest request) {
        HttpSession session = request.getSession(false);
       if( session!=null ) {
       User user = !Objects.isNull(session.getAttribute("loggedInUser")) ? (User)session.getAttribute("loggedInUser"): null;
       if( user!=null ) {
         return "用户:" + user.getUserName() + "已登陆";
       }
       }
       return "用户退出";
    }
}

在上述代码中,我们使用Redis来存储已登录用户的Session信息,并通过Session ID来实现踢出功能。如果用户登录成功,并且已经有相同用户名的用户登录了,我们会使前一个用户的Session失效,然后更新Redis中的Session信息为当前用户的Session ID。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值