Spring常用注解汇总

Spring常用注解汇总,第1张

Spring常用注解汇总
  • 一、Spring中的常用注解
    • 1.1 Java配置类相关注解
      • 1.1.1 @Bean
      • 1.1.2 @Configuration
      • 1.1.3 @ComponentScan
      • 1.1.4 @WishlyConfiguration
    • 1.2 声明Bean相关注解
      • 1.2.1 @Repository
      • 1.2.2 @Service
      • 1.2.3 @Controller
      • 1.2.4 @Component
    • 1.3 注入Bean相关注解
      • 1.3.1 @Required (不属于Spring的注解)
      • 1.3.2 @Autowired
      • 1.3.3 @Inject
      • 1.3.4 @Resource
      • 1.3.5 @Qualifier
    • 1.4 切面(AOP)相关注解
      • 1.4.1 @Aspect
      • 1.4.2 @After
      • 1.4.3 @Before
      • 1.4.4 @Around
      • 1.4.5 @PointCut
    • 1.5 Value注解
    • 1.6 @Scope注解——Bean的属性支持
    • 1.7 环境切换相关注解
      • 17.1 @Profile
      • 1.7.2 @Conditional
    • 1.8 异步相关注解
      • 1.8.1 @EnableAsync
      • 1.8.2 @Async
    • 1.9 测试相关注解
      • 1.9.1 @RunWith
      • 1.9.2 @ContextConfiguration
    • 1.10 其他注解
      • 1.10.1 @EqualsAndHashCode
      • 1.10.2 @SuppressWarnings
  • 二、SpringMVC中的常用注解
    • 2.1 声明Bean相关注解
      • @RestController
    • 2.2 Request请求相关注解
      • 2.2.1 @RequestMapping
      • 2.2.2 @GetMapping
      • 2.2.3 @PostMapping
      • 2.2.4 @PutMapping
      • 2.2.5 @PatchMapping
      • 2.2.6 @DeleteMapping
      • 2.2.7 @RequestHeader
    • 2.3 参数相关注解
      • 2.3.1 @RequestBody
      • 2.3.2 @PathVariable
      • 2.3.3 @RequestParam
    • 2.4 响应结果相关注解
      • 2.4.1 @ResponseBody
      • 2.4.2 @ResponseStatus
    • 2.5 异常相关注解
      • 2.5.1 @ExceptionHandler
      • 2.5.2 @ControllerAdvice
    • 2.6 其他注解
      • 2.6.1 @EnableWebMvc
      • 2.6.2 @ModelAttribute
      • 2.6.3 @InitBinder
      • 2.6.4 @Transactional
  • 三、SpringBoot中的常用注解
    • 3.1 启动类相关注解
      • 3.1.1 @SpringBootApplication
      • 3.1.2 @SpringBootConfiguration
      • 3.1.3 @EnableAutoConfiguration
      • 3.1.4 @ComponentScan
    • 3.2 导入文件相关注解
      • 3.2.1 @ImportAutoConfiguration
      • 3.2.2 @ImportResource
      • 3.2.3 @PropertySource 与 @PropertySources
    • 3.3 @AutoConfiguration相关注解
      • 3.3.1 @AutoConfigurationPackage
      • 3.3.2 @AutoConfigureBefore
      • 3.3.3 @AutoConfigureAfter
      • 3.3.4 @AutoConfigureOrder
    • 3.4 其他注解
      • 3.4.1 @Lookup
      • 3.4.2 @Role
      • 3.4.3 @Scope
      • 3.4.4 @Lazy
      • 3.4.5 @Primary
      • 3.4.6 @Profile
      • 3.4.7 @DependsOn
      • 3.4.8 @PostConstruct
      • 3.4.9 @Description
      • 3.4.10 @EnableAspectConfiguration
      • 3.4.11 EnableLoadTimeWeaving
  • 四、SpringCloud相关注解
    • 4.1 @EnableEurekaServer
    • 4.2 @EnableDiscoveryClient
    • 4.3 @LoadBalanced
    • 4.4 @EnableCircuitBreaker
    • 4.5 @HystrixCommand(fallbackMethod=”backMethod”)
    • 4.6 @EnableConfigServer
    • 4.7 @EnableZuulProxy
    • 4.8@SpringCloudApplication
    • 4.9 @ConfigurationProperties
  • 五、JSON常用注解
    • 5.1 @JsonIgnoreProperties
    • 5.2 @JsonIgnore
    • 5.3 @JsonFormat
    • 5.4 @JsonSerialize
    • 5.5 @JsonDeserialize
    • 5.6 @Transient
    • 5.7 @JsonIgnoreType
    • 5.8 @JsonProperty
    • 5.9 只在序列化情况下生效的注解
      • 5.9.1 @JsonPropertyOrder
      • 5.9.2 @JsonInclude
      • 5.9.3 @JsonInclude(JsonInclude.Include.NON_NULL)
    • 5.10 在反序列化情况下生效的注解
      • @JsonSetter
  • 六、JPA相关注解
    • 6.1 @Entity ,@Table(name="")
    • 6.2 @MappedSuperClass
    • 6.3 @NoRepositoryBean
    • 6.4 @Column
    • 6.5 @Id
    • 6.6 @Transient
      • 6.7 @Basic
    • 6.8 @JsonIgnore
    • 6.9 @JoinColumn、@OneToOne、@OneToMany、@ManyToOne
      • @OneToOne
      • @ManyToOne 与@OneToMany

一、Spring中的常用注解 1.1 Java配置类相关注解 1.1.1 @Bean

此注解是导入第三方包里面的注解,作用在方法上,声明当前方法的返回值为一个 bean。

@Bean注解用于告诉方法,产生了一个 Bean 对象,然后这个 Bean 对象会交由 Spring 管理。产生这个 Bean 对象的方法 Spring 只会调用一次,随后这个 Spring 会将这个 Bean 对象放在自己的 IOC 容器中。

public class test{

    // 使用 @Bean 注解作用在方法上,表明 myBean 需要交由 Spring 进行管理
    // 未指定 bean 名称,默认采用的是 "方法名" + "首字母小写" 的配置方式
    @Bean
    public MyBean myBean(){
        return null;
    }
}
1.1.2 @Configuration

此注解作用在类上,声明当前类为配置类,被注解的类内部包含有一个或多个被@Bean注解的方法。

