程序员
文章平均质量分 90
油腻的程序猿啊
这个作者很懒,什么都没留下…
展开
-
Spring Boot + Prometheus + Grafana 打造可视化监控,一目了然
现在可以启动Prometheus了,命令行输入:prometheus.exe --config.file=prometheus.yml 访问http://localhost:9090/targets,查看Spring Boot采集状态是否正常。由于开启了安全认证,所以访问这个URL的需要提示输入账号/密码,如果提示404请检查下你的请求地址是否正确,如果不设置management.context-path则默认地址是http://ip:port/prometheus。原创 2022-10-05 15:08:33 · 415 阅读 · 0 评论 -
AQS:Java 中悲观锁的底层实现机制
AQS(AbstractQueuedSynchronizer)是 Java 并发包中,实现各种同步组件的基础。比如各种锁:ReentrantLock、ReadWriteLock、StampedLock各种线程同步工具类:CountDownLatch、CyclicBarrier、Semaphore线程池中的 WorkerLock 接口的实现基本都是通过聚合了一个 AQS 的子类来完成线程访问控制的。Doug Lea 曾经介绍过 AQS 的设计初衷。原创 2022-09-22 11:06:09 · 113 阅读 · 0 评论 -
读懂HikariCP一百行代码,多线程就是个孙子!
通常,我在看书的时候一般不写代码,因为我的脑袋被设定成单线程的,一旦同时喂给它不同的信息,它就无法处理。但多线程对电脑来说就是小菜一碟,它可以同时做很多事,看起来匪夷所思。好希望把自己的大脑皮层移植到这些牛x的设备上。用人脑思考电脑正在思考的问题,这本身就是一种折磨。但平常的工作和面试中,又不得不面对这样的场景,所以多线程就成了编程路上一块难啃的骨头。HikariCP是SpringBoot默认的数据库连接池,它毫不谦虚的的起了一个叫做光的名字,这让国产Druid很没面子。原创 2022-09-21 10:27:59 · 841 阅读 · 0 评论 -
Java开发利器之Guava Cache
总结:第一种写法更像是前面说到的Map,在对数据进行CRUD操作时,需要用户手动对缓存进行同步的更新或删除操作,所以叫ManualCache(手动),当然Guava Cache对Map的加强依然有效,比如过期清除,缓存容量限制。此时构建的是一个实现了Cache接口的LoadingCache,相比ManualCache,提供了缓存回填机制,即当缓存不存在时,会基于CacheLoader查询数据并将结果回填到缓存, 在高并发时,可以有效地基于缓存锁减少对系统资源的调用。降低系统数据读写压力...原创 2022-09-21 10:08:03 · 396 阅读 · 0 评论 -
CPU流水线与指令乱序执行
说了这么多,很可能在我之后的文章中被一句话带过。其实我想表达的思想就是,实际代码运行的顺序可能和我们代码编写的顺序并不一致。记住这句话很容易,但或许总会有人像我一样想稍微深入一点来了解这句话的本质吧。除了本文所述,CPU和高速缓存之间的交互过程中,硬件工程师也着实给软件开发者挖了不少坑,内存屏障就是在这种背景下产生的。原创 2022-09-13 11:43:28 · 667 阅读 · 0 评论 -
Java对象转换最佳方案
UserDO@Data}复制代码UserDTO@Data}复制代码软件系统一般都会进行分层,领域模型也会随之进行分层,即每层都有自己关注的模型对象;分层的主要原因是便于维护。模型之间的对象经常要互相转换,常用的转换实现有反射和get/set,反射的性能很差不建议使用然后写了基于get/set实现的beancopier和mapstruct使用方式,简单测试了下性能,mapstrcut优于其它各种对象转换方式。原创 2022-09-13 10:30:19 · 308 阅读 · 0 评论 -
Netty 系列之编解码器和 handler 的调用机制
编写网络应用程序时,因为数据在网络中传输的都是二进制字节码数据,在发送数据时就需要编码,接收数据时就需要解码codec(编解码器) 的组成部分有两个:decoder(解码器)和 encoder(编码器)。encoder 负责把业务数据转换成字节码数据,decoder 负责把字节码数据转换成业务数据Protobuf 是 Google 发布的开源项目,全称 Google Protocol Buffers,是一种轻便高效的结构化数据存储格式,可以用于结构化数据串行化,或者说序列化。原创 2022-09-12 10:22:45 · 466 阅读 · 0 评论 -
SpringBoot 源码 | prepareEnvironment 方法解析
执行完成准备环境的 prepareEnvironment 方法之后,会继续执行容器上下文启动前的其他准备工作,后续我会继续更新,欢迎共同讨论,一同进步。原创 2022-09-12 09:54:29 · 573 阅读 · 0 评论 -
手把手教你用Java获取IP归属地
前几个月微信公众号上线了IP归属地的功能,后续知乎、抖音等平台纷纷添加了该功能。如果是国内的用户精确到省份,国外用户精确到国家。本文就使用Java实现获取IP归属地。!原创 2022-09-12 09:40:22 · 286 阅读 · 0 评论 -
Dubbo反序列化漏洞分析集合
调用相应的反序列化函数对数据流进行反序列化操作。,如果不满足则直接抛出异常。若pojo为Map实例,则从pojo(也就是一开始的第三个参数)获取key为“class”的值,并通过反射得到class所对应的类type,再判断对象的类型进行下一步处理。在之前的分析中我们知道了这个方法是用来获取数据体中的一些信息用的,其中一种利用方式就是通过在读取version的时候,调用readUTF方法,跟进。主要是通过获取tag位,进行相应的处理,但是这里关键的就是,当这里不是一个String类型的时候,将会抛出异常。原创 2022-09-09 10:49:23 · 3802 阅读 · 0 评论 -
基于SpringDataElasticsearch+SpEL表达式实现ES动态索引
一般情况下,当我们使用去操作ES时,索引名称都会在@Document注解中写死,每次都是对这个固定的索引进行操作。假如我们现在处于一个多租户系统中,每个租户都有自己所对应的用户数据,而这些用户数据都会被导入到ES中,那怎么实现各个租户的用户数据索引隔离呢?换言之,在同一个索引结构的情况下怎么实现一个租户一个索引?解决方案:使用SpEL表达式动态获取索引。原创 2022-09-09 10:15:15 · 442 阅读 · 0 评论 -
Spring的循环依赖,到底是什么样的
什么是循环依赖,说到循环依赖,这个实际上是没有那么复杂的,就比如很简单的说,A 引用了 B ,而这个时候 B 也引用了 A ,那么这种情况实际上就是出现了循环依赖的问题了,实际上也可以把循环依赖称之为循环引用,两个或者两个以上的bean互相持有对方,最终形成闭环。这个时候,我们看到这个初始化的过程,一般就应该能猜到会发生 循环依赖 的位置是哪一步了,而单从 bean 的初始化来看,循环依赖发生的位置就是在 createBeanInstance 实例化 以及 populateBean 填充属性 当中,原创 2022-09-09 10:13:02 · 78 阅读 · 0 评论 -
聊聊 Java 数据结构与算法中的堆最小堆和最大堆
堆的历史堆的数据结构有很多种体现形式,包括;2-3堆、B堆、斐波那契堆,而在 Java API 中最常用的是用于实现优先队列的二叉堆,它是由 JWJ Williams 在 1964 年引入的,作为堆排序算法的数据结构。另外在 Dijkstra 算法等几种高效的图算法中,堆也是非常重要的。原创 2022-09-08 16:41:26 · 1303 阅读 · 0 评论 -
详细图解 Netty Reactor 启动全流程
本文我们通过图解源码的方式完整地介绍了整个Netty服务端启动流程,并介绍了在启动过程中涉及到的相关的属性以及配置方式。的创建初始化过程以及类的继承结构。其中重点介绍了向Reactor的注册过程以及Reactor线程的启动时机和pipeline的初始化时机。最后介绍了绑定端口地址的整个流程。上述介绍的这些流程全部是异步操作,各种回调绕来绕去的,需要反复回想下,读异步代码就是这样,需要理清各种回调之间的关系,并且时刻提醒自己当前的执行线程是什么?原创 2022-09-07 14:55:31 · 409 阅读 · 0 评论 -
手摸手 Spring Cloud Gateway + JWT 实现登录认证
目录通过本文你会掌握以下知识点:如何用认证服务做登录认证。如何生成 JWT 令牌(Token)如何用 Gateway 对 Token 验证。Gateway 如何从 Token 中拿到用户信息并转发给业务服务。业务服务如何从请求中拿到身份信息处理业务逻辑。如何刷新令牌。本篇还是基于我的开源项目 PassJava 作为讲解。PassJava 开源地址:https://github.com/Jackson0714/PassJava-Platform。原创 2022-09-07 09:43:51 · 2963 阅读 · 0 评论 -
spring项目中starter包的原理,以及自定义starter包的使用
我们最早配置spring应用的时候,必须要经历的步骤: 1.pom文件中引入相关的jar包,包括spring,redis,jdbc等等 2.通过properties或者xml配置相关的信息 3.不断调试直到可以使用。问题:时间长,复杂,同时在写下一个项目的时候大概率要经过相同的模式配置才能达到可以使用的状态。同时在众多的jar中,我们需要相互配置依赖间的版本关系,十分的复杂原始版本:我们就想到能不能把这些jdbc整合起来,类似于深度学习中anaconda下载依赖一样去管理,依赖间的关系不需要我们去负责,而是原创 2022-09-04 13:08:30 · 184 阅读 · 0 评论 -
Spring Security -- 前后端分离时的安全处理方案
今天就带大家来学习一下在前后端分离的开发模式下,如何保护我们项目的安全。有的小伙伴会问,啥是前后端分离啊?如果你对此一无所知,一一哥只能建议你先查阅一下相关资料,本文 只能带你简单了解一下前后端分离的概念,毕竟今天我们是在讲解如何保证安全性的。还有的小伙伴会说,前后端分离有什么了不起,为啥就需要单独处理?它和前后端不分离时有什么不同?那么就让我们带着这些疑问来开始今天的内容吧!我们还是先来了解一下前后端分离这种开发模式吧,看看到底什么是前后端分离!原创 2022-09-03 13:20:28 · 1491 阅读 · 0 评论 -
深入Spring Boot :整合Redis详解
Spring Data Redis是Spring Data项目中的一个主要模块,它提供了从Spring应用程序中轻松配置和访问Redis的功能、提供了与应用交互的低级和高级抽象,使开发者摆脱了对基础结构的关注,例如提供了RedisCacheManager。从Spring3.1开始,Spring框架提供了对Cache的支持,提供了一个对缓存使用的抽象,通过在既有代码中添加少量它定义的各种annotation,即能够达到缓存方法的返回对象的作用。添加图片注释,不超过 140 字(可选)...原创 2022-08-31 10:40:02 · 1559 阅读 · 0 评论 -
这样的API网关查询接口优化,我是被迫的
是的,我翻看了几遍后端代码确认没看错,上述页面上的信息是通过API网关系统中的一个查询接口得到的,并且接口的处理逻辑使用了单线程线性处理,也就是下面这样的。于是找负责前端的大佬沟通沟通,我提供三个接口分别用于查询不同的数据,前端系统请求不同的接口查询不同的数据,这样查询结果会更快,用户体验会更好,没想到大佬一句话就把我怼回来了“项目排期都满了,没人手配合你了”。需求是根据产品经理的解说,这个页面上的信息加载太慢了,特别是随着业务的快速发展,数据量大增后更慢,需要对查询接口的性能做优化。...原创 2022-08-31 10:31:13 · 130 阅读 · 0 评论 -
实战级详解Spring框架中引入阿里开源组件Nacos作配置中心
推荐Data ID采用类Java包的命名规则保证全局唯一性,例如com.abc.trade.datasource.properties,需要注意的是Nacos默认支持JSON、XML、YAML和Properties格式的配置项解析,所以如果Data ID的名称中包含.,它的名称后缀要以.json/.xml/.yaml/.properties结尾,如果Data ID的名称中不包含.,Nacos默认使用.properties格式解析配置项。所以,配置中心应运而生,可以集中、灵活、动态的管理这些参数配置。...原创 2022-08-31 10:14:41 · 785 阅读 · 0 评论 -
聊一聊Redis官方置顶推荐的Java客户端Redisson
写这篇的时候,相信有很多朋友还在用Jedis作为Redis的客户端,我不禁有很多问号,Jedis还香吗?如果你早些年说它香我信,但是都2020年了,它真的不那么香了。那为什么还继续使用它呢?大部分原因或多或少是因为一遗留代码没人敢大动,就这样吧;二新项目没人主导使用其它实现做替换。祖传代码不轻易大动,这个真理必须相信,且坚持相信;至于没人主导拍板做技术替换,可能是习惯了Jedis的用法,也可能是没人了解其它技术实现,当然还有其它原因,有兴趣分享的朋友可以在评论区聊一聊。咳咳,扯远了,来聊我们今天的话题-Re原创 2022-08-31 09:56:52 · 673 阅读 · 0 评论 -
DDD之落地实践
面向数据建模,面向过程编程,没有真正“面向对象”只注重结果,不注重过程,service层动辄数百上千行,充斥着过程代码、胶水代码,要么臃肿、要么流水账、要不重复、要么逻辑分散,后期极难维护代码耦合严重,层与层之间互相调用、逆向调用,牵一发而动全身代码无法体现业务,在大家都不爱写注释的情况下,随着时间的推移,代码业务逻辑将无人理解,不敢改也改不动。那么有没有一个好的解决方案呢?今天要讲的DDD就是一个不错的选择。...原创 2022-08-29 15:15:15 · 586 阅读 · 0 评论 -
工厂模式有三个Level,你能用Go写到第几层?
我们用几个较为简单的例子和大家一起学习了下三个工厂模式各自的场景和优缺点,实际使用的时候项目一开始需求还没那么明确的时候推荐还是先用简单工厂,等我们业务理解更透彻后如果确实需要再升级到工厂方法也不迟。抽象工厂也是,如果确定引入产品生态的概念才能更好地进行领域建模,再开始使用抽象工厂也不迟。...原创 2022-08-29 09:52:59 · 376 阅读 · 0 评论 -
写了一款Jetbrains插件,为了Markdown
里面配置了GitHub Actions的工作流,具体来说就是我们自动将插件提交到GitHub之后,GitHub会根据这个工作流为我们自动做一些我们配置的事情,比如安装依赖,比如发布到Jetbrain官方插件库等,默认不需要更改。」之类的关键词,找到网友之前分享的开发博客,一般写的详细的博客(可能需要多找几篇)会给出官方地址,然后,抛弃这篇文章,投入官方文档的怀抱吧。我当时想的就是这几个问题,所以我的第一反应是:作为一个成熟的软件开发商,应该会提供实例代码给我们,我们就能抄参考了。...原创 2022-08-29 09:26:13 · 556 阅读 · 0 评论 -
十分钟让你搞懂会用Spring Retry
在这篇文章中,我们看到了的不同特性,我们清楚使用它能使应用程序更加健壮。我们实践了最为常见的几种用法,主要包括@Retryable注释和。那么哪些地方我们能用到呢?有这两点建议仅在临时错误上使用重试。不建议它在永久错误中使用它,因为这样可能导致系统性能问题。它不是熔断器的替代的一种方式,最好在允许的情况下,既使用熔断器,又使用重试器。...原创 2022-08-28 10:24:05 · 328 阅读 · 0 评论 -
百亿级数据分表后怎么分页查呢?
举个很简单的例子,原本41位的时间戳你觉得用不完,用户ID是10位的,订单号的生成规则带上用户ID,落具体表的时候根据订单号中10位用户ID hash取模,这样无论根据订单号还是用户ID查询效果都是一样的。因为对于B端来说轻微的延迟是可以接受的,所以可以采取异步的方式去落B端订单。分库分表首先是基于现有的业务量和未来的增量做出判断,比如拼多多这种日单量5000万的,半年数据得有百亿级别了,那都得分到4096张表了对吧,但是实际的操作是一样的,对于你们的业务分4096那就没有必要了,根据业务做出合理的选择。.原创 2022-08-28 10:21:26 · 137 阅读 · 0 评论 -
MongoDB进阶指南!
想必大家很多人都在业务开发的时候遇到这样的痛点。最近在用数据库存储数据的时候发现这么一个坑,例如从消息队列中监听消息的时候,原来的做法是将监听的消息json数据存储在数据库,以便好对异常消息数据进行追溯,消息内容使用text类型存储,起初因为数据内容很短,没啥毛病,但是当随着业务的扩展,收到的消息内容越来越长,最后发现数据库中的text字段类型无法很好的支持查询,于是在这个时候,就开始考虑采用更加合适的数据库来存储这种消息数据!...原创 2022-08-28 10:12:44 · 509 阅读 · 0 评论 -
spring赌上未来的一击:WebFlux性能实测
通过本文实操以及linux服务器下长时间的压测,可以验证的是我们可以使用WebFlux来替代SpringMVC,从而获取更好的性能,更高的并发。500用户请求时候可以看到hello3接口的响应时间已经是hello1和hello2两个接口响应时间的2倍以上了,但是基于project reactor响应编程开发方式的响应时间依旧和200用户一致。可以看见传统的SpringMVC方式已经有阻塞了,最长的一次请求1107ms,但是整体性能基本一致,因为200个线程刚好是tomcat的线程池最大默认数。原创 2022-08-24 11:15:36 · 434 阅读 · 0 评论 -
金九银十:搞定这两个开源项目,30k轻松吧?
如何让方法论能够实际落地到你的业务项目中去,比如为了保证数据的最终一致性,我们项目中如何如何做的,我们用到的是一个二阶段提交的思想,另外我们的业务场景满足CAP中的CP,等等。leetcode第20题——有效的括号 大学的时候,我们进实验室搞ACM,也是刷题,一开始刷杭电的题,刷100多道以后觉得自己有所提升了,就开始刷清华的题,然后参加校内赛,然后再去参加省赛。刷多了,你的逻辑思维会更加缜密,思考问题也更加全面,最终体现的就是你的代码质量会极大的提升,bug也就自然少了,我觉得这才是刷题的最大好处。原创 2022-08-24 11:02:04 · 120 阅读 · 0 评论 -
节后面试必备:Spring 面试63问
一个Spring Bean 的定义包含容器必知的所有配置元数据,包括如何创建一个bean,它的生命周期详情及它的依赖。Spring元数据配置方式XML配置文件基于注解的配置基于java的配置在Spring框架中,当一个bean仅被用作另一个bean的属性时,它能被声明为一个内部bean。内部bean可以用setter注入“属性”和构造方法注入“构造参数”的方式来实现,内部bean通常是匿名的,它们的Scope一般是prototype。Spring 依赖注入四种方式构造器注入。原创 2022-08-24 10:39:35 · 131 阅读 · 0 评论 -
40 个 常用的 SpringBoot 注解,你知道几个?
RequestBody在处理请求方法的参数列表中使用,它可以将请求主体中的参数绑定到一个对象中,请求主体参数是通过HttpMessageConverter传递的,根据请求主体中的参数名与对象的属性名进行匹配并绑定值。@Bean注解主要的作用是告知Spring,被此注解所标注的类将需要纳入到Bean管理工厂中。@Repository注解也是@Component注解的延伸,与@Component注解一样,被此注解标注的类会被Spring自动管理起来,@Repository注解用于标注DAO层的数据持久化类。原创 2022-08-24 10:37:44 · 128 阅读 · 0 评论 -
JDK9到底为什么要将String的底层实现由char「」改成了byte「」
但是在 Java 中,一个字符(char)就是 2 个字节,占 4 个字节的字符,在 Java 里也是用两个 char 来存储的,而String的各种操作,都是以Java的字符(char)为单位的,charAt是取得第几个char,subString取的也是第几个到第几个char组成的子串,甚至length返回的都是char的个数。也就是说,从 char[] 到 byte[],中文是两个字节,纯英文是一个字节,在此之前呢,中文是两个字节,英文也是两个字节。原创 2022-08-24 10:31:01 · 436 阅读 · 0 评论 -
45 个 Git 经典操作场景,专治不会合代码
如果你需要删除推了的提交(pushed commits),你可以使用下面的方法。可是,这会不可逆的改变你的历史,也会搞乱那些已经从该仓库拉取(pulled)了的人的历史。简而言之,如果你不是很确定,千万不要这么做。这只能在没有推送之前有用. 如果你已经推了, 唯一安全能做的是 git revert SHAofBadCommit, 那会创建一个新的提交(commit)用于撤消前一个提交的所有变化(changes);原创 2022-08-24 10:28:11 · 200 阅读 · 0 评论 -
深入理解 Spring 事务:入门、使用、原理
Spring 事务是复杂一致性业务必备的知识点,掌握好 Spring 事务可以让我们写出更好地代码。这篇文章我们将介绍 Spring 事务的诞生背景,从而让我们可以更清晰地了解 Spring 事务存在的意义。接着,我们会介绍如何快速使用 Spring 事务。接着,我们会介绍 Spring 事务的一些特性,从而帮助我们更好地使用 Spring 事务。最后,我们会总结一些 Spring 事务常见的问题,避免大家踩坑。Spring 事务 - 思维导图。原创 2022-08-22 11:03:41 · 95 阅读 · 0 评论 -
Java线上CPU内存冲高问题排查步骤
4.1 排查命令总结top:查看系统进程CPU与内存占用情况,找到占用最多的进程IDtop -Hp 进程号:查看该进程号的所有线程CPU与内存占用情况,找到占用最多的线程ID(显示的PID即为10进制线程编号,printf "%x\n" 进程号转为16进制线程号)jstack 进程号 >> stack.txt:将进程号所属进程的堆栈信息输出到stack.txt中jstack 进程号 | grep 16进制线程号。原创 2022-08-22 11:02:29 · 588 阅读 · 0 评论 -
从零开始打造一款基于 SpringBoot+SpringCloud 的后台权限管理系统
随着 Spring Boot 和 Spring Cloud 的诞生和流行,集智慧于大成的 Spring 技术体系成为行业开发的首选之一。市场代表需求,技术代表能力。显而易见,在当今开发领域中,谁能更好地掌握这些主流开发技术,谁就能在跟别人竞争的时候多一些筹码,谁就能获得更好的就业机会、薪资报酬和发展空间。要想更好地掌握开发技术和知识,就要进入项目多写代码,当然,对于大多数人来说,最好的成长方式,就是能够进入优秀的项目,跟着优秀的前辈,产出优秀的代码。原创 2022-08-20 17:17:15 · 232 阅读 · 0 评论 -
Kafka 面试套路居然这样多!读完大神的 Kafka 核心手册,秒杀面试官!全网最强!!
Kafka 速度的秘诀在于,它把所有的消息都变成一个批量的文件,并且进行合理的批量压缩,减少网络 IO 损耗,通过 mmap 提高 IO 速度,写入数据的时候由于单个 partition 是末尾添加所以速度最优;生产者发送消息的基本流程,使用 Kafka 生产者序列化,分区,消费者的入门,消费者中的基础概念,消费者中的核心概念,Kafka 中的消费安全,消费者提交偏移量导致的问题,分区再均衡,优雅退出,反序列化,独立消费者。你看,这样的回答,是不是就更全面了?发布于 2022-08-20 13:29。原创 2022-08-20 13:31:42 · 291 阅读 · 0 评论 -
完整实现 - 通过 DelayQueue 实现延时任务
一、DelayQueue 的应用原理二、订单延时任务的实现三、订单处理四、优缺点实现延时任务有很多的方法,网上关于延时任务的实现的文章已经不少了。比如:实现延时任务的 10 种方法等等。但是这些文章基本上都是将方法大概的列举一下,给出部分示例代码,对于有经验的老程序员可能一看就知道该怎么去把它实现完整,但是对于初学者来说不够友好。所以,。小概念:什么是延时任务?举个例子:你买了一张火车票,必须在 30 分钟之内付款,否则该订单被自动取消。原创 2022-08-20 10:52:02 · 161 阅读 · 0 评论 -
HttpServletResponse 实战之下载文件与动态验证码【Javaweb】
web 服务器从客户端接收 HTTP 请求,并创建表示该请求的 HttpServletRequest 对象和表示该请求响应的 HTTP ServletResponse。HttpServletReques:获取客户端请求过来的参数。HttpServletResponse:给客户端响应一些信息。原创 2022-08-20 10:47:01 · 305 阅读 · 0 评论 -
2022 各互联网大厂面经及总结 + 大厂 Java 岗面试真题解析(进大厂必看攻略)
人人都想进大厂,基础很重要,要好好打磨,然后进阶部分理论加实践一起,方可事半功倍。很多 Java 开发者面试之前,可能没有较长的工作时间或者较为丰富的工作经验,所以不知道互联网公司或者一线互联网公司技术面试都会问哪些问题?再加上可能自己准备也不充分,去面试没几个回合就被面试官几个问题打蒙了,最后以惨败收场。(这里收集了一些同行程序员的大厂面试过程及总结予以参考)。原创 2022-08-20 10:21:05 · 1332 阅读 · 0 评论