1.spring框架常用注解
1、@Autowired
@Autowired顾名思义,就是自动装配,其作用是为了消除代码Java代码里面的getter/setter与bean属性中的property。
@Autowired默认按类型匹配的方式,在容器查找匹配的Bean,当有且仅有一个匹配的Bean时,Spring将其注入@Autowired标注的变量中。
@Autowired注解的意思就是,当Spring发现@Autowired注解时,将自动在代码上下文中找到和其匹配(默认是类型匹配)的Bean,并自动注入到相应的地方去。
有一个细节性的问题是,假如bean里面有两个property,主类里面又去掉了属性的getter/setter并使用@Autowired注解标注这两个属性那会怎么样?
答案是Spring会按照xml优先的原则去主类中寻找这两个属性的getter/setter,导致的结果就是初始化bean报错。
因为,@Autowired注解要去寻找的是一个Bean,Tiger和Monkey的Bean定义都给去掉了,自然就不是一个Bean了,Spring容器找不到也很好理解。
那么,如果属性找不到我不想让Spring容器抛出异常,而就是显示null,可以吗?
可以的,其实异常信息里面也给出了提示了,就是将@Autowired注解的required属性设置为false即可: @Autowired(required=false)
此时,找不到tiger、monkey两个属性,Spring容器不再抛出异常而是认为这两个属性为null。
2、@Qualifier(指定注入Bean的名称)
如果容器中有一个以上匹配的Bean,则可以通过@Qualifier注解限定Bean的名称。
出现这种情况通常有两种解决办法:
(1)、在配置文件中删除其中一个实现类,Spring会自动去base-package下寻找Car接口的实现类,发现Car接口只有一个实现类,便会直接引用这个实现类。
(2)、实现类就是有多个该怎么办?此时可以使用**@Qualifier注解来指定Bean的名称**:
@Autowired
@Qualifier("bmwCar")
private ICar car;
3、@Resource
@Resource注解与@Autowired注解作用非常相似。
@Resource(name="tiger")
private Tiger tiger;
@Resource(type=Monkey.class)
private Monkey monkey;
@Resource的装配顺序:
(1)、@Resource后面没有任何内容,默认通过name属性去匹配bean,找不到再按type去匹配
(2)、指定了name或者type则根据指定的类型去匹配bean
(3)、指定了name和type则根据指定的name和type去匹配bean,任何一个不匹配都将报错
区分一下@Autowired和@Resource两个注解的区别:
(1)、@Autowired默认按照byType方式进行bean匹配,@Resource默认按照byName方式进行bean匹配
(2)、@Autowired是Spring的注解,@Resource是J2EE的注解,这个看一下导入注解的时候这两个注解的包名就一清二楚了
Spring属于第三方的,J2EE是Java自己的东西,因此,建议使用@Resource注解,以减少代码和Spring之间的耦合。
4、@Service
package com.spring.model;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
@Service("Zoo")
@Scope("prototype")
public class Zoo {
@Autowired
private Tiger tiger;
@Autowired
private Monkey monkey;
public String toString(){
return tiger + "\n" + monkey;
}
}
Zoo.java在Spring容器中存在的形式就是"zoo",即可以通过ApplicationContext的getBean(“zoo”) 方法来得到Zoo.java。
@Service注解,其实做了两件事情:
(1)、声明Zoo.java是一个bean,这点很重要,因为Zoo.java是一个bean,其他的类才可以使用@Autowired将Zoo作为一个成员变量自动注入。
(2)、Zoo.java在bean中的id是"zoo",即类名且首字母小写。
使用注解来构造IOC容器
用注解来向Spring容器注册Bean。需要在applicationContext.xml中注册
<context:component-scan base-package=”pagkage1[,pagkage2,…,pagkageN]”/>。
<context:component-scan base-package="cn.gacl.java"/>
表明cn.gacl.java包及其子包中,如果某个类的头上带有特定的注解**【@Component/@Repository/@Service/@Controller】**,就会将这个对象作为Bean注册进Spring容器。
5.AOP中的注解
(1)@Aspect(切面):通常是一个类,里面可以定义切入点和通知
(4)@Pointcut(切入点):就是带有通知的连接点,在程序中主要体现为书写切入点表达式
(3)JointPoint(连接点):程序执行过程中明确的点,一般是方法的调用
(4)Advice(通知):AOP在特定的切入点上执行的增强处理,有@before,@after,@afterReturning,@afterThrowing,@around
(5)AOP代理:AOP框架创建的对象,代理就是目标对象的加强。Spring中的AOP代理可以使JDK动态代理,也可以是CGLIB代理,前者基于接口,后者基于子类
(注意:@Around注解描述的方法其规范要素:
1)返回值类型为Object (用于封装目标方法的执行结果)
2)参数类型ProceedingJoinPoint (用于封装要执行的目标方法信息)
3)抛出的异常为Throwable (用于封装执行目标方法时抛出的异常)
4)在@Around注解描述的方法内部,可以手动调用目标方法
1、@Component
@Component是所有受Spring 管理组件的通用形式,@Component注解可以放在类的头上,@Component不推荐使用。
2、@Controller
@Controller对应表现层的Bean,也就是Action。
使用@Controller注解标识UserAction之后,就表示要把UserAction交给Spring容器管理,在Spring容器中会存在一个名字为"userAction"的action,这个名字是根据UserAction类名来取的。
注意:如果@Controller不指定其value【@Controller】,则默认的bean名字为这个类的类名首字母小写,如果指定value【@Controller(value=“UserAction”)】或者【@Controller(“UserAction”)】,则使用value作为bean的名字。
@Controller
@Scope("prototype")
public class UserAction extends BaseAction<User>{
这里的UserAction还使用了@Scope注解,@Scope(“prototype”)表示将Action的范围声明为原型,可以利用容器的scope="prototype"来保证每一个请求有一个单独的Action来处理,避免struts中Action的线程安全问题。
spring 默认scope 是单例模式(scope=“singleton”),这样只会创建一个Action对象,每次访问都是同一Action对象,数据不安全,
struts2 是要求每次次访问都对应不同的Action,scope=“prototype” 可以保证当有请求的时候都创建一个Action对象。
3、@Service
@Service对应的是业务层Bean
@Service(“userService”)注解是告诉Spring,当Spring要创建UserServiceImpl的的实例时,bean的名字必须叫做"userService",这样当Action需要使用UserServiceImpl的的实例时,就可以由Spring创建好的"userService",然后注入给Action:在Action只需要声明一个名字叫"userService"的变量来接收由Spring注入的"userService"即可。
4、@ Repository
@Repository对应数据访问层Bean
@Repository(value=“userDao”)注解是告诉Spring,让Spring创建一个名字叫"userDao"的UserDaoImpl实例。
当Service需要使用Spring创建的名字叫"userDao"的UserDaoImpl实例时,就可以使用@Resource(name = “userDao”)注解告诉Spring,Spring把创建好的userDao注入给Service即可。
================================================
@Configuration把一个类作为一个IOC容器,它的某个方法头上如果注册了@Bean,就会作为这个Spring容器中的Bean。
@Scope注解 作用域
@Lazy(true) 表示延迟初始化
@Service用于标注业务层组件
@Controller用于标注控制层组件
@Repository用于标注数据访问组件,即DAO组件。
@Component泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注。
@Scope用于指定scope作用域的(用在类上)
@PostConstruct用于指定初始化方法(用在方法上)
@PreDestory用于指定销毁方法(用在方法上)
@DependsOn:定义Bean初始化及销毁时的顺序
@Primary:自动装配时当出现多个Bean候选者时,被注解为@Primary的Bean将作为首选者,否则将抛出异常
@Autowired 默认按类型装配,如果我们想使用按名称装配,可以结合@Qualifier注解一起使用。如下:
@Autowired @Qualifier(“personDaoBean”) 存在多个实例配合使用
@Resource默认按名称装配,当找不到与名称匹配的bean才会按类型装配。
@PostConstruct 初始化注解
@PreDestroy 摧毁注解 默认 单例 启动就加载
@Async异步方法调用
2.SpringMVC常用注解及其介绍
接口入参
Controller 接口参数注解详情
1.@Controller
在SpringMVC中,controller主要负责处理前端控制器(DispatcherServlet )发过来的请求,经过业务逻辑层处理之后封装层一个model,并将其返回给view进行展示。@controller注解通常用于类上,如果结合Thymeleaf模板使用的话,会返回一个页面。如果是前后端分离的项目,则使用@RestController,表明返回的是json格式数据。
2.@RestController
在介绍RestController之前,我们先点进去看一下:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Controller
@ResponseBody
public @interface RestController {
@AliasFor(
annotation = Controller.class
)
String value() default "";
}
可以发现,@RestController注解里面包含了@Controller注解和@ResponseBody注解,@ResponseBody 注解是将返回的数据结构转换为 JSON 格式,所以说可以这么理解:@RestController = @Controller + @ResponseBody ,省了很多事,我们使用 @RestController 之后就不需要再使用 @Controller 了。
3.@RequestMapping(提供路由信息,负责URL到Controller中的具体函数的映射)
@RequestMapping 是一个用来处理请求地址映射的注解,它可以用于类上,也可以用于方法上。用于类上的注解会将一个特定请求或者请求模式映射到一个控制器之上,表示类中的所有响应请求的方法都是以该地址作为父路径;方法的级别上注解表示进一步指定到处理方法的映射关系。
该注解有6个属性,一般在项目中比较常用的有三个属性:value、method 和 produces。
value 属性:指定请求的实际地址,value 可以省略不写;
method 属性:指定请求的类型,主要有 GET、PUT、POST、DELETE,默认为 GET。
produces 属性:指定返回内容类型,如 produces = “application/json; charset=UTF-8”。
@RequestMapping 注解比较简单,举个例子:
@RestController
@RequestMapping(value = "/test", produces = "application/json; charset=UTF-8")
public class TestController {
@RequestMapping(value = "/get", method = RequestMethod.GET)
public String testGet() {
return "success";
}
}
这个很简单,启动项目在浏览器中输入 localhost:8080/test/get 测试一下即可。
四种不同的请求方式,都有相应的注解。不用每次在 @RequestMapping 注解中加 method 属性来指定,上面的 GET 方式请求可以直接使用 @GetMapping(“/get”) 注解,效果一样。相应地,PUT 方式、POST 方式和 DELETE 方式对应的注解分别为 @PutMapping、@PostMapping 和 DeleteMapping。
4.@PathVariable
@PathVariable 注解主要用来获取 URL 参数,Spring Boot 支持 Restfull 风格的 URL,比如一个 GET 请求携带一个参数 id,我们将 id 作为参数接收,可以使用 @PathVariable 注解。如下:
@GetMapping("/user/{id}")
public String testPathVariable(@PathVariable Integer id) {
System.out.println("获取到的id为:" + id);
return "success";
}
这里需要注意一个问题,如果想要 URL 中占位符中的 id 值直接赋值到参数 id 中,需要保证 URL 中的参数和方法接收参数一致,否则将无法接收。如果不一致的话,其实也可以解决,需要用 @PathVariable 中的 value 属性来指定对应关系。如下:
@RequestMapping("/user/{idd}")
public String testPathVariable(@PathVariable(value = "idd") Integer id) {
System.out.println("获取到的id为:" + id);
return "success";
}
对于访问的 URL,占位符的位置可以在任何位置,不一定非要在最后,比如这样也行:/xxx/{id}/user。另外,URL 也支持多个占位符,方法参数使用同样数量的参数来接收,原理和一个参数是一样的,例如:
@GetMapping("/user/{idd}/{name}")
public String testPathVariable(@PathVariable(value = "idd") Integer id, @PathVariable String name) {
System.out.println("获取到的id为:" + id);
System.out.println("获取到的name为:" + name);
return "success";
}
运行项目,在浏览器中请求:localhost:8080/test/user/2/zhangsan, 可以看到控制台输出如下信息:
获取到的id为:2
获取到的name为:zhangsan
所以它支持多个参数的接收。同样地,如果 URL 中的参数和方法中的参数名称不同的话,也需要使用 value 属性来绑定两个参数。
5.@RequestParam
@RequestParam 注解顾名思义,也是获取请求参数的,上面我们介绍了 @PathValiable 注解也是获取请求参数的,那么 @RequestParam 和 @PathVariable 有什么不同呢?
@PathValiable 是从 URL 模板中获取参数值, 即这种风格的 URL:
http://localhost:8080/user/{id}
@RequestParam 是从 Request 里获取参数值,即这种风格的 URL:
http://localhost:8080/user?id=1
对于@RequestParam 注解代码测试如下:
@GetMapping("/user") //注意这里请求路径的写法是不一样的
public String testRequestParam(@RequestParam Integer id) {
System.out.println("获取到的id为:" + id);
return "success";
}
同样的@RequestParam 注解的value 属性是比较常用的,其作用和@PathVariable注解的value属性是一样的。此外@RequestParam 注解还有两个属性比较常用:
required 属性:true 表示该参数必须要传,否则就会报 404 错误,false 表示可有可无。
defaultValue 属性:默认值,表示请求中没有同名参数时的默认值。
从 URL 中可以看出,@RequestParam 注解用于 GET 请求上时,接收拼接在 URL 中的参数。除此之外,该注解还可以用于 POST 请求,接收前端表单提交的参数,假如前端通过表单提交 username 和 password 两个参数,那我们可以使用 @RequestParam 来接收,用法和上面一样。
6.@RequestBody
1.RequestBody注解用于接收前端传来的实体
注解用于接收前端传来的实体,接收参数也是对应的实体,比如前端通过 JSON 提交传来两个参数 username 和 password,此时我们需要在后端封装一个实体来接收。在传递的参数比较多的情况下,使用 @RequestBody 接收会非常方便。例如:
定义User类代码此处省略…
@PostMapping("/user")
public String testRequestBody(@RequestBody User user) {
System.out.println("获取到的username为:" + user.getUsername());
System.out.println("获取到的password为:" + user.getPassword());
return "success";
}
可以看出,@RequestBody 注解用于 POST 请求上,接收 JSON 实体参数。它和上面我们介绍的表单提交有点类似,只不过参数的格式不同,一个是 JSON 实体,一个是表单提交。在实际项目中根据具体场景和需要使用对应的注解即可。
2.接收前台参数时,@requestBody 用与不用的区别
使用@RequestBody注解时,是用于接收Content-Type为application/json类型的请求,数据类型是JSON:{“aaa”:“111”,“bbb”:“222”}
不使用@RequestBody注解时,可以接收Content-Type为application/x-www-form-urlencoded类型的请求所提交的数据,数据格式:aaa=111&bbb=222 ,form表单提交以及jQuery的.post()方法所发送的请求就是这种类型。
7.@PropertySource 注解读取指定文件并将属性注入到配置类(动态导入资源文件)
@PropertySource是Spring boot为了方便引入properties配置文件提供的一个注解,可以标注在SpringBoot的启动类上,还可以标注在配置类(使用@Configuration标注的类)上。
例如:@PropertySource(value = {“classpath:/properties/redis.properties”}),将classpath下的redis.properties,注入到Spring环境中,使用@Value(“${key}”)取值。
1.1指定配置文件为属性赋值
说明: 由于YML配置文件中的数据一般都是系统级别的数据,所以一般的业务数据都会写到properties的配置文件中.
1.2 编辑RedisController
package com.jt.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
//动态获取ip和端口数据
//@ResponseBody 作用1: 将对象转化为JSON 作用2: 如果返回值是String类型,则返回字符串本身
// 作用3: 一般客户端发起ajax请求时,采用该注解返回数据, 将不会执行视图解析器操作
@RestController
//动态的导入pro配置文件,交给spring容器进行加载.
@PropertySource("classpath:/properties/redis.properties")
public class RedisController {
@Value("${redis.host}") //spel表达式
private String host; // = "192.168.126.130"; private String host; // = "192.168.126.130";
@Value("${redis.port}")
private Integer port; // = 6379;
@Value("${pro.redis.host}")
private String proHost;
@Value("${pro.redis.port}")
private Integer proPort;
//指定properties文件进行赋值操作.
@RequestMapping("/getMsg")
public String getMsg(){
//从yml配置文件中动态获取
return host + ":" + port;
}
@RequestMapping("/getPro")
public String getPro(){
return proHost + ":" + proPort;
}
}
1.3 环境切换
在实际开发中,经常会有多种环境配置,例如开发环境、测试环境、生产环境等。在不同的环境下,配置有可能是不一样的,比如接口地址、数据库连接配置等。为了避免频繁的修改配置文件,我们可以通过配置实现动态切换。
yml文件中多个环境可以用三横杆来分割: —
每个环境定义不同名字,#第一份配置文件,用来切换指定环境
#以下为配置环境的切换
spring:
profiles:
active: prod
---
spring:
profiles: prod #表示生产环境
#tomcat具体配置
server:
port: 80
servlet:
context-path: / #表示路径
---
spring:
profiles: test #表示测试环境
#tomcat具体配置
server:
port: 81
servlet:
context-path: /
---
spring:
profiles: dev #表示开发环境
#tomcat具体配置
server:
port: 8088
servlet:
context-path: /jt
3.SpringBoot注解
4.Lombok中的注解
1.@Data 注意,重写的toString方法一般只会添加自己的属性信息,父级的属性不会添加
2.@Accessors(chain=true) 链式加载
@EqualsAndHashCode 实现equals()方法和hashCode()方法 @ToString:实现toString()方法
@Data 注解在类上;提供类所有属性的 getting 和 setting 方法,此外还提供了equals、canEqual、hashCode、toString 方法
@Setter 注解在属性上;为属性提供 setting 方法
@Getter 注解在属性上;为属性提供 getting 方法
@Log4j 注解在类上;为类提供一个 属性名为log 的 log4j 日志对象
@NoArgsConstructor 注解在类上;为类提供一个无参的构造方法
@AllArgsConstructor 注解在类上;为类提供一个全参的构造方法
@Cleanup 关闭流
@Synchronized:对象同步
@SneakyThrows:抛出异常
@ConfigurationProperties 把同类的配置信息自动封装成实体类:可以使属性文件中的值和类中的属性对应起来;使用方式有两种 : 1、在类上使用该注解 2、在工厂方法上使用该注解 (@bean)
注意:在springBoot中除了使用这个注解读取属性文件值外,还可以用@Value注解。
5.Dubbo框架的注解
1.@Reference : 给接口注入对象.对象信息从注册中心获取.利用rpc调用
@Reference(loadbalance = “random”) //默认策略 负载均衡随机策略
@Reference(loadbalance = “roundrobin”) //轮询方式
@Reference(loadbalance = “consistenthash”) //一致性hash 消费者绑定服务器提供者
@Reference(loadbalance = “leastactive”) //挑选当前负载小的服务器进行访问
@Reference(timeout = 3000,check = false) //设置调用超时时间为3秒,check为如果在注册中心没有找到这个对象,也允许先启动不报错
6.SpringCloud的注解
(1).@EnableEurekaServer:开启Eureka注册中心功能
.在主程序类名上添加注解 @EnableEurekaServer ,表示 将此项目作为SpringCloud中的注册中心
(2).@EnableDiscoveryClient :将自己自动注册到注册中心
(3).@LoadBalanced:给容器中注入一个RestTemplate并使用Ribbon进行负载均衡调用
@LoadBalanced //负载均衡
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
(4).@EnableFeignClients:开启Feign功能;通过动态代理的方式实现负载均衡调用其他服务
/**
* 调用指定服务名称 “user-service” 的 @GetMapping("/movie") 映射方法
* 这个方法声明与用户服务端Controller映射的方法声明一致即可。
*/
@FeignClient(value="user-service") //与被调用端的服务名称一致
public interface MovieServiceFeign {
@GetMapping("/movie")
public Movie getNewMovie(); //与被调用服务端的映射方法一致
}
(5).开启断路保护功能@EnableCircuitBreaker
通过@HystrixCommand(fallbackMethod=“xxx”)来指定出错时调用xx方法
/*使用Hystrix进行服务的熔断
* 1)、引入Hystrix的starter
* 2)、开启xxx功能 :@EnableCircuitBreaker
* 3)、@FeignClient(value="user-service",fallback=指定这个接口的异常处理类(异常处理类必须实现这个接口))
*/
@FeignClient(value="user-service",fallback=MovieFeignExceptionHandlerService.class)
(6)开启可视化监控功能
@EnableHystrixDashboard
@EnableHystrix
7、jackson常用注解汇总
提起 jackson,在日常使用中,由于涉及到各种序列化和反序列化的处理,就不能不提 注解,了解注解的常用方式可以极大地方便我们处理序列化,今天分享一些在使用 jackson 中涉及到的注解。
目录:
- 1.@JsonAlias - 字段别名,反序列化
- 2.@JsonIgnore -序列化时忽略字段
- 3.@JsonFormat - 设置格式,如日期时间等
7.1、@JsonAlias
作用:
主要运用于参数映射。
如:将admin_id 的值赋予adminId
使用场景:
接收第三方参数,并对参数进行驼峰化或别名。
如:
1、是在反序列化的时候可以让Bean的属性接收多个json字段的名称。
@JsonAlias({"admin_id","id"})
private Long adminId;
此时:可以将响应/请求参数里的admin_id、id、adminId的值赋予对象adminId上。
参数为:
{
"id": 789,
"adminId":123,
"admin_id":456
}
优先级为:取最下面的参数,这里是取admin_id
2.当有两个属性用到了id时:(尽量避免重复使用,难以维护)
@JsonAlias({"admin_id","id"})
private Long adminId;
@JsonProperty("name")
private String adminName;
@JsonAlias("id")
private String adminAddress;
参数为:
{
"adminId": 123,
"id": 789,
"admin_name": "qqq",
"name": "zzz",
"admin_address": "aaa"
}
打印结果为:
{"adminAddress":"789","adminId":123,"adminName":"zzz"}
7.2、@JsonIgnore
作用:
在json序列化时将java bean中的一些属性忽略掉,序列化和反序列化都受影响。
一般标记在属性或者方法上,在返回的json数据就不包含该属性
使用场景:
将一个User序列化成Json数据并返回给前台,当我们在User的password和email属性上添加@JsonIgnore注解时,即使后台给这两个属性赋值了,返回前台的Json也不包含它们。
注意:当前端以json格式向后台传password的值,且后台是以实体User接收时,@JsonIgnore同样会忽略,即不接收password字段的值。若想避免此类情况,建议使用form表单的形式提交参数,而非json格式。
public class User {
private String name;
private String age;
private String sex;
@JsonIgnore //添加JsonIgnore注解,返回时被忽略
private String password;
@JsonIgnore //添加JsonIgnore注解,返回时被忽略
private String email;
public User() {}
}
7.3、@JsonInclude
作用:
@JsonInclude注解的作用是指定实体类在序列化时的策略,在实体类序列化成json的时候在某些策略下,加了该注解的字段不去序列化该字段。
使用场景: 一个接口需要过滤掉返回值为null的字段,即值为null的字段不返回,可以在实体类中增加如下注解。1、将该标记放在属性上,如果该属性为NULL则不参与序列化 。2、如果放在类上边,那对这个类的全部属性起作用
注解中的规则:
- ALWAYS // 默认策略,任何情况都执行序列化, 即默认返回全部字段
- NON_NULL // 非空 属性为NULL 不序列化 ,即值为null的字段不返回
- NON_ABSENT // null的不会序列化,但如果类型是AtomicReference,依然会被序列化
- NON_EMPTY // null、集合数组等没有内容、空字符串等,都不会被序列化
- NON_DEFAULT // 如果字段是默认值,就不会被序列化
- CUSTOM // 此时要指定valueFilter属性,该属性对应一个类,用来自定义判断被JsonInclude修饰的字段是否序列化
- USE_DEFAULTS //当JsonInclude在类和属性上都有时,优先使用属性上的注解,此时如果在序列化的get方法上使用了JsonInclude,并设置为USE_DEFAULTS,就会使用类注解的设置
// 在类上加入@JsonInclude(value = JsonInclude.Include.NON_NULL),表明该类为NULL的字段不参加序列化!
@JsonInclude(JsonInclude.Include.NON_NULL)
public class User {
private String name;
private String age;
private String sex;
private String password;
private String email;
//null、空集合都不参加序列化。类和属性同时加,属性优先。
@JsonInclude(value = JsonInclude.Include.NON_EMPTY)
private List<String> type;
}
7.4、@JsonFormat
注:项目中有遇到@JsonFormat注解不生效,后替换@JSONField成功(具体原因后续有空再排查)
作用:
- Date和String的相互转化
- 时差调整
使用场景:
- 一般后台传值给前台时
// Date和String的自动转化
import com.fasterxml.jackson.annotation.JsonFormat;
/**
* 后台返给前台时, 日期自动格式化
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date birth;
- 在我们中国来讲和我们的北京时间,会相差8个小时,因为我们是东八区(北京时间)。所以我们在格式化的时候要指定时区(timezone )
//指定时区
/**更新时间 用户可以点击更新,保存最新更新的时间。**/
@JsonFormat(pattern="yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
private Date updateTime;
@JsonFormat 和 @DateTimeFormat 区别
1、说到@JsonFormat,这里不得不提下@DateTimeFormat
- @JsonFormat: 用于序列化和反序列化 JSON 数据中的日期时间字段,确保数据从后端到前端的一致性
- @DateTimeFormat: 用于解析和格式化 Web 请求中的日期时间参数(一般只对URL 参数有效,如果是请求体的参数需要注意),确保数据从前端到后端的正确处理
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date time;
8、@JSONField
Fastjson 是阿里巴巴开源的一个高性能 JSON 处理库,旨在提供快速的 JSON
序列化和反序列化功能。
8.1 添加依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.66</version>
</dependency>
8.2 属性介绍
package com.alibaba.fastjson.annotation;
public @interface JSONField {
// 配置序列化和反序列化的顺序,1.1.42版本之后才⽀持
int ordinal() default 0;
// 指定字段的名称
String name() default "";
// 指定字段的格式,对⽇期格式有⽤
String format() default "";
// 是否序列化
boolean serialize() default true;
// 是否反序列化
boolean deserialize() default true;
}
- 修改属性名 (name)
在实际项目中,后端开发人员经常会遇到前端和后端字段命名不一致的情况。使用@JSONField注解中的name属性,可以轻松解决这个问题。例如,前端可能使用user_name来表示用户名,而后端可能使用username。通过@JSONField注解,可以在不修改后端代码的情况下,轻松实现字段名称的映射。
public class User {
@JSONField(name = "user_name")
private String username;
}
- 忽略字段 (serialize 和 deserialize)
在涉及用户数据的应用中,保护敏感信息(如密码、身份证号等)非常重要。通过@JSONField注解中的serialize属性,可以避免敏感字段被暴露在JSON响应中。例如,可以设置serialize = false,确保密码字段不会被序列化。我们也可以使用deserialize = false来指定字段在反序列化时被忽略。
public class User {
@JSONField(serialize = false)
private String password;
}
- 日期格式化 (format)
前后端入参、返参需要对日期格式化时,用在Date属性上,自动格式化日期
birthDate字段在序列化为JSON时会被格式化为yyyy-MM-dd的字符串格式。例如,2024-08-26。
反之,当从JSON字符串反序列化为Java对象时,Fastjson也会根据这个格式来解析日期字符串。
public class User {
@JSONField(format = "yyyy-MM-dd")
private Date birthDate;
}
9、@Validated校验请求参数
1.@Validated和@Valid的区别和使用注意事项
1.1来源
@Validated :是Spring框架特有的注解,属于Spring的一部分,也是JSR 303的一个变种。它提供了一些 @Valid 所没有的额外功能,比如分组验证。
@Valid:Java EE提供的标准注解,它是JSR 303规范的一部分,主要用于Hibernate Validation等场景。
1.2注解位置
@Validated : 用在类、方法和方法参数上,但不能用于成员属性。
@Valid:可以用在方法、构造函数、方法参数和成员属性上。
1.3是否支持分组
@Validated :支持分组验证,可以更细致地控制验证过程。此外,由于它是Spring专有的,因此可以更好地与Spring的其他功能(如Spring的依赖注入)集成。
@Valid:主要支持标准的Bean验证功能,不支持分组验证。 嵌套验证
1.4是否支持嵌套校验
@Validated :不支持嵌套验证。
@Valid:支持嵌套验证,可以嵌套验证对象内部的属性。
2.集成依赖
以下依赖推荐使用spring-boot-starter-validation,可以跟springBoot更好的集成
<!--第一种:valid依赖-->
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>版本号</version>
</dependency>
<!--第二种:集成于web依赖中(注意版本号)-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>xxxx.RELEASE</version>
</dependency>
<!-- 第三种:springboot的validation-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
3.@Valid常用注解
(1)嵌套校验
在被检验的字段上添加 @Valid 注解就可以实现嵌套检验
@Data
public class User3 {
@Valid
List<User2> user2List;
@Valid
private User2 user2;
}
@Data
class User2 {
@NotBlank(message = "用户名不能为空!")
private String username;
}
4.@Validated常用注解
(1)常用校验
public R save(@Validated @RequestBody User user){
}
@Data
public class User {
// @NotNull:验证属性不能为null。
@NotNull( message= "用户名不能为null")
private String username;
// @NotBlank:验证字符串属性不能为空且长度必须大于0。
@NotBlank(message = "用户名不能为空且长度必须大于0")
private String username1;
// @Size:验证字符串属性的长度范围。
@Size(min = 6, max = 20,message = "密码最小6位,最长20位")
private String password;
// @Min:验证数字属性的最小、大值。
@Min(value = 18,message = "年龄最小18岁")
@Max(value = 100,message = "年龄最大100岁")
private int age;
// @DecimalMin:验证数字属性的最小、大值(包括小数)。
@DecimalMin("0.01")
@DecimalMax("1000.00")
private BigDecimal price;
// @Email:验证字符串属性是否符合Email格式。
@Email(message = "必须符合Email格式")
private String email;
@URL(message = "logo必须是一个合法的url地址")
private String logo;
@Pattern(regexp = "[A-Za-z0-9]+", message = "首字母必须在a-z或者A-Z之间")
private String firstLetter;
//分组校验
@Null(message = "id不为空",groups = AddGroup.class)
@NotNull(message = "id不能为空",groups = UpdateGroup.class)
private String id;
//自定义注解校验1,
@ListValue(insValue= {0,1,2,99},message = "类型不符合")
private Integer type;
//自定义注解校验2,
@ListValue(strValue= {"启用","禁用"},message = "状态类型不符合")
private String type1;
}
(2)分组校验
//需要校验的参数,如加了分组校验,其余未在分组中的不会再校验。如上图只会校验id,其余不会校验
public R save(@Validated(value = UpdateGroup.class) @RequestBody User user){
}
//添加分组
public interface AddGroup {
}
//修改分组
public interface UpdateGroup {
}
(3)自定义的校验注解
@Documented
//关联自定义的校验器
@Constraint(validatedBy = {ListValueIntConstraintValidator.class, ListValueStrConstraintValidator.class} /*【可以指定多个不同的校验器,适配不同类型的校验 】*/)
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
public @interface ListValue {
String message() default "{com.atguigu.common.valid.ListValue.message}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
int[] intValue() default {};
String[] strValue() default {};
}
(4)自定义的校验器
//自定义校验器1
public class ListValueIntConstraintValidator implements ConstraintValidator<ListValue, Integer> {
private Set<Object> set = new HashSet<Object>();
/**
* 初始化
*
* @param constraintAnnotation
*/
@Override
public void initialize(ListValue constraintAnnotation) {
ConstraintValidator.super.initialize(constraintAnnotation);
int[] values = constraintAnnotation.intValue();
if (values == null) {
return;
}
for (int value : values) {
set.add(value);
}
}
/**
* 校验规则
*
* @param value
* @param constraintValidatorContext
* @return
*/
@Override
public boolean isValid(Integer value, ConstraintValidatorContext constraintValidatorContext) {
return set.contains(value);
}
}
//自定义校验器2
public class ListValueStrConstraintValidator implements ConstraintValidator<ListValue, String> {
private Set<Object> set = new HashSet<Object>();
/**
* 初始化
*
* @param constraintAnnotation
*/
@Override
public void initialize(ListValue constraintAnnotation) {
ConstraintValidator.super.initialize(constraintAnnotation);
String[] str = constraintAnnotation.strValue();
if (str == null) {
return;
}
for (String value : str) {
set.add(value);
}
}
/**
* 校验规则
*
* @param value
* @param constraintValidatorContext
* @return
*/
@Override
public boolean isValid(String value, ConstraintValidatorContext constraintValidatorContext) {
return set.contains(value);
}
}