@Configuration
public class MyConfiguration{

    @Bean
    public MyBean myBean1(){
        return null;
    }
    
	@Bean
    public MyBean myBean2(){
        return null;
    }

	@Bean
    public MyBean myBean3(){
        return null;
    }
    ...
}

注意:
@Configuration注解的配置类有如下要求:

  1. @Configuration不可以是final类型;
  2. @Configuration不可以是匿名类;
  3. 嵌套的configuration必须是静态类。
1.1.3 @ComponentScan

此注解作用在类上,一般和 @Configuration 注解一起使用,用于根据定义的扫描路径对 Component 进行扫描,把符合扫描规则的类装配到 Spring 容器中。如果没有指定扫描包,那么默认会扫描此配置类所在的 package。

@Configuration
@ComponentScan(value = "com.work.service",useDefaultFilters = true)
public class MyComponentScan {
}
1.1.4 @WishlyConfiguration

此注解作用在类上,为 @Configuration 注解和 @ComponentScan 注解的组合注解,可以代替这两个注解使用。

@WishlyConfiguration
public class MyWishlyConfiguration {
}
1.2 声明Bean相关注解 1.2.1 @Repository

此注解作用在类上,在数据访问层使用(dao层),则表明该类具有对对象进行 CRUD 的功能。

@Repository
public interface UserMapper {
	/**
     * 登录
     * @param userInfo
     * @return
     */
    public UserInfo login(UserInfo userInfo);
}
1.2.2 @Service

此注解作用在类上,在业务逻辑层使用(service层)。

@Service
public class MyServiceImpl implements MyService {
    @Autowired
    UserMapper userMapper ;

    @Override
    public UserInfo login(UserInfo userInfo) {
        return userInfoMapper.login(userInfo);
    }
}
1.2.3 @Controller

此注解作用在类上,在表示层使用,代表该类是控制器类。

控制层里面的每个方法都可以调用 @Service 标识的类,也就是可以调用业务逻辑层的方法。

@Controller
public class UserInfoController {

    @Autowired
    UserInfoService userInfoService;
    
    /**
     * 登录
     * @return
     */
    @RequestMapping("/Login")
    public UserInfo login(UserInfo userInfo)
    {
        return userInfoService.login(userInfo);
    }
}
1.2.4 @Component

此注解泛指各种组件,没有明确的角色。当组件不好归类的时候,我们可以使用这个注解进行标注,标识为一个 Bean。

@Controller、@Service、@Repository 都可以称为 @Component。

1.3 注入Bean相关注解 1.3.1 @Required (不属于Spring的注解)

此注解作用在 bean 的 setter 方法上,用来标识此属性是必须的,必须在配置阶段注入。

public class User {
 
 	private String username;

	@Required
	public void setUserame(String username){
		this.username = username;
	}
}

注意:

  1. 这里只能在 setter 方法上家 @Required ;
  2. 如果任何带有 @Required 的属性未设值的话,将会抛出BeanInitializationException异常。
1.3.2 @Autowired

此注解由 Spring 提供,可以作用在变量上、setter方法上、构造函数上,显式地声明依赖。

/**
 * 作用在变量上
 */
@Controller
public class UserController {
    @Autowired                               
    private UserInfoService userInfoService;                   
}

/**
 * 作用在 setter 上
 */
 public class User {
 
 	private String username;
	private Integer age;

	@Autowired 
	public void setUserame(String username){
		this.username = username;
	}
	
	@Autowired 
	public void setAge(Integer age){
		this.age= age;
	}
 }

/**
 * 作用在构造函数上
 */
 public class User {
 
 	private String username;
	private Integer age;

	@Autowired 
	public User(String username, Integer age){
		this.username = username;
		this.age= age;
	}
 }
1.3.3 @Inject

此注解由 JSR-330 提供,用法和 @Autowired 一样。

1.3.4 @Resource

此注解是Java自己的注解,作用与 @Autowired 相同,但是 @Resource 是按照名称匹配的。

@Service("service1")
public class UserSeviceImpl implement UserService {                
}
@Service("service2")
public class UserSeviceImpl implement UserService {                
}


@Controller
public class UserController {
	// 当有两个名字相同的 service 时,必须要明确指出注入 bean 的名称
    @Resource(name = "service1")                             
    private UserService service1;     

	@Resource(name = "service2")                             
    private UserService service2;                  
}

小贴士:
@Resource 有两个属性是比较重要的:name 和 type。Spring 会将 @Resource 注解的 name 属性解析为 bean 的名字,而 type 属性则解析为 bean 的类型。
如果使用 name 属性,则使用 byName 的自动注入策略;如果使用 type 属性则使用 byType 自动注入策略。如果既不指定 name 也不指定 type 属性,则按照 type 进行注入的自动注入策略进行注入。

1.3.5 @Qualifier

此注解与 @Autowired 一起使用,可以让我们对注入的过程有更多的控制。

@Qualifier 可以被用在单个构造器或者方法的参数桑,当上下文中有几个相同类型的 bean 时,使用 @Autowired 则无法区分要绑定的 bean,此时可以使用 @Qualifier 来指定名称。

@Service("service1")
public class UserSeviceImpl implement UserService {                
}
@Service("service2")
public class UserSeviceImpl implement UserService {                
}


@Controller
public class UserController {
	// 当有两个名字相同的 service 时,必须要明确指出注入 bean 的名称
    @Autowired   
    @Qualifier("service1")                         
    private UserService service1;     

	@Autowired   
    @Qualifier("service2")                           
    private UserService service2;                  
}
1.4 切面(AOP)相关注解

Spring 支持 AspectJ 的注解式切面编程。

1.4.1 @Aspect

此注解作用在类上,用于声明一个切面,使用 @After、@Before、@Aroud 做增强处理,可直接将拦截规则(切点)作为参数。

Spring AOP 面向切面编程,可以用来配置事务、做日志、权限验证、在用户请求时做一些处理等等,使用 @Aspect做一个切面就可以直接实现。

1.4.2 @After

此注解作用在方法上,在方法执行之后执行。

1.4.3 @Before

此注解作用在方法上,在方法执行之前执行。

1.4.4 @Around

此注解作用在方法上,在方法执行之前与之后执行。

1.4.5 @PointCut

