
java
文章平均质量分 87
星之宇
这个作者很懒,什么都没留下…
展开
专栏收录文章
- 默认排序
- 最新发布
- 最早发布
- 最多阅读
- 最少阅读
-
SPIRNG 事务管理
说明本文介绍一下,事务的传播性,事务只读,隔离性和@Transactional注解的常用参数说明。@Transactional标签的使用在类上的注解当标于类前时,表示类中所有方法都进行事务处理,例:@Transactionalpublic class TestServiceImpl implements TestService{} 类中某些不需要事务@Transactionalpublic class TestServiceBean implements TestService{原创 2021-09-07 16:23:13 · 233 阅读 · 0 评论 -
java学习系列-Spring篇02:控制反转(IoC)与依赖注入(DI)
Spring中有3个核心的概念:控制反转(Ioc)、依赖注入(DI)、面向切面编程(AOP),spring中其他的技术都是依靠3个核心的技术建立起来的,所以玩spring需要先对这3个概念有个深入的理解。本文我们先介绍其中的两个:控制反转和依赖注入,而aop我们后面有专门的文章详解。引出spring有2个类,A和B,如下:public class A{ public void m1(){}}public class B{ public void m1();}上面2个类都有原创 2020-09-06 20:45:04 · 186 阅读 · 0 评论 -
java学习系列-Spring篇01:为何要学spring?
为什么需要学习spring?最大程度的简化了开发spring是一个非常优秀的java框架,其目标是为了简化java企业级开发,spring出来已经十几年了,这期间也一直围绕着这个目标在进行,像后面需要学习的springmvc、springboot、springcloud,这些技术也都是围绕着简化开发的目标在努力,到目前为止已经做的足够好了,可以说spring除了不能帮助我们实现业务逻辑代码之外,其他的事情spring都尽量去帮我们简化了,使用spring可以帮助我们节约大量开发时间。不使用spri原创 2020-08-23 12:05:27 · 342 阅读 · 0 评论 -
SpringSecurity + JWT,从入门到精通
权限系统躲不开的概念,在Shiro和Spring Security之间,你一般选啥?在前后端分离的项目中,你知道怎么Spring security整合JWT么,来看看这篇文章哈!思维导图如下:RBAC 全称为基于角色的权限控制,本段将会从什么是 RBAC,模型分类,什么是权限,用户组的使用,实例分析等几个方面阐述 RBAC思维导图绘制思维导图如下什么是 RBACRBAC 全称为用户角色权限控制,通过角色关联用户,角色关联权限,这种方式,间阶的赋予用户的权限,如下图所示对于通常的系统而言,原创 2020-08-18 23:53:32 · 795 阅读 · 0 评论 -
Spring Boot注解大全
一、注解(annotations)列表@SpringBootApplication:包含了@ComponentScan、@Configuration和@EnableAutoConfiguration注解。其中@ComponentScan让spring Boot扫描到Configuration类并把它加入到程序上下文。@Configuration 等同于spring的XML配置文件;使用Java代码可以检查类型安全。@EnableAutoConfiguration 自动配置。@ComponentS转载 2020-08-18 22:39:27 · 180 阅读 · 0 评论 -
Java 强、弱、软、虚,你属于哪一种?
Java中的四种引用Java中有四种引用类型:强引用、软引用、弱引用、虚引用。Java为什么要设计这四种引用Java的内存分配和内存回收,都不需要程序员负责,都是由伟大的JVM去负责,一个对象是否可以被回收,主要看是否有引用指向此对象,说的专业点,叫可达性分析。Java设计这四种引用的主要目的有两个:可以让程序员通过代码的方式来决定某个对象的生命周期;有利用垃圾回收。强引用强引用是最普遍的一种引用,我们写的代码,99.9999%都是强引用:Object o = new Obje原创 2020-08-18 22:18:19 · 169 阅读 · 0 评论 -
java学习系列-高并发33:学会使用JUC中常见的集合,常看看!
JUC集合框架图图可以看到,JUC的集合框架也是从Map、List、Set、Queue、Collection等超级接口中继承而来的。所以,大概可以知道JUC下的集合包含了一一些基本操作,并且变得线程安全。MapConcurrentHashMap功能和HashMap基本一致,内部使用红黑树实现的。特性:迭代结果和存入顺序不一致key和value都不能为空线程安全的ConcurrentSkipListMap内部使用跳表实现的,放入的元素会进行排序,排序算法支持2种方式来指定:通原创 2020-08-16 17:11:20 · 325 阅读 · 0 评论 -
java学习系列-高并发32:google提供的一些好用的并发工具类
guava maven配置 com.google.guava guava 27.0-jre### guava中常用几个类MoreExecutors:提供了一些静态方法,是对juc中的Executors类的一个扩展。Futures:也提供了很多静态方法,是对juc中Future的一个扩展。案例1:异步执行任务完毕之后回调package com.itsoku.chat34;import com.google.common.util.concurrent.Listenab原创 2020-08-16 17:10:58 · 526 阅读 · 0 评论 -
java学习系列-高并发31:怎么演示公平锁和非公平锁?
先理解一下什么是公平锁、非公平锁?公平锁和非公平锁体现在别人释放锁的一瞬间,如果前面已经有排队的,新来的是否可以插队,如果可以插队表示是非公平的,如果不可用插队,只能排在最后面,是公平的方式。示例测试公平锁和非公平锁的时候,可以这么来:在主线程中先启动一个t1线程,在t1里面获取锁,获取锁之后休眠一会,然后在主线中启动10个father线程去排队获取锁,然后在t1中释放锁代码的前面一步再启动一个线程,在这个线程内部再创建10个son线程,去获取锁,看看后面这10个son线程会不会排到上面10个fat原创 2020-08-16 17:10:31 · 204 阅读 · 0 评论 -
java学习系列-高并发30:JUC中工具类CompletableFuture,必备技能
CompletableFuture是java8中新增的一个类,算是对Future的一种增强,用起来很方便,也是会经常用到的一个工具类,熟悉一下。CompletionStage接口CompletionStage代表异步计算过程中的某一个阶段,一个阶段完成以后可能会触发另外一个阶段一个阶段的计算执行可以是一个Function,Consumer或者Runnable。比如:stage.thenApply(x -> square(x)).thenAccept(x -> System.out.pri原创 2020-08-16 17:10:11 · 257 阅读 · 0 评论 -
java学习系列-高并发29:JUC中原子类,一篇就够了
JUC中原子类介绍什么是原子操作?atomic 翻译成中文是原子的意思。在化学上,我们知道原子是构成一般物质的最小单位,在化学反应中是不可分割的。在我们这里 atomic 是指一个操作是不可中断的。即使是在多个线程一起执行的时候,一个操作一旦开始,就不会被其他线程干扰,所以,所谓原子类说简单点就是具有原子操作特征的类,原子操作类提供了一些修改数据的方法,这些方法都是原子操作的,在多线程情况下可以确保被修改数据的正确性。JUC中对原子操作提供了强大的支持,这些类位于java.util.concurren原创 2020-08-16 17:09:46 · 263 阅读 · 0 评论 -
java学习系列-高并发28:实战篇,微服务日志的伤痛,一并帮你解决掉
日志有什么用?系统出现故障的时候,可以通过日志信息快速定位问题,修复bug,恢复业务提取有用数据,做数据分析使用本文主要讨论通过日志来快速定位并解决问题。日志存在的痛点先介绍一下多数公司采用的方式:目前比较流行的是采用springcloud(或者dubbo)做微服务,按照业拆分为多个独立的服务,服务采用集群的方式部署在不同的机器上,当一个请求过来的时候,可能会调用到很多服务进行处理,springcloud一般采用logback(或者log4j)输出日志到文件中。当系统出问题的时候,按照系统故障原创 2020-08-15 13:22:17 · 358 阅读 · 0 评论 -
java学习系列-高并发05:深入理解进程和线程
进程进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。程序是指令、数据及其组织形式的描述,进程是程序的实体。进程具有的特征:动态性:进程是程序的一次执行过程,是临时的,有生命期的,是动态产生,动态消亡的并发性:任何进程都可以同其他进行一起并发执行独立性:进程是系统进行资源分配和调度的一个独立单位结构性:进程由程序,数据和进程控制块三部分组成我们经常使用windows系统,经常会看见.exe后缀的文件,双击这个.e原创 2020-08-15 13:11:36 · 193 阅读 · 0 评论 -
java学习系列-高并发27:高并发中计数器的实现方式有哪些?
需求:一个jvm中实现一个计数器功能,需保证多线程情况下数据正确性。我们来模拟50个线程,每个线程对计数器递增100万次,最终结果应该是5000万。我们使用4种方式实现,看一下其性能,然后引出为什么需要使用LongAdder、LongAccumulator。方式一:synchronized方式实现package com.itsoku.chat32;import java.util.ArrayList;import java.util.List;import java.util.concurr原创 2020-08-15 12:59:32 · 387 阅读 · 0 评论 -
java学习系列-高并发26:获取线程执行结果,这6种方法你都知道?
在一个线程中需要获取其他线程的执行结果,能想到几种方式?各有什么优缺点?结合这个需求,我们使用6种方式,来对之前学过的知识点做一个回顾,加深记忆。方式1:Thread的join()方法实现代码:package com.itsoku.chat31;import java.sql.Time;import java.util.concurrent.*;/** * */public class Demo1 { //用于封装结果 static class Result<原创 2020-08-15 12:49:25 · 438 阅读 · 0 评论 -
java学习系列-高并发25:高并发中常见的限流方式
常见的限流的场景秒杀活动,数量有限,访问量巨大,为了防止系统宕机,需要做限流处理国庆期间,一般的旅游景点人口太多,采用排队方式做限流处理医院看病通过发放排队号的方式来做限流处理。常见的限流算法通过控制最大并发数来进行限流使用漏桶算法来进行限流使用令牌桶算法来进行限流通过控制最大并发数来进行限流以秒杀业务为例,10个iphone,100万人抢购,100万人同时发起请求,最终能够抢到的人也就是前面几个人,后面的基本上都没有希望了,那么我们可以通过控制并发数来实现,比如并发数控制在10个原创 2020-08-15 11:58:21 · 310 阅读 · 0 评论 -
java学习系列-高并发24:实战篇,接口性能提升几倍原来这么简单
案例讲解电商app都有用过吧,商品详情页,需要给他们提供一个接口获取商品相关信息:商品基本信息(名称、价格、库存、会员价格等)商品图片列表商品描述信息(描述信息一般是由富文本编辑的大文本信息)数据库中我们用了3张表存储上面的信息:商品基本信息表:t_goods(字段:id【商品id】、名称、价格、库存、会员价格等)商品图片信息表:t_goods_imgs(字段:id、goods_id【商品id】、图片路径),一个商品会有多张图片商品描述信息表:t_goods_ext(字段:id,goo原创 2020-08-15 11:50:44 · 200 阅读 · 0 评论 -
java学习系列-高并发23:JUC底层工具类Unsafe,高手必须要了解
基本介绍最近我们一直在学习java高并发,java高并发中主要涉及到类位于java.util.concurrent包中,简称juc,juc中大部分类都是依赖于Unsafe来实现的,主要用到了Unsafe中的CAS、线程挂起、线程恢复等相关功能。所以如果打算深入了解JUC原理的,必须先了解一下Unsafe类。先上一幅Unsafe类的功能图:Unsafe是位于sun.misc包下的一个类,主要提供一些用于执行低级别、不安全操作的方法,如直接访问系统内存资源、自主管理内存资源等,这些方法在提升Ja原创 2020-08-15 11:44:08 · 308 阅读 · 0 评论 -
java学习系列-高并发22:java中的CAS,你需要知道的东西
我们需要解决的问题需求:我们开发了一个网站,需要对访问量进行统计,用户每次发一次请求,访问量+1,如何实现呢?下面我们来模仿有100个人同时访问,并且每个人对咱们的网站发起10次请求,最后总访问次数应该是1000次。实现访问如下。方式1代码如下:package com.itsoku.chat20;import java.util.concurrent.CountDownLatch;import java.util.concurrent.TimeUnit;/** * */publi原创 2020-08-15 11:24:56 · 188 阅读 · 0 评论 -
java学习系列-高并发21:JUC中的Executor框架详解2
需要解决的问题还是举个例子说明更好理解一些。买新房了,然后在网上下单买冰箱、洗衣机,电器商家不同,所以送货耗时不一样,然后等他们送货,快递只愿送到楼下,然后我们自己将其搬到楼上的家中。用程序来模拟上面的实现。示例代码如下:package com.itsoku.chat18;import java.util.concurrent.*;/** * */public class Demo12 { static class GoodsModel { //商品名称原创 2020-08-15 11:06:55 · 171 阅读 · 0 评论 -
java学习系列-高并发20:JUC中的Executor框架详解1
Executors框架介绍Executors框架是Doug Lea的神作,通过这个框架,可以很容易的使用线程池高效地处理并行任务。Excecutor框架主要包含3部分的内容:任务相关的:包含被执行的任务要实现的接口:Runnable接口或Callable接口任务的执行相关的:包含任务执行机制的核心接口Executor,以及继承自Executor的ExecutorService接口。Executor框架中有两个关键的类实现了ExecutorService接口(ThreadPoolExecutor和S原创 2020-08-15 11:00:05 · 221 阅读 · 0 评论 -
java学习系列-高并发19:掌握JUC中的阻塞队列
Queue接口队列是一种先进先出(FIFO)的数据结构,java中用Queue接口来表示队列。Queue接口中定义了6个方法:public interface Queue<E> extends Collection<E> { boolean add(e); boolean offer(E e); E remove(); E poll(); E element(); E peek();}每个Queue方法都有两种形式:(1)原创 2020-08-12 23:39:10 · 231 阅读 · 0 评论 -
java学习系列-高并发18:ThreadLocal、InheritableThreadLocal(通俗易懂)
需要解决的问题我们还是以解决问题的方式来引出ThreadLocal、InheritableThreadLocal,这样印象会深刻一些。目前java开发web系统一般有3层,controller、service、dao,请求到达controller,controller调用service,service调用dao,然后进行处理。我们写一个简单的例子,有3个方法分别模拟controller、service、dao。代码如下:package com.itsoku.chat24;import java.原创 2020-08-12 23:14:54 · 187 阅读 · 0 评论 -
java学习系列-高并发17:JAVA线程池,这一篇就够了
什么是线程池大家用jdbc操作过数据库应该知道,操作数据库需要和数据库建立连接,拿到连接之后才能操作数据库,用完之后销毁。数据库连接的创建和销毁其实是比较耗时的,真正和业务相关的操作耗时是比较短的。每个数据库操作之前都需要创建连接,为了提升系统性能,后来出现了数据库连接池,系统启动的时候,先创建很多连接放在池子里面,使用的时候,直接从连接池中获取一个,使用完毕之后返回到池子里面,继续给其他需要者使用,这其中就省去创建连接的时间,从而提升了系统整体的性能。线程池和数据库连接池的原理也差不多,创建线程去处理原创 2020-08-12 22:57:25 · 803 阅读 · 0 评论 -
java学习系列-高并发16:JUC中的循环栅栏CyclicBarrier的6种使用场景
CyclicBarrier简介CyclicBarrier通常称为循环屏障。它和CountDownLatch很相似,都可以使线程先等待然后再执行。不过CountDownLatch是使一批线程等待另一批线程执行完后再执行;而CyclicBarrier只是使等待的线程达到一定数目后再让它们继续执行。故而CyclicBarrier内部也有一个计数器,计数器的初始值在创建对象时通过构造参数指定,如下所示:public CyclicBarrier(int parties) { this(parties, n原创 2020-08-12 22:40:12 · 300 阅读 · 0 评论 -
java学习系列-高并发15:JUC中等待多线程完成的工具类CountDownLatch,必备技能
本节内容介绍CountDownLatch及使用场景提供几个示例介绍CountDownLatch的使用手写一个并行处理任务的工具类假如有这样一个需求,当我们需要解析一个Excel里多个sheet的数据时,可以考虑使用多线程,每个线程解析一个sheet里的数据,等到所有的sheet都解析完之后,程序需要统计解析总耗时。分析一下:解析每个sheet耗时可能不一样,总耗时就是最长耗时的那个操作。我们能够想到的最简单的做法是使用join,代码如下:package com.itsoku.chat13;原创 2020-08-10 01:46:04 · 209 阅读 · 0 评论 -
java学习系列-高并发14:JUC中的Semaphore(信号量)
Semaphore(信号量)为多线程协作提供了更为强大的控制方法,前面的文章中我们学了synchronized和重入锁ReentrantLock,这2种锁一次都只能允许一个线程访问一个资源,而信号量可以控制有多少个线程可以访问特定的资源。Semaphore常用场景:限流举个例子:比如有个停车场,有5个空位,门口有个门卫,手中5把钥匙分别对应5个车位上面的锁,来一辆车,门卫会给司机一把钥匙,然后进去找到对应的车位停下来,出去的时候司机将钥匙归还给门卫。停车场生意比较好,同时来了100两车,门卫手中只有5原创 2020-08-10 00:41:28 · 352 阅读 · 1 评论 -
java学习系列-高并发13:JUC中的LockSupport工具类,必备技能
本文主要内容:讲解3种让线程等待和唤醒的方法,每种方法配合具体的示例介绍LockSupport主要用法对比3种方式,了解他们之间的区别LockSupport位于**java.util.concurrent(简称juc)**包中,算是juc中一个基础类,juc中很多地方都会使用LockSupport,非常重要,希望大家一定要掌握。关于线程等待/唤醒的方法,前面的文章中我们已经讲过2种了:方式1:使用Object中的wait()方法让线程等待,使用Object中的notify()方法唤醒线程原创 2020-08-10 00:14:51 · 300 阅读 · 0 评论 -
java学习系列-高并发12:JUC中的Condition对象
内容synchronized中实现线程等待和唤醒Condition简介及常用方法介绍及相关示例使用Condition实现生产者消费者使用Condition实现同步阻塞队列Object对象中的wait(),notify()方法,用于线程等待和唤醒等待中的线程,大家应该比较熟悉,想再次了解的朋友可以移步到 java学习系列-高并发05:线程的基本操作.synchronized中等待和唤醒线程示例package com.itsoku.chat09;import java.util.concu原创 2020-08-09 03:01:47 · 234 阅读 · 0 评论 -
java学习系列-高并发11:JUC:ReentrantLock重入锁
synchronized的局限性synchronized是java内置的关键字,它提供了一种独占的加锁方式。synchronized的获取和释放锁由jvm实现,用户不需要显示的释放锁,非常方便,然而synchronized也有一定的局限性,例如:当线程尝试获取锁的时候,如果获取不到锁会一直阻塞,这个阻塞的过程,用户无法控制如果获取锁的线程进入休眠或者阻塞,除非当前线程异常,否则其他线程尝试获取锁必须一直等待JDK1.5之后发布,加入了Doug Lea实现的java.util.concur原创 2020-08-09 00:19:37 · 212 阅读 · 0 评论 -
java学习系列-高并发10:线程中断的几种方式
本文主要探讨一下中断线程的几种方式。通过一个变量控制线程中断代码:package com.itsoku.chat05;import java.util.concurrent.TimeUnit;public class Demo1 { public volatile static boolean exit = false; public static class T extends Thread { @Override public void run() { while原创 2020-08-08 23:42:29 · 244 阅读 · 0 评论 -
java学习系列-高并发09:线程安全和synchronized关键字
什么是线程安全?当多个线程去访问同一个类(对象或方法)的时候,该类都能表现出正常的行为(与自己预想的结果一致),那我们就可以所这个类是线程安全的。看一段代码:package com.itsoku.chat04;public class Demo1 { static int num = 0; public static void m1() { for (int i = 0; i < 10000; i++) { num++; } } public static clas原创 2020-08-06 22:57:55 · 194 阅读 · 0 评论 -
java学习系列-高并发08:用户线程和守护线程
守护线程是一种特殊的线程,在后台默默地完成一些系统性的服务,比如垃圾回收线程、JIT线程都是守护线程。与之对应的是用户线程,用户线程可以理解为是系统的工作线程,它会完成这个程序需要完成的业务操作。如果用户线程全部结束了,意味着程序需要完成的业务操作已经结束了,系统可以退出了。所以当系统只剩下守护进程的时候,java虚拟机会自动退出。java线程分为用户线程和守护线程,线程的daemon属性为true表示是守护线程,false表示是用户线程。下面我们来看一下守护线程的一些特性。程序只有守护线程时,系统会原创 2020-08-06 22:39:17 · 171 阅读 · 0 评论 -
java学习系列-高并发07:线程组
线程组我们可以把线程归属到某个线程组中,线程组可以包含多个线程以及线程组,线程和线程组组成了父子关系,是个树形结构,如下图:使用线程组可以方便管理线程,线程组提供了一些方法方便方便我们管理线程。创建线程关联线程组创建线程的时候,可以给线程指定一个线程组,代码如下:package com.itsoku.chat02;import java.util.concurrent.TimeUnit;/*** <b>description</b>:<br>*/原创 2020-08-04 23:37:02 · 195 阅读 · 0 评论 -
java学习系列-高并发06:volatile与Java内存模型
public class Demo09 { public static boolean flag = true; public static class T1 extends Thread { public T1(String name) { super(name); } @Override public void run() { System.out.println("线程" + this.getName() + " in"); while (flag) {原创 2020-08-01 23:13:54 · 159 阅读 · 0 评论 -
java学习系列-高并发05:线程的基本操作
新建线程新建线程很简单。只需要使用new关键字创建一个线程对象,然后调用它的start()启动线程即可。Thread thread1 = new Thread1();t1.start();那么线程start()之后,会干什么呢?线程有个run()方法,start()会创建一个新的线程并让这个线程执行run()方法。这里需要注意,下面代码也能通过编译,也能正常执行。但是,却不能新建一个线程,而是在当前线程中调用run()方法,将run方法只是作为一个普通的方法调用。Thread thread1原创 2020-08-01 22:43:03 · 174 阅读 · 0 评论 -
java学习系列-高并发04:JMM相关的一些概念
JMM(java内存模型),由于并发程序要比串行程序复杂很多,其中一个重要原因是并发程序中数据访问一致性和安全性将会受到严重挑战。如何保证一个线程可以看到正确的数据呢?这个问题看起来很白痴。对于串行程序来说,根本就是小菜一碟,如果你读取一个变量,这个变量的值是1,那么你读取到的一定是1,就是这么简单的问题在并行程序中居然变得复杂起来。事实上,如果不加控制地任由线程胡乱并行,即使原本是1的数值,你也可能读到2。因此我们需要在深入了解并行机制的前提下,再定义一种规则,保证多个线程间可以有小弟,正确地协同工作。而原创 2020-08-01 21:56:14 · 809 阅读 · 0 评论 -
API 接口需要如何设计才能保证安全?防重?
实际的业务中,难免会跟第三方系统进行数据的交互与传递,那么如何保证数据在传输过程中的安全呢(防窃取)?除了https的协议之外,能不能加上通用的一套算法以及规范来保证传输的安全性呢?一:token 简介Token:访问令牌access token, 用于接口中, 用于标识接口调用者的身份、凭证,减少用户名和密码的传输次数。一般情况下客户端(接口调用方)需要先向服务器端申请一个接口调用的账号,服务器会给出一个appId和一个key, key用于参数签名使用,注意key保存到客户端,需要做一些安全处理,防止原创 2020-07-30 20:30:57 · 650 阅读 · 0 评论 -
java学习系列-高并发03:有关并行的两个重要定律
有关为什么要使用并行程序的问题前面已经进行了简单的探讨。总的来说,最重要的应该是处于两个目的。第一,为了获得更好的性能;第二,由于业务模型的需要,确实需要多个执行实体。在这里,我将更加关注第一种情况,也就是有关性能的问题。将串行程序改造为并发程序,一般来说可以提高程序的整体性能,但是究竟能提高多少,甚至说究竟是否真的可以提高,还是一个需要研究的问题。目前,主要有两个定律对这个问题进行解答,一个是Amdahl定律,另外一个是Gustafson定律。Amdahl(阿姆达尔)定律Amdahl定律是计算机原创 2020-07-28 23:08:53 · 258 阅读 · 0 评论 -
java学习系列-高并发02:并发级别
由于临界区的存在,多线程之间的并发必须受到控制。根据控制并发的策略,我们可以把并发的级别分为阻塞、无饥饿、无障碍、无锁、无等待几种。阻塞一个线程是阻塞的,那么在其他线程释放资源之前,当前线程无法继续执行。当我们使用synchronized关键字或者重入锁时,我们得到的就是阻塞的线程。synchronize关键字和重入锁都试图在执行后续代码前,得到临界区的锁,如果得不到,线程就会被挂起等待,直到占有了所需资源为止。无饥饿(Starvation-Free)如果线程之间是有优先级的,那么线程调度的时候总原创 2020-07-27 22:12:55 · 194 阅读 · 0 评论