安排上了!一文掌握 Spring Boot 常用注解

发表于 3年以前  | 总阅读数:409 次

1. 目录

Spring Boot 常用注解

可以看到七哥给大家整理的目录,我个人觉得还是比较清晰的,也尽可能的完善了,我带着大家过一遍,整清楚了含义和用法,剩下的就交给你们去实战了。

2. Bean处理

下面这些注解都是处理 Spring 中 Bean 相关的。

@Resource

依赖注入,自动导入标注的对象到当前类中,比如我们的 Controller 类通常要导入 Service 类(需要注意这里 Service 类要被 Spring 容器管理)。

<span style="font-family:Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, PingFang SC, Cambria, Cochin, Georgia, Times, Times New Roman, serif;">@Component、``@Repository、``@Service、``@Controller、``@RestController

我们一般使用 @Resource 注解让 Spring 容器帮我们自动装配 bean。要想把类标识成可用于 @Resource 注解自动装配的 bean 就需要我们使用这几个注解了,它们表示对应的类将被 Spring 容器管理。

  • @Component :通用的注解,可标注任意类为 Spring 组件。如果一个 Bean 不知道属于哪个层,可以使用@Component 注解标注;
  • @Repository : 对应持久层即 Dao 层,主要用于数据库相关操作;
  • @Service : 对应服务层,主要涉及一些复杂的逻辑,需要用到 Dao 层;
  • @Controller : 对应 Spring MVC 控制层,一般需要注入 Service 类返回结果数据;
  • @RestController : 继承于 @Controller,区别在于标注后整个类所有方法将直接返回 JSON 数据,不再需要视图解析处理,目前前后端分离的项目后端都是直接用这个注解的;

@Configuration

标注是 Java 代码的配置类, Spring Boot 中推荐这种做法不再使用 xml 配置了;

@Configuration
public class AppConfig {
   //相当于 xml 中配置 Bean
    @Bean 
    public TransferService transferService() {
        return new TransferServiceImpl();
    }

}

@Scope

声明 Spring Bean 的作用域,作用于一共有以下几种:

  • singleton:唯一 bean 实例,Spring 中的 bean 默认都是单例的。
  • prototype:每次请求都会创建一个新的 bean 实例。
  • request:每一次 HTTP 请求都会产生一个新的 bean,该 bean 仅在当前 HTTP request 内有效。
  • session:每一次 HTTP 请求都会产生一个新的 bean,该 bean 仅在当前 HTTP session 内有效。

3. HTTP请求

下面这些注解对应 Http 常见的请求方式,用于标注接口路径请求。

@GetMapping

等价于 @RequestMapping(value="/test",method=RequestMethod.GET)

@PostMapping

@PostMapping("/users")
public ResponseEntity<User> createUser(@RequestBody @Valid User user) {
    userService.save(user);
    return new ResponseEntity(HttpStatus.OK);
}

@PutMapping

put 方式的请求,常用语更新服务器上的资源。举个例子:PUT /users/7(更新编号为 7 的学生)

@DeleteMapping

DELETE 请求,从服务器删除特定的资源。

4. 前后端参数传递

@RequestParam & @PathVariable

@RequestParam 用在方法的参数前面,获取请求中表单类型的key=value格式的数据。

@PathVariable 用于获取请求路径中的参数。

@PostMapping("/{id}")
public ResponseEntity<List<User>> getUser(@PathVariable long id,@RequestParam String macAddress) {
    return new ResponseEntity(userService.findById(id),HttpStatus.OK);
}

@RequestBody

获取请求 body 中的数据,常用于搭配 @PostMapping 请求来提交对象数据. 请求体 的Content-Type 必须为 application/json 格式的数据,接收到数据之后会自动将数据绑定到 Java 对象上去。

系统会使用 HttpMessageConverter 或者自定义的 HttpMessageConverter将请求的 body 中的 json 字符串转换为 java 对象。

@PostMapping("/users")
public ResponseEntity<User> createUser(@RequestBody @Valid User user) {
    userService.save(user);
    return new ResponseEntity(HttpStatus.OK);
}