此注解作用在类上,声明切点在 java 配置类中使用 @EnableAspectJAutoProxy 注解开启 Spring 对 AspectJ 代理的支持。

1.5 Value注解
  • 支持如下方式的注入:

    注入普通字符
    注入 *** 作系统属性
    注入表达式结果
    注入其它bean属性
    注入文件资源
    注入网站资源
    注入配置文件

  • @Value 注解三种情况的用法。

    ${} 是去找外部配置的参数,将值赋过来;
    #{} 是 SpEL 表达式,去寻找对应变量的内容;
    #{} 直接写字符串就是将字符串的值注入进去。

1.6 @Scope注解——Bean的属性支持

此注解作用在方法上(得有@Bean),设置Spring容器如何新建Bean实例。、

@Scope设置类型包括5种:

  • Singleton

    单例,一个Spring容器中只有一个bean实例,默认模式。

  • Protetype

    每次调用新建一个bean。

  • Request

    在web项目中,给每个 http request 新建一个 bean。

  • Session

    在web项目中,给每个 http session 新建一个 bean。

  • GlobalSession

    给每一个 global http session 新建一个 Bean 实例。

1.7 环境切换相关注解 17.1 @Profile

指定组件在哪个环境的情况下才能被注册到容器中,不指定的情况下任何环境下都能注册这个组件。

/**
 * Profile:Spring为我们提供的可以根据当前环境,动态的激活和切换一系列组件的功能。
 * 
 * 开发环境develop、测试环境test、生产环境master
 * 数据源:(/dev) (/test) (/master)
 *
 * @Profile:指定组件在哪个环境的情况下才能被注册到容器中,不指定的情况下任何环境下都能注册这个组件。
 * 
 * 1) 加了环境标识的 bean,只有这个环境被激活的时候才能注册到容器中。默认是default环境;
 * 2) 写在配置类上,只有是指定的环境的时候,整个配置类里面的所有配置才能开始生效。
 * 
 */
@Configuration
public class ProfileTest{
	
	@Profile("default")
	@Bean("test")
	public String default{
		return "default";
	}
	
	@Profile("dev")
	@Bean("dev")
	public String dev{
		return "dev";
	}

	@Profile("master")
	@Bean("master")
	public String master{
		return "master";
	}
}
1.7.2 @Conditional

通过实现 Condition 接口,并重写 matches 方法,从而决定该 bean 是否被实例化。

/**
 * 实体类
 */
public class Animal {
}

/**
 * 实现condition的类
 */
public class Conditional implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata annotatedTypeMetadata) {
        // context 代表Ioc容器  context.getBeanFactory 从Ioc容器里获取容器工厂  
     // 调用该容器工厂,判断是否包含该bean名为animal
        if(context.getBeanFactory().containsBean("animal")){
            return true;
        }
        return false;
    }
}

/**
 * 配置类
 */
@Configuration
public class ConditionTest {
    @Bean
    public Animal animal() {
        return new Animal();
    }
}

/**
 * 测试类
 */
public class ConditionTest {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext ctx=new AnnotationConfigApplicationContext(com.configuration.ConditionTest.class);
        String[] beans=ctx.getBeanDefinitionNames();
        for(String str:beans){
            System.out.println("bean信息:"+str);
        }
    }
}
1.8 异步相关注解 1.8.1 @EnableAsync

此注解作用在类上,配置类中通过此注解开启对异步任务的支持。

1.8.2 @Async

在实际执行的 bean 方法中使用该注解来声明其是一个异步任务(方法上或类上所有的方法都将异步,需要 @EnableAsync 开启异步任务)。

1.9 测试相关注解 1.9.1 @RunWith

运行器,Spring 中通常用于对 JUnit 的支持。

1.9.2 @ContextConfiguration

用来加载配置配置文件,其中classes属性用来加载配置类。

