分布式session共享解决方案

22 篇文章 1 订阅
订阅专栏
5 篇文章 0 订阅
订阅专栏

分布式session共享解决方案

1.分布式 Session 问题

  • 示意图

image-20230219173607725

  • 解读上图,假如我们去购买商品
  1. 当 Nginx 对请求进行负载均衡后, 可能对应到不同的 Tomcat
  2. 比如第 1 次请求, 均衡到 TomcatA, 这时 Session 就记录在 TomcatA, 第 2 次请求,
    均衡到 TomcatB, 这时就出现问题了,因为 TomcatB 会认为该用户是第 1 次来,就会
    允许购买请求
  3. 这样就会造成重复购买

2.解决方案

2.1Session 绑定/粘滞

什么是 session 绑定/粘滞/黏滞

image-20230219173702703

  • 解读上图

概述: 服务器会把某个用户的请求, 交给 tomcat 集群中的一个节点,以后此节点就负责该保存该用户的session

  1. Session 绑定可以利用负载均衡的源地址 Hash(ip_hash)算法实现
  2. 负载均衡服务器总是将来源于同一个 IP 的请求分发到同一台服务器上,也可以根据 Cookie 信息将同一个用户的请求总是分发到同一台服务器上
  3. 这样整个会话期间,该用户所有的请求都在同一台服务器上处理,即 Session 绑定
    在某台特定服务器上,保证 Session 总能在这台服务器上获取。这种方法又被称为
    session 黏滞/粘滞

ps:nginx配置ip_hash示例

upstream llpservers{
	ip_hash;
	server 192.168.79.111:8081;
	server 192.168.79.111:8080;
}

优点: 不占用服务端内存

缺点:

  1. 增加新机器,会重新 Hash,导致重新登录
  2. 应用重启, 需要重新登录
  3. 某台服务器宕机,该机器上的 Session 也就不存在了,用户请求切换到其他机器后因为没有 Session 而无法完成业务处理, 这种方案不符合系统高可用需求, 使用较少

2.2Session 复制

image-20230219174427596

ps:可以通过配置tomcat实现session配置

  • Session 复制是小型架构使用较多的一种服务器集群 Session 管理机制
  • 应用服务器开启 Web 容器的 Session 复制功能,在集群中的几台服务器之间同步
    Session 对象,使每台服务器上都保存了所有用户的 Session 信息
  • 这样任何一台机器宕机都不会导致 Session 数据的丢失,而服务器使用 Session 时,
    也只需要在本机获取即可

优点: 不占用服务端内存

缺点:

  1. 增加新机器,会重新 Hash,导致重新登录
  2. 应用重启, 需要重新登录
  3. 某台服务器宕机,该机器上的 Session 也就不存在了,用户请求切换到其他机器后因为没有 Session 而无法完成业务处理, 这种方案不符合系统高可用需求, 使用较少

2.3前端存储

优点: 不占用服务端内存

缺点:

  1. 存在安全风险
  2. 数据大小受 cookie 限制
  3. 占用外网带宽

2.4 后端集中存储

优点:安全,容易水平扩展

缺点:增加复杂度,需要修改代码

3.代码实现

现在主流的解决方案还是将用户登录信息在后端集中存储,这里列举两种存储方式

3.1 SpringSession 实现分布式 Session

基本说明

将用户 Session 不再存放到各自登录的 Tomcat 服务器,而是统一存在 Redis,从而解决Session 分布式问题

  1. 如图, 将用户的 Session 信息统一保存到 Redis 进行管理
  2. 说明: SpringSession在默认情况下是以原生形式保存的

image-20230219200625731

引入依赖

<!--spring data redis 依赖, 即 spring 整合 redis-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
    <version>2.4.5</version>
</dependency>
<!--pool2 对象池依赖-->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
    <version>2.9.0</version>
</dependency>
<!--实现分布式 session, 即将 Session 保存到指定的 Redis-->
<dependency>
    <groupId>org.springframework.session</groupId>
    <artifactId>spring-session-data-redis</artifactId>
</dependency>

image-20230219200828662

3.2直接将用户信息统一放入 Redis

基本说明

前面将 Session 统一存放到指定 Redis, 是以原生的形式存放, 在操作时, 还需要反序列化,不方便,我们可以直接将登录用户信息统一存放到 Redis, 利于操作

