快到年尾了,不知道大家阳康了没,为了今后工作顺利,多了解springSpringBoot常用注解总没错。 啥? 你还没工作?那还不去Freemen上找一份自己满意的工作。 可以毫不夸张地说,这篇文章介绍的SpringSpringBoot常用注解基本已经涵盖你工作中遇到的大部分常用的场景。对于每一个注解我都说了具体用法,掌握搞懂,使用SpringBoot来开发项目基本没啥大问题了! 为什么要写这篇文章? 最近看到网上有一篇关于SpringBoot常用注解的文章被转载的比较多,我看了文章内容之后属实觉得质量有点低,并且有点会误导没有太多实际使用经验的人(这些人又占据了大多数)。所以,自己索性花了大概两天时间简单总结一下了。 整个目录如下,内容有点多: 因为我个人的能力和精力有限,如果有任何不对或者需要完善的地方,请帮忙指出!Guide哥感激不尽!1。SpringBootApplication 这里先单独拎出SpringBootApplication注解说一下,虽然我们一般不会主动去使用它。 Guide哥:这个注解是SpringBoot项目的基石,创建SpringBoot项目之后会默认在主类加上。SpringBootApplicationpublicclassSpringSecurityJwtGuideApplication{publicstaticvoidmain(java。lang。String〔〕args){SpringApplication。run(SpringSecurityJwtGuideApplication。class,args);}} 我们可以把SpringBootApplication看作是Configuration、EnableAutoConfiguration、ComponentScan注解的集合。packageorg。springframework。boot。autoconfigure;Target(ElementType。TYPE)Retention(RetentionPolicy。RUNTIME)DocumentedInheritedSpringBootConfigurationEnableAutoConfigurationComponentScan(excludeFilters{Filter(typeFilterType。CUSTOM,classesTypeExcludeFilter。class),Filter(typeFilterType。CUSTOM,classesAutoConfigurationExcludeFilter。class)})publicinterfaceSpringBootApplication{。。。。。。}packageorg。springframework。boot;Target(ElementType。TYPE)Retention(RetentionPolicy。RUNTIME)DocumentedConfigurationpublicinterfaceSpringBootConfiguration{} 根据SpringBoot官网,这三个注解的作用分别是:EnableAutoConfiguration:启用SpringBoot的自动配置机制ComponentScan:扫描被Component(Service,Controller)注解的bean,注解默认会扫描该类所在的包下所有的类。Configuration:允许在Spring上下文中注册额外的bean或导入其他配置类2。SpringBean相关 2。1。Autowired 自动导入对象到类中,被注入进的类同样要被Spring容器管理比如:Service类注入到Controller类中。ServicepublicclassUserService{。。。。。。}RestControllerRequestMapping(users)publicclassUserController{AutowiredprivateUserServiceuserService;。。。。。。} 2。2。Component,Repository,Service,Controller 我们一般使用Autowired注解让Spring容器帮我们自动装配bean。要想把类标识成可用于Autowired注解自动装配的bean的类,可以采用以下注解实现:Component:通用的注解,可标注任意类为Spring组件。如果一个Bean不知道属于哪个层,可以使用Component注解标注。Repository:对应持久层即Dao层,主要用于数据库相关操作。Service:对应服务层,主要涉及一些复杂的逻辑,需要用到Dao层。Controller:对应SpringMVC控制层,主要用户接受用户请求并调用Service层返回数据给前端页面。 2。3。RestController RestController注解是Controller和ResponseBody的合集,表示这是个控制器bean,并且是将函数的返回值直接填入HTTP响应体中,是REST风格的控制器。 Guide哥:现在都是前后端分离,说实话我已经很久没有用过Controller。如果你的项目太老了的话,就当我没说。 单独使用Controller不加ResponseBody的话一般使用在要返回一个视图的情况,这种情况属于比较传统的SpringMVC的应用,对应于前后端不分离的情况。ControllerResponseBody返回JSON或XML形式数据 关于RestController和Controller的对比,请看这篇文章:RestControllervsController。 2。4。Scope 声明SpringBean的作用域,使用方法:BeanScope(singleton)publicPersonpersonSingleton(){returnnewPerson();} 四种常见的SpringBean的作用域:singleton:唯一bean实例,Spring中的bean默认都是单例的。prototype:每次请求都会创建一个新的bean实例。request:每一次HTTP请求都会产生一个新的bean,该bean仅在当前HTTPrequest内有效。session:每一次HTTP请求都会产生一个新的bean,该bean仅在当前HTTPsession内有效。 2。5。Configuration 一般用来声明配置类,可以使用Component注解替代,不过使用Configuration注解声明配置类更加语义化。ConfigurationpublicclassAppConfig{BeanpublicTransferServicetransferService(){returnnewTransferServiceImpl();}}3。处理常见的HTTP请求类型 5种常见的请求类型:GET:请求从服务器获取特定资源。举个例子:GETusers(获取所有学生)POST:在服务器上创建一个新的资源。举个例子:POSTusers(创建学生)PUT:更新服务器上的资源(客户端提供更新后的整个资源)。举个例子:PUTusers12(更新编号为12的学生)DELETE:从服务器删除特定的资源。举个例子:DELETEusers12(删除编号为12的学生)PATCH:更新服务器上的资源(客户端提供更改的属性,可以看做作是部分更新),使用的比较少,这里就不举例子了。 3。1。GET请求 GetMapping(users)等价于RequestMapping(valueusers,methodRequestMethod。GET)GetMapping(users)publicResponseEntityListUsergetAllUsers(){returnuserRepository。findAll();} 3。2。POST请求 PostMapping(users)等价于RequestMapping(valueusers,methodRequestMethod。POST) 关于RequestBody注解的使用,在下面的前后端传值这块会讲到。PostMapping(users)publicResponseEntityUsercreateUser(ValidRequestBodyUserCreateRequestuserCreateRequest){returnuserRespository。save(user);} 3。3。PUT请求 PutMapping(users{userId})等价于RequestMapping(valueusers{userId},methodRequestMethod。PUT)PutMapping(users{userId})publicResponseEntityUserupdateUser(PathVariable(valueuserId)LonguserId,ValidRequestBodyUserUpdateRequestuserUpdateRequest){。。。。。。} 3。4。DELETE请求 DeleteMapping(users{userId})等价于RequestMapping(valueusers{userId},methodRequestMethod。DELETE)DeleteMapping(users{userId})publicResponseEntitydeleteUser(PathVariable(valueuserId)LonguserId){。。。。。。} 3。5。PATCH请求 一般实际项目中,我们都是PUT不够用了之后才用PATCH请求去更新数据。PatchMapping(profile)publicResponseEntityupdateStudent(RequestBodyStudentUpdateRequeststudentUpdateRequest){studentRepository。updateDetail(studentUpdateRequest);returnResponseEntity。ok()。build();}4。前后端传值 掌握前后端传值的正确姿势,是你开始CRUD的第一步! 4。1。PathVariable和RequestParam PathVariable用于获取路径参数,RequestParam用于获取查询参数。 举个简单的例子:GetMapping(klasses{klassId}teachers)publicListTeachergetKlassRelatedTeachers(PathVariable(klassId)LongklassId,RequestParam(valuetype,requiredfalse)Stringtype){。。。} 如果我们请求的url是:klasses{123456}teachers?typeweb 那么我们服务获取到的数据就是:klassId123456,typeweb。 4。2。RequestBody 用于读取Request请求(可能是POST,PUT,DELETE,GET请求)的body部分并且ContentType为applicationjson格式的数据,接收到数据之后会自动将数据绑定到Java对象上去。系统会使用HttpMessageConverter或者自定义的HttpMessageConverter将请求的body中的json字符串转换为java对象。 我用一个简单的例子来给演示一下基本使用! 我们有一个注册的接口:PostMapping(signup)publicResponseEntitysignUp(RequestBodyValidUserRegisterRequestuserRegisterRequest){userService。save(userRegisterRequest);returnResponseEntity。ok()。build();} UserRegisterRequest对象:DataAllArgsConstructorNoArgsConstructorpublicclassUserRegisterRequest{NotBlankprivateStringuserName;NotBlankprivateStringpassword;FullNameNotBlankprivateStringfullName;} 我们发送post请求到这个接口,并且body携带JSON数据:{userName:coder,fullName:shuangkou,password:123456} 这样我们的后端就可以直接把json格式的数据映射到我们的UserRegisterRequest类上。 需要注意的是:一个请求方法只可以有一个RequestBody,但是可以有多个RequestParam和PathVariable。如果你的方法必须要用两个RequestBody来接受数据的话,大概率是你的数据库设计或者系统设计出问题了!5。读取配置信息 很多时候我们需要将一些常用的配置信息比如阿里云oss、发送短信、微信认证的相关配置信息等等放到配置文件中。 下面我们来看一下Spring为我们提供了哪些方式帮助我们从配置文件中读取这些配置信息。 我们的数据源application。yml内容如下::wuhan2020:2020年初武汉爆发了新型冠状病毒,疫情严重,但是,我相信一切都会过去!武汉加油!中国加油!myprofile:name:Guide哥email:koushuangbwcx163。comlibrary:location:湖北武汉加油中国加油books:name:天才基本法description:二十二岁的林朝夕在父亲确诊阿尔茨海默病这天,得知自己暗恋多年的校园男神裴之即将出国深造的消息对方考取的学校,恰是父亲当年为她放弃的那所。name:时间的秩序description:为什么我们记得过去,而非未来?时间流逝意味着什么?是我们存在于时间之内,还是时间存在于我们之中?卡洛罗韦利用诗意的文字,邀请我们思考这一亘古难题时间的本质。name:了不起的我description:如何养成一个新习惯?如何让心智变得更成熟?如何拥有高质量的关系?如何走出人生的艰难时刻? 5。1。value(常用) 使用Value({property})读取比较简单的配置信息:Value({wuhan2020})Stringwuhan2020; 5。2。ConfigurationProperties(常用) 通过ConfigurationProperties读取配置信息并与bean绑定。ComponentConfigurationProperties(prefixlibrary)classLibraryProperties{NotEmptyprivateStringlocation;privateListBookbooks;SetterGetterToStringstaticclassBook{Stringname;Stringdescription;}省略gettersetter。。。。。。} 你可以像使用普通的Springbean一样,将其注入到类中使用。 5。3。PropertySource(不常用) PropertySource读取指定properties文件ComponentPropertySource(classpath:website。properties)classWebSite{Value({url})privateStringurl;省略gettersetter。。。。。。} 更多内容请查看我的这篇文章:《10分钟搞定SpringBoot如何优雅读取配置文件?》。6。参数校验 数据的校验的重要性就不用说了,即使在前端对数据进行校验的情况下,我们还是要对传入后端的数据再进行一遍校验,避免用户绕过浏览器直接通过一些HTTP工具直接向后端请求一些违法数据。 JSR(JavaSpecificationRequests)是一套JavaBean参数校验的标准,它定义了很多常用的校验注解,我们可以直接将这些注解加在我们JavaBean的属性上面,这样就可以在需要校验的时候进行校验了,非常方便! 校验的时候我们实际用的是HibernateValidator框架。HibernateValidator是Hibernate团队最初的数据校验框架,HibernateValidator4。x是BeanValidation1。0(JSR303)的参考实现,HibernateValidator5。x是BeanValidation1。1(JSR349)的参考实现,目前最新版的HibernateValidator6。x是BeanValidation2。0(JSR380)的参考实现。 SpringBoot项目的springbootstarterweb依赖中已经有hibernatevalidator包,不需要引用相关依赖。如下图所示(通过idea插件MavenHelper生成): 非SpringBoot项目需要自行引入相关依赖包,这里不多做讲解,具体可以查看我的这篇文章:《如何在SpringSpringBoot中做参数校验?你需要了解的都在这里!》。 需要注意的是:所有的注解,推荐使用JSR注解,即javax。validation。constraints,而不是org。hibernate。validator。constraints 6。1。一些常用的字段验证的注解NotEmpty被注释的字符串的不能为null也不能为空NotBlank被注释的字符串非null,并且必须包含一个非空白字符Null被注释的元素必须为nullNotNull被注释的元素必须不为nullAssertTrue被注释的元素必须为trueAssertFalse被注释的元素必须为falsePattern(regex,flag)被注释的元素必须符合指定的正则表达式Email被注释的元素必须是Email格式。Min(value)被注释的元素必须是一个数字,其值必须大于等于指定的最小值Max(value)被注释的元素必须是一个数字,其值必须小于等于指定的最大值DecimalMin(value)被注释的元素必须是一个数字,其值必须大于等于指定的最小值DecimalMax(value)被注释的元素必须是一个数字,其值必须小于等于指定的最大值Size(max,min)被注释的元素的大小必须在指定的范围内Digits(integer,fraction)被注释的元素必须是一个数字,其值必须在可接受的范围内Past被注释的元素必须是一个过去的日期Future被注释的元素必须是一个将来的日期。。。。。。 6。2。验证请求体(RequestBody)DataAllArgsConstructorNoArgsConstructorpublicclassPerson{NotNull(messageclassId不能为空)privateStringclassId;Size(max33)NotNull(messagename不能为空)privateStringname;Pattern(regexp((ManWomanUGM)),messagesex值不在可选范围)NotNull(messagesex不能为空)privateStringsex;Email(messageemail格式不正确)NotNull(messageemail不能为空)privateStringemail;} 我们在需要验证的参数上加上了Valid注解,如果验证失败,它将抛出MethodArgumentNotValidException。RestControllerRequestMapping(api)publicclassPersonController{PostMapping(person)publicResponseEntityPersongetPerson(RequestBodyValidPersonperson){returnResponseEntity。ok()。body(person);}} 6。3。验证请求参数(PathVariables和RequestParameters) 一定一定不要忘记在类上加上Validated注解了,这个参数可以告诉Spring去校验方法参数。RestControllerRequestMapping(api)ValidatedpublicclassPersonController{GetMapping(person{id})publicResponseEntityIntegergetPersonByID(ValidPathVariable(id)Max(value5,message超过id的范围了)Integerid){returnResponseEntity。ok()。body(id);}} 更多关于如何在Spring项目中进行参数校验的内容,请看《如何在SpringSpringBoot中做参数校验?你需要了解的都在这里!》这篇文章。7。全局处理Controller层异常 介绍一下我们Spring项目必备的全局处理Controller层异常。 相关注解:ControllerAdvice:注解定义全局异常处理类ExceptionHandler:注解声明异常处理方法 如何使用呢?拿我们在第5节参数校验这块来举例子。如果方法参数不对的话就会抛出MethodArgumentNotValidException,我们来处理这个异常。ControllerAdviceResponseBodypublicclassGlobalExceptionHandler{请求参数异常处理ExceptionHandler(MethodArgumentNotValidException。class)publicResponseEntitylt;?handleMethodArgumentNotValidException(MethodArgumentNotValidExceptionex,HttpServletRequestrequest){。。。。。。}} 更多关于SpringBoot异常处理的内容,请看我的这两篇文章:SpringBoot处理异常的几种常见姿势使用枚举简单封装一个优雅的SpringBoot全局异常处理!8。JPA相关 8。1。创建表 Entity声明一个类对应一个数据库实体。 Table设置表明EntityTable(namerole)publicclassRole{IdGeneratedValue(strategyGenerationType。IDENTITY)privateLongid;privateStringname;privateStringdescription;省略gettersetter。。。。。。} 8。2。创建主键 Id:声明一个字段为主键。 使用Id声明之后,我们还需要定义主键的生成策略。我们可以使用GeneratedValue指定主键生成策略。 1。通过GeneratedValue直接使用JPA内置提供的四种主键生成策略来指定主键生成策略。IdGeneratedValue(strategyGenerationType。IDENTITY)privateLongid; JPA使用枚举定义了4中常见的主键生成策略,如下: Guide哥:枚举替代常量的一种用法publicenumGenerationType{使用一个特定的数据库表格来保存主键持久化引擎通过关系数据库的一张特定的表格来生成主键,TABLE,在某些数据库中,不支持主键自增长,比如Oracle、PostgreSQL其提供了一种叫做序列(sequence)的机制生成主键SEQUENCE,主键自增长IDENTITY,把主键生成策略交给持久化引擎(persistenceengine),持久化引擎会根据数据库在以上三种主键生成策略中选择其中一种AUTO} GeneratedValue注解默认使用的策略是GenerationType。AUTOpublicinterfaceGeneratedValue{GenerationTypestrategy()defaultAUTO;Stringgenerator()default;} 一般使用MySQL数据库的话,使用GenerationType。IDENTITY策略比较普遍一点(分布式系统的话需要另外考虑使用分布式ID)。 2。通过GenericGenerator声明一个主键策略,然后GeneratedValue使用这个策略IdGeneratedValue(generatorIdentityIdGenerator)GenericGenerator(nameIdentityIdGenerator,strategyidentity)privateLongid; 等价于:IdGeneratedValue(strategyGenerationType。IDENTITY)privateLongid; jpa提供的主键生成策略有如下几种:publicclassDefaultIdentifierGeneratorFactoryimplementsMutableIdentifierGeneratorFactory,Serializable,ServiceRegistryAwareService{SuppressWarnings(deprecation)publicDefaultIdentifierGeneratorFactory(){register(uuid2,UUIDGenerator。class);register(guid,GUIDGenerator。class);canbedonewithUUIDGeneratorstrategyregister(uuid,UUIDHexGenerator。class);deprecatedfornewuseregister(uuid。hex,UUIDHexGenerator。class);uuid。hexisdeprecatedregister(assigned,Assigned。class);register(identity,IdentityGenerator。class);register(select,SelectGenerator。class);register(sequence,SequenceStyleGenerator。class);register(seqhilo,SequenceHiLoGenerator。class);register(increment,IncrementGenerator。class);register(foreign,ForeignGenerator。class);register(sequenceidentity,SequenceIdentityGenerator。class);register(enhancedsequence,SequenceStyleGenerator。class);register(enhancedtable,TableGenerator。class);}publicvoidregister(Stringstrategy,ClassgeneratorClass){LOG。debugf(RegisteringIdentifierGeneratorstrategy〔s〕〔s〕,strategy,generatorClass。getName());finalClasspreviousgeneratorStrategyToClassNameMap。put(strategy,generatorClass);if(previous!null){LOG。debugf(overriding〔s〕,previous。getName());}}} 8。3。设置字段类型 Column声明字段。 示例: 设置属性userName对应的数据库字段名为username,长度为32,非空Column(nameusername,nullablefalse,length32)privateStringuserName; 设置字段类型并且加默认值,这个还是挺常用的。Column(columnDefinitiontinyint(1)default1)privateBooleanenabled; 8。4。指定不持久化特定字段 Transient:声明不需要与数据库映射的字段,在保存的时候不需要保存进数据库。 如果我们想让secrect这个字段不被持久化,可以使用Transient关键字声明。Entity(nameUSER)publicclassUser{。。。。。。TransientprivateStringsecrect;notpersistentbecauseofTransient} 除了Transient关键字声明,还可以采用下面几种方法:staticStringsecrect;notpersistentbecauseofstaticfinalStringsecrectSatish;notpersistentbecauseoffinaltransientStringsecrect;notpersistentbecauseoftransient 一般使用注解的方式比较多。 8。5。声明大字段 Lob:声明某个字段为大字段。LobprivateStringcontent; 更详细的声明:Lob指定Lob类型数据的获取策略,FetchType。EAGER表示非延迟加载,而FetchType。LAZY表示延迟加载;Basic(fetchFetchType。EAGER)columnDefinition属性指定数据表对应的Lob字段类型Column(namecontent,columnDefinitionLONGTEXTNOTNULL)privateStringcontent; 8。6。创建枚举类型的字段 可以使用枚举类型的字段,不过枚举字段要用Enumerated注解修饰。publicenumGender{MALE(男性),FEMALE(女性);privateStringvalue;Gender(Stringstr){valuestr;}}EntityTable(namerole)publicclassRole{IdGeneratedValue(strategyGenerationType。IDENTITY)privateLongid;privateStringname;privateStringdescription;Enumerated(EnumType。STRING)privateGendergender;省略gettersetter。。。。。。} 数据库里面对应存储的是MAILFEMAIL。 8。7。增加审计功能 只要继承了AbstractAuditBase的类都会默认加上下面四个字段。DataAllArgsConstructorNoArgsConstructorMappedSuperclassEntityListeners(valueAuditingEntityListener。class)publicabstractclassAbstractAuditBase{CreatedDateColumn(updatablefalse)JsonIgnoreprivateInstantcreatedAt;LastModifiedDateJsonIgnoreprivateInstantupdatedAt;CreatedByColumn(updatablefalse)JsonIgnoreprivateStringcreatedBy;LastModifiedByJsonIgnoreprivateStringupdatedBy;} 我们对应的审计功能对应地配置类可能是下面这样的(SpringSecurity项目):ConfigurationEnableJpaAuditingpublicclassAuditSecurityConfiguration{BeanAuditorAwareStringauditorAware(){return()Optional。ofNullable(SecurityContextHolder。getContext())。map(SecurityContext::getAuthentication)。filter(Authentication::isAuthenticated)。map(Authentication::getName);}} 简单介绍一下上面设计到的一些注解:CreatedDate:表示该字段为创建时间时间字段,在这个实体被insert的时候,会设置值CreatedBy:表示该字段为创建人,在这个实体被insert的时候,会设置值LastModifiedDate、LastModifiedBy同理。 EnableJpaAuditing:开启JPA审计功能。 8。8。删除修改数据 Modifying注解提示JPA该操作是修改操作,注意还要配合Transactional注解使用。RepositorypublicinterfaceUserRepositoryextendsJpaRepositoryUser,Integer{ModifyingTransactional(rollbackForException。class)voiddeleteByUserName(StringuserName);} 8。9。关联关系OneToOne声明一对一关系OneToMany声明一对多关系ManyToOne声明多对一关系MangToMang声明多对多关系 更多关于SpringBootJPA的文章请看我的这篇文章:一文搞懂如何在SpringBoot正确中使用JPA。9。事务Transactional 在要开启事务的方法上使用Transactional注解即可!Transactional(rollbackForException。class)publicvoidsave(){。。。。。。} 我们知道Exception分为运行时异常RuntimeException和非运行时异常。在Transactional注解中如果不配置rollbackFor属性,那么事物只会在遇到RuntimeException的时候才会回滚,加上rollbackForException。class,可以让事物在遇到非运行时异常时也回滚。 Transactional注解一般用在可以作用在类或者方法上。作用于类:当把Transactional注解放在类上时,表示所有该类的public方法都配置相同的事务属性信息。作用于方法:当类配置了Transactional,方法也配置了Transactional,方法的事务会覆盖类的事务配置信息。 更多关于关于Spring事务的内容请查看:可能是最漂亮的Spring事务管理详解一口气说出6种Transactional注解失效场景10。json数据处理 10。1。过滤json数据 JsonIgnoreProperties作用在类上用于过滤掉特定字段不返回或者不解析。生成json时将userRoles属性过滤JsonIgnoreProperties({userRoles})publicclassUser{privateStringuserName;privateStringfullName;privateStringpassword;JsonIgnoreprivateListUserRoleuserRolesnewArrayList();} JsonIgnore一般用于类的属性上,作用和上面的JsonIgnoreProperties一样。publicclassUser{privateStringuserName;privateStringfullName;privateStringpassword;生成json时将userRoles属性过滤JsonIgnoreprivateListUserRoleuserRolesnewArrayList();} 10。2。格式化json数据 JsonFormat一般用来格式化json数据。: 比如:JsonFormat(shapeJsonFormat。Shape。STRING,patternyyyyMMddTHH:mm:ss。SSSZ,timezoneGMT)privateDatedate; 10。3。扁平化对象GetterSetterToStringpublicclassAccount{JsonUnwrappedprivateLocationlocation;JsonUnwrappedprivatePersonInfopersonInfo;GetterSetterToStringpublicstaticclassLocation{privateStringprovinceName;privateStringcountyName;}GetterSetterToStringpublicstaticclassPersonInfo{privateStringuserName;privateStringfullName;}} 未扁平化之前:{location:{provinceName:湖北,countyName:武汉},personInfo:{userName:coder1234,fullName:shaungkou}} 使用JsonUnwrapped扁平对象之后:GetterSetterToStringpublicclassAccount{JsonUnwrappedprivateLocationlocation;JsonUnwrappedprivatePersonInfopersonInfo;。。。。。。}{provinceName:湖北,countyName:武汉,userName:coder1234,fullName:shaungkou}11。测试相关 ActiveProfiles一般作用于测试类上,用于声明生效的Spring配置文件。SpringBootTest(webEnvironmentRANDOMPORT)ActiveProfiles(test)Slf4jpublicabstractclassTestBase{。。。。。。} Test声明一个方法为测试方法 Transactional被声明的测试方法的数据会回滚,避免污染测试数据。 WithMockUserSpringSecurity提供的,用来模拟一个真实用户,并且可以赋予权限。TestTransactionalWithMockUser(usernameuserid18163138155,authoritiesROLETEACHER)voidshouldimportstudentsuccess()throwsException{。。。。。。} 暂时总结到这里吧!虽然花了挺长时间才写完,不过可能还是会一些常用的注解的被漏掉,所以,我将文章也同步到了Github上去,Github地址:https:github。comSnailclimbJavaGuideblobmasterdocssystemdesignframeworkspringspringannotations。md欢迎完善! 看完的同学是不是想惊呼:太棒了。 本文转载自JavaGuide