@ContextConfiguration 注解通常与 @RunWith(SpringJUnit4ClassRunner.class) 联合使用用来测试。

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath*:/*.xml"})
public class CDPlayerTest {
}

小贴士:
@ContextConfiguration 括号里的 locations = {“classpath*😕*.xml”} 就表示将 classpath 路径里所有的 xml 文件都包括进来,自动扫描的 bean 就可以拿到,此时就可以在测试类中使用 @Autowired注解来获取之前自动扫描包下的所有 bean。

1.10 其他注解 1.10.1 @EqualsAndHashCode

任意类的定义都可以添加 @EqualsAndHashCode 注解,让 lombok 帮我们生成 equals(Object other) 和 hashCode() 方法的实现。

默认情况下会使用非静态和非 transient 型字段来生成,但是也通过在字段上添加 @EqualsAndHashCode.Include 或者 @EqualsAndHashCode.Exclude 修改使用的字段(甚至指定各种方法的输出)。

或者也可以通过在类上使用 @EqualsAndHashCode(onlyExplicitlyIncluded = true) ,且在特定字段或特定方法上添加 @EqualsAndHashCode.Include 来指定他们。

1.10.2 @SuppressWarnings

Suppress 抑制;镇压;废止 Warnings警告

@SuppressWarnings(“resource”) 是J2SE 提供的一个批注。该批注的作用是给编译器一条指令,告诉它对被批注的代码元素内部的某些警告保持静默。

@SuppressWarnings 批注允许我们选择性地取消特定代码段(即,类或方法)中的警告。其中的想法是当我们看到警告时,我们会调查它,如果确定它不是问题,就可以添加一个 @SuppressWarnings 批注,以使我们不会再看到警告。

虽然它听起来似乎会屏蔽潜在的错误,但实际上它将提高代码安全性,因为它将防止我们对警告无动于衷 — 我们看到的每一个警告都将值得注意。

二、SpringMVC中的常用注解 2.1 声明Bean相关注解

@Repository、@Service、@Controller、@Component 四个注解是组件型注解,向容器中注入组件,用法与 Spring 中相同。

@RestController

此注解作用在类上,是一个组合注解,相当于 @Controller 和 @ResponseBody 的组合。意味着该 Controller 的所有方法都默认加上了 @ResponseBody。

2.2 Request请求相关注解 2.2.1 @RequestMapping

此注解作用在类或方法上,用于处理请求地址映射,其中有几个参数分别如下:

  • value:定义 request 请求的映射地址。

  • method:定义 request 地址请求的方式,包括【GET, POST, HEAD, OPTIONS, PUT, PATCH, DELETE, TRACE.】默认接受 get 请求,如果请求方式和定义的方式不一样则请求无法成功。

  • params:定义 request 请求中必须包含的参数值。

  • headers:定义 request 请求中必须包含某些指定的请求头,如:RequestMapping(value = “/something”, headers = “content-type=text/*”)说明请求中必须要包含 “text/html”, “text/plain” 这中类型的 Content-type 头,才是一个匹配的请求。

  • consumes:定义请求提交内容的类型。

  • produces:指定返回的内容类型,仅当 request 请求头中的 (Accept) 类型中包含该指定类型才返回。

@RequestMapping(value="/toLogin", params = {"name=qhj"},headers = {"Accept-Encoding=gzip, deflate, br"}, method = RequestMethod.GET)
public String toLogin(){
  System.out.println("请求成功");
  return "login";
}
2.2.2 @GetMapping

此注解作用在类或方法上,用于将 http get 请求映射到特定处理程序的方法上。

具体来说,@GetMapping 是一个组合注解,是 @RequestMapping(method = RequestMethod.GET)的缩写。

@GetMapping("/login")
public String toLogin(){
  System.out.println("请求成功");
  return "login";
}
2.2.3 @PostMapping

此注解作用在类或方法上,用于将 http post 请求映射到特定处理程序的方法上,其更倾向于处理添加信息的 *** 作。

具体来说,@PostMapping 是一个组合注解,是 @RequestMapping(method = RequestMethod.POST)的缩写。

@PostMapping("/doLogin")
public String doLogin(){
  System.out.println("请求成功");
  return "/dologin";
}
2.2.4 @PutMapping

此注解与 @PostMapping 注解作用等同,但是其更倾向于处理更新信息的 *** 作,是 @RequestMapping(method = RequestMethod.PUT) 的缩写。

@PutMapping("/update")
public String update(){
  System.out.println("请求成功");
  return "update";
}
2.2.5 @PatchMapping

Patch 方式是对 put 方式的一种补充。put 方式是可以更新数据的,但是更新的是整体,patch 是对局部更新。

2.2.6 @DeleteMapping

此注解作用在类或方法上,用于将 http delete 请求映射到特定处理程序的方法上。

具体来说,@DeleteMapping 是一个组合注解,是 @RequestMapping(method = RequestMethod.DELETE)的缩写。

@DeleteMapping("/delete")
public String delete(){
  System.out.println("请求成功");
  return "delete";
}
2.2.7 @RequestHeader

此注解作用在方法上,用于将请求头中的变量值映射到控制器的参数中。

如果 @RequestHeader 绑定的变量值在请求头中不存在,Spring 会将控制器中的参数初始化为 null。

@GetMapping("/checkToken")
public List<User> checkToken(@RequestHeader(value = "token") String token) {
    return null;
}
2.3 参数相关注解 2.3.1 @RequestBody

此注解作用在参数前,主要用来接收前端传递给后端的请求体中(request 体)的数据,而不是直接连接在地址后面。

GET方式无请求体,所以使用 @RequestBody 接收数据时前端不能使用 GET 方式提交数据,而需要用 POST 方式进行提交。

在后端的同一个接收方法里,@RequestBody 与 @RequestParam 可以同时使用,@RequestBody 最多只能有一个,而 @RequestParam 可以有多个。

@PostMapping("/saveUser")
public User saveUser(@RequestBody User user){
	User user = userMapper.save(user);
	return user;
}
2.3.2 @PathVariable

此注解作用在参数前,通过 @PathVariable 可以将 url 中占位符参数绑定到控制器处理方法的形参中:url 中的 {xxx} 占位符可以通过 @PathVariable(“xxx”) 绑定到 *** 作方法的入参中。

@PathVariable 主要用于接收 http://localhost:port/path/{参数值} 数据。

@GetMapping("/getAllPosition/{pageNum}/{pageSize}")
public PageInfo<Position> getAllPosition(HttpServletRequest request, @PathVariable(value = "pageNum") int pageNum,@PathVariable(value = "pageSize") int pageSize) {
    PageInfo<Position> pageInfo = positionService.getAllPosition(pageNum, pageSize);
    return pageInfo;
}
2.3.3 @RequestParam

此注解作用在参数前,用于将请求参数区数据映射到功能处理方法的参数上。

@RequestParam 主要用于接收 http://host:port/path?参数名=参数值 数据,这里后面也可以不跟参数值:

http://localhost:8887/test2?id=id2&name=name2

@RequestMapping("test2")
public String testRequestParam(@RequestParam("id") String id, @RequestParam("name") String name) {
    return "id=" + id + ", name=" + name;
}

@RequestParam 注解的参数如下所示:

  • value:请求中传入参数的名称,如果不设置后台接口的value值,则会默认为该变量名。

  • required:该参数是否为必传项。默认是 true,表示请求中一定要传入对应的参数,否则会报404错误,如果设置为 false 时,当请求中没有此参数,将会默认为 null,而对于基本数据类型的变量,则必须有值,这时会抛出空指针异常。如果允许空值,则接口中变量需要使用包装类来声明。

  • defaultValue:参数的默认值,如果请求中没有同名的参数时,该变量默认为此值。注意默认值可以使用 SpEL 表达式,如 “#{systemProperties[‘java.vm.version’]}”。

2.4 响应结果相关注解 2.4.1 @ResponseBody

此注解作用在方法上,将返回的对象通过适当的转换器转换为指定的格式后写入到 response 对象的 body区,通常用来返回 JSON 格式或 XML 格式的数据。

@RequestMapping("/doLogin")
@ResponseBody
public Object doLogin(@RequestBody User user, HttpSession session) {
	return userMapper.login(user);
}
2.4.2 @ResponseStatus

此注解作用在方法和 exception 类上,声明此方法或异常类返回的http状态码。

可以在 Controller 上使用此注解,这样所有的 @RequestMapping 都会继承。

2.5 异常相关注解 2.5.1 @ExceptionHandler

此注解作用在方法上,可以用来统一处理方法抛出的异常。

使用这个注解时,需要定义一个异常的处理方法,然后给这个方法加上 @ExceptionHandler 注解,这个方法就会处理类中其他方法(被@RequestMapping注解)抛出的异常。

@ExceptionHandler 注解中也可以添加参数,参数是某个异常类的反射,代表这个方法专门用于处理该类异常。

// 表示只有方法抛出 NumberFormatException 异常时,才会调用该方法。
@ExceptionHandler(NumberFormatException.class)
public String handleExeption(Exception ex) {
    return ex.printStackTrace();
}

注意:

  1. 当异常发生时,Spring会选择最接近抛出异常的处理方法。
  2. 使用 @ExceptionHandler 时尽量不要使用相同的注解参数,如果定义了两个处理相同异常的处理方法,在编译时会通过,但是在此异常真正被抛出时,会因有两个同名异常处理方法而报错。
2.5.2 @ControllerAdvice
  • 全局异常处理

    使用 @ControllerAdvice 实现全局异常处理,只需要定义类,添加该注解即可。

    @ControllerAdvice
    public class GlobalExceptionHandler {
        @ExceptionHandler(Exception.class)
        @ResponseBody //为了能够返回数据
        public R error(Exception e){
            e.printStackTrace();
            return R.error().message("执行了全局异常处理...");
        }
    }
    

    在这个类中可以定义多个方法,不同的方法处理不同的异常。

  • 全局数据绑定

    全局数据绑定功能可以用来做一些初始化的数据 *** 作,我们可以将一些公共的数据定义在添加了 @ControllerAdvice 注解的类中,这样,在每一个 Controller 的接口中,就都能够访问到这些数据。

    // 定义全局数据
    @ControllerAdvice
    public class MyGlobalExceptionHandler {
    	// 标记该方法的返回数据是一个全局数据。
    	// 默认情况下,这个全局数据的 key 就是返回的变量名,value 就是方法返回值。
        @ModelAttribute(name = "myData")
        public Map<String,Object> mydata() {
            Map<String, Object> map = new HashMap<>();
            map.put("id", 1001);
            map.put("name", "qhj");
            return map;
        }
    }
    
    // 在 Controller 中获取全局数据
    @RestController
    public class HelloController {
        @GetMapping("/hello")
        public String hello(Model model) {
            Map<String, Object> map = model.asMap();
            System.out.println(map);
            int i = 1 / 0;
            return "hello controller advice";
        }
    }
    
  • 全局数据预处理

    当两个实体类中的属性重名时,前端传递数据后无法进行区分,此时,通过 @ControllerAdvice 的全局数据预处理可以解决这个问题。

// 步骤一、给接口中的变量取别名
@PostMapping("/book")
public void addBook(@ModelAttribute("b") Book book, @ModelAttribute("a") Author author) {
    System.out.println(book);
    System.out.println(author);
}

// 步骤二、进行请求数据预处理
@ControllerAdvice
public class resolveData{

	// 表示该方法用来处理和Book类相关的参数,在方法中,给参数添加一个 b 前缀,即请求参数要有b前缀。
	@InitBinder("b")
	public void b(WebDataBinder binder) {
	    binder.setFieldDefaultPrefix("b.");
	}
	@InitBinder("a")
	public void a(WebDataBinder binder) {
	    binder.setFieldDefaultPrefix("a.");
	}
}

// 步骤三、请求发送时,通过给不同对象的参数添加不同的前缀,可以实现参数的区分。
2.6 其他注解 2.6.1 @EnableWebMvc

此注解作用在类上,表示在配置类中开启 Web MVC 的配置支持。

2.6.2 @ModelAttribute

此注解主要的作用是将数据添加到模型对象中,用于视图页面显示,有两种用法:

  • 注释方法

    如果把 @ModelAttribute 放在方法的注解上时,代表的是:该Controller的所有方法在调用前,先执行此 @ModelAttribute 方法。

    可以把这个 @ModelAttribute 特性,应用在 BaseController 当中,所有的 Controller 继承 BaseController,即可实现在调用 Controller 时,先执行@ModelAttribute 方法。比如权限的验证(也可以使用Interceptor)等。

  • 注释一个方法的参数

    当作为方法的参数使用,指示的参数应该从模型中检索。如果不存在,它应该首先实例化,然后添加到模型中,一旦出现在模型中,参数字段应该从具有匹配名称的所有请求参数中填充。

2.6.3 @InitBinder

此注解作用在方法上,用来设置 WebDataBinder,WebDataBinder 用来自动绑定前台请求参数到Model中。

2.6.4 @Transactional

此注解作用在类上时,表示所有该类的公共方法都配置相同的事务属性信息。当类级别配置了@Transactional,方法级别也配置了@Transactional,应用程序会以方法级别的事务属性信息来管理事务,换言之,方法级别的事务属性信息会覆盖类级别的相关配置信息。

事务的属性信息如下:

属性名说明
name当在配置文件中有多个 TransactionManager , 可以用该属性指定选择哪个事务管理器。
propagation事务的传播行为,默认值为 REQUIRED。
isolation事务的隔离度,默认值采用 DEFAULT。
timeout事务的超时时间,默认值为-1。如果超过该时间限制但事务还没有完成,则自动回滚事务。
read-only指定事务是否为只读事务,默认值为 false;为了忽略那些不需要事务的方法,比如读取数据,可以设置 read-only 为 true。
rollback-for用于指定能够触发事务回滚的异常类型,如果有多个异常类型需要指定,各类型之间可以通过逗号分隔。
no-rollback- for抛出 no-rollback-for 指定的异常类型,不回滚事务。
三、SpringBoot中的常用注解 3.1 启动类相关注解 3.1.1 @SpringBootApplication

此注解作用在类上,是Spring Boo项目 的核心注解,目的是开启自动配置。是@SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan 三个注解的组合注解。

3.1.2 @SpringBootConfiguration

在这个类的源码中又有一个 @Configuration 的注解。

@Configuration 这个注解的作用就是声明当前类是一个配置类,然后Spring会自动扫描到添加了@Configuration 的类,读取其中的配置信息。

而 @SpringBootConfiguration 是来声明当前类是 SpringBoot 应用的配置类,项目中只能有一个。所以一般我们无需自己添加

3.1.3 @EnableAutoConfiguration

此注解表示开启自动配置,告诉 SpringBoot 基于所添加的依赖,去“猜测”你想要如何配置 Spring。

比如我们引入了spring-boot-starter-web,而这个启动器中帮我们添加了 tomcat、SpringMVC 的依赖,此时自动配置就知道你是要开发一个 web 应用,所以就帮你完成了 web 及 SpringMVC 的默认配置了!

我们使用 SpringBoot 构建一个项目,只需要引入所需框架的依赖,配置就可以交给SpringBoot 处理了。

3.1.4 @ComponentScan

配置组件扫描的指令,提供了类似与< context:component-scan >标签的作用,通过basePackageClasses 或者 basePackages 属性来指定要扫描的包。如果没有指定这些属性,那么将从声明这个注解的类所在的包开始,扫描包及子包。

而 @SpringBootApplication 注解声明的类就是 main 函数所在的启动类,因此扫描的包是该类所在包及其子包。因此,一般启动类会放在一个比较前的包目录中。

3.2 导入文件相关注解 3.2.1 @ImportAutoConfiguration

导入配置类,一般做测试的时候使用,正常优先使用 @EnableAutoConfiguration。

从根本上来说,@ImportAutoConfiguration 是 @Import 的增强,限制了它使用的特定范围。

使用 @EnableAutoConfiguration 时会扫描整个类路径下,包括依赖引入的 jar 包所有的自动配置类(被注解了@Configuration 的类),尝试进行自动配置。

而 @ImportAutoConfiguration 只运行在你注解中提供的配置类。更准确的来说,@ImportAutoConfiguration 与 @EnableAutoConfiguration 的功能更相似,而且能够更细粒度的控制导入的类。

3.2.2 @ImportResource
  • 导入xml配置文件

    可以分为两种模式,相对路径的 classpath,绝对路径的 file。

    @Value("${properties中的键}") 
    private String xxx;
    

    注意:单文件可以不写 value 或 locations。
    取值:使用 @Value 注解取配置文件中的值。

  • 导入额外的配置文件

    也可用于导入 Spring 的 xml 配置文件,让该配置文件中定义的 bean 对象加载到 Spring 容器中。

    // Spring 配置文件 beans.xml
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    
        <!--将 myService以xml的方式,注入到容器中-->
        <bean id="myService" class="com.qhj.springboot.service.myService"></bean>
    </beans>
    
    
    /**
     * Spring Boot里面没有Spring的配置文件,我们自己编写的配置文件,也不能自动识别;
     * 如果想让Spring的配置文件生效,加载到 Spring 容器中来;
     * 使用@ImportResource注解,将其标注在一个配置类上(此处配置在启动类)
     */
    @SpringBootApplication
    @ImportResource(locations = {"classpath:beans.xml"})
    public class BootApplication {
    
        public static void main(String[] args) {
            // Spring应用启动        
            SpringApplication.run(BootApplication.class,args);
        }
    }
    