需求分析/图解

直接将登录用户信息统一存放到 Redis, 利于操作

image-20230219202714967

image-20230219203300481

image-20230219203241485

代码+配置实现

引入依赖

        <!--spring data redis 依赖, 即 spring 整合 redis-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
            <version>2.4.5</version>
        </dependency>
        <!--pool2 对象池依赖-->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
            <version>2.9.0</version>
        </dependency>
        <!--实现分布式 session, 即将 Session 保存到指定的 Redis-->
        <!--<dependency>-->
        <!--    <groupId>org.springframework.session</groupId>-->
        <!--    <artifactId>spring-session-data-redis</artifactId>-->
        <!--</dependency>-->

redis配置

public class RedisConfig {

    @Bean
    public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory redisConnectionFactory) {

        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();

        //设置连接池工厂
        redisTemplate.setConnectionFactory(redisConnectionFactory);

        //首先解决key的序列化方式
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        redisTemplate.setKeySerializer(stringRedisSerializer);

        //解决value的序列化方式
        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);

        ObjectMapper objectMapper = new ObjectMapper();
        //将当前对象的数据类型也存入序列化的结果字符串中
        objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);

        // 解决jackson2无法反序列化LocalDateTime的问题
        objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
        objectMapper.registerModule(new JavaTimeModule());
        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);

        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);

        return redisTemplate;
    }
}
#配置redis
  redis:
    host: 192.168.79.202
    port: 6379
    database: 0
    timeout: 10000ms
    lettuce:
      pool:
        #最大连接数
        max-active: 12
        #最大链接阻塞等待时间,默认是-1
        max-wait: 10000ms
        #最大空闲链接,默认是8
        max-idle: 200
        #最小空闲数,默认是0
        min-idle: 5

改造登录接口

@Override
public RespBean doLogin(LoginVo loginVo, HttpServletRequest request, HttpServletResponse response) {
    //接收到mobile和password[midPass]
    String mobile = loginVo.getMobile();
    String password = loginVo.getPassword();
    //判断手机号和密码是否为空
    // if (!StringUtils.hasText(mobile) || !StringUtils.hasText(password)) {
    //     return RespBean.error(RespBeanEnum.LOGIN_ERROR);
    // }
    //判断手机号码是否合格
    // if (!ValidatorUtil.isMobile(mobile)) {
    //     return RespBean.error(RespBeanEnum.MOBILE_ERROR);
    // }
    //查询DB,看看用户是否存在
    User user = userMapper.selectById(mobile);
    if (user == null) {
        // return RespBean.error(RespBeanEnum.LOGIN_ERROR);
        throw new BusinessException(RespBeanEnum.LOGIN_ERROR);
    }
    //将中间密码(客户端|前端经过了一次加密加盐)转换为最终存储到数据库得密码并进行比对
    if (!MD5Util.midPassToDBPass(password, user.getSlat()).equals(user.getPassword())) {
        // return RespBean.error(RespBeanEnum.LOGIN_ERROR);
        throw new BusinessException(RespBeanEnum.LOGIN_ERROR);
    }
    //登录成功
    //给每个用户生成一个ticket-唯一
    String ticket = UUIDUtil.uuid();
    //将登录成功的用户保存到session中
    //实现分布式session,将登录信息存放到redis中
    redisTemplate.opsForValue().set("user:" + ticket, user,30, TimeUnit.MINUTES);
    // request.getSession().setAttribute(ticket, user);
    CookieUtil.setCookie(request, response, "userTicket", ticket);
    return RespBean.success();
}
@Override
public User getUserByTicket(HttpServletRequest request, HttpServletResponse response, String userTicket) {
    if (!StringUtils.hasText(userTicket)) {
        return null;
    }
    User user = (User) redisTemplate.opsForValue().get("user:" + userTicket);
    //获取用户登录信息,更新cookie,刷新过期时间
    if (user != null) {
        CookieUtil.setCookie(request, response, "userTicket", userTicket);
        return user;
    }
    return null;
}
@RequestMapping("/toList")
public String toList(Model model, @CookieValue("userTicket") String userTicket, HttpServletRequest request, HttpServletResponse response) {
    //如果cookie没有生成,则表示没有登录
    if (!StringUtils.hasText(userTicket)) {
        return "login";
    }
    User user = userService.getUserByTicket(request, response, userTicket);
    //用户没有成功登录
    if (null == user) {
        return "login";
    }
    //将user放入到model中
    model.addAttribute("user", user);
    return "goodsList";
}