强调一下:请求方法只可以有一个@RequestBody,但是可以有多个 @RequestParam@PathVariable。 如果你的方法必须要用两个 @RequestBody 来接受数据的话,那你就只思考下你的设计了,或者套娃形式的。

@ResponseBody

表示该方法的返回结果直接写入 HTTP response body 中,格式为 json。上面我们提到的 @RestController 其实就是 @Controller 和 @ResponseBody 两个结合起来的。

5. 读取配置

@value

可以在任意 Spring 管理的 Bean 中通过这个注解获取任何来源配置的属性值。比如我们的 application.properties 或者 application.yml 配置文件中配置的属性值,当然也可以是 JVM 属性配置或者系统环境变量配置的值,如果对 Spring Boot 应用程序都有哪些属性配置源以及它们之间的优先级不了解的小伙伴可以看我之前的文章:[Spring Boot 属性配置你所不知道的细节] 。

@Value("${who}")
String name;

@ConfigurationProperties(重点)

上面 @Value 在每个类中获取属性配置值的做法其实是不推荐的,我们一般在企业项目开发中,不会使用那么杂乱无章的写法而且维护也麻烦,通过就是一次性读取到一个 Java 配置类,然后需要使用的地方直接引用这个类就可以多次访问了,方便维护。

@Component
@ConfigurationProperties(prefix = "my", ignoreUnknownFields = false)
@Data
public class MyProperties implements Serializable {

    private String name;

    private String username;

    private List<Book> books;

    @Data
    static class Book implements Serializable{
        private int id;
        private String bookName;
    }

}

@PropertySource

这个注解是用来指定读取我们自定义的配置文件的。

@Component
@ConfigurationProperties(prefix= "my" )
@PropertySource(value = {"classpath:my.properties"})
@Data
public class MyProperties {
    private int maxValue= 0;
}

6. 参数校验

数据的校验的重要性就不用说了,即使在前端对数据进行校验的情况下,我们还是要对传入后端的数据再进行一遍校验,避免用户绕过浏览器直接通过一些 HTTP 工具直接向后端请求一些违法数据。

JSR(Java Specification Requests) 是一套 JavaBean 参数校验的标准,它定义了很多常用的校验注解,我们可以直接将这些注解加在我们 JavaBean 的属性上面,这样就可以在需要校验的时候进行校验了,非常方便!

校验的时候我们实际用的是 Hibernate Validator 框架。Hibernate Validator 是 Hibernate 团队最初的数据校验框架,Hibernate Validator 4.x 是 Bean Validation 1.0(JSR 303)的参考实现,Hibernate Validator 5.x 是 Bean Validation 1.1(JSR 349)的参考实现,目前最新版的 Hibernate Validator 6.x 是 Bean Validation 2.0(JSR 380)的参考实现。

需要注意的是从 Spring Boot 2.3开始,我们还需要显式地添加 spring-boot-starter-validation 依赖项,在此之前的 Spring Boot 版本是在 spring-boot-starter-web 依赖项中包含的不需要额外引入。

我现在使用的是 Spring Boot 2.5.2 版本了,所以手动增加依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-validation</artifactId>
    <version>2.5.2</version>
</dependency>

需要注意的是: 所有的注解,推荐使用 JSR 注解,即 javax.validation.constraints,而不是 org.hibernate.validator.constraints