3.2.3 @PropertySource 与 @PropertySources

@PropertySource 用于引入单个配置文件,@PropertySources 用于引入多个配置文件。

// 引入单个properties文件
@PropertySource(value = {"classpath:xxxx/xxxx.properties"})
// 引入多个properties文件
@PropertySource(value = {"classpath:xxxx/xxxx.properties","classpath:xxxx/xxxx.properties"})

@PropertySource 或者 @PropertySources 引入的数据都是存在环境变量ConfigurableEnvironment中的。

// cat.properties内容
parent=tiger

// 类Cat
public class Cat {
  @Value("猫") //直接注入字符串
  private String name;
  @Value("#{12+2}") //支持EL表达式
  private int age;
  @Value("${parent}") //支持配置文件读取
  private String parent;
  public Cat() {
    System.out.println("猫被初始化");
  }
  @Override
  public String toString() {
    return "Cat{" +
        "name='" + name + '\'' +
        ", age=" + age +
        ", parent='" + parent + '\'' +
        '}';
  }
}

// 配置
@Import({Cat.class})
@PropertySources({@PropertySource(value ="cat.properties")})
public class Appconfig {
}

// 测试
public class Demo {
  public static void main(String[] args) {

    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Appconfig.class);
    Cat bean = context.getBean(Cat.class);
    System.out.println(bean); //Cat{name='猫', age=14, parent='tiger'}
    ConfigurableEnvironment environment = context.getEnvironment();
    System.out.println(environment.getProperty("parent")); //tiger
  }
}
3.3 @AutoConfiguration相关注解 3.3.1 @AutoConfigurationPackage