3.3 实现 WebMvcConfigurer ,优化登录

需求分析/图解

  1. 获取浏览器传递的 cookie 值,进行参数解析,直接转成 User 对象,继续传递
@RequestMapping("/toList")
//通过自定义参数解析器,封装user信息供controller层方法使用
public String toList(Model model, User user) {
    //用户没有成功登录
    if (null == user) {
        return "login";
    }
    //将user放入到model中
    model.addAttribute("user", user);
    return "goodsList";
}

代码+配置实现

自定义参数解析器

/**
 * 自定义参数解析器
 */
@Component
public class UserArgumentResolver implements HandlerMethodArgumentResolver {

    @Resource
    private UserService userService;

    /**
     * 如果这个方法返回 true 才会执行下面的 resolveArgument 方法
     * 返回 false 不执行下面的方法
     *
     * @param parameter
     * @return
     */
    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        Class<?> parameterType = parameter.getParameterType();
        //如果controller层方法中含有User类型的参数,则执行下面的resolveArgument方法
        return parameterType == User.class;
    }


    /**
     * 这个方法,类似拦截器,将传入的参数,取出 cookie 值,然后获取对应的 User 对象
     * 并把这个 User 对象作为参数继续传递
     *
     * @param parameter
     * @param mavContainer
     * @param webRequest
     * @param binderFactory
     * @return
     * @throws Exception
     */
    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
        HttpServletRequest request =
                webRequest.getNativeRequest(HttpServletRequest.class);
        HttpServletResponse response =
                webRequest.getNativeResponse(HttpServletResponse.class);
        String userTicket = CookieUtil.getCookieValue(request, "userTicket");
        if (!StringUtils.hasText(userTicket)) {
            return null;
        }
        return userService.getUserByTicket(request, response, userTicket);

    }
}

添加自定义参数解析器到解析器列表中

@EnableWebMvc
@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Resource
    private UserArgumentResolver userArgumentResolver;

    /**
     * 静态资源加载
     * @param registry
     */
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/**").addResourceLocations("classpath:/static/");
    }

    /**
     * 将自定义参数解析器添加到解析器列表中
     * @param resolvers
     */
    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
        resolvers.add(userArgumentResolver);
    }

}

改造controller层代码

//登录功能
@RequestMapping("/doLogin")
@ResponseBody
public RespBean doLogin
(@Validated LoginVo loginVo, HttpServletRequest request, HttpServletResponse response) {
    log.info("{}", loginVo);
    return userService.doLogin(loginVo, request, response);
}

3.4使用拦截器进行登录校验

自定义登录认证注解

