Springboot 注解

1|0@validated

服务器和浏览器互不信任,不能因为前端加入参判断了后台就不处理了,这样是不对的。

比如前台传过来一个对象作为入参参数,这个对象中有些属性允许为空,有些属性不允许为空。那么你还在使用if()else{}进行非空判断吗?不妨尝试下使用注解,可以使用@Validated

1|1基础使用

因为spring-boot已经引入了基础包,所以直接使用就可以了
1 首先在controller上声明需要对数据进行校验

@RestController @RequestMapping("/api/v1") public class Demo1Controller { @PostMapping("/insert") public String validatedDemo1(@Validated @RequestBody Use1Dto use1Dto){ System.out.println(use1Dto); return "success"; } }

2 然后在bean上声明需要被校验的字段

@Data public class User1Dto { /** * 用户名 */ @NotBlank(message = "用户名不能为空!") private String username; /** * 性别 */ @NotBlank(message = "性别不能为空!") private String gender; /** * 年龄 */ @Min(value = 1, message = "年龄有误!") @Max(value = 120, message = "年龄有误!") private int age; /** * 地址 */ @NotBlank(message = "地址不能为空!") private String address; /** * 邮箱 */ @Email(message = "邮箱有误!") private String email; /** * 手机号码 */ @Pattern(regexp = "^(13[0-9]|14[579]|15[0-3,5-9]|16[6]|17[0135678]|18[0-9]|19[89])\\d{8}$",message = "手机号码有误!") private String mobile; }

而后,当输入不能满足条件是,就会抛出异常,而后统一由异常中心处理
也可以用BindingResult,但是用了这个后就必须手动处理异常,侵入了正常的逻辑过程,并不推荐.

说明:若不做异常处理,@Validated注解的默认异常消息如下(示例):

2020-09-05 21:48:38.106 WARN 9796 --- [nio-8080-exec-3] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.bind.MethodArgumentNotValidException: Validation failed for argument [0] in public java.lang.String com.example.validateddemo.controller.DemoController.validatedDemo1(com.example.validateddemo.entity.dto.UseDto): [Field error in object 'useDto' on field 'username': rejected value [null]; codes [NotBlank.useDto.username,NotBlank.username,NotBlank.java.lang.String,NotBlank]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [useDto.username,username]; arguments []; default message [username]]; default message [用户名不能为空!]] ]

1|2常用注解类型

注意,不要错用了异常类型,比如在int上不可用@size

数值检查,建议使用在StirngInteger类型,不建议使用在int类型上,因为表单值为""时无法转换为int,但可以转换为Stirng"",Integernull

1|3嵌套校验

1|0@Validated或者@Valid区别

  1. @Validated:可以用在类型、方法和方法参数上。但是不能用在成员属性(字段)上
  2. @Valid:可以用在方法、构造函数、方法参数和成员属性(字段)上
  3. 两者是否能用于成员属性(字段)上直接影响能否提供嵌套验证的功能。

1|0未嵌套情况

比如我们现在有个实体叫做Item

public class Item { @NotNull(message = "id不能为空") @Min(value = 1, message = "id必须为正整数") private Long id; @NotNull(message = "props不能为空") @Size(min = 1, message = "至少要有一个属性") private List<Prop> props; }

Item带有很多属性,属性里面有:pidvidpidNamevidName,如下所示:

public class Prop { @NotNull(message = "pid不能为空") @Min(value = 1, message = "pid必须为正整数") private Long pid; @NotNull(message = "vid不能为空") @Min(value = 1, message = "vid必须为正整数") private Long vid; @NotBlank(message = "pidName不能为空") private String pidName; @NotBlank(message = "vidName不能为空") private String vidName; }

属性这个实体也有自己的验证机制,比如pidvid不能为空,pidNamevidName不能为空等。
现在我们有个ItemController接受一个Item的入参,想要对Item进行验证,如下所示:

@RestController public class ItemController { @RequestMapping("/item/add") public void addItem(@Validated Item item) { doSomething(); } }