此注解的作用是将添加该注解的类所在的 package 作为 自动配置package 进行管理。

包含该注解的 package 会被 AutoConfigurationPackages 注册。

可以通过 AutoConfigurationPackages 工具类获取自动配置package列表。当通过注解@SpringBootApplication 标注启动类时,已经为启动类添加了 @AutoConfigurationPackage 注解。路径为 @SpringBootApplication -> @EnableAutoConfiguration -> @AutoConfigurationPackage。
也就是说当 SpringBoot 应用启动时默认会将启动类所在的 package 作为自动配置的 package。

3.3.2 @AutoConfigureBefore

在指定配置类初始化前加载。

// 说明 User将会在 Person 之前加载
@AutoConfigureBefore(Person.class)
public class User{
}
3.3.3 @AutoConfigureAfter

在指定配置类初始化后加载。

3.3.4 @AutoConfigureOrder

指定配置类初始化顺序,越小初始化越早。

注意:SpringBoot 只会对从 spring.factories 文件读取到的配置类进行排序。

3.4 其他注解 3.4.1 @Lookup

此注解作用在方法行,根据方法返回的类型,去容器中捞出对应的实例。

举例:如果有一个类C,需要用到类B,如果使用 @Autowired 注解注入B,那么B每次调用都是同一个对象,即使B不是单例的。而 @Lookup 提供了一种方式以抽象方法的方式来获取Bean

@Component
@Scope(scopeName= ConfigurableBeanFactory.SCOPE_PROTOTYPE) //原型 也就是非单例
public class B {
    public  void sayHi(){
        System.out.println("hi");
    }
}

@Component
public abstract class C {

    public void hello(){
        B b = getB();
        b.sayHi();
    }
    
    @Lookup
    public abstract B getB(); //一般都是抽象方法
}
3.4.2 @Role

bean角色定义为ROLE_APPLICATION(默认值)、ROLE_SUPPORT(辅助角色)、ROLE_INFRASTRUCTURE(后台角色,用户无感)。