/**
 * 登录认证注解
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Authorization {
}

登录认证拦截器

public class AuthorizationInterceptor implements HandlerInterceptor {



    @Resource
    private RedisTemplate redisTemplate;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if (!(handler instanceof HandlerMethod)) {
            return true;
        }
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        Method method = handlerMethod.getMethod();
        Authorization annotation = method.getAnnotation(Authorization.class);
        String userTicket = CookieUtil.getCookieValue(request, "userTicket");
        if (annotation != null) {
            User user = (User) redisTemplate.opsForValue().get("user:" + userTicket);
            if (user != null) {
                //TODO 还可以进一步封装,比如将用户信息封装到ThreadLocal中便于后续接口获取
                return true;
            }
        }
        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 {

    }
}
@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Resource
    private UserArgumentResolver userArgumentResolver;

    /**
     * 静态资源加载
     * @param registry
     */
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/**").addResourceLocations("classpath:/static/");
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //表示拦截所有请求
        registry.addInterceptor(authorizationInterceptor()).addPathPatterns("/**")
                .excludePathPatterns("classpath:/static/")
                .excludePathPatterns("/toLogin")
                .excludePathPatterns("classpath:/templates/");
    }

    @Bean
    AuthorizationInterceptor authorizationInterceptor(){
        return new AuthorizationInterceptor();
    }

}

AuthorizationInterceptor对添加了@Authorization注解的controller层方法统一进行登录认证,无需再每个方法都去做用户是登录的校验操作

@Authorization   
@RequestMapping("/toList")
public String toList(Model model) {
    //将user放入到model中
    model.addAttribute("user", user);
    return "goodsList";
}
详解Java分布式Session共享解决方案
08-19
"详解Java分布式Session共享解决方案" 在Java分布式系统中,Session共享是一个非常重要的问题。Session是客户端与服务器通讯会话跟踪技术,服务器与客户端保持整个通讯的会话基本信息。在分布式系统中,Session共享...
详解基于Spring Boot/Spring Session/Redis的分布式Session共享解决方案
08-30
基于Spring Boot/Spring Session/Redis的分布式Session共享解决方案 分布式Session共享是Web开发中的一个常见问题,特别是当网站使用多台服务器时,如何共享Session信息变得非常重要。在本文中,我们将讨论基于...
分布式Session共享解决方案
weixin_34138056的博客
12-13 278
image.png Session服务器用来保存用户操作的一系列会话信息,由Web容器进行管理。单机情况下,不存在Session共享的情况,分布式情况下,如果不进行Session共享会出现请求落到不同机器要重复登录的情况,一般来说解决Session共享有以下几种方案。 1、session复制 s...
分布式架构下,Session共享有什么方案?
weixin_63719049的博客
02-11 1099
2.存入cookie中:将session存储到cookie中,但是缺点也明显,例如每次请求都要带着session,数据存储在客户端本地,是有风险的;1.不要有Session:但是确实在某些场景下,是可以没有session的,其实在很多借口类系统当中,都提倡【API无状态服务】;4.我们现在的系统会把session放到Redis中存储,虽然结构上变的复杂,并且需要多访问一次Redis,也就是每一次的接口访问,都不依赖于session,不依赖于前一次的接口访问,用jwt的token;
【转】多台服务器共享session问题_不同网站 共用一个session
最新发布
2401_83620927的博客
04-12 382
频,并且后续会持续更新**
分布式架构下,Session共享方案
m0_69949258的博客
10-23 554
分布式架构下,Session共享有哪些方案
你还不明白如何解决分布式Session?看这篇就够了!
weixin_43167418的博客
06-18 165
平常做的项目都是在一台应用系统,并且所有的操作都在一台Tomcat服务器上,并不会引发Session共享的问题,所以并不会对我们的系统产生影响,但是当我们部署多个微服务的时候,再搭配Nginx进行负载均衡时,如果不处理分布式Session问题,我们在系统中访问不同功能时就会频繁出现用户登录的操作。图解分析原因:前提:用户登录功能和图中的商品订单模块、秒杀抢购模块属于单独的...
如何解决session共享问题?
qq_47288175的博客
10-09 980
如何解决session共享
简单了解4种分布式session解决方案
08-19
分布式Session解决方案详解 分布式Session是指在多台服务器上存储和管理Session信息,以确保在分布式系统中Session的一致性和可靠性。现有的分布式Session解决方案有多种,本文将详细介绍四种常见的分布式Session...
分布式解决session共享方案一
11-05
分布式解决session共享方案一,可参考
WEB Session 分布式处理方案
08-17
购物车分布式Session处理方案,一个用户的分布式的购物车在集群分布式的情况下怎么处理解决Session共享的问题
apache+tomcat实现session共享
weixin_34175509的博客
03-22 79
apache+tomcat上篇文章,实现了负载均衡,现在我们实现session共享一、tomcat集群配置,session 同步配置:tomcat1配置 A、修改Engine节点信息: <Engine name="Catalina" defaultHost="localhost" jvmRoute="tomcat1">B、去掉<Cluster> &...
Apache代理Tomcat实现session共享构建网上商城系统
weixin_34356555的博客
10-05 338
一、环境介绍二、安装配置后端服务器三、安装配置前端服务器四、配置Tomcat服务器实现session共享五、构建网上商城系统一、环境介绍系统版本:CentOS 6.4_x86_64Mysql版本:mysql-5.1.66-2.el6_3.x86_64Apache版本:httpd-2.2.15-26.el6Tomcat版本:apache-tomcat-7.0.33 点此下载Jd...
session共享怎么做的(分布式如何实现session共享)?
学亮编程手记
01-31 2023
session共享怎么做的(分布式如何实现session共享)? 问题描述:一个用户在登录成功以后会把用户信息存储在session当中,这时session所在服务器为server1,那 么用户在 session 失效之前如果再次使用 app,那么可能会被路由到 server2,这时问题来了,server 没有该用户的 session,所以需要用户重新登录,这时的用户体验会非常不好,所以我们想如何...
分布式session共享问题
wang20010104的博客
04-05 1259
分布式session共享问题
228、商城业务-认证服务-自定义SpringSession完成子域session共享
pyd1040201698的博客
09-15 224
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; import org.springframework.data.redis.serializer.RedisS...
分布式Session管理
星之宇的博客
09-04 226
分布式Session管理概述maven 引用配置application.yml使用 概述 由于Http连接是无状态的,所以使用Tomcat或其他应用服务器作为服务器的时候Tomcat内部会维护一个叫做Session的东东用来保存客户端的状态,一般情况下每个客户端都有一个cookie里面保存着叫jsessionid的cookie,每次访问tomcat的时候都会携带上,Tomcat可以根据这个jsessionid找到对应的session。就像你去超市买东西,门口的储物柜可以视作一个session容器,而打出的二
分布式session
好记性不如烂笔头
03-05 1419
分布式session实现方式 不使用session 使用 JWT(Json Web Token)生成的Token 储存用户身份,然后再从数据库或者 cache 中获取其他的信息。这样无论请求分配到哪个服务器都无所谓 tomcat+redis方案 方便,但是与tomcat容器重耦合 使用 session 的代码,跟以前一样,还是基于 tomcat 原生的 session 支持即可,然后就是用一个...
分布式 session 的4个解决方案,你觉得哪个最好?
Java精选
07-26 279
方案1:session复制(session同步)原理:就是让这两个服务器之间互相同步session,比如左边服务器之前保存了一个1,右边服务器之前保存了一个2,他们两个一同步,那么左边服务器保存了1,2,右边服务器也保存了1,2。这样做的话,我们无论去哪个服务器,都相当于能拿到全量的session数据,这样就不用担心负载均衡到哪个服务器了。面试宝典:https://www...
分布式 前端session 共享
09-17
分布式前端session共享是一种实现分布式系统中实现前端用户会话的机制。在传统的单体应用中,前端会话通常可以直接存储在后端服务器的内存或数据库中,但在分布式系统中,由于涉及多个前端实例和后端服务实例,需要实现前端会话的共享,以保证用户在不同的前端实例间的状态一致性和无缝切换。 实现分布式前端session共享的常用方案包括: 1. 使用缓存中间件:可以通过使用像Redis或Memcached等缓存中间件,将前端会话数据存储在缓存中,实现多个前端实例之间的共享。前端实例可以通过访问同一个缓存中间件,来读取和写入会话数据。 2. 使用数据库存储:将前端会话数据存储在数据库中,通过数据库实现数据的共享。前端实例可以访问同一个数据库,来读取和写入会话数据。 3. 使用分布式协议:通过一致性哈希算法或其他分布式算法,将前端会话数据进行分片,然后分散存储在多个前端实例中。每个前端实例只需存储自己负责的会话数据,实现数据的共享与分布。 4. 使用共享存储:可使用像NFS(Network File System)这样的共享文件系统,将前端会话数据存储在共享文件中,实现多个前端实例之间的数据访问共享。 无论选择哪种方案,需要注意的是要解决会话数据的一致性和并发访问的问题。可以采用同步策略、加锁机制或乐观锁等方法来保证会话数据的一致性。同时,还需要考虑到共享会话数据的性能要求,确保能够支持高并发和低延迟的访问。

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

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
写文章

热门文章

  • Spring-Retry(重试机制) 16385
  • Maven打包跳过测试的5种方式 13051
  • 基于EasyExcel实现百万级数据导入导出 11481
  • MyBatis流式查询 9363
  • 数据字典表设计 9315

分类专栏

  • SpringBoot整合 13篇
  • RabbitMQ 6篇
  • 设计模式 23篇
  • RocketMQ 7篇
  • Kafka 7篇
  • 工具 10篇
  • nginx 9篇
  • 解决方案 5篇
  • linux 26篇
  • 并发编程 8篇
  • 代码片段 22篇
  • SpringBoot 25篇
  • SpringSecurity 1篇
  • java新特性 11篇
  • JavaSE 13篇
  • 虚拟机 3篇
  • redis 17篇
  • zookeeper 1篇
  • javaWeb 19篇
  • MyBatis 8篇
  • Spring 21篇
  • maven 1篇
  • docker 3篇
  • juc 12篇
  • 第三方 6篇
  • 面试题 3篇
  • SpringCloud 9篇
  • SpringMVC 8篇

最新评论

  • RocketMQ-Windows版本安装

    鲨鱼辣椒&!: 现在是不是没有rocketmq-console文件夹了啊

  • 基于EasyExcel锁定指定列导出数据到excel

    面向老板编程: 大哥,怎么重写啊

  • 基于EasyExcel锁定指定列导出数据到excel

    板砖Java: 请问在哪里重写order

  • SpringBoot 集成 RabbitMQ

    llp1110: 你好,是在写测试方法的时候写错了调用方法,已纠正 感谢提醒

  • SpringBoot 集成 RabbitMQ

    Alex_houjie: 在讲解topic模式的时候,controller的代码是不是错误了,写成direct模式的了

您愿意向朋友推荐“博客详情页”吗?

  • 强烈不推荐
  • 不推荐
  • 一般般
  • 推荐
  • 强烈推荐
提交

最新文章

  • SpringBoot整合jasypt加密配置文件敏感信息
  • RocketMQ源码安装
  • RocketMQ-Windows版本安装
2024年12篇
2023年82篇
2022年186篇
2021年4篇

目录

目录

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值

哆哆女性网宝宝起名字哪里网站好mac是什么意思斗罗大陆黄文(H)张哲轩个人资料起名字网智能起名属鼠的人适合起什么名字使命召唤1中文版魏姓起名子龙临专线凡人修仙传电视剧独占病美人师尊diskgenius专业版破解属虎宝宝起名宜用字免费起名字工具双胞胎起名大全免费取名成吉思汗简介按辈份起名吾爱破解网童起名字的含义发簪店铺起名太阳能公司名字起名大全今天百度为什么用不了mobike陈文龙中国语言文字网最强会长黑神中华免费起名字网站大全要求人心净化先要求人生美化是谁的名言男男孩在线起名姓和的名字怎么起淀粉肠小王子日销售额涨超10倍罗斯否认插足凯特王妃婚姻不负春光新的一天从800个哈欠开始有个姐真把千机伞做出来了国产伟哥去年销售近13亿充个话费竟沦为间接洗钱工具重庆警方辟谣“男子杀人焚尸”男子给前妻转账 现任妻子起诉要回春分繁花正当时呼北高速交通事故已致14人死亡杨洋拄拐现身医院月嫂回应掌掴婴儿是在赶虫子男孩疑遭霸凌 家长讨说法被踢出群因自嘲式简历走红的教授更新简介网友建议重庆地铁不准乘客携带菜筐清明节放假3天调休1天郑州一火锅店爆改成麻辣烫店19岁小伙救下5人后溺亡 多方发声两大学生合买彩票中奖一人不认账张家界的山上“长”满了韩国人?单亲妈妈陷入热恋 14岁儿子报警#春分立蛋大挑战#青海通报栏杆断裂小学生跌落住进ICU代拍被何赛飞拿着魔杖追着打315晚会后胖东来又人满为患了当地回应沈阳致3死车祸车主疑毒驾武汉大学樱花即将进入盛花期张立群任西安交通大学校长为江西彩礼“减负”的“试婚人”网友洛杉矶偶遇贾玲倪萍分享减重40斤方法男孩8年未见母亲被告知被遗忘小米汽车超级工厂正式揭幕周杰伦一审败诉网易特朗普谈“凯特王妃P图照”考生莫言也上北大硕士复试名单了妈妈回应孩子在校撞护栏坠楼恒大被罚41.75亿到底怎么缴男子持台球杆殴打2名女店员被抓校方回应护栏损坏小学生课间坠楼外国人感慨凌晨的中国很安全火箭最近9战8胜1负王树国3次鞠躬告别西交大师生房客欠租失踪 房东直发愁萧美琴窜访捷克 外交部回应山西省委原副书记商黎光被逮捕阿根廷将发行1万与2万面值的纸币英国王室又一合照被质疑P图男子被猫抓伤后确诊“猫抓病”

哆哆女性网 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化