Bean字段验证注解

  • @NotEmpty 被注释的字符串的不能为 null 也不能为空
  • @NotBlank 被注释的字符串非 null,并且必须包含一个非空白字符
  • @Null 被注释的元素必须为 null
  • @NotNull 被注释的元素必须不为 null
  • @AssertTrue 被注释的元素必须为 true
  • @AssertFalse 被注释的元素必须为 false
  • @Pattern(regex=,flag=)被注释的元素必须符合指定的正则表达式
  • @Email 被注释的元素必须是 Email 格式。
  • @Min(value)被注释的元素必须是一个数字,其值必须大于等于指定的最小值
  • @Max(value)被注释的元素必须是一个数字,其值必须小于等于指定的最大值
  • @DecimalMin(value)被注释的元素必须是一个数字,其值必须大于等于指定的最小值
  • @DecimalMax(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值
  • @Size(max=, min=)被注释的元素的大小必须在指定的范围内
  • @Digits (integer, fraction)被注释的元素必须是一个数字,其值必须在可接受的范围内
  • @Past被注释的元素必须是一个过去的日期
  • @Future 被注释的元素必须是一个将来的日期

验证请求体(RequestBody)

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {

    @Min(100)
    private Long id;

    @NotNull(message = "name 不能为空")
    @NotEmpty
    @JsonProperty(value = "name")
    private String name;

}

只需要在请求处理方法中需要验证的参数前加上 @Valid 注解就会开启校验了,如果验证失败将抛出异常:MethodArgumentNotValidException

@PostMapping("/users")
public ResponseEntity<User> createUser(@RequestBody @Valid User user) {
    userService.save(user);
    return new ResponseEntity(HttpStatus.OK);
}

@Validated

如果你的入参不是用一个 Java 对象来接收的话,比如用 @PathVariables 和 @RequestParam 注解来获取入参,这种情况下要校验参数不要忘记在类的头上加 @Validated 注解,这个参数可以告诉 Spring 去校验方法参数。

@RestController
@RequestMapping("/user")
@Validated
public class UserController {
   @GetMapping("/{id}")
    public ResponseEntity<List<User>> findById( @PathVariable @Max(value = 5,message = "超过 id 的范围了") long id) {
        return new ResponseEntity(userService.findById(id),HttpStatus.OK);
    }

}

7. 统一异常处理

异常处理通常也是我们在开发中一定要做的,因为不可能将一些程序员才能看懂的异常抛出到前端去(总会有不靠谱的同事忘记捕获异常的),所以一般都会加上统一的异常处理,在对用户不友好的错误堆栈转换为普通用户可以看懂的文案提示。

这里涉及到的注解只有两个:

  1. @ControllerAdvice : 定义全局异常处理类,包含 @Component 所以可以被 Spring 扫描到。
  2. @ExceptionHandler : 声明异常处理方法,表示遇到这个异常,就执行标注的方法。
@ControllerAdvice
@ResponseBody
class GlobalDefaultExceptionHandler {
  // 如果是遇到注解中指定的异常就会进这个方法处理后返回
    @ExceptionHandler({MethodArgumentNotValidException.class, ConstraintViolationException.class})
    public Map argumentErrorHandler(HttpServletRequest req, Exception e) throws Exception {
        Map map = new HashMap();
        map.put("error", "参数不合法");
        map.put("param", req.getParameterMap());
        return map;
    }
}

8. JPA数据持久化

上面是百度百科给的概念,只能说在实际项目开发中还是用的不多,大家还是喜欢用 Mybatis,不过相比更加简洁的技术还是要学习下的。

创建表

  • @Entity
  • @Table

这俩是放在 Java Bean 上面用来标注数据库实体对象和表明之间的映射关系的。

@Data
@Entity
@Table("user")
public class User {
    @Id
    @GeneratedValue
    @JsonProperty(value = "id")
    private Long id;

创建主键

  • @Id
  • @GeneratedValue

这俩主键放在 Bean 的字段上,用来标识数据库的主键以及主键自动生成的。通过 @GeneratedValue直接使用 JPA 内置提供的四种主键生成策略来指定。

  • GenerationType.TABLE 持久化引擎通过关系数据库的一张特定的表格来生成主键;
  • GenerationType.SEQUENCE 随机序列;
  • GenerationType.IDENTITY 主键自增长;
  • GenerationType.AUTO 持久化引擎会根据数据库在以上三种主键生成策略中选择,默认选择的就是这个策略;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

设置字段类型

@Column 声明字段。

比如:Java Bean 属性名为 nickName 对应的数据库字段名为 user_name,长度为 32,非空。

@Column(name = "user_name", nullable = false, length=32)
private String nickName;

设置字段类型并且加默认值,这个还是挺常用的。

Column(columnDefinition = "tinyint(1) default 1")
private Boolean enabled;

指定不持久化特定字段

@Transient :有一些字段我们有时间不需要落库,就可以加上这个注解就好了。

@声明事务

这个注解可以作用于类上,也可以作用于方法上。前者表示所有该类的 public 方法都配置相同的事务属性信息,后者表示当类配置了@Transactional,方法也配置了@Transactional,方法的事务会覆盖类的事务配置信息。

Exception 分为运行时异常 RuntimeException 和非运行时异常。在 @Transactional 注解中如果不配置 rollbackFor 属性,那么事物只会在遇到 RuntimeException 的时候才会回滚,加上 rollbackFor=Exception.class ,可以让事物在遇到非运行时异常时也回滚。

@Transactional(rollbackFor = Exception.class)
public void save() {
  ......
}

9. JSON格式处理

指定过滤字段

  • @JsonIgnoreProperties 作用在类上用于过滤掉特定字段不返回或者不解析。
  • @JsonIgnore一般用于类的属性上,作用和上面的@JsonIgnoreProperties 一样。
//生成json时将userRoles属性过滤
@JsonIgnoreProperties({"password"})
public class User {
    private String userName;
    private String fullName;
    @JsonIgnore
    private String password;
}

格式化 json 数据

@JsonFormat(pattern="yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
private Date createDate;

要注意的是,它只会在类似 @ResponseBody 返回 json 数据的时候,才会返回格式化的 yyyy-MM-dd HH:mm:ss 时间,你直接使用System.out.println()输出的话,仍然是类似 Fri Dec 01 21:05:20 CST 2017 这样的时间样式。

扁平化对象

@JsonUnwrapped

这个可能不太好说,大家直接看代码就懂了:

@Getter
@Setter
@ToString
public class Account {
  @JsonUnwrapped
  private Location location;
  @JsonUnwrapped
  private PersonInfo personInfo;

  @Getter
  @Setter
  @ToString
  public static class Location {
     private String provinceName;
     private String countyName;
  }
  @Getter
  @Setter
  @ToString
  public static class PersonInfo {
    private String userName;
    private String fullName;
  }
}

未扁平化之前:

{
    "location": {
        "provinceName":"广东",
        "countyName":"深圳"
    },
    "personInfo": {
        "userName": "sevenluo",
        "fullName": "程序员七哥"
    }
}

使用 @JsonUnwrapped 扁平对象之后:

@Getter
@Setter
@ToString
public class Account {
    @JsonUnwrapped
    private Location location;
    @JsonUnwrapped
    private PersonInfo personInfo;
    ......
}
{
  "provinceName":"广东",
  "countyName":"深圳",
  "userName": "sevenluo",
  "fullName": "程序员七哥"
}

10. 测试处理

@ActiveProfiles一般作用于测试类上, 用于声明生效的 Spring 配置文件。

@Test声明一个方法为测试方法。

@Transactional被声明的测试方法执行后数据会被回滚,避免污染测试数据。

@WithMockUser Spring Security 提供的,用来模拟一个真实用户,并且可以赋予权限。

11. 配置启动

@SpringBootApplication : 等价于使用 @Configuration、@EnableAutoConfiguration、@ComponentScan 三个注解。

@Configuration:声明是是一个 Java 形式的配置类,Spring Boot 提倡基于 Java 的配置,相当于你之前在 xml 中配置 bean;

@EnableAutoConfiguration:类级别的注解,这个注解告诉 Spring Boot 根据添加的 jar 依赖猜测你想如何配置 Spring,也就是 Spring 实现自动配置的开关。

@ComponentScan:标注哪些路径下的类需要被Spring扫描。

@Conditional:Spring4 新提供的注解,通过 @Conditional 注解可以根据代码中设置的条件装载不同的 bean,也是SpringBoot实现自动配置的基石。

Spring Boot 源码中大量扩展了 @Condition 注解,用于实现智能的自动化配置,满足各种使用场景。下面我给大家列举下:

  • @ConditionalOnBean :配置了某个特定的Bean时条件为真。
  • @ConditionalOnMissingBean :没有配置特定的Bean时条件为真。
  • @ConditionalOnClass:Classpath里有指定的类时条件为真。
  • @ConditionalOnMissingClass:Classpath里没有指定的类时条件为真。
  • @ConditionalOnExpression:给定的SpEL表达式计算结果为true。
  • @ConditionalOnJava:Java的版本匹配特定值或者一个范围值。
  • @ConditionalOnJndi:参数中给定的 JNDI 位置必须存在一个,如果没有给参数,则要有 JNDI InitialContext。
  • @ConditionalOnProperty:指定的配置属性要有一个明确的值。
  • @ConditionalOnResource:Classpath里没有指定的资源。
  • @ConditionalOnWebApplication:这是一个Web应用程序。
  • @ConditionalOnNotWebApplication:这不是一个Web应用程序。

那目前暂定就先总结这么多,虽然花了不少时间,但是难免有遗漏,七哥后续也会继续更新,也欢迎大家评论区指导和补充,谢谢啦。

总结

大家在看的过程中也别担心记不住,根本不用死记硬背,可以先收藏起来嘛。学编程很多时候就是灌个耳音,知道有这么个东西就好了,用的时候搜索一下就好。我都会打包给到大家。

本文由哈喽比特于3年以前收录,如有侵权请联系我们。
文章来源:https://mp.weixin.qq.com/s/WlnW-Hfnc5Z7l4O5_f9EtQ

 相关推荐

刘强东夫妇:“移民美国”传言被驳斥

京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。

发布于:1年以前  |  808次阅读  |  详细内容 »

博主曝三大运营商,将集体采购百万台华为Mate60系列

日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。

发布于:1年以前  |  770次阅读  |  详细内容 »

ASML CEO警告:出口管制不是可行做法,不要“逼迫中国大陆创新”

据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。

发布于:1年以前  |  756次阅读  |  详细内容 »

抖音中长视频App青桃更名抖音精选,字节再发力对抗B站

今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。

发布于:1年以前  |  648次阅读  |  详细内容 »

威马CDO:中国每百户家庭仅17户有车

日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。

发布于:1年以前  |  589次阅读  |  详细内容 »

研究发现维生素 C 等抗氧化剂会刺激癌症生长和转移

近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。

发布于:1年以前  |  449次阅读  |  详细内容 »

苹果据称正引入3D打印技术,用以生产智能手表的钢质底盘

据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。

发布于:1年以前  |  446次阅读  |  详细内容 »

千万级抖音网红秀才账号被封禁

9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...

发布于:1年以前  |  445次阅读  |  详细内容 »

亚马逊股东起诉公司和贝索斯,称其在购买卫星发射服务时忽视了 SpaceX

9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。

发布于:1年以前  |  444次阅读  |  详细内容 »

苹果上线AppsbyApple网站,以推广自家应用程序

据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。

发布于:1年以前  |  442次阅读  |  详细内容 »

特斯拉美国降价引发投资者不满:“这是短期麻醉剂”

特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。

发布于:1年以前  |  441次阅读  |  详细内容 »

光刻机巨头阿斯麦:拿到许可,继续对华出口

据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。

发布于:1年以前  |  437次阅读  |  详细内容 »

马斯克与库克首次隔空合作:为苹果提供卫星服务

近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。

发布于:1年以前  |  430次阅读  |  详细内容 »

𝕏(推特)调整隐私政策,可拿用户发布的信息训练 AI 模型

据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。

发布于:1年以前  |  428次阅读  |  详细内容 »

荣耀CEO谈华为手机回归:替老同事们高兴,对行业也是好事

9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。

发布于:1年以前  |  423次阅读  |  详细内容 »

AI操控无人机能力超越人类冠军

《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。

发布于:1年以前  |  423次阅读  |  详细内容 »

AI生成的蘑菇科普书存在可致命错误

近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。

发布于:1年以前  |  420次阅读  |  详细内容 »

社交媒体平台𝕏计划收集用户生物识别数据与工作教育经历

社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”

发布于:1年以前  |  411次阅读  |  详细内容 »

国产扫地机器人热销欧洲,国产割草机器人抢占欧洲草坪

2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。

发布于:1年以前  |  406次阅读  |  详细内容 »

罗永浩吐槽iPhone15和14不会有区别,除了序列号变了

罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。

发布于:1年以前  |  398次阅读  |  详细内容 »
 相关文章
Android插件化方案 5年以前  |  237231次阅读
vscode超好用的代码书签插件Bookmarks 2年以前  |  8065次阅读
 目录