美文网首页
健康管理系统花絮(4)

健康管理系统花絮(4)

作者: 页川叶川 | 来源:发表于2019-05-01 14:10 被阅读0次
    • 第四课主要是基于 redis 实现单点登录。早期互联网应用由于用户少、访问量低,多个系统的代码可以部署在一台机器中,所以 session 可以直接共享。但是随着互联网的发展,现如今大型网站均是分布式系统,session 无法再像以前那样共享。
    • 单点登录就是在这样多系统共存的环境下,实现一次登录,多次访问不同的互信的系统,单点登录可以简化用户操作,提高友好性。单点登录可以有多种实现方式,本实验采用 token+ redis 方式实现。在用户第一次访问后端接口时直接跳到登录页面,使用账号、密码验证用户真实性,验证成功后,后端返回给用户随机产生的 token(存储在 redis 中)。随后,用户访问后端的接口都要携带这个 token,使用 token 来验证用户的有效性。用户注销时,token 从redis 中删除。
    文件夹结构图.png

    RedisConfig.java

    // 标识configuration
    @Configuration
    public class RedisConfig {
    
        @Bean
        @SuppressWarnings("all")
        public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
            RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
            template.setConnectionFactory(factory);
    
            Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
            ObjectMapper om = new ObjectMapper();
            om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
            om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
            jackson2JsonRedisSerializer.setObjectMapper(om);
    
            StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
            // key采用String的序列化方式
            template.setKeySerializer(stringRedisSerializer);
            // hash的key也采用String的序列化方式
            template.setHashKeySerializer(stringRedisSerializer);
            // value序列化方式采用jackson
            template.setValueSerializer(jackson2JsonRedisSerializer);
            // hash的value序列化方式采用jackson
            template.setHashValueSerializer(jackson2JsonRedisSerializer);
    
            template.afterPropertiesSet();
    
            return template;
        }
    
    }
    

    WebConfig.java

    // 标识configuration
    @Configuration
    public class WebConfig extends WebMvcConfigurationSupport{
    
        // 自动注入拦截器
        @Autowired
        private LoginInterceptor loginInterceptor;
    
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            registry.addInterceptor(loginInterceptor).addPathPatterns("/user/**").excludePathPatterns("/user/login");
    
            super.addInterceptors(registry);
        }
    }
    

    UserController.java

    // 标记controller,返回json数据,URL前缀:/user
    @RestController
    @RequestMapping("user")
    public class UserController {
    
        // 自动注入service
        @Autowired
        private UserService userService;
    
        /**
         * 登录
         * @param user
         * @return
         */
        @PostMapping("login")
        public ResultObject login(@RequestBody User user) {
            if (user == null) {
                return new ResultObject(-1, "param empty", null);
            }
            ResultObject resultObject = userService.login(user);
            return resultObject;
        }
    
        /**
         * 测试单点登录
         * @param
         * @return
         */
        @GetMapping("test")
        public ResultObject test() {
            ResultObject resultObject = new ResultObject(1, "test success", null);
            return resultObject;
        }
    
        /**
         * 注销
         * @param token
         * @return
         */
        @GetMapping("logout")
        public ResultObject logout(@RequestParam String token) {
            ResultObject resultObject = userService.logout(token);
            return resultObject;
        }
    
    }
    

    UserMapper.java

    @Mapper
    public interface UserMapper {
    
        /**
         * 查询用户
         * @param user
         * @return
         */
        @Select("select id, name, gender, age, password from user " +
                " where name = #{name} and password = #{password}")
        User select(User user);
    }
    

    ResultObject.java

    public class ResultObject {
    
        // 后台状态
        private int code;
        // 相关消息
        private String msg;
        // 后台返回数据
        private Object result;
    
        // 构造函数
        public ResultObject() {
            super();
            // TODO Auto-generated constructor stub
        }
        // 构造函数
        public ResultObject(int code, String msg, Object result) {
            super();
            this.code = code;
            this.msg = msg;
            this.result = result;
        }
    
        // 属性setter、getter方法
        public int getCode() {
            return code;
        }
        public void setCode(int code) {
            this.code = code;
        }
        public String getMsg() {
            return msg;
        }
        public void setMsg(String msg) {
            this.msg = msg;
        }
        public Object getResult() {
            return result;
        }
        public void setResult(Object result) {
            this.result = result;
        }
    
        // 重写toString方法
        @Override
        public String toString() {
            return "ResultObject [code=" + code + ", msg=" + msg + ", result=" + result + "]";
        }
    }
    

    User.java

    @JsonInclude(JsonInclude.Include.NON_DEFAULT)
    public class User implements Serializable {
    
        private static final long serialVersionUID = 1L;
        // 主键自增id
        private int id;
        // 姓名
        private String name;
        // 性别
        private int gender;
        // 年龄
        private int age;
        // 密码
        private String password;
    
        // 构造函数
        public User() {
            super();
            // TODO Auto-generated constructor stub
        }
        // 构造函数
        public User(String name, int gender, int age, String password) {
            super();
            this.name = name;
            this.gender = gender;
            this.age = age;
            this.password = password;
        }
    
        // 属性setter、getter方法
        public int getId() {
            return id;
        }
    
        public void setId(int id) {
            this.id = id;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getGender() {
            return gender;
        }
    
        public void setGender(int gender) {
            this.gender = gender;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        public String getPassword() {
            return password;
        }
    
        public void setPassword(String password) {
            this.password = password;
        }
    
        // 重写toString方法
        @Override
        public String toString() {
            return "User [id=" + id + ", name=" + name + ", gender=" + gender + ", age=" + age + ", password=" + password + "]";
        }
    }
    

    LoginInterceptor.java

    @Component
    public class LoginInterceptor  implements HandlerInterceptor{
    
        private static final Log logger = LogFactory.getLog(LoginInterceptor.class);
    
        @Autowired
        private RedisUtil redisUtil;
    
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
            try {
                // 校验用户是否已经登录, 如果登录过, 将之前用户踢掉, 同时更新缓存中用户信息
                // 获取用户id
                // step 1 检查请求是否携带token
    
                String token = request.getParameter("token");
                if (token == null) {
                    render(response, "lack token");
                    return false;
                }
    
                // step 2  检查token是否合法
                User user = (User)redisUtil.get(token);
                if (user != null) {
                    Object preToken = redisUtil.get(Integer.toString(user.getId()));
                    // step 3  检查同一账号是否被其他用户登录
                    if (!token.equals(preToken)) {
                        render(response, "another user login");
                        return false;
                        // step 4  至此登录成功,查看token过期时间是否小于1分钟, 返回值单位毫秒,故 * 1000比较
                    } else {
                        Long expire = redisUtil.getExpire(token);
                        if (expire < 60 * 1000) {
                            redisUtil.expire(token, 60 * 30);
                        }
                    }
                } else {
                    render(response, "token error");
                    return false;
                }
            } catch (Exception e) {
                logger.info("preHandle=" + e);
            }
            return true;
        }
    
        @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 void render(HttpServletResponse response, String msg) throws IOException {
            ResultObject resultObject = new ResultObject(-1, msg, null);
    
            JSONObject object = new JSONObject(resultObject);
    
            response.setContentType("application/json;charset=UTF-8");
            OutputStream out = response.getOutputStream();
            out.write(object.toString().getBytes("UTF-8"));
            out.flush();
            out.close();
        }
    }
    

    UserService.java

    @Service
    public class UserService {
    
        // 自动注入mapper
        @Autowired
        private UserMapper userMapper;
    
        // 自动注入redisUtil
        @Autowired
        private RedisUtil redisUtil;
    
        /**
         * 登录
         * @param user
         * @return
         */
        public ResultObject login(User user) {
            ResultObject resultObject = new ResultObject();
    
            // 查询用户账号、密码是否正确
            User fullUser = userMapper.select(user);
            // 不正确直接返回
            if (fullUser == null) {
                resultObject.setCode(-1);
                resultObject.setMsg("name or password error");
                return resultObject;
            }
    
            // 生成随机token
            String token = UUID.randomUUID().toString();
            int interval = 60 * 5;
    
            // 将用户的token作为key, 用户信息作为value
            redisUtil.set(token, fullUser, interval);
            // 防止同一个账号多人登录
            redisUtil.set(Integer.toString(fullUser.getId()), token, interval);
    
            resultObject.setCode(1);
            resultObject.setMsg("login success");
            Map<String, Object> map = new HashMap<>();
            map.put("token", token);
    
            fullUser.setPassword(null);
            map.put("user", fullUser);
            resultObject.setResult(map);
    
            return resultObject;
        }
    
        /**
         * 注销
         * @param token
         * @return
         */
        public ResultObject logout(String token) {
            User user = (User)redisUtil.get(token);
            redisUtil.del(Integer.toString(user.getId()));
            redisUtil.del(token);
            return new ResultObject(1, "success", null);
        }
    
    }
    

    RedisUtil.java

    @Component
    public class RedisUtil {
    
        @Autowired
        private RedisTemplate<String, Object> redisTemplate;
    
        /**
         * 设置过期时间
         * @param key
         * @param time
         * @return
         */
        public boolean expire(String key, long time) {
            try {
                if (time > 0) {
                    redisTemplate.expire(key, time, TimeUnit.SECONDS);
                }
                return true;
            } catch (Exception e) {
                e.printStackTrace();
                return false;
            }
        }
    
        /**
         * 获取key的过期时间
         * @param key
         * @return
         */
        public long getExpire(String key) {
            return redisTemplate.getExpire(key, TimeUnit.SECONDS);
        }
    
        /**
         * 检测key是否存在
         * @param key
         * @return
         */
        public boolean hasKey(String key) {
            try {
                return redisTemplate.hasKey(key);
            } catch (Exception e) {
                e.printStackTrace();
                return false;
            }
        }
    
        /**
         * 删除key
         * @param key
         */
        @SuppressWarnings("unchecked")
        public void del(String... key) {
            if (key != null && key.length > 0) {
                if (key.length == 1) {
                    redisTemplate.delete(key[0]);
                } else {
                    redisTemplate.delete(CollectionUtils.arrayToList(key));
                }
            }
        }
    
        /**
         * 获取key
         * @param key
         * @return
         */
    
        public Object get(String key) {
            return key == null ? null : redisTemplate.opsForValue().get(key);
        }
    
        /**
         * 设置key
         * @param key
         * @param value
         * @return
         */
        public boolean set(String key, Object value) {
            try {
                redisTemplate.opsForValue().set(key, value);
                return true;
            } catch (Exception e) {
                e.printStackTrace();
                return false;
            }
        }
    
        /**
         * 设置带有过期时间的key,默认永不过期
         * @param key
         * @param value
         * @param time
         * @return
         */
        public boolean set(String key, Object value, long time) {
            try {
                if (time > 0) {
                    redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
                } else {
                    set(key, value);
                }
                return true;
            } catch (Exception e) {
                e.printStackTrace();
                return false;
            }
        }
    
        /**
         * value + delta
         * @param key
         * @param delta
         * @return
         */
        public long incr(String key, long delta) {
            if (delta < 0) {
                throw new RuntimeException("delta must > 0");
            }
            return redisTemplate.opsForValue().increment(key, delta);
        }
    
        /**
         * value - delta
         * @param key
         * @param delta
         * @return
         */
        public long decr(String key, long delta) {
            if (delta < 0) {
                throw new RuntimeException("delta must > 0");
            }
            return redisTemplate.opsForValue().increment(key, -delta);
        }
    }
    

    文集推荐:

    Java基础方法集1
    Python基础知识完整版
    Spring Boot学习笔记
    Linux指令进阶
    Java高并发编程
    SpringMVC基础知识进阶
    Mysql基础知识完整版
    健康管理系统学习花絮(学习记录)
    Node.js基础知识(随手笔记)
    MongoDB基础知识
    Dubbo学习笔记
    Vue学习笔记(随手笔记)

    声明:发表此文是出于传递更多信息之目的。若有来源标注错误或侵犯了您的合法权益,请作者持权属证明与本我们(QQ:981086665;邮箱:981086665@qq.com)联系联系,我们将及时更正、删除,谢谢。

    相关文章

      网友评论

          本文标题:健康管理系统花絮(4)

          本文链接:https://www.haomeiwen.com/subject/krainqtx.html