在上图中,如果Item实体的props属性不额外加注释,只有@NotNull@Size,无论入参采用@Validated还是@Valid验证,Spring Validation只会对Itemidprops做非空和数量验证,不会对props字段里的Prop实体进行字段验证,也就是@Validated@Valid加在方法参数前,都不会自动对参数进行嵌套验证。也就是说如果传的List中有Proppid为空或者是负数,入参验证不会检测出来。

1|0嵌套情况

为了能够进行嵌套验证,必须手动在Item实体的props字段上明确指出这个字段里面的实体也要进行验证。由于@Validated不能用在成员属性(字段)上,但是@Valid能加在成员属性(字段)上,而且@Valid类注解上也说明了它支持嵌套验证功能,那么我们能够推断出:@Valid加在方法参数时并不能够自动进行嵌套验证,而是用在需要嵌套验证类的相应字段上,来配合方法参数上@Validated@Valid来进行嵌套验证。

修改Item类如下所示:

public class Item { @NotNull(message = "id不能为空") @Min(value = 1, message = "id必须为正整数") private Long id; @Valid // 嵌套验证必须用@Valid @NotNull(message = "props不能为空") @Size(min = 1, message = "props至少要有一个自定义属性") private List<Prop> props; }

然后我们在ItemControlleraddItem函数上再使用@Validated或者@Valid,就能对Item的入参进行嵌套验证。此时Item里面的props如果含有Prop的相应字段为空的情况,Spring Validation框架就会检测出来,记录相应的错误。

1|0@Validated和@Valid在嵌套验证功能上的区别

@Validated:用在方法入参上无法单独提供嵌套验证功能。不能用在成员属性(字段)上,也无法提示框架进行嵌套验证。能配合嵌套验证注解@Valid进行嵌套验证。

@Valid:用在方法入参上无法单独提供嵌套验证功能。能够用在成员属性(字段)上,提示验证框架进行嵌套验证。能配合嵌套验证注解@Valid进行嵌套验证。

1|4BindingResult

@PostMapping("/a") @ApiOperation(value = "测试", notes = "") public void test(@RequestBody @Valid TestEntity test,BindingResult bindingResult) { System.out.println(test.toString()); if (bindingResult.hasErrors()) { throw new 自定义Exception("错误提示码",bindingResult.getFieldError().getDefaultMessage()); } }

bindingResult.hasErrors() 判断是否校验通过,未通过bindingResult.getFieldError().getDefaultMessage()获取在TestEntity的属性设置的自定义message,如果没有设置,则返回默认值javax.validation.constraints.XXX.message

@RequestMapping("/b") @ResponseBody public Response runBydomain(@RequestBody @Validated TaskDomainVO taskDomainVO, BindingResult bindingResult) { log.info("Execution code analyze,", taskDomainVO.toString()); if (bindingResult.hasErrors()) { String errorCode = bindingResult.getAllErrors().get(0).getDefaultMessage(); log.info("Execution failed, errorCode:{}", errorCode); return new Response(ResultCode.GLOBAL_PARAM_ERROR, errorCode); }

2|0@Json***

jacksonmavern 依赖

<dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.5.3</version> </dependency>

使用的背景
springboot项目中定义了很多类,我们在rest返回中直接返回或者在返回对象中使用这些类,spring已经使用jackson自动帮我们完成这些的to json。但是有时候自动转的json内容太多,或者格式不符合我们的期望,因此需要调整类的to json过程,或者说希望自定义类的json过程

2|1@JsonProperty

1|0概念

  • 此注解用于属性上,作用是把该属性的名称序列化为另外一个名称,如把trueName属性序列化为name@JsonProperty(“name”)
  • 对属性名称重命名,比如在很多场景下Java对象的属性是按照规范的驼峰书写,但在数据库设计时使用的是下划线连接方式,此处在进行映射的时候就可以使用该注解。

1|0用法

例如:使用该注解将以下表结构转化为 Javabean

public class CustomerInfo{ private int id; //使用 @JsonProperty注解将表结构中的字段映射到实体类中 @JsonProperty("customer_name") private String customerName; @JsonProperty("customer_id") private String customerId; @JsonProperty("product_id") private String productId; @JsonProperty("source_address") private String sourceAddress; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getCustomerName() { return customerName; } public void setCustomerName(String customerName) { this.customerName = customerName; } public String getCustomerId() { return customerId; } public void setCustomerId(String customerId) { this.customerId = customerId; } public String getProductId() { return productId; } public void setProductId(String productId) { this.productId = productId; } public String getSourceAddress() { return sourceAddress; } public void setSourceAddress(String sourceAddress) { this.sourceAddress = sourceAddress; } }

2|2@JsonIgnore

1|0概念

  • 用于属性或者方法上(最好是属性上),用来完全忽略被注解的字段和方法对应的属性,即便这个字段或方法可以被自动检测到或者还有其他的注解,一般标记在属性或者方法上,返回的json数据即不包含该属性。

1|0用法

使用情景:需要把一个List转换成json格式的数据传递给前台。但实体类中基本属性字段的值都存储在快照属性字段中。此时我可以在业务层中做处理,把快照属性字段的值赋给实体类中对应的基本属性字段。最后,我希望返回的json数据中不包含这两个快照字段,那么在实体类中快照属性上加注解@JsonIgnore,那么最后返回的json数据,将不会包含customerIdproductId两个属性值。

public class CustomerInfo { private int id; //使用 @JsonIgnore注解在生成json数据时,忽略该字段 private String customerName; @JsonIgnore private String customerId; @JsonIgnore private String productId; private String sourceAddress; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getCustomerName() { return customerName; } public void setCustomerName(String customerName) { this.customerName = customerName; } public String getCustomerId() { return customerId; } public void setCustomerId(String customerId) { this.customerId = customerId; } public String getProductId() { return productId; } public void setProductId(String productId) { this.productId = productId; } public String getSourceAddress() { return sourceAddress; } public void setSourceAddress(String sourceAddress) { this.sourceAddress = sourceAddress; } }

2|3@JsonIgnoreProperties

1|0概念

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

1|0用法:

@JsonIgnoreProperties(ignoreUnknown = true),将这个注解写在类上之后,就会忽略类中不存在的字段。这个注解还可以指定要忽略的字段,例如 @JsonIgnoreProperties(value = {"fullName", "comment"})

@Data @JsonIgnoreProperties(value = {"fullName", "comment"}) public class User { private String id; private String name; private String fullName; private String comment; private String mail; @JsonIgnore private String address; @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss") private Date regDate; private Date reg2Date; }

说明:User类的fullNamecomment字段会被@JsonIgnoreProperties注解忽略。address字段会被@JsonIgnore注解忽略。regDate会按照@JsonFormat(timezone = “GMT+8”, pattern = “yyyy-MM-dd HH:mm:ss”)进行格式转。

@ApiOperation(value = "按用户id删除", notes="private") @ApiImplicitParams({ @ApiImplicitParam(name = "userId", defaultValue = "2", value = "userID", required = true, dataType = "string", paramType = "path"), }) @DeleteMapping(value = "/users/{userId}", produces = "application/json;charset=UTF-8") public User delUser(@PathVariable String userId) { User user = (User)userSvc.deleteById(userId); log.info("rest del user={} by id={}", user, userId); return user; }

可以看到返回的对象是User,然后commentfullNameaddress属性被忽略了,regDate的格式进行转换。

2|4@JsonFormat

1|0概念

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

1|0用法

@JsonFormat(pattern="yyyy-MM-dd HH:mm:ss") private Date updateTime;

3|0读取配置文件

  • @ConfigurationProperties : 是springboot的注解,用于把主配置文件(application.properties、application.yml)中配置属性设置到对于的Bean属性上
  • @PropertySource :是spring的注解,用于加载指定的属性配置文件到Spring的Environment中,可以和 @Value@ConfigurationProperties配合使用
  • @EnableConfigurationProperties : 用来开启ConfigurationProperties注解配置;如果不使用的话,@ConfigurationProperties加入注解的类上加@Component也是可以交于springboot管理。

3|1读取默认配置文件(application.properties、application.yml)

application.yml配置:

person: name: wumingshi

1|0实现方式一 @ConfigurationProperties + @Component作用于类上

@ConfigurationProperties(prefix = "person") @Componment @Data // lombok,用于自动生成getter、setter public class Person { private String name} @RestController @RequestMapping("/db") public class TestController { @Autowired private Person person; @GetMapping("/person") public String parsePerson() { return person.getName(); } }

1|0实现方式二 @ConfigurationProperties + @Bean作用在配置类的bean方法上

@Data public class Person { private String name; } @Configuration public class PersonConf{ @Bean @ConfigurationProperties(prefix="person") public Person person(){ return new Person(); } } @RestController @RequestMapping("/db") public class TestController { @Autowired private Person person; @GetMapping("/person") public String parsePerson() { return person.getName(); } }

1|0实现方式三 @ConfigurationProperties注解到普通类、 @EnableConfigurationProperties注解定义为bean

@ConfigurationProperties(prefix="person") @Data public class Person { private String name; } // 说明: @EnableConfigurationProperties可以直接注到启动类上,也可以放在自定义配置类,自定义配置类使用@Configuration标注 @SpringBootApplication @EnableConfigurationProperties(Person.class) public class DbApplication { public static void main(String[] args) { SpringApplication.run(DbApplication.class, args); } } @RestController @RequestMapping("/db") public class TestController { @Autowired private Person person; @GetMapping("/person") public String parsePerson() { return person.getName(); } }

1|0实现方式四 @Value作用属性上

@RestController @RequestMapping("/db") public class TestController { @Value("${person.name}") private String name; @GetMapping("/person") public String parsePerson() { return name; } }

1|0实现方式五 使用自带的Environment对象

@RestController @RequestMapping("/db") public class TestController { @Autowired private Environment environment; @GetMapping("/person") public String parsePerson() { return environment.getProperty("person.name"); } }

3|2读取自定义配置文件(比如:config.properties)

说明: PropertySource默认不支持yml、yaml

config.properties配置

person.name=wumingshi

1|0实现方式一 @Configuration + @PropertySource + Environment

@Data public class Person { private String name; } @Configuration @PropertySource(value = "classpath:config.properties") public class PersonConf { @Autowired private Environment environment; @Bean public Person person(){ Person person = new Person(); person.setName(environment.getProperty("person.name")); return person; } } @RestController @RequestMapping("/db") public class TestController { @Autowired private Person person; @GetMapping("/person") public String parsePerson() { return person.getName(); } }

1|0实现方式二 @Component+ @PropertySource + @Value

@Component @PropertySource(value = "classpath:config.properties") @Data public class Person { @Value("${person.name}") private String name; } @RestController @RequestMapping("/db") public class TestController { @Autowired private Person person; @GetMapping("/person") public String parsePerson() { return person.getName(); } }

1|0实现方式三 @Component+ @PropertySource + @ConfigurationProperties

@Component @PropertySource("classpath:dangxiaodang.properties") @ConfigurationProperties(prefix = "person") public class Person{ private String name; } @RestController @RequestMapping("/db") public class TestController { @Autowired private Person person; @GetMapping("/person") public String parsePerson() { return person.getName(); } }

实际使用

import lombok.Data; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.PropertySource; import org.springframework.core.env.Environment; import org.springframework.stereotype.Component; @Data @PropertySource(value = "classpath:config.properties") @Component public class ProjectConfig { @Autowired private Environment env; public String getProperty(String str){ return env.getProperty(str); } public String getProjectPathForCover(String str){ return env.getProperty("cover_root_path")+"/"+str; } public String getProjectRootPath(){return env.getProperty("root_path");} }

__EOF__

本文作者😎
本文链接https://www.cnblogs.com/dongye95/p/15980115.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   dongye95  阅读(123)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示