3.4.3 @Scope

指定bean的作用域,默认singleton,其它包括prototype、request、session、globalSession等。

3.4.4 @Lazy

使bean懒加载,取消bean预初始化。

3.4.5 @Primary

自动装配时当出现多个Bean候选者时,被注解为 @Primary 的 Bean 将作为首选者,否者将抛出异常。

3.4.6 @Profile

指定Bean在哪个环境下被激活。

3.4.7 @DependsOn

依赖的 bean 注册完成,才注册当前类,依赖 bean 不存在会报错。用于控制bean加载顺序。

3.4.8 @PostConstruct

bean 的属性都注入完毕后,执行注解标注的方式进行初始化工作。

3.4.9 @Description

添加 bean 的文字描述。

3.4.10 @EnableAspectConfiguration

启动 AspectJ 自动配置。

3.4.11 EnableLoadTimeWeaving

启动类加载器动态增强功能,使用 instrumentation 实现。

四、SpringCloud相关注解 4.1 @EnableEurekaServer

用在 springboot 启动类上,表示这是一个 eureka 服务注册中心。

4.2 @EnableDiscoveryClient

用在 springboot 启动类上,表示这是一个服务,可以被注册中心找到.

4.3 @LoadBalanced

此注解作用在方法上,用于开启负载均衡能力。

//  @LoadBalanced这个注解是让 RestTemplate 开启负载均衡的能力
@LoadBalanced
public RestTemplate getRestTemplate() {
    return new RestTem plate();
}
4.4 @EnableCircuitBreaker

用在启动类上,开启断路器功能。

4.5 @HystrixCommand(fallbackMethod=”backMethod”)

用在方法上,fallbackMethod 指定断路回调方法。

4.6 @EnableConfigServer

用在启动类上,表示这是一个配置中心,开启 Config Server。

4.7 @EnableZuulProxy

开启 zuul 路由,用在启动类上。

4.8@SpringCloudApplication

@SpringBootApplication、@EnableDiscovertyClient、@EnableCircuitBreaker分别是 SpringBoot 注解、注册服务中心Eureka注解、断路器注解。

对于 SpringCloud 来说,这是每一微服务必须应有的三个注解,所以 @SpringCloudApplication 这一注解就是以上三个注解的集合。

4.9 @ConfigurationProperties

此注解作用在类或方法上,该注解有一个 prefix 属性,通过指定的前缀,绑定配置文件中的配置。

Spring 源码中大量使用了 ConfigurationProperties 注解,比如 server.por t就是由该注解获取到的,通过与其他注解配合使用,能够实现 Bean 的按需配置。

spring.datasource.url=jdbc:mysql://127.0.0.1:8888/test?useUnicode=false&autoReconnect=true&characterEncoding=utf-8
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
@ConfigurationProperties(prefix = "spring.datasource")
@Component
public class DatasourcePro {
    private String url;
    private String username;
    private String password;
    // 配置文件中是driver-class-name, 转驼峰命名便可以绑定成功
    private String driverClassName;
    private String type;
 
    ...
}

注意:

  1. @ConfigurationProperties 和 @value 有着相同的功能,但是 @ConfigurationProperties的写法更为方便;
  2. @ConfigurationProperties 的 POJO类的命名比较严格,因为它必须和 prefix 的后缀名要一致,不然值会绑定不上,特殊的后缀名是“driver-class-name”这种带横杠的情况,在POJO里面的命名规则是 下划线转驼峰 就可以绑定成功,所以就是 “driverClassName”。
五、JSON常用注解 5.1 @JsonIgnoreProperties

此注解作用在类上,作用是 json 序列化时将 java bean 中的一些属性忽略掉,序列化和反序列化都受影响。

写法将此标签加在类的类名上 ,可以多个属性也可以单个属性。

// 生成 json 时将 name 和 age 属性过滤掉
@JsonIgnoreProperties({"name"},{"age"})
public class User{ 
    private  String name;
    private int age;
}
5.2 @JsonIgnore

此注解作用在属性或者方法上(最好是属性上),作用和 @JsonIgnoreProperties 一样。

// 生成json 时不生成age 属性
public class User{
    private String name;
    @JsonIgnore
    private int age;
}
5.3 @JsonFormat

此注解作用在属性或者方法上(最好是属性上),可以方便的把 Date 类型数据直接转化为我们想要的模式。

public class User{
    @JsonFormat(pattern = “yyyy-MM-dd HH-mm-ss”)
    private Date date;
}
5.4 @JsonSerialize

此注解作用在属性或者 getter 方法上,主要用于数据转换(将 java 对象序列化为 json 数据),在序列化时嵌入我们自定义的代码。

// 自定义序列化代码
public class MySerializerUtils extends JsonSerializer<Integer> {
    @Override
    public void serialize(Integer status, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException, JsonProcessingException {
        String statusStr = "";
        switch (status) {
            case 0:
                statusStr = "未激活";
                break;
            case 1:
                statusStr = "已激活";
                break;
            default:
                statusStr = "未知";
        }
        jsonGenerator.writeString(statusStr);
    }
}


/**
 * 在实体类上需要装换的字段上加上注解
 */
@JsonSerialize(using = MySerializerUtils.class)
private int statusStr;
5.5 @JsonDeserialize

此注解作用在属性或者 setter 方法上,主要用于数据转换(将 json 数据反序列化为 java 对象),用于在反序列化时可以嵌入我们自定义的代码,类似于 @JsonSerialize 注解。

/**
 * 在实体类上需要装换的字段上加上注解
 */
@JsonDeserialize(using = MySerializerUtils.class)
private int statusStr;
5.6 @Transient

java 的 transient 关键字的作用是需要实现 Serilizable 接口,将不需要序列化的属性前添加关键字transient,序列化对象的时候,这个属性就不会序列化到指定的目的地中。

如果一个属性并非数据库表的字段映射(不存到数据库中,只是做一个临时变量),就务必将其标示为 @Transient,否则ORM框架默认其注解为@Basic。

public class User implements Serializable,Cloneable {
    private static final long serialVersionUID = 1L;
    @Transient
    private boolean enabled = false;
}
5.7 @JsonIgnoreType

此注解作用在类上,使用该注解的类作为其他类的属性时,在序列化和反序列化期间将忽略该属性。即只有在该类作为其他类的属性时才会被忽略,直接序列化、反序列化该类是正常的。

// 该类自己序列化和反序列化是正常的
@JsonIgnoreType
public class Address {
    private String street;
    private String city;
}    

public class Employee {
    private String name;
    private String dept;
    // 在序列化和反序列化时忽略该属性
    private Address address;
}    
5.8 @JsonProperty

此注解作用在属性上,可以指定某个属性和 json 映射的名称,将该属性的名称序列化为另一份自己想要的名称。

。这个注解也比较常用。

public class SomeEntity {
	// java中命名要遵循驼峰规则,则为userName,这时通过该注解来指定两者的映射规则即可
    @JsonProperty("user_name")
    private String userName;

