自定义博客皮肤VIP专享

*博客头图:

格式为PNG、JPG,宽度*高度大于1920*100像素,不超过2MB,主视觉建议放在右侧,请参照线上博客头图

请上传大于1920*100像素的图片!

博客底图:

图片格式为PNG、JPG,不超过1MB,可上下左右平铺至整个背景

栏目图:

图片格式为PNG、JPG,图片宽度*高度为300*38像素,不超过0.5MB

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+
  • 博客(168)
  • 收藏
  • 关注

原创 Tomcat是如何实现异步Servlet的

01 前言本篇文章我们来聊聊Tomcat是如何实现异步Servlet的以及异步Servlet的使用场景。02 手撸一个异步的Servlet我们直接借助SpringBoot框架来实现一个Servlet,这里只展示Servlet代码:@WebServlet(urlPatterns = "/async",asyncSupported = true)@Slf4jpublic class AsyncServlet extends HttpServlet { ExecutorServic

2021-08-30 20:14:55 518 1

原创 Tomcat性能优化(二)

六、NIO连接器前端整体框图1、图解tomcat总体流程(源码详细分析解读见视频)连接器在Tomcat中是一个重要的组件,叫做Tomcat前端,这个前端框架不是通常我们讲的Web前端,那是structs,javascript,jsp这些内容,这里讲的是以NIO的方式,来描述从socket请求到Request对象的过程,而我们理解的Tomcat后端,通常是以CoyoteAdapter为分界点,后端框架通过Mapper进行映射,可以总结为下面的示意图:Tomcat前端接受的是Socket请

2021-08-30 20:13:56 527

原创 MySQL 慢查询记录原理和内容解析

背景本文并不准备说明如何开启记录慢查询,只是将一些重要的部分进行解析。如何记录慢查询可以自行参考官方文档:5.4.5 The Slow Query Log本文使用 Percona 版本来开启参数 log_slow_verbosity,得到了更详细的慢查询信息。通常情况下信息没有这么多,但是一定是包含关系,本文也会使用 Percona 的参数解释说明一下这个参数的含义。一、慢查询中的时间实际上慢查询中的时间就是时钟时间,是通过操作系统的命令获得的时间,如下是 Linux 中获取时间的方式

2021-08-30 20:06:41 375

原创 Java IO流知识体系

Java IO流知识体系IO流I/O(Input/Output)流,即输入/输出流,是Java中实现输入/输出的基础,它可以方便地实现数据的输入/输出操作。1.1同步与异步,阻塞与非阻塞同步,一个任务的完成之前不能做其他操作,必须等待(等于在打电话)异步,一个任务的完成之前,可以进行其他操作(等于在聊QQ)阻塞,是相对于CPU来说的, 挂起当前线程,不能做其他操作只能等待非阻塞,,无须挂起当前线程,可以去执行其他操作1.2什么是BIOBIO:同步并阻塞,服务器实现一个连接一

2021-08-30 20:05:05 228

原创 分享:关于 JVM 内存的 N 个问题和定位工具

JVM的内存区域是怎么划分的?JVM的内存划分中,有部分区域是线程私有的,有部分是属于整个JVM进程;有些区域会抛出OOM异常,有些则不会,了解JVM的内存区域划分以及特征,是定位线上内存问题的基础。那么JVM内存区域是怎么划分的呢?首先是程序计数器(Program Counter Register),在JVM规范中,每个线程都有自己的程序计数器。这是一块比较小的内存空间,存储当前线程正在执行的Java方法的JVM指令地址,即字节码的行号。如果正在执行Native方法,则这个计数器为空。该内存区域是

2021-08-23 11:02:04 137

原创 说说多线程并发问题,这样回答面试官非常满意

多线程并发问题,基本是面试必问的。大部分同学应该都知道 Synchronized , Lock ,部分同学能说到 volatile 、 并发包 ,优秀的同学则能在前面的基础上,说出Synchronized、volatile的原理,以及并发包中常用的数据结构,例如ConcurrentHashMap的原理。这篇文章将总结多线程并发的各种处理方式,希望对大家有所帮助。一、多线程为什么会有并发问题为什么多线程同时访问(读写)同个变量,会有并发问题?Java 内存模型规定了所有的变量都存储

2021-08-23 11:00:46 193

原创 聊聊Java BIO(同步阻塞IO)、NIO(非阻塞IO)、AIO(异步IO)

Java中有阻塞IO、非阻塞IO。阻塞IO可以理解为“一个连接对应于一线程”。非阻塞IO可以理解为“一个请求(一个请求里面可能会有多个连接【长连接短连接】)对应于一线程”。BIOJava中BIO也成为同步阻塞IO。同步阻塞IO模式下,服务器实现模式为一个连接对应一个线程,即:有连接请求从客户端发起时,服务器端就需要创建一个线程进行处理,如果有大量连接时,服务器就需要创建大量线程进行处理。当然可以通过线程池机制改善。阻塞IO适用场景为:连接数较小且固定的架构模式,这种方式对服务器资源要求比

2021-08-23 10:58:58 303

原创 原型设计模式

亦称: 克隆、Clone、Prototype意图原型模式是一种创建型设计模式, 使你能够复制已有对象, 而又无需使代码依赖它们所属的类。问题如果你有一个对象, 并希望生成与其完全相同的一个复制品, 你该如何实现呢? 首先, 你必须新建一个属于相同类的对象。 然后, 你必须遍历原始对象的所有成员变量, 并将成员变量值复制到新对象中。不错! 但有个小问题。 并非所有对象都能通过这种方式进行复制, 因为有些对象可能拥有私有成员变量, 它们在对象本身以外是不可见的。“从外部”

2021-08-23 10:58:08 81

原创 玩转Redis:Redis高级数据结构及核心命令

本文更适合用于复习总结,阅读》实战》阅读 更有效果哟,主要包含以下内容:Sorted Set(有序集合); String(字符串); List(列表); Set(集合); Hash(散列);文章思路:数据结构应用场景及注意事项; 数据结构各命令对比分析;异常统一说明:error(out of range)导图简写@EOOR;负数偏移量表示倒数第几,导图简写@LBN(last but number);1、ZSet应用场景及注意事项1.1、ZSet应用场景ZSe

2021-08-23 10:56:49 107

原创 Spring AOP详解笔记全网开源,学透并发只需3天

概述AOP是aspect-oriented programming的缩写,译为面向切面编程。利用 AOP 可以对业务逻辑的各个部分进行隔离,从而使得 业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。简单来说,AOP就是不修改源代码在主干功能里面添加新功能。底层原理‍‍AOP底层使用了动态代理:在有接口的时候使用JDK 动态代理、在没有接口的时候使用CGLIB字节码动态代理。JDK动态代理简介使用JDK 动态代理需要用到JDK中的Proxy类里面的newPro

2021-08-23 10:51:50 146

原创 Elasticsearch 分页查询四种解决方案与原理

1、from + size 浅分页常用的分页查询根据from+size语句如下:GET /my_index/my_type/_search{ "query": { "match_all": {}}, "from": 10, "size": 5}上面的查询表示从搜索结果中取第10条开始的5条数据。这个查询语句在 Elasticsearch 集群内部是怎么执行?假设该索引只有primary shards,没有 replica shards,假设10个分片。搜索一般

2021-08-20 17:45:49 560

原创 SpringIOC解决循环依赖的流程图

该例子假设User1中有User2属性,User2中有User1属性,代码大致如下@Componentpublic class User1 { @Autowired private User2 user2;}@Componentpublic class User2 { @Autowired private User1 user1;}然后执行过程图大致为这里解决循环依赖的点主要是靠第三步:将user1对象提前放入三级缓存中,这样子就相当于提前把对

2021-08-20 17:44:19 127

原创 JWT token过期后自动续期的解决方案

在文中给出的例子中,仅实现了登录认证,但是并没有设置token的过期时间,在实际应用中,token一般都需要设置过期时间。如何设置token的过期时间前文《Java面试常见问题:JWT是什么?》介绍过,JWT token的payload部分是一个json串,是要传递数据的一组声明,这些声明被JWT标准称为claims。JWT标准里面定义的标准claim包括:iss(Issuser):JWT的签发主体; sub(Subject):JWT的所有者; aud(Audience):JWT的接..

2021-08-20 17:43:02 3447

原创 深入理解SQL原理:一条SQL查询语句是如何执行的?

本篇文章将通过一条 SQL 的执行过程来介绍 MySQL 的基础架构。首先有一个 user_info 表,表里有一个 id 字段,执行下面这条查询语句:select * from user_info where id = 1;返回结果为:+----+----------+----------+--------+------+---------------------+---------------------+| id | username | password | openid |

2021-08-20 17:41:44 114

原创 支撑百万级并发,Netty如何实现高性能内存管理

Netty作为一款高性能网络应用程序框架,实现了一套高性能内存管理机制通过学习其中的实现原理、算法、并发设计,有利于我们写出更优雅、更高性能的代码;当使用Netty时碰到内存方面的问题时,也可以更高效定位排查出来本文基于Netty4.1.43.Final介绍其中的内存管理机制ByteBuf分类Netty使用ByteBuf对象作为数据容器,进行I/O读写操作,Netty的内存管理也是围绕着ByteBuf对象高效地分配和释放当讨论ByteBuf对象管理,主要从以下方面进行分类:Poo

2021-08-20 17:40:09 215

原创 JAVA8日期处理

Java 8推出了整套的日期时间API,有了这套API就可以放弃所有的java.util.Date、java.sql.Date、Timestamp、Calendar等,也不用再担心SimpleDateFormat的线程安全问题,同时还提供了更好用的日期处理方法。接下来就开始学习一下这套API的使用获取当前日期时间获取当天日期public static LocalDate today() { return LocalDate.now();}获取当前...

2021-08-20 17:39:02 98

原创 单例设计模式

亦称: 单件模式、Singleton意图单例模式是一种创建型设计模式, 让你能够保证一个类只有一个实例, 并提供一个访问该实例的全局节点。问题单例模式同时解决了两个问题, 所以违反了_单一职责原则_:保证一个类只有一个实例。 为什么会有人想要控制一个类所拥有的实例数量? 最常见的原因是控制某些共享资源 (例如数据库或文件) 的访问权限。它的运作方式是这样的: 如果你创建了一个对象, 同时过一会儿后你决定再创建一个新对象, 此时你会获得之前已创建的对象, 而不是一个新对象。注意,

2021-08-20 17:37:26 86

转载 看完必懂得观察者设计模式

什么是观察者设计模式?观察者(Observer)模式的定义:指多个对象间存在一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。这种模式有时又称作发布—订阅模式、模型—视图模式,它是对象行为型模式。一对多例如:一次下单需要插入数据库,需要通知用户下单成功,需要更改库存等。点击获取观察者模式的定义观察者设计模式的结构观察者模式的主要角色如下。抽象主题角色 具体主题角色 抽象观察者角色 具体观察者角色点击获取主要角色的描述观察者

2021-08-20 10:35:49 201

转载 Netty 粘包和拆包

前言前面几个章节主要解析了 Netty 的编码、解码问题,那么是否有了编解码器,我们的 Netty 通信就能正常了呢?TCP 协议在传输数据时没有办法判断数据是什么时候结束的,它无法识别一段完整的信息,因此可能会导致接受到的数据和发送时的数据不一致的情况。因此需要人为的指定一种规范的协议,从而保证数据的安全性,比如:我们所熟悉的 HTTP 协议。本节内容,我们主要需要以下两点知识TCP 拆包、粘包的原因; TCP 拆包、粘包的解决方案。2. 学习目的拆包、粘包在 TCP 协议当中,或

2021-08-20 09:28:17 156

转载 Spring源码分析之IOC循环依赖详解

1.什么是循环依赖?当多个Bean相互依赖时则构成了循环依赖,例如A,B两个Bean。其中A中存在属性B,B中存在属性A,当Spring在实例化A时发现A中存在属性B,就去实例化B,实例化B时又发现存在属性A,一直在循环注入依赖,导致循环依赖问题出现。2.Spring是怎么解决循环依赖的?Spring中会通过各种Bean中间状态来达到Bean还未实例化完成时提前将Bean提前注入到依赖Bean的属性中,假设说Bean有三种状态分别是青年态(一级缓存)、胚胎态(二级缓存)、小蝌蚪态(三级缓存)其中

2021-08-17 17:35:04 248

转载 Redis实战 | Redis数据5种类型详解

Redis是目前非常主流的KV数据库,它因高性能的读写能力而著称,其实还有另外一个优势,就是Redis提供了更加丰富的数据类型,这使得Redis有着更加广泛的使用场景。那Redis提供给用户的有哪些数据类型呢?主要有:string(字符串)、List(列表)、Set(集合)、Hash(哈希)、Zset(有序集合)、HyperLogLogs(计算基数用的一种数据结构)、Streams(Redis 5.0提供一种建模日志用的全新数据结构)。需要注意的是这里说的数据类型是指Redis值的数据类型,而Redis

2021-08-17 17:34:14 445

转载 百亿级并发系统设计-实战教程

如何设计一个高并发系统?说实话,如果面试官问你这个题目,那么你必须要使出全身吃奶劲了。为啥?因为你没看到现在很多公司招聘的 JD 里都是说啥有高并发经验者优先。如果你确实有真才实学,在互联网公司里干过高并发系统,那你确实拿 offer 基本如探囊取物,没啥问题。面试官也绝对不会这样来问你,否则他就是蠢。假设你在某知名电商公司干过高并发系统,用户上亿,一天流量几十亿,高峰期并发量上万,甚至是十万。那么人家一定会仔细盘问你的系统架构,你们系统啥架构?怎么部署的?部署了多少台机器?缓存咋用的?MQ 咋

2021-08-17 17:33:09 316

转载 Netty 通讯协议设计概要

前言上节内容,我们主要介绍了 Netty 的粘包和拆包问题,并且大致介绍了 Netty 提供的常见拆包器,分别是固定长度拆包器、行拆包器、分隔符拆包器、基于长度域拆包器,但是它们只是相对简单的协议,也就是说无法满足复杂的业务场景,因此,我们可以通过自定义协议的方式去解决 TCP 的粘包和拆包问题。2. 了解什么是协议首先,我们大概了解什么是协议,协议可以把它认为是一种规则而不是技术,约束客户端和服务端之间通讯,数据组装和拆分的一种规范。客户端安装某种规范去组装数据,把数据传输给服务端,服务端再.

2021-08-17 17:31:28 505

转载 toString()、String.valueOf、(String)强转,啥区别?

前言相信大家在日常开发中这三种方法用到的应该很多,尤其是前两种,经常在开发的时候,随心所欲,想用哪个用哪个,既然存在,那就应该有它存在的道理,那么什么情况下用哪个呢?二、代码实例1、基本类型(1)基本类型没有toString()方法(2)推荐使用(3)无法强转(String)是标准的类型转换,将Object类型转为String类型,使用(String)强转时,最好使用instanceof做一个类型检查,以判断是否可以进行强转,否则容易抛出ClassCast

2021-08-17 17:30:39 195

转载 java开发技术之ArrayList的实现原理

1. ArrayList概述ArrayList是List接口的可变数组的实现。实现了所有可选列表操作,并允许包括 null 在内的所有元素。除了实现 List 接口外,此类还提供一些方法来操作内部用来存储列表的数组的大小。每个ArrayList实例都有一个容量,该容量是指用来存储列表元素的数组的大小。它总是至少等于列表的大小。随着向ArrayList中不断添加元素,其容量也自动增长。自动增长会带来数据向新数组的重新拷贝,因此,如果可预知数据量的多少,可在构造ArrayList时指定其容量。在添加大量

2021-08-17 17:29:42 413

转载 一文读懂哈希和一致性哈希算法

哈希 Hash 算法介绍哈希算法也叫散列算法, 不过英文单词都是 Hash, 简单一句话概括, 就是可以把任意长度的输入信息通过算法变换成固定长度的输出信息, 输出信息也就是哈希值, 通常哈希值的格式是16进制或者是10进制, 比如下面的使用 md5 哈希算法的示例md5("123456") => "e10adc3949ba59abbe56e057f20f883e"主要特点:不可逆 从哈希值不能推导出原始数据, 所以Hash算法广泛应用在现代密码体系中 无碰撞 不同的信息进行哈希

2021-08-17 17:28:51 384

转载 一文看懂Java锁机制

背景知识指令流水线CPU的基本工作是执行存储的指令序列,即程序。程序的执行过程实际上是不断地取出指令、分析指令、执行指令的过程。几乎所有的冯•诺伊曼型计算机的CPU,其工作都可以分为5个阶段:取指令、指令译码、执行指令、访存取数和结果写回。现代处理器的体系结构中,采用了流水线的处理方式对指令进行处理。指令包含了很多阶段,对其进行拆解,每个阶段由专门的硬件电路、寄存器来处 理,就可以实现流水线处理。实现更高的CPU吞吐量,但是由于流水线处理本身的额外开销,可能会增加延迟。cpu多级

2021-08-17 17:26:46 180

转载 redis五种基本数据类型的应用场景是啥?

string缓存简单key-value存储分布式锁setnx key value,当key不存在时,将 key 的值设为 value ,返回1若给定的 key 已经存在,则setnx不做任何动作,返回0。当setnx返回1时,表示获取锁,做完操作以后del key,表示释放锁,如果setnx返回0表示获取锁失败,整体思路大概就是这样计数器如知乎每个问题的被浏览器次数set key 0incr key // incr readcount::{帖子id} 每阅读一

2021-08-17 15:44:29 90

转载 java枚举类型,为什么强烈推荐使用?看看它的7种场景方法

枚举是 JDK 1.5 新增的数据类型,使用枚举我们可以很好的描述一些特定的业务场景,比如一年中的春、夏、秋、冬,还有每周的周一到周天,还有各种颜色,以及可以用它来描述一些状态信息,比如错误码等。枚举类型不止存在在 Java 语言中,在其它语言中也都能找到它的身影,例如 C# 和 Python 等,但我发现在实际的项目中使用枚举的人很少,所以本文就来聊一聊枚举的相关内容,好让朋友们对枚举有一个大概的印象,这样在编程时起码还能想到有“枚举”这样一个类型。枚举的 7 种使用方法很多人不使用枚

2021-08-17 15:42:59 2488

转载 5分钟了解Tomcat的组成和工作原理

Server和ServiceTomcat中Server是最顶级的组件,它代表Tomcat的运行实例,一个JVM中只会包含一个Server。为了方便扩展,Server中引入了监听器Listener组件;为了方便集成JNDI,引入了GlobalNamingResources组件。Server中最重要的组件还是Service。一个Server包括多个Service在Tomcat中,Service组件是服务的抽象,一个Server中可以包含多个Service。Service组件负责从接收客户端请求到

2021-08-16 09:20:22 221

转载 Vue中的MVVM原理解析和实现

下面由我阿巴阿巴的详细走一遍Vue中MVVM原理的实现,这篇文章大家可以学习到:1.Vue数据双向绑定核心代码模块以及实现原理2.订阅者-发布者模式是如何做到让数据驱动视图、视图驱动数据再驱动视图3.如何对元素节点上的指令进行解析并且关联订阅者实现视图更新1、思路整理实现的流程图:我们要实现一个类MVVM简单版本的Vue框架,就需要实现以下几点:1、实现一个数据监听Observer,对数据对象的所有属性进行监听,数据发生变化可以获取到最新值通知订阅者。2、.

2021-08-12 11:45:32 1130

转载 放弃 StringBuilder!Java8的StringJoiner,真香

为什么会新增这样一个string辅助类?原有的stringbuilder太死板,不支持分割,如果想让最终的字符串以逗号隔开,需要这样写StringBuilder sb = new StringBuilder();IntStream.range(1,10).forEach(i->{ sb.append(i+""); if( i < 10){ sb.append(",") } });是不是太死板了,不好用,StringJoiner怎样写呢?

2021-08-12 11:44:35 134

转载 Mybatis开发要点:resultType和resultMap的区别?

Mybatis返回Xml返回值有resultType和resultMap,我们一般都该如何选择呢?一、resultType1.1 resultType介绍当使用resultType做SQL语句返回结果类型处理时,对于SQL语句查询出的字段在相应的pojo中必须有和它相同的字段对应,而resultType中的内容就是pojo在本项目中的位置。1.2 映射规则基本类型 :resultType=基本类型 List类型: resultType=List中元素的类型 Map类型 单条记录:re

2021-08-12 11:43:48 230

转载 数据库连接池c3p0

简介c3p0是用于创建和管理连接,利用“池”的方式复用连接减少资源开销,和其他数据源一样,也具有连接数控制、连接可靠性测试、连接泄露控制、缓存语句等功能。目前,hibernate自带的连接池就是c3p0。本文将包含以下内容(因为篇幅较长,可根据需要选择阅读):c3p0的使用方法(入门案例、JDNI使用) c3p0的配置参数详解 c3p0主要源码分析使用例子-入门需求使用C3P0连接池获取连接对象,对用户数据进行简单的增删改查(sql脚本项目中已提供)。工程环境JDK:1.8

2021-08-12 11:41:35 2153

转载 别再写满屏的 if、else 了,试试策略模式

你还在写满屏的 if/ else/ switch 之类的判断逻辑吗?栈长在开发人员的代码中看过太多这样的低级代码了,真的太 low,极不好维护,本文栈长就教你如何用策略模式干掉 if/ else/ switch,让你的代码更优雅。什么是策略模式?比如说对象的某个行为,在不同场景中有不同的实现方式,这样就可以将这些实现方式定义成一组策略,每个实现类对应一个策略,在不同的场景就使用不同的实现类,并且可以自由切换策略。策略模式结构图如下:策略模式需要一个策略接口,不同的策略实现不同的实

2021-08-12 11:37:30 316 2

转载 基础-中级-高级”Java程序员面试

Java基础(对象+线程+字符+接口+变量+异常+方法)面向对象和面向过程的区别? Java 语言有哪些特点? 关于 JVM JDK 和 JRE 最详细通俗的解答 Oracle JDK 和 OpenJDK 的对比 Java 和 C++的区别? 什么是 Java 程序的主类?应用程序和小程序的主类有何不同? Java 应用程序与小程序之间有哪些差别? 字符型常量和字符串常量的区别 构造器 Constructor 是否可被 override? 重载和重写的区别? Java 面向对象编程三

2021-08-12 11:36:37 140

转载 大促高并发系统下JVM如何调优

JVM调优实战JVM调优实战以web项目为例。调优主要从两个方面入手,一是tomcat容器的优化,二是JVM虚拟机的调优。调优的原则是控制变量法,先优化tomcat,再优化JVM虚拟机,二者不要同时进行,否则,可能越调性能越差。 下面我们首先来进行tomcat容器的优化。tomcat优化1.禁用AJP服务#优化一:禁用AJP服务,一般是使用Nginx+tomcat的架构,所以用不着AJP协议,所以把AJP连接器禁用。 #将下面的配置注释掉 <Connector port="800

2021-08-12 11:32:17 698

转载 for、foreach、stream 哪家的效率更高

比较for循环、foreach循环及Stream方法效率for循环首先,10000数据的for循环,代码如下:publicclassForTest{publicstaticvoidmain(String[]args){LongstartTime=System.currentTimeMillis();formMethod();LongendTime=System.currentTimeMillis();...

2021-08-12 11:30:08 1446

转载 MySQL中IN和OR的查询效率和区别

最近遇到了一个网站卡死的问题,但是过了几分钟网站又好了,我让工作了 4 年的一个同事排查问题,他找了半天,毫无头绪。然后,我帮他找到了定时任务,其中有个 sql 查询,执行效率很慢,我建议将 or 改为 in,效率提升了几百倍。下面我们一起回顾一下这个问题。场景描述两个表关联查询 table1 的数据量接近 100 万 table2 的数据量接近 900 万 查询条件中的 title 字段没有加索引 原始查询语句SELECT a.id as id FROM `table1` as a

2021-08-12 11:28:08 1880

转载 别再if-else走天下了,整个注解多优雅

策略模式经常在网上看到一些名为“别再if-else走天下了”,“教你干掉if-else”等之类的文章,大部分都会讲到用策略模式去代替if-else。策略模式实现的方式也大同小异。主要是定义统一行为(接口或抽象类),并实现不同策略下的处理逻辑(对应实现类)。客户端使用时自己选择相应的处理类,利用工厂或其他方式。注解实现本文要说的是用注解实现策略模式的方式,以及一些注意点。 话不多说,还是以最常 见的订单处理为例。首先定义这样一个订单实体类:@Datapublic class Order {

2021-08-12 11:26:48 140

空空如也

空空如也

TA创建的收藏夹 TA关注的收藏夹

TA关注的人

提示
确定要删除当前文章?
取消 删除