👨🎓作者:Java学术趴 🏦仓库:Github、Gitee ✏️博客:CSDN、掘金、InfoQ、云+社区 🚫特别声明:原创不易,未经授权不得转载或抄袭,如需转载可联系小编授权。 🙏版权声明:文章里的部分文字或者图片来自于互联网以及百度百科,如有侵权请尽快联系小编。
☠️每日毒鸡汤:放心,闭上眼,睡一觉,反正明天也不一定比今天好。
👋大家好!我是你们的老朋友Java学术趴。今天的文章是小编经过了长达两个星期的创作,毫不出牛逼的说,这篇文章完全可以作为一个字典查询。里面几乎包含了你目前你可以用到的所有SpringBoot注解,只要你轻轻的来一下全局搜索,你想要的答案马上就会出现,特别适合在蹲坑、无赖的时候看看哦。这还不赶紧收藏一波,当然,如果感觉对你有帮助的话,希望可以点赞加关注哦,小编会一直陪伴着大家,给大家一直分享技术干货i,在这来先谢谢大家啦,嘻嘻🤭。话不多说,上正文。
先简单介绍一下使用注解开发的重要性:
使用 Spring 开发时,进行配置主要有两种方式,一是 xml 的方式,二是 java config 的方式。Spring 技术自身也在不断的发展和改变,从当前 Springboot 的火热程度来看,java config 的应用是越来越广泛了,在使用 java config 的过程当中,我们不可避免的会有各种各样的注解打交道,所有,注解在实际开发中的地位很高。
@SpringBootApplication :它是SpringBoot的启动类注解,其中由三个注解组成。
@MapperScan("mapper接口包路径信息") :扫描指定包下所有的接口类,然后所有接口在编译之后都会生成相应的实现类,也就是针对Mapper进行一个声明。加上这个注解之后,就不用在每个Mapper接口上使用@Mapper注解。
@MapperScan注解多个包。
@SpringBootApplication
@MapperScan("cn.gyyx.mapper")
// 这个注解可以扫描 cn.gyyx.mapper 这个包下面的所有接口类,可以把这个接口类全部的进行动态代理。
public class WardenApplication {
public static void main(String[] args) {
SpringApplication.run(WardenApplication.class,args);
}
}
复制代码
在application.yml的MyBatis-plus配置:
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
map-underscore-to-camel-case: true
mapper-locations: classpath:cn/gyyx/mapper/xml/*.xml
复制代码
这里 mapper-locations 配置的是:dao层 xml 文件的路径。
@EnableOpenApi : Swagger 3.0 的启用注解,添加上这个注解之后就可以使用Swagger3.0的Api文档。
@EnableTransactionManagement :开启声明式事务的支持。添加该注解后,Spring容器会自动扫描被 @Transactional注解的方法和类。
所有的数据访问技术都有事务处理机制,这些技术提供了API用来开启事务、提交事务以完成数据操纵,或者在发生错误的时候回滚数据。Spring支持声明式事务,这是基于AOP实现的。
@EnableAsync : 表示项目支持异步方法调用。此添加该注解之后,Spring容器会自动扫描被 @Async注解的方法或者类,对该方法进行异步操作。即该方法和调用者不在一个线程中进行。
@EnableScheduling : 开启项目对定时任务的支持,此添加该注解之后,Spring容器会自动扫描被 @Scheduled注解的方法,被 @Scheduled注解声明的方法为定时任务,在指定的时间进行自动的执行。
@EnableCaching : 开启基于注解的缓存,声明之后SpringBoot就可以识别@Cacheable注解声明的缓存方法。
@Getter/@Setter : 注解在类上, 为类提供读写属性。
@ToString : 注解在类上, 为类提供 toString() 方法。
@EqualsAndHashCode : 注解在类上, 为类提供 equals() 和 hashCode() 方法。
在类是继承父类的情况下,EqualsAndHashCode实则就是在比较两个对象的属性;
@NoArgsConstructor :注解在实体类上, 为类提供无参构造方法。
@RequiredArgsConstructor :注解在实体类上,提供有指定参数的构造方法。
@AllArgsConstructor : 注解在实体类上,提供全参构造方法。
@NonNull : 注解在参数上, 如果获取到的这个参数为 null , 就会报出异常, throw new NullPointException(参数名)。 注意 :这个注解是注释在实体类的属性上,而不是实体类上。
@Data :@Data相当于@Getter @Setter @RequiredArgsConstructor @ToString @EqualsAndHashCode这5个注解的合集。写这一个注解就不用写其中包含的这5个注解了。
@Builder : 注解在实体类上, 为类提供一个内部的 Builder。
@Synchronized : 注解在方法上, 为方法提供同步锁。 注意:这个是注解在方法上,而不是类上。
@Log4j : 注解在各个层,提供一个属性名为 log 的 log4j 的日志对象。之后就可以在任何地方直接使用log.info()打印日志。
以前使用打印日志,必须先创建一个打印日志的Logger对象,调用Logger对象中的info()方法进行打印。
private final Logger logger = LoggerFactory.getLogger(当前类名.class);
logger.info("方法被触发了");
复制代码
加入了@Log4j注解之后,直接使用 log.info() 方法打印日志信息
log.info("方法被触发了");
复制代码
@Slf4j : 注解在各个层,提供一个属性名为 log 的 Slf4j 的日志对象。他的用法和上面的@Log4一样。
@Accessors : Accessor的中文含义是存取器。这个注解是针对实体类中的 getter与setter方法而言的。
包含的属性:
fluent属性:参数值为true/false
@Data
@Accessors(fluent = true)
public class Person {
private int id;
private String name;
// 生成的getter和setter方法如下,方法体略
// getter省略了get
public int id() {}
// setter省略了set,并且返回值是:Person对象
public Person id(int id) {}
public String name() {}
public Person name(String name) {}
}
复制代码
chain属性:参数值为true/false
@Data
@Accessors(chain = true)
public class Person {
private int id;
private String name;
// 生成的setter方法如下,方法体略
public Person setId(int id) {}
public Person setName(String name) {}
}
复制代码
这样写的好处:
prefix属性:参数为String类型
@Data
@Accessors(prefix = "zqr")
class Person {
private int zqrId;
private String zqrName;
// 生成的getter和setter方法如下,方法体略
public int getId() {}
public void setId(int id) {}
public String getName() {}
public void setName(String name) {}
}
复制代码
相当于字符串截取功能,在生成getter和setter方法的时候,会自动截取去除指定前缀,然后加上get与set;
如上代码,生成的不是getZqrId(),而是getId()。遵守驼峰命名规则。
@ApiModel :在实体类上边使用,标记类时swagger的解析类。这样生成的Swagger的Api文档就会存在对该类的详细介绍。
记住两个常用的参数:value以及description
@ApiModel(value="Assets对象", description="关于资产的实体类")
复制代码
@ApiModelProperty : 使用在被 @ApiModel 注解的模型类的属性上。这样生成的Swagger的Api文档就会存在对这个属性的详细介绍。
记住几个常用的参数:value、name、dataType、required、example、hidden、readOnly、allowEmptyValue
@ApiModelProperty(value = "光宇编号", example = "TM1234");
复制代码
@JsonFormat :它是一个时间格式化注解,比如我们存储在mysql中的数据是date类型的,当我们读取出来封装在实体类中的时候,就会变成英文时间格式,而不是yyyy-MM-dd HH:mm:ss这样的中文时间,因此我们需要用到JsonFormat注解来格式化我们的时间。
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8");
复制代码
当不使用这个注解仍然想让时间不解析为英文时间格式,那么就需要在 application.yml 中对jackson进行配置。
配置完之后就可以省略 @JsonFormat 注解了。
当然也可以使用 @JsonFormat(pattern = "yyyy-MM-dd ",timezone = "GMT+8") 来进行格式的覆盖。
@JsonIgnore :此注解是类注解,作用是json序列化时将java bean中的一些属性忽略掉,序列化和反序列化都受影响。也就是在前后端进行数据交互的时候会忽略掉这个注解,不传递关于这个注解的任何参数值。
@JsonIgnore
private Integer mainId;
复制代码
@JsonSerialize :该注解的作用是解决前后端传递的时候数据转换的,该注解用在属性的 getter() 方法上。
该注解不仅可以转换数据的类型还可以转变前后端传递的数据
改变前端后传递的数据类型,实体类中的数据类型是Data类型,但是传递到前端的数据类型需要时间戳
// 实体类中的某个属性
/** 订单创建时间 */
@JsonSerialize(using = DateToLongSerializer.class)
private Date createTiem;
复制代码
在使用 @JsonSerialize 注解的时候,需要一个进行数据转换的工具类
// 这个工具类必须继承 JsonSerializer<T> ,其中这个泛型 T 指的是实体类中该属性的类型
public class DateToLongSerializer extends JsonSerializer<Date> {
// 必须覆盖重写这个方法
@Override
public void serialize(Date date, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
// 这快就是将date日期转换为时间戳进行返回
jsonGenerator.writeNumber(date.getTime() / 1000);
}
}
复制代码
数据库中存储的:以1、0来记录性别,其中1是男,0是女。要求返回前端的是男或者女,而不是0或者1
// 存储性别的实体类
@Table(name = "sys_user")
@Data
public class User {
@JsonSerialize(using = GenderSerializer.class)
private String gender;
}
复制代码
编写进行数据转换的工具类
// 实现数据转换的工具类
/**
性别注解(1:男 0:女)
*/
public class GenderSerializer extends JsonSerializer {
@Override
public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException, JsonProcessingException {
if ("1".equals(value)) {
gen.writeString("男");
} else {
gen.writeString("女");
}
}
}
复制代码
这个后端返回到前端的就是男或者女,而不是0或者1。当然,如果前端传递到后端是男或女,后端会通过该注解自动解析为0或1,存储到数据库中。
@Excel(name = "无效时间", width = 15, format = "yyyy-MM-dd HH:mm:ss")
复制代码
@DateTimeFormat(pattren = "yyyy-MM-dd HH:mm:ss")
复制代码
@DateTimeFormat @JsonFormat 使用注意的地方:
@DateTimeFormat(pattern="yyyy-MM-dd")
private Date alertDate;
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm")
public Date getAlertDate() {
return alertDate;
}
public void setAlertDate(Date alertDate) {
this.alertDate = alertDate;
}
复制代码
@TableName : 在实体类上指定,指定实体类和数据库表的映射关系。重点:当实体类的类名在转成小写后和数据库表名相同时,可以不指定该注解。
@TableName("alarm_prehandle"); // 参数为表名,该注解在实体类上
复制代码
@Tableld : 用于指定实体类的某个属性为对应的数据表中的主键。这个注解在实体类中只存在一个。
// value:指定对应表中的字段名,当声明的属性名和表中的字段名一致的时候可以省略不写。
// type:是主键的类型,AUTO代表的主键自增
@TableId(value = "id", type = IdType.AUTO);
private Integer id;
复制代码
@TableField : 解决实体类中属性名和表中的字段名不一致(非驼峰),还有对象中的某个属性不在表中进行忽略。
在开发中一般在 application.yml 对MyBatis进行实体类的驼峰与表中_对应的配置。此时会对实体类中的大写字母转为小写,并且在单词之间拼接 _ ,让其与数据库字段对应。
通过以下代码说明 @TableField 的几种用法
@Data
@NoArgsConstructor
@AllArgsConstructor
@TableName("tb_user")
// 注意:此时在MyBatis中配置了实体类中的属性驼峰与表中_相对应的配置,所以不一定都要指定@TableField
public class User{
private Integer id;
// @TableField(value = "user_name") 可以省略,因为配置了MyBatis
private String userName;
//不希望password出现在查询结果中,默认为true,还可以指定update、detete、insert
@TableField(select = false)
private String passWord;
// 解决字段名不一致,此时不满足MyBatis配置的驼峰和_对应
// 其实这个有个小技巧,就是你可以自定义一个属性名,然后通过@TableField指定它对应数据库表中的某个字段的值,那么此时这个自定义的属性就存在了数据表中某个字段的值,然后可以传递给前端进行响应操作。
@TableField(value = "email")
private String mail;
// 当address属性在数据库表中不存在,但是我们必须使用这个属性的时候,就可以使用 exist = false 进行忽略,这样在MyBatis-plus解析实体类的时候就会忽略这个属性。否则会报错。
// 如果不使用 exist 进行忽略,那么必须使用value让它对应表中的某个字段才可以。
@TableField(exist = false)//指明该属性在数据库表的字段中不存在
private String address;
}
复制代码
@TableField完成字段自动填充的操作
实现方式:这个自动填充是添加到实体类中的某个属性之上,是对该属性在进行指定操作的时候完成自动填充
/**
* 创建人
*/
// 该属性对应的数据表中的字段(creator_id)会在执行 insert 语句的时候会自动进行填充
@TableField(fill = FieldFill.INSERT)
private long creatorId;
/**
* 创建时间
*/
@TableField(fill = FieldFill.INSERT)
private date gmtCreat;
/**
* 修改人
*/
// 该属性对应的数据表中的字段值会在插入和更新的时候自动填充
@TableField(fill = FieldFill.INSERT_UPDATE)
private long modifierId;
/**
* 修改时间
*/
@TableField(fill = FieldFill.INSERT_UPDATE)
private date gmtModified;
/**
* 是否可用
*/
// 该属性对应的数据表中的字段会在修改的时候自动填充
@TableField(fill = FieldFill.UPDATE)
private boolean availableFlag;
复制代码
这样我们在具体业务中对实体类进行赋值就可以不用对这些公共字段进行赋值,在执行插入或者更新时就能自动赋值并插入数据库。
重点:那么这些自动填充的数据从何而来????
package cn.gyyx.config;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
import java.util.Date;
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
// 覆盖重写 insertFill()、updateFill() 方法,代表插入和更新
@Override
public void insertFill(MetaObject metaObject) {
// this此时代表的就是:MetaObject实例对象,metaObject
// 方法的第一个参数是:实体类中的属性名。第二个参数是:自动赋值的值。第三个参数this
this.setFieldValByName("updateDate", new Date(), metaObject);
this.setFieldValByName("createTime", new Date(), metaObject);
this.setFieldValByName("deleteFlag", 0, metaObject);
this.setFieldValByName("operUser", "username", metaObject);
}
@Override
public void updateFill(MetaObject metaObject) {
this.setFieldValByName("updateDate", new Date(), metaObject);
}
}
复制代码
常用的验证注解
注意:这来要也别注意一下 @NotNull、@NotNull、@NotBlank以及@NotEmpty注解的区别
空检查
@Null 验证对象是否为null
@NotNull 验证对象是否不为null, 无法查检长度为0的字符串
@NotBlank 检查约束字符串是不是Null还有被Trim的长度是否大于0,只对字符串,且会去掉前后空格.
@NotEmpty 检查约束元素是否为NULL或者是EMPTY.
Booelan检查
@AssertTrue 验证 Boolean 对象是否为 true
@AssertFalse 验证 Boolean 对象是否为 false
长度检查
@Size(min=, max=) 验证对象(Array,Collection,Map,String)长度是否在给定的范围之内
@Length(min=, max=) 验证注解的元素值长度在min和max区间内
日期检查
@Past 验证 Date 和 Calendar 对象是否在当前时间之前
@Future 验证 Date 和 Calendar 对象是否在当前时间之后
@Pattern 验证 String 对象是否符合正则表达式的规则
数值检查,建议使用在Stirng,Integer类型,不建议使用在int类型上,因为表单值为“”时无法转换为int,但可以转换为Stirng为"",Integer为null
@Min 验证 Number 和 String 对象是否大等于指定的值
@Max 验证 Number 和 String 对象是否小等于指定的值
@DecimalMax 被标注的值必须不大于约束中指定的最大值. 这个约束的参数是一个通过BigDecimal定义的最大值的字符串表示.小数存在精度
@DecimalMin 被标注的值必须不小于约束中指定的最小值. 这个约束的参数是一个通过BigDecimal定义的最小值的字符串表示.小数存在精度
@Digits 验证 Number 和 String 的构成是否合法
@Digits(integer=,fraction=) 验证字符串是否是符合指定格式的数字,interger指定整数精度,fraction指定小数精度。
@Range(min=, max=) 验证注解的元素值在最小值和最大值之间
@Range(min=10000,max=50000,message="range.bean.wage")
private BigDecimal wage;
@Valid 递归的对关联对象进行校验, 如果关联对象是个集合或者数组,那么对其中的元素进行递归校验,如果是一个map,则对其中的值部分进行校验.(是否进行递归验证)
@CreditCardNumber信用卡验证
@Email 验证是否是邮件地址,如果为null,不进行验证,算通过验证。
@ScriptAssert(lang= ,script=, alias=)
@URL(protocol=,host=, port=,regexp=, flags=)
@Constraint : 指定自定义注解逻辑类,使用的是反射机制 Class.class
复制代码
使用这个验证直接的时候,需要在 pom.xml 中加入依赖
<dependency>
<groupId>jakarta.validation</groupId>
<artifactId>jakarta.validation-api</artifactId>
</dependency>
复制代码
为什么要使用这两个注解,
这两个注解的区别:
使用方式:
@RestController
@Slf4j
public class VerifyController {
@PostMapping(value = "/valid")
public void verifyValid(@Validated @RequestBody Person person) {
// ...
}
}
复制代码
第一步:创建一个实体类
import lombok.Data;
import org.hibernate.validator.constraints.Length;
import org.hibernate.validator.constraints.Range;
import javax.validation.constraints.*;
import java.io.Serializable;
import java.util.List;
/**
* @Description TODO PersonBean
* @Author Java学术趴
* @可以自己在每个实体类上随意的添加校验注解
*/
@Data
public class PersonBean implements Serializable {
private static final long serialVersionUID = -8374325179529529802L;
/**
* 年龄
*/
@Range(min = 1, max = 99, message = "年龄必须在1~99之间")
private Integer personAge;
/**
* 姓名
*/
@Length(min = 5, max = 10, message = "用户名长度必须在5~10之间")
private String personName;
/**
* 密码
*/
@Length(min = 5, max = 10, message = "密码长度必须在5~10之间")
@NotBlank(message = "密码不能为空")
private String password;
/**
* 手机号
*/
@Pattern(regexp = "^[1]([3][0-9]{1}|59|58|88|89)[0-9]{8}$", message = "手机号格式有误")
@Length(min = 11, max = 11, message = "手机号必须为11位")
private String personPhone;
/**
* 邮箱
*/
@Email(message = "邮箱格式有误")
private String personEmail;
/**
* 资产
*/
@Pattern(regexp = "^(([1-9]{1}\d*)|([0]{1}))(\.(\d){0,2})?$", message = "金额有误!必须是数字且最多保留两位小数")
private String personMoney;
/**
* 照片
*/
@Size(min = 1, max = 3, message = "集合长度的范围为1~3")
@NotEmpty(message = "集合不能为空")
private List<String> photoList;
}
复制代码
第二步:Controller
@RestController
@RequestMapping("/person")
@Validated
public class PersonController {
@GetMapping("/get")
public DataResult get(@Range(max = 10, message = "age最大值为10") @RequestParam("age") Integer age,@NotBlank(message = "name不可以为空") @Length(min = 3, message = "name长度最少是3") @RequestParam("name") String name) {
return DataResult.success();
}
@PostMapping("/post")
public DataResult post(@Validated @RequestBody PersonBean person) {
return DataResult.success();
}
}
复制代码
解释:
这个配置文件可以直接复制粘贴到代码中使用。
import org.hibernate.validator.HibernateValidator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
/**
* @Description TODO 配置Springboot校验模式
* @Author Java学术趴
*/
@Configuration
public class ValidatorConfig {
/**
* validation默认会校验完所有字段,然后返回所有的验证失败信息。
* 可以通过一些简单的配置,开启Fail Fast模式,只要有一个验证失败就立即返回
*/
@Bean
public Validator validator() {
ValidatorFactory validatorFactory = Validation
.byProvider(HibernateValidator.class)
.configure()
.failFast(true)
.buildValidatorFactory();
Validator validator = validatorFactory.getValidator();
return validator;
}
}
复制代码
/**
* @Description TODO 全局异常管理
* @Author admin
* @Date 2020/12/11
*/
import com.lgy.demo.util.DataResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.*;
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(value = MethodArgumentNotValidException.class)
public DataResult validateException(MethodArgumentNotValidException e) {
List<FieldError> fieldErrors = e.getBindingResult().getFieldErrors();
List<String> list = new ArrayList<>();
for (FieldError error : fieldErrors) {
list.add(error.getField() + error.getDefaultMessage());
}
return DataResult.custom(500, "参数有误!", list.get(0));
}
@ExceptionHandler(value = ConstraintViolationException.class)
public DataResult validateException(ConstraintViolationException e) {
Set<ConstraintViolation<?>> violations = e.getConstraintViolations();
List<String> list = new ArrayList<>();
for (ConstraintViolation<?> item : violations) {
list.add(item.getMessage());
}
return DataResult.custom(500, "参数有误!", list.get(0));
}
}
复制代码
因为上面我们配置了校验模式:只要有一个验证失败就立即返回信息,所以这里返回的都是list.get(0);
接下来我们发送请求验证一下:
get请求
post请求:
测试通过
实现方式:
1. 定义两个分组接口 : 定义两个interface,实现javax.validation.groups.Default接口:
public interface Add extends Default {
}
public interface Update extends Default {
}
复制代码
2. 在实体类中给属性添加验证注解的时候指定验证的分组
@Data
public class Person {
@NotEmpty(groups = Update.class, message = "更新时候id不能为空")
private Long id;
@NotEmpty(groups = {Add.class,Update.class}, message = "姓名不能为空")
private String name;
}
复制代码
3. 使用分组进行参数的验证
@RestController
@Slf4j
public class VerifyController {
@PostMapping(value = "/validated/add")
public void add(@Validated(value = Add.class) @RequestBody Person person) {
...
}
@PostMapping(value = "/validated/update")
public void update(@Validated(value = Update.class) @RequestBody Person person) {
...
}
}
复制代码
分组的原理:
即使springboot内置了各种注解去帮助我们校验参数,但是当面对复杂参数校验时,还是不能满足我们的要求,这时候我们就需要自定义校验注解。
现在我们来定义一个校验身份证号的注解,实现方式:
第一步:先定义一个注解
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.*;
/**
* @Description TODO 身份证号校验注解
* @Author Java学术趴
* @Date 2020/12/11
*/
@Documented
@Target({ElementType.PARAMETER, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = IdCardValidate.class)
public @interface IdCard {
String message() default "身份证号码不合法";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
复制代码
注解类里面前三个参数是固定必须的,直接复制即可,@Constraint(validatedBy = IdCardValidate.class)指定的是下面我们自己创建的校验逻辑实现类。
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
/**
* @Description TODO 身份证校验逻辑
* @Author admin
* @Date 2020/12/14
*/
public class IdCardValidate implements ConstraintValidator<IdCard, String> {
@Override
public void initialize(IdCard constraintAnnotation) {
}
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
//这里只是举例,此处输入你的校验逻辑,成功返回true,否则返回false
String id = "123456789";
if (value.equals(id)) {
return true;
}
return false;
}
}
复制代码
使用自定义注解
@IdCard
@NotBlank(message = "身份证为必填项")
private String idCard;
复制代码
@Controller : 加在类上面的注解,使得类里面的每个方法都返回一个视图页面。
但是在实际开发中,我们一般只是让后端的方法返回给前端是查询的数据,而不是一个新的视图页面。如果使用@Controller注解必须结合@ResponseBody,让这个方法返回给前端的不是一个视图,而只是给前端传递查询到的数据。
可以把@ResponseBody注解加到Controller类上或者是Controller层的方法上。
@Controller
public class HelloController {
@GetMapping(value="/hello")
@ResponseBody
public String say(){//返回json 数据
return "gril";
}
@GetMapping(value="/hello1")
public String say1(){//返回视图
return "sys/index1";
}
复制代码
为了解决这个麻烦的操作,SpringBoot中提供了@RestController注解解决这个问题,如下:
@RestController :从Spring 4.0以后产生的,用来将json/xml数据发送到前台页面,而不是返回视图页面。它相当于@Controller和@ResponseBody。
@RestController加在类上面的注解,使得类里面的每个方法都将json/xml返回数据加返回到前台页面中。梭所以在实际开发中,我们一般都使用这个注解。
@RequestMapping("路径信息") :@RequestMapping 来映射请求,也就是通过它来指定控制器可以处理哪些URL请求。这个注解可以使用在Controller层的类或者方法上。
@RequestMapping中的参数:
@RestController
@RequestMapping("/user")
// @RequestMapping(value = "/user")
public class UserController {
@RequestMapping("/login")
public String login() {
return "success";
}
}
// 此时请求的实际路径是:/user/login
// 在类上的@RequestMapping相当于声明一个根路径,在请求的时候他会把类和方上的路径进行拼接
复制代码
method属性:
通过method属性来指定请求的类型:有GET(查)、POST(增)、PUT(改)、DELETE(删),由于浏览器表单无法发送 DELETE 和 PUT 请求,如果使用的话需要进行处理,所以我们在开发中一般使用 CET和POST请求方式完成请求任务。
@RestController
@RequestMapping(path = "/user")
public class UserController {
// 通过 method 属性来指定请求的类型,此时只能使用GET请求访问,使用POST会报错。
@RequestMapping(path = "/login", method=RequestMethod.GET)
public String login() {
return "success";
}
}
复制代码
@RestController
@RequestMapping(path = "/user")
public class UserController {
// 通过 method 属性来指定请求的类型,此时只能使用POST请求访问,使用GET会报错。
@RequestMapping(path = "/login", method=RequestMethod.POST)
public String login() {
return "success";
}
}
复制代码
@RestController
@RequestMapping(path = "/user")
public class UserController {
// 该方法将同时接收通过GET和POST方式发来的请求
@RequestMapping(path = "/login", method={RequestMethod.POST,RequestMethod.GET})
public String login() {
return "success";
}
}
复制代码
params属性:
http://localhost/SpringMVC/user/login?username=kolbe&password=123456
复制代码
@Controller
@RequestMapping(path = "/user")
public class UserController {
// 该方法将接收 /user/login 发来的请求,且请求参数必须为 username=kolbe&password=123456
@RequestMapping(path = "/login", params={"username=kolbe","password=123456"})
public String login() {
return "success";
}
}
复制代码
headers 属性:
@Controller
@RequestMapping(path = "/user")
public class UserController {
// 表示只接收 localhost:8080 发来的请求,不会处理其他请求
@RequestMapping(path = "/login", headers="Host=localhost:8080")
public String login() {
return "success";
}
}
复制代码
带有占位符的URL
@Controller
@RequestMapping(path = "/user")
public class UserController {
// 当只存在一个参数的时候,可以省略@PathVariable("id")注解,但是后边的参数名必须和{}中的占位符名字一致,否则找不到会报错。
// 当给定 @PathVariable("id") 的时候括号中的参数名字必须和{}中占位符的名字一致。此时后边的参数可以随便定义其他的名字比如:@PathVariable("id") Integer param
@RequestMapping(value="/{id}", method=RequestMethod.GET)
public String show(@PathVariable("id") Integer id) {
return "success";
}
}
复制代码
在这个控制器中 show() 方法将可以接收 user/1、user/2、user/3等等的路径请求,请求的方法必须为GET,使用 @PathVariable 为应用实现 REST 规范提供了具大的便利条件。
相似组合注解还有:@PutMapping、@DeleteMapping、@PatchMapping分别对用method的PUT、Delete以及Patch
@Api :这个注解是Swagger中的一个注解,专门用于在Controller类上,针对这个Controller接口类生成一个文档的描述,在之后生成的Swagger的Api文档中会对这个Controller进行介绍。
参数信息:
@Api(tags = "列表1")
@Api(tags = {"列表1","列表2"})
复制代码
// 用于 Controller 类上
@Api(tags = "客户端通信服务端接口")
复制代码
@ApiOperation : 这个也是Swagger中的一个注解,作用在Controller类中的方法上,针对这个接口进行描述,会在Swagger的Api文档中进行记录。
参数信息:
// 用于 Controller 类中的接口上
@ApiOperation(value = "客户端下载对应脚本", notes = "下载脚本")
复制代码
这两个Swagger注解用于 Controller 类上,还有 @ApiModel()以及@ApiModelProperty()用于实体类上,注意区分
@Autowired : spring可以自动帮你把bean里面引用的对象的setter/getter方法省略,它会自动帮你set/get。他会帮你完成对该Bean对象的自动装配。
@Autowired这个注解是属于SpringBoot的
@Autowired自动创建和装配的原理: 默认加在IOC容器中的组件,容器会调用无参构造器创建对象,在进行初始化赋值等操作,如果只有有参构造,Spring会调用有参构造,有参构造函数会自动注入。
@Autowired使用的地方:
注意:使用 @Autowrite声明的对象一般声明为 private
package com.sue.cache.service;
import org.springframework.stereotype.Service;
@Service
public class TestService1 {
public void test1() {
}
}
package com.sue.cache.service;
import org.springframework.stereotype.Service;
@Service
public class TestService2 {
//自动装配一个 Service 层的实例对象
@Autowired
private TestService1 testService1;
public void test2() {
}
}
复制代码
@Autowride的使用原理,他是在返回数据的时候使用DI技术实现的。DAO层不用使用@Autowited,因为这层不需要实体类
注意:
byType
方式。
byName
进行自动装配,需要和 @Qualifier() 注解 配套使用
@Autowired() @Qualifier("baseDao") private BaseDao baseDao; 复制代码
byName : 会搜索整个配置文件中的bean,如果有相同名称的bean则自动装配,否则显示异常。(类名) byType : 会搜索整个配置文件中的bean,如果有相同类型的bean则自动装配,否则显示异常。(类的类别) 复制代码
required
参数默认是true,表示开启自动装配,有些时候我们不想使用自动装配功能,可以将该参数设置成false。
required = true :开启自动装配(默认) required = false : 关闭自动装配(需手动开启) 复制代码
在 IDEA 中 @Autowired 存在下划线,但是可以正常使用。这是为什么呢???
private final CategoryMapper categoryMapper;
public CategoryServiceImpl(CategoryMapper categoryMapper) {
this.categoryMapper = categoryMapper;
}
复制代码
但是在实际开发中,我们都直接使用 @Autowired 来简化开发的难度。
@Autowired
private CategoryMapper categoryMapper;
复制代码
所以他会存在一个提醒的下画波浪线,但是不影响使用。
@Resource :@Resource注解和@Autowired注解一样,都是为了装配Bean,但是两者在使用上又有少许区别。@Resource默认按照名字装配Bean,即会按照name属性的值来找到具有相同id的Bean Definition 并注入。如果@Resource没有指定name属性,则会根据这个将要被注入的属性的名字来进行Bean装配。
@Component(value = "renlei")
public class Person {
String name;
Integer age;
}
复制代码
使用 @Resource(name = "renlei") 中name属性值去对应@Component(value = "renlei") 中的value值
@Component
public class House {
//@Resource的name属性的值与Person类的@Component的value值相对应【都是 renlei】,所以可以进行装配
@Resource(name = "renlei")
private Person p1;
//@Resource的name属性的值与Person类的@Component的value值不对应,一个是relei,一个是person,所以装配失败
@Resource(name = "person")
private Person p1;
//@Reource 没有指定name的值,所以容器会拿这个p1变量的名字去Bean池子中查找id为renlei的bean并装配到这个renlei变量中。装配成功
@Reource
private Person renlei;
// @Reource 没有指定name的值,所以容器会拿这个p1变量的名字去Bean池子中查找id为p1的bean并装配到这个 p1变量中。如果找不到,就按照类型来进行装配,都是Person类,所以装配成功
// 注意:这里存在一个先更具 byName方式匹配之后根据 byType方式匹配,都不成功的时候才会报错。
@Reource
private Person p1;
}
复制代码
@Resource这个注解是属于 J2EE的。用于属性或者方法上,一般用于属性上。
@Resource注解使用的过程:
注意:@Resource先使用 byName 进行匹配,匹配不成功给则使用 byType 方式,如果还是匹配失败,则报错。在实际开发中,我们一般都给 @Service、@Controller以及@Repository 的value属性,所以在项目中使用的 @Resource 注解都是使用的 byType 类型匹配方式。
@Value("张三")
private String name;
// 以上用法相当于
private String name = "张三";
复制代码
@Value :项目启动时,用于读取配置文件给静态文件赋值。读取SpringBoot的主配置文件中的属性值。
使用方式:
student:
name:张三
age:20
room:java
复制代码
@Value("${student.name}")
private String name;
// 此时的name等于张三
复制代码
如果配置参数 student.name 在配置文件中未定义则注入失败,抛出异常IllegalArgumentException
java.lang.IllegalArgumentException:
Could not resolve placeholder 'server.error.path' in value "${server.error.path}"
复制代码
@Value("{...:{...}}") 嵌套使用
@Value("${student.name:${studnet.age:/student.room}}")
private String info;
复制代码
@Value("#{"张三"}")
private String name;
// 此时的name等于张三
复制代码
org.springframework.expression.spel.SpelEvaluationException:
EL1008E: Property or field 'student' cannot be found on object of type
'org.springframework.beans.factory.config.BeanExpressionContext'
- maybe not public or not valid?
复制代码
@Value("#{student.name ?: '张三'}")
复制代码
这个 @Value 注解可以使用在任何层
@PathVariable : 映射URL绑定的占位符。
带占位符的URL是 Spring3.0 新增的功能,URL中的 {xxx} 占位符可以通过 @PathVariable("xxx") 绑定到操作方法的入参中。
@RequestMapping("/user/{id}")
public String testPathVariable(@PathVariable("id") String id){
System.out.println("路径上的占位符的值="+id);
return "success";
}
复制代码
@RequestMapping("/user/{id}")
// 这个参数名必须是id,和占位符一致才可以识别到。
public String testPathVariable(String id){
System.out.println("路径上的占位符的值="+id);
return "success";
}
复制代码
@RequestMapping("/user/{id}")
// @PathVariable("id") 中的参数名必须和占位符一致,此时后面的参数可以任意给定。
public String testPathVariable(@PathVariable("id") String myId){
System.out.println("路径上的占位符的值="+myId);
return "success";
}
复制代码
@RequestMapping("/user/{id}/{name}")
public String testPathVariable(@PathVariable("id") String myId, @PathVariable("name") String myName,){
System.out.println("路径上的占位符的值="+id);
return "success";
}
复制代码
@RequestParam : 这个注解是用于后端接收数据的。接收的参数是来自requestHeader中,即请求头。通常用于GET请求,像POST、DELETE等其它类型的请求也可以使用。比如常见的url:http://localhost:8081/spring-boot-study/novel/findByAuthorAndType?author=唐家三少&type=已完结
@RequestMapping(value = "add",method = RequestMethod.GRT)
public void addPeople(@RequestParam(value = "name", required = fasle,default = "Java学术趴") String name,@RequestParam(value = "age") Integer age){
.....
}
复制代码
@RequestBody :这个注解也是用于后端接收数据的。接收的参数是来自requestBody中,即请求体。通常用于接收POST、DELETE等类型的请求数据,GET类型也可以适用。一般用于处理非 Content-Type: application/x-www-form-urlencoded编码格式的数据,比如:application/json、application/xml等类型的数据。
application/json
类型的数据而言,使用注解@RequestBody可以将body里面所有的json数据传到后端,后端再进行解析。@RequestMapping(value = "add",method = RequestMethod.GRT)
public void addPeople(@RequestBody People people){
.....
}
复制代码
在后端的同一个接收方法里,@RequestBody与@RequestParam()可以同时使用,@RequestBody最多只能有一个,而@RequestParam()可以有多个。
@ExceptionHandler()
public String handleExeption2(Exception ex) {
System.out.println("抛异常了:" + ex);
ex.printStackTrace();
String resultStr = "异常:默认";
return resultStr;
}
复制代码
比如上面的handleExeption2()方法,给这个方法加上@ExceptionHandler注解,这个方法就会处理类中其他方法(被@RequestMapping注解)抛出的异常。
@ExceptionHandler注解中可以添加参数,参数是某个异常类的class,代表这个方法专门处理该类异常,比如这样:
@ExceptionHandler(NumberFormatException.class)
public String handleExeption(Exception ex) {
System.out.println("抛异常了:" + ex);
ex.printStackTrace();
String resultStr = "异常:NumberFormatException";
return resultStr;
}
复制代码
此时注解的参数是NumberFormatException.class,表示只有方法抛出NumberFormatException时,才会调用该方法。如果抛出其他的异常的时候,这个方法就不可以接收到这个异常。
当异常发生时,Spring会选择最接近抛出异常的处理方法。
比如之前提到的NumberFormatException,这个异常有父类RuntimeException,RuntimeException还有父类Exception,如果我们分别定义异常处理方法,@ExceptionHandler分别使用这三个异常作为参数,比如这样:
@ExceptionHandler(NumberFormatException.class)
public String handleExeption(Exception ex) {
System.out.println("抛异常了:" + ex);
ex.printStackTrace();
String resultStr = "异常:NumberFormatException";
return resultStr;
}
@ExceptionHandler()
public String handleExeption2(Exception ex) {
System.out.println("抛异常了:" + ex);
ex.printStackTrace();
String resultStr = "异常:默认";
return resultStr;
}
@ExceptionHandler(RuntimeException.class)
public String handleExeption3(Exception ex) {
System.out.println("抛异常了:" + ex);
ex.printStackTrace();
String resultStr = "异常:RuntimeException";
return resultStr;
}
复制代码
那么,当代码抛出NumberFormatException时,调用的方法将是注解参数NumberFormatException.class的方法,也就是handleExeption(),而当代码抛出IndexOutOfBoundsException时,调用的方法将是注解参数RuntimeException的方法,也就是handleExeption3()。
标识了@ExceptionHandler注解的方法,返回值类型和标识了@RequestMapping的方法是统一的,可参见@RequestMapping的说明,比如默认返回Spring的ModelAndView对象,也可以返回String,这时的String是ModelAndView的路径,而不是字符串本身。
有些情况下我们会给标识了@RequestMapping的方法添加 @ResponseBody,比如使用Ajax的场景,直接返回字符串,异常处理类也可以如此操作,添加@ResponseBody注解后,可以直接返回字符串,比如这样:
@ExceptionHandler(NumberFormatException.class)
@ResponseBody
public String handleExeption(Exception ex) {
System.out.println("抛异常了:" + ex);
ex.printStackTrace();
String resultStr = "异常:NumberFormatException";
return resultStr;
}
复制代码
这样的操作可以在执行完方法后直接返回字符串本身。
使用@ExceptionHandler时尽量不要使用相同的注解参数。
如果我们定义两个处理相同异常的处理方法:
@ExceptionHandler(NumberFormatException.class)
@ResponseBody
public String handleExeption(Exception ex) {
System.out.println("抛异常了:" + ex);
ex.printStackTrace();
String resultStr = "异常:NumberFormatException";
return resultStr;
}
@ExceptionHandler(NumberFormatException.class)
@ResponseBody
public String handleExeption2(Exception ex) {
System.out.println("抛异常了:" + ex);
ex.printStackTrace();
String resultStr = "异常:默认";
return resultStr;
}
复制代码
两个方法都处理NumberFormatException,这种定义方式编译可以通过,而当NumberFormatException真正被抛出时,Spring会给我们报错:
java.lang.IllegalStateException: Ambiguous @ExceptionHandler method mapped for [class java.lang.NumberFormatException]: {public java.lang.String TestController.handleExeption(java.lang.Exception), public java.lang.String TestController.handleExeption2(java.lang.Exception)}
at org.springframework.web.method.annotation.ExceptionHandlerMethodResolver.addExceptionMapping(ExceptionHandlerMethodResolver.java:102) ~[spring-web-5.0.5.RELEASE.jar:5.0.5.RELEASE]
at org.springframework.web.method.annotation.ExceptionHandlerMethodResolver.<init>(ExceptionHandlerMethodResolver.java:66) ~[spring-web-5.0.5.RELEASE.jar:5.0.5.RELEASE]
复制代码
@ControllerAdvice
public class MyAdviceException {
//MaxUploadSizeExceededException,这个是异常类,这里可以枚举多个异常
@ExceptionHandler(MaxUploadSizeExceededException.class)
public void myexcept(MaxUploadSizeExceededException e, HttpServletResponse response){
response.setContentType("text/html;charset=utf-8");
PrintWriter writer = null;
try {
writer = response.getWriter();
} catch (IOException ex) {
ex.printStackTrace();
}
writer.write("文件太大,请重新选择");
writer.flush();
writer.close();
}
}
复制代码
1. 给controller中的某个方法配置CORS
controller方法的CORS配置,您可以向@RequestMapping注解处理程序方法添加一个@CrossOrigin注解,以便启用CORS(默认情况下,@CrossOrigin允许在@RequestMapping注解中指定的所有源和HTTP方法):
为单独的方法配置跨域请求
@RestController
@RequestMapping("/account") public class AccountController {
@CrossOrigin
@GetMapping("/{id}")
public Account retrieve(@PathVariable Long id) { // ...
}
@DeleteMapping("/{id}")
public void remove(@PathVariable Long id) { // ...
}
}
复制代码
@CrossOrigin注解中的参数
2.为整个controller启用@CrossOrigin
在这个例子中,对于retrieve()和remove()处理方法都启用了跨域支持,还可以看到如何使用@CrossOrigin属性定制CORS配置。
@CrossOrigin(origins = "http://domain2.com", maxAge = 3600)
@RestController
@RequestMapping("/account") public class AccountController {
@GetMapping("/{id}") public Account retrieve(@PathVariable Long id) { // ...
}
@DeleteMapping("/{id}") public void remove(@PathVariable Long id) { // ...
}
}
复制代码
3. 同时使用controller和方法级别的CORS配置,Spring将合并两个注释属性以创建合并的CORS配置。
@CrossOrigin(maxAge = 3600)
@RestController
@RequestMapping("/account") public class AccountController {
@CrossOrigin(origins = "http://domain2.com")
@GetMapping("/{id}")
public Account retrieve(@PathVariable Long id) {
// ...
}
@DeleteMapping("/{id}")
public void remove(@PathVariable Long id) {
// ...
}
}
复制代码
@InitBinder : 在实际操作中经常会碰到表单中的日期 字符串和Javabean中的日期类型的属性自动转换, 而springMVC默认不支持这个格式的转换,所以必须要手动配置, 自定义数据类型的绑定才能实现这个功能。
@InitBinder用于在@Controller中标注于方法,表示为当前控制器注册一个属性编辑器或者其他,只对当前的Controller有效。
@RequestMapping("test")
@Controller
public class TestController {
@InitBinder
public void InitBinder(WebDataBinder binder){
DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
CustomDateEditor dateEditor = new CustomDateEditor(df, true);
binder.registerCustomEditor(Date.class,dateEditor);
}
@RequestMapping(value="/param",method=RequestMethod.GET)
@ResponseBody
public Map<String,Object> getFormatData(Date date) throws ParseException{
Map<String,Object> map = new HashMap<String, Object>();
map.put("name", "zhangsan");
map.put("age", 22);
map.put("date",date);
return map;
}
}
复制代码
@Service注解一般写在业务层的接口实现类上,而不是接口上。
@Service : @Service注解用于类上,标记当前类是一个service类,加上该注解会将当前类自动注入到spring容中。
@Service
public class CourseDAOImpl extends HibernateDaoSupport implements CourseDAO{
...
}
复制代码
@Service("courseDAOImpl") :这个表示给类命名一个别名,方便注入到其他类中。不加这个参数值的话,默认别名就是当前类名,但是首字母小写。
在实际开发中,我们一般都直接使用 @Sevice
@Scope :Spring IOC 容器中的一个作用域,在 Spring IOC容器中,他用来配置Bean实例的作用域对象。
@Scope的几种作用域:
默认的作用域是:singleton(单实例)
@Reponsitory :@Reponsitory的作用与@Controller,@Service的作用都是把对象交给Spring管理。@Reponsitory是标注在Dao层接口上,作用是将接口的一个实现类交给Spring管理。
注意:
这个 @Repository 完全可以省略不写,也完全可以实现自动注入,但是在IDEA中会存在一个红色的波浪线。原因如下:
@Mapper : 这个注解一般使用在Dao层接口上,相当于一个mapper.xml文件,它的作用就是将接口生成一个动态代理类。加入了@Mapper注解,目的就是为了不再写mapper映射文件。这个注解就是用来映射mapper.xml文件的。
@Mapper使用的原理:
注意:
在实际开发中,如何使用@Mapper、@MapperSacn、@Reponsitory注解???
建议:
@Select :该注解的目的是为了取代mapper.xml中的select标签,只作用于方法上面。此时就不要在写mapper.xml文件了。
@Select注解的源码
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Select
{
String[] value();
}
复制代码
从上述可以看到两点信息:
所以,@Select注解的用法是这样的:
@Select({ "select * from xxx", "select * from yyy" })
Person selectPersonById(Integer id);
复制代码
虽然@Select注解的值是字符数组,但是真正生效的应该是最后那条SQL语句。这一点请大家要留意一下。
普通的字符串值,只能实现变量的替换功能,实现简单的SQL语句,如下所示,
@Select("select * from t_person where id = #{id}")
Person selectPersonById(Integer id);
复制代码
如果要想实现复杂的逻辑判断,则需要使用标签 ,如下所示:
@Select("<script> select * from t_person where id = #{id}
<when test='address !=null'> and address = #{address}
</when> </script>")
Person selectPersonById(Integer id);
复制代码
其实,标签 注解专用的,其他的注解,例如@Insert、@Update、@Delete等等,都可以使用的。
@Param : 动态代理接口向映射文件中传递参数的时候,会使用@Param注解,并且如果动态代理接口使用了@Param这个注解,那么映射文件中的标签中可以不用写parameterType属性,可以直接接收@Param中传递来的参数值。
先来看一下动态代理接口中是怎样写的,如下图:
再来看一下与动态代理接口对应的映射文件中是怎样接收参数的,如下图:
mapper中的方法:
public User selectUser(@Param("userName") String name,@Param("password") String pwd);
复制代码
映射到xml中的标签 <select id="selectUser" resultMap="User"> select * from user where user_name = #{userName} and user_password=#{password} </select> 其中where user_name = #{userName} and user_password = #{password}中的userName和password都是从注解@Param()里面取出来的,取出来的值就是方法中形式参数 String name 和 String pwd的值。 重点:当只存在一个参数的时候,此时可以省略这个 @@Param注解,但是两个参数必须使用这个注解。 5.4.2 @Param注解JavaBean对象 SQL语句通过@Param注解中的别名把对象中的属性取出来然后复制 mapper中的方法: public List<User> getAllUser(@Param("user") User u); 映射到xml中的标签
<select id="getAllUser" parameterType="com.vo.User" resultMap="userMapper">
select
from user t where 1=1
and t.user_name = #{user.userName}
and t.user_age = #{user.userAge}
</select>
复制代码
注意点:
@Configuration :用于定义配置类,可替换xml配置文件,被注解的类内部包含有一个或多个被@Bean注解的方法,这些方法将会被AnnotationConfigApplicationContext或AnnotationConfigWebApplicationContext类进行扫描,并用于构建bean定义,初始化Spring容器。
我们相当于把xml配置文件转换成了一个配置类。这个配置类就相当于xml配置文件。
注意:
@Configuration配置spring并启动spring容器
以前我们需要使用 xml 文件来进行spring的配置:
@Configuration标注在类上,相当于把该类作为spring的xml配置文件中的<beans>
,作用为:配置spring容器(应用上下文)
@Bean注解就是声明其中的标签
@Configuation等价于
@Bean等价于
举例说明:将指定的组件添加到SpringBoot的IOC容器中。
使用SpringBoot解决这个xml配置文件
现在的Spring Boot已经不需要向以前一样了,有一个注解@Configuration(翻译:配置)可以供使用
这个时候在类里边不能写bean标签了需要使用@bean注解,想要构建出user和pet对象需要自己将它创造出来。 @bean:给容器中添加组件,以方法名作为组件的id。返回类型为组件类型,返回的值,就是组件在容器中的实例对象。
注意:@Bean这个注解需要声明在方法名上面,使用@Configuration、@Bean就可以完全代替xml配置文件
这个配置文件会在SpringBoot启动的时候进行注册加载,就会创建出User以及Pet实例对象。
正常的实例名称就是方法的名称,当然可以使用修改这个实例对象的名字。
重点:给容器中注册的组件默认是单实例的,就是说无论我们从容器中获取多少次,这些实例对象都是同一个实例对象。当然被 @Configuration 注解的配置类也是一个组件。
同时,在Spring Boot 5.2之后的@Configuration注解多了一个属性proxyBeanMethods,默认为true(翻译:代理bean的方法)
@Bean:这个注解用于告诉方法,产生一个Bean对象,然后这个Bean对象交给Spring管理。产生这个Bean对象的方法Spring只会调用一次,随后这个Spring将会将这个Bean对象放在自己的IOC容器中;
@Configuration
public class AppConfig {
// 使用@Bean 注解表明myBean需要交给Spring进行管理
// 未指定bean 的名称,默认采用的是 "方法名" + "首字母小写"的配置方式
@Bean
public MyBean myBean(){
return new MyBean();
}
}
public class MyBean {
public MyBean(){
System.out.println("MyBean Initializing");
}
}
复制代码
如果发现销毁方法没有执行,原因是bean销魂之前程序已经结束了,可以手动close下如下:
AnnotationConfigApplicationContext applicationContext2 = new AnnotationConfigApplicationContext(MainConfig.class);
User bean2 = applicationContext2.getBean(User.class);
System.out.println(bean2);
//手动执行close方法
applicationContext2.close();
复制代码
@component :把普通pojo实例化到spring容器中,相当于xml配置文件中的 。泛指各种组件,就是说当我们的类不属于各种归类的时候(不属于@Controller、@Services等的时候),我们就可以使用@Component来标注这个类。把当前类对象存入到Spring容器中。
<context:component-scan base-package=”com.mmnc”>
# base-package表示为需要扫描的所有子包。
复制代码
这个注解和@controller 、@service、@repository注解一样,都是把声明的类交给Spring进行管理。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。