	// // 假如 trueName 最后为"小明",转化为 json 后: {"name":"小明"}
	@JsonProperty("name") 
	private String trueName;	 
}
5.9 只在序列化情况下生效的注解 5.9.1 @JsonPropertyOrder

此注解作用在类上,在将 java pojo 对象序列化成为 json 字符串时,使用 @JsonPropertyOrder 可以指定属性在 json 字符串中的顺序。

@AllArgsConstructor
@JsonPropertyOrder(alphabetic = true)//按字母排序
@JsonPropertyOrder({ "name", "id" })//自定义排序
public class OrderTestBean {
    public int id;
    public String name;
}
5.9.2 @JsonInclude

此注解作用在类上,在将 java pojo 对象序列化成为 json 字符串时,使用 @JsonInclude 注解可以控制在哪些情况下才将被注解的属性转换成 json。

例如只有属性不为 null 时。

@JsonInclude(JsonInclude.Include.NON_NULL)
public class Student
{
    private int id;
    private String username;
    private String sex;
    private String address;
    ...
}
5.9.3 @JsonInclude(JsonInclude.Include.NON_NULL)

此注解作用在类上,返给前端的 json 里就没有 null 类型的字段,即实体类与 json 互转的时候属性值为null的不参与序列化。

另外还有很多其它的范围,例如 NON_EMPTY、NON_DEFAULT等。

5.10 在反序列化情况下生效的注解 @JsonSetter

标注于 setter 方法上,类似 @JsonProperty ,也可以解决 json 键名称和 java pojo 字段名称不匹配的问题。

除了重命名之外,@JsonSetter 还可以指定如何处理 JSON 中的 ‘null’。

private static class Person {
    private String name;

	// 结果:Person{name=''}
    @JsonSetter(nulls = Nulls.AS_EMPTY)
    public void setName(String name) {
        this.name = name;
    }
}

Nulls 的可能取值: SET、 SKIP、 FAIL、 AS_EMPTY 和 DEFAULT

六、JPA相关注解 6.1 @Entity ,@Table(name=“”)

表明这是一个实体类,一般用于 jpa,这两个注解一块使用,但是如果表名和实体类名相同的话,@Table可以省略。

6.2 @MappedSuperClass

基于代码复用和模型分离的思想,在项目开发中使用 jpa 的 @MappedSuperClass 注解,将实体类的多个属性分别封装到不同的非实体类中。

例如,数据库表中都需要 id 来表示编号,id 是这些映射实体类的通用属性,交给 jpa 统一生产主键id 编号,那么使用一个父类来封装这些通用属性,并用 @MappedSuperClass 标识。

注意:

  1. 标注为 @MappedSuperClass 的类将不是一个完整的实体类,它将不会映射到数据库表,但是它的属性都映射到其子类的数据库字段中。
  2. 标注 @MappedSuperClass 的类不能再标注 @Entity 或 @Table 注解,也无需实现序列化接口。
6.3 @NoRepositoryBean

一般用做父类的 repository,有这个注解,spring 不会去实例化该 repository。

6.4 @Column

如果字段名和列名相同,则可以省略。

6.5 @Id

表示该属性为主键。

6.6 @Transient

表示该属性并非一个到数据库表的字段的映射,ORM 框架将忽略该属性。

如果一个属性并非数据库表的字段映射,就务必将其标注为 @Transient,否则,ORM框架默认将其注解为@Basic。

6.7 @Basic

@Basic 是实体类与数据库字段映射时最简单的类型。

类型支持Java基本类型(byte、short、int、long、float、double、char、boolean),包装类,枚举类,以及实现了serializable接口的类型。

@basic注解有两个属性:

  1. fetch用来指定属性的加载机制

    有两个选项:EAGER(即时加载,默认值)和LAZY(懒加载),即时加载意味着当实例化对象的时候必须加载该属性值,懒加载是指当实例化对象时不加载该对象,只有当调用该属性时才加载。

  2. optional用来指定属性是否可空

    有两个选项:true(可空,默认值)和false

    如果实体类上不加 @Basic 注解,它也会自动加上@Basic,并使用默认值。

6.8 @JsonIgnore

在实体类向前台返回数据时用来忽略不想传递给前台的属性或接口。

Bean实体中会有某些运维字段,返回信息给前台的时候,不希望将对应值一并返回。此时可以在对应属性上加上 @JsonIgnore,或者可以在User类上加上注解 @JsonIgnoreProperties(value=“{password}”)。

6.9 @JoinColumn、@OneToOne、@OneToMany、@ManyToOne

@JoinColumn 与 @Column 注解一样,是用于注释表中的字段的。

@OneToOne

一对一 关联关系。

在数据库中之标示两张表之间的一对一关系,这是 hibernate 与 jpa 之中实体关系最简单的一种,一对一时只需要在两个关联实体的任意一个中,将关联的另一个实体,当做其一个属性,并在该属性上使用 @OneToOne 注解即可。

@ManyToOne 与@OneToMany

一对多关联关系与多对一关联关系。

一对多与多对一,是各种物理数据模型中最常见的关联关系,绝大多数的项目开发中都不可避免。

而 @ManyToOne 与@ OneToMany 的最大区别就是在于标注使用的一方是多的一方还是一的一方,简单的区分就是当前 Class 的实体在这个关联关子中扮演的是多的一方就是用 @ManyToOne,反之一的一方则使用 @OneToMany。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/905234.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-15
下一篇 2022-05-15

发表评论

登录后才能评论

评论列表(0条)

保存