Web:
@Controller:组合注解(组合了@Component 注解),应用在 MVC 层(控制层)。
@RestController:该注解为一个组合注解,相当于@Controller 和@ResponseBody 的组合,注解在类上,意味着,该 Controller 的所有方法都默认加上了@ResponseBody。
@RequestMapping:用于映射 Web 请求,包括访问路径和参数。如果是 Restful 风格接口,还可以根据请求类型使用不同的注解:
@GetMapping
@PostMapping
@PutMapping
@DeleteMapping
@ResponseBody:支持将返回值放在 response 内,而不是一个页面,通常用户返回 json 数据。
@RequestBody:允许 request 的参数在 request 体中,而不是在直接连接在地址后面。
@PathVariable:用于接收路径参数,比如 @RequestMapping(“/hello/{name}”)申明的路径,将注解放在参数中前,即可获取该值,通常作为 Restful 的接口实现方法。
@RestController:该注解为一个组合注解,相当于@Controller 和@ResponseBody 的组合,注解在类上,意味着,该 Controller 的所有方法都默认加上了@ResponseBody。
容器:
@Component:表示一个带注释的类是一个“组件”,成为 Spring 管理的 Bean。当使用基于注解的配置和类路径扫描时,这些类被视为自动检测的候选对象。同时@Component 还是一个元注解。
@Service:组合注解(组合了@Component 注解),应用在 service 层(业务逻辑层)。
@Repository:组合注解(组合了@Component 注解),应用在 dao 层(数据访问层)。
@Autowired:Spring 提供的工具(由 Spring 的依赖注入工具(BeanPostProcessor、BeanFactoryPostProcessor)自动注入)。
@Qualifier:该注解通常跟 @Autowired 一起使用,当想对注入的过程做更多的控制,@Qualifier 可帮助配置,比如两个以上相同类型的 Bean 时 Spring 无法抉择,用到此注解
@Configuration:声明当前类是一个配置类(相当于一个 Spring 配置的 xml 文件)
@Value:可用在字段,构造器参数跟方法参数,指定一个默认值,支持 #{} 跟 ${} 两个方式。一般将 SpringbBoot 中的 application.properties 配置的属性值赋值给变量。
@Bean:注解在方法上,声明当前方法的返回值为一个 Bean。返回的 Bean 对应的类中可以定义 init()方法和 destroy()方法,然后在@Bean(initMethod=”init”,destroyMethod=”destroy”)定义,在构造之后执行 init,在销毁之前执行 destroy。
@Scope:定义我们采用什么模式去创建 Bean(方法上,得有@Bean) 其设置类型包括:Singleton 、Prototype、Request 、 Session、GlobalSession。
AOP:
@Aspect:声明一个切面(类上) 使用@After、@Before、@Around 定义建言(advice),可直接将拦截规则(切点)作为参数。
@After :在方法执行之后执行(方法上)。
@Before: 在方法执行之前执行(方法上)。
@Around: 在方法执行之前与之后执行(方法上)。
@PointCut: 声明切点 在 java 配置类中使用@EnableAspectJAutoProxy 注解开启 Spring 对 AspectJ 代理的支持(类上)。
事务:
@Transactional:在要开启事务的方法上使用@Transactional 注解,即可声明式开启事务。
其他总结
@ConditionalOnProperty: 控制配置类@Configuration是否生效.(实现是通过havingValue与配置文件中的值对比,返回为true则配置类生效,反之失效.)
- 配置类代码:
/**
* @prefix prefix为配置文件中的前缀,
* @name name为配置的名字
* @havingValue 是与配置的值对比值,当两个值相同返回true,配置类生效.
*/
@Configuration
@ConditionalOnProperty(prefix = "filter",name = "loginFilter",havingValue = "true")
public class FilterConfig {
@Bean
public FilterRegistrationBean getFilterRegistration() {
FilterRegistrationBean filterRegistration = new FilterRegistrationBean(new LoginFilter());
filterRegistration.addUrlPatterns("/*");
return filterRegistration;
}
}
- 配置文件中的代码
filter.loginFilter=true
@ConditionalOnClass注解与@ConditionalOnProperty
@ConditionalOnClass注解作用: 某个class位于类路径上,才会实例化一个Bean。即判断当前classpath下是否存在指定类,若是则将当前的配置装载入spring容器
@ConditionalOnProperty:控制@Configuration是否生效
Spring提供的Condition
除了自己自定义Condition之外,Spring还提供了很多Condition给我们用
@ConditionalOnBean 仅仅在当前上下文中存在某个对象时,才会实例化一个Bean
@ConditionalOnClass 某个class位于类路径上,才会实例化一个Bea
@ConditionalOnExpression 当表达式为true的时候,才会实例化一个Bean。
比如:
@ConditionalOnExpression("true")
@ConditionalOnExpression("${my.controller.enabled:false}")
4. @ConditionalOnMissingBean 仅仅在当前上下文中不存在某个对象时,才会实例化一个Bean
5. @ConditionalOnMissingClass 某个class类路径上不存在的时候,才会实例化一个Bean
6. @ConditionalOnNotWebApplication 不是web应用
(8)题外话:怎么在Condition中获取application.properties的配置项
在实际开发中,我们的条件可能保存在application.properties中,那么怎么在Condition中获取呢,这个很简单,主要通过ConditionContext进行获取,具体代码如下:
Java代码
String port = context.getEnvironment().getProperty("server.port");
System.out.println(port);
@Primary: 使用@Autowired时,当多个候选者有资格自动装配单值依赖项时,应优先考虑注解Bean。
@InitBinder: Spring可以自动封装Bean(基本数据类型(int,String等)),如果传递过来的是特殊对象,则需要手动进行封装。
Spring提供了@initBinder(初始化绑定封装)注解和WebDataBinder工具。用户只需要向WebDataBinder注册自己需要的类型的属性编辑器即可。
/*
前台传递过来的String类型时间,通过下面的初始化绑定,转换成Date类型
*/
@initBinder
public void initBinder(WebDataBinder binder){
SimpleDateFormate sdf=new SimpleDateFormate("yyyy-MM-dd HH:mm");
binder.registerCustomEditor(Date.class,new CustomDateEditor(sdf,true));//true表示允许空值,false不允许
}
lombok常用注解
@Builder: 自动生成流式 set 值写法,从此之后再也不用写一堆 setter 了
@Data: 加了这个注解,等于同时加了以下注解
@Getter/@Setter
@ToString
@EqualsAndHashCode
@RequiredArgsConstructor
@NoArgsConstructor, @AllArgsConstructor, @RequiredArgsConstructor
这三个都是在自动生成该类的构造器,差别只在生成的构造器的参数不一样而已
- @NoArgsConstructor : 生成一个没有参数的构造器
- @AllArgsConstructor : 生成一个包含所有参数的构造器
- @RequiredArgsConstructor : 生成一个包含 final 修饰词的变量参数 的构造器, 如果所有的变量都没有用 final 修饰的 话,那就会生成一个没有参数的构造器
注意一个 Java 的小坑
@AllArgsConstructor 时,一定要补上 @NoArgsConstrcutor
(当我们没有指定构造器时,Java 编译器会帮我们自动生成一个没有任何参数的构造器给该类,但是如果我们自己写了构造器之后,Java 就不会自动帮我们补上那个无参数的构造器了)
@ConditionalOnMissingBean,它是修饰bean的一个注解,主要实现的是,当你的bean被注册之后,如果而注册相同类型的bean,就不会成功,它会保证你的bean只有一个,即你的实例只有一个,当你注册多个相同的bean时,会出现异常,以此来告诉人员。
获取接口请求中的参数
1、@PathVariable: 映射 URL 绑定的占位符, 能使传过来的参数绑定到路由上。
@RequestMapping(value = "/user/{userid}/view") //占位符 userid
public String view ( @PathVariable("userid") String userid){ //@PathVariable 中指定 userid
System.out.println("userid= "+userid); //此处可以获取:userid= 031267
return SUCCESS;
}
2、@RequestParam :获取request请求参数中的值
请求路径:http://www.test.com/user/query?username=zhangsan&age=20
@RequestMapping(value = "/user/query")
public String query(@RequestParam(value="username") String username) {
System.out.println("username = " + username); //此处打印:username = zhangsan
return SUCCESS;
}
3、@RequestBody :获取 request 请求体 body 的值
仅限用于post请求
一般情况下,@RequestBody只处理 Content-Type 是 application/json 或者 application/xml。
@PostMapping
public String add(@RequestBody User user)
{
return "";
}
@PostConstruct是Java自带的注解@PostConstruct注解的方法在项目启动的时候执行这个方法,也可以理解为在spring容器启动的时候执行,可作为一些数据的常规化加载,比如数据字典之类的。执行顺序Constructor >> @Autowired >> @PostConstruct
注解@SuppressWarnings()是用来忽略警告的,内部参数不同,忽略的警告不同。
@InitBinder
@InitBinder用于在@Controller中标注于方法上,表示为当前控制器注册一个属性编辑器,只对当前的Controller有效。@InitBinder标注的方法必须有一个参数WebDataBinder。所谓的属性编辑器可以理解就是帮助我们完成参数绑定。
@ResponseBody
@RequestMapping(value = "/test")
public String test(@RequestParam String name,@RequestParam Date date) throws Exception {
System.out.println(name);
System.out.println(date);
return name;
}
@InitBinder
public void initBinder(WebDataBinder binder){
binder.registerCustomEditor(String.class,
new StringTrimmerEditor(true));
binder.registerCustomEditor(Date.class,
new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"), false));
}
上面例子中,@InitBinder方法会帮助我们把String类型的参数先trim再绑定,而对于Date类型的参数会先格式化在绑定。例如当请求是/test?name=%20zero%20&date=2018-05-22时,会把zero绑定到name,再把时间串格式化为Date类型,再绑定到date。
这里的@InitBinder方法只对当前Controller生效,要想全局生效,可以使用@ControllerAdvice。通过@ControllerAdvice可以将对于控制器的全局配置放置在同一个位置,注解了@ControllerAdvice的类的方法可以使用@ExceptionHandler,@InitBinder,@ModelAttribute注解到方法上,这对所有注解了@RequestMapping的控制器内的方法有效。
@ControllerAdvice
public class GlobalControllerAdvice {
@InitBinder
public void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(String.class,
new StringTrimmerEditor(true));
binder.registerCustomEditor(Date.class,
new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"), false));
}
}
除了使用@ControllerAdvice来配置全局的WebDataBinder,还可以使用RequestMappingHandlerAdapter:
@Bean
public RequestMappingHandlerAdapter webBindingInitializer() {
RequestMappingHandlerAdapter adapter = new RequestMappingHandlerAdapter();
adapter.setWebBindingInitializer(new WebBindingInitializer(){
@Override
public void initBinder(WebDataBinder binder, WebRequest request) {
binder.registerCustomEditor(Date.class, new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"), false));
}
});
return adapter;
}
如上示例,可以实现同样的效果。
@ControllerAdvice中除了配置@InitBinder,还可以有@ExceptionHandler用于全局处理控制器里面的异常;@ModelAttribute作用是绑定键值对到Model里,让全局的@RequestMapping都能获得在此处设置的键值对。
补充:如果 @ExceptionHandler注解中未声明要处理的异常类型,则默认为方法参数列表中的异常类型。示例:
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
@ResponseBody
String handleException(Exception e){
return "Exception Deal! " + e.getMessage();
}
}
其他记录
@Bean+@Qualifier(“name”)指定别名。
给每个Bean添加不同的名字:
@Configuration
@ComponentScan
public class AppConfig {
@Bean("z")
ZoneId createZoneOfZ() {
return ZoneId.of("Z");
}
@Bean
@Qualifier("utc8")
ZoneId createZoneOfUTC8() {
return ZoneId.of("UTC+08:00");
}
}
存在多个同类型的Bean时,注入ZoneId又会报错:
NoUniqueBeanDefinitionException: No qualifying bean of type ‘java.time.ZoneId’ available: expected single matching bean but found 2
意思是期待找到唯一的ZoneId类型Bean,但是找到两。因此,注入时,要指定Bean的名称:
@Component
public class MailService {
@Autowired(required = false)
@Qualifier("z") // 指定注入名称为"z"的ZoneId
ZoneId zoneId = ZoneId.systemDefault();
...
}
@Component
public class MailService {
@Value("#{smtpConfig.host}")
private String smtpHost;
@Value("#{smtpConfig.port}")
private int smtpPort;
}
@Component
public class SmtpConfig {
@Value("${smtp.host}")
private String host;
@Value("${smtp.port:25}")
private int port;
public String getHost() {
return host;
}
public int getPort() {
return port;
}
}
注意观察#{}这种注入语法,它和${key}不同的是,#{}表示从JavaBean读取属性。"#{smtpConfig.host}"的意思是,从名称为smtpConfig的Bean读取host属性,即调用getHost()方法。
Spring容器可以通过@PropertySource自动读取配置,并以@Value(“${key}”)的形式注入;
可以通过${key:defaultValue}指定默认值;
以#{bean.property}形式注入时,Spring容器自动把指定Bean的指定属性值注入。
EnableScheduling
@EnableScheduling 在配置类上使用,开启计划任务的支持(类上)
非典型结构下的初始化
那么如果,我们一定要加载非root package下的内容怎么办呢?
方法一:使用@ComponentScan注解指定具体的加载包,比如:
@SpringBootApplication
@ComponentScan(basePackages="com.example")
public class Bootstrap {
public static void main(String[] args) {
SpringApplication.run(Bootstrap.class, args);
}
}
方法二:使用@Bean注解来初始化,比如:
@SpringBootApplication
public class Bootstrap {
public static void main(String[] args) {
SpringApplication.run(Bootstrap.class, args);
}
@Bean
public CustomerController customerController() {
return new CustomerController();
}
}
@SpringBootApplication
public class Bootstrap {
public static void main(String[] args) {
SpringApplication.run(Bootstrap.class, args);
}
@Bean
public CustomerController customerController() {
return new CustomerController();
}
}
在应用中我们可以通过@Value注解来加载这些自定义的参数,比如:
@Component
public class Book {
@Value("${book.name}")
private String name;
@Value("${book.author}")
private String author;
// 省略getter和setter
}
@Value注解加载属性值的时候可以支持两种表达式来进行配置:
一种是我们上面介绍的PlaceHolder方式,格式为 ${…},大括号内为PlaceHolder
另外还可以使用SpEL表达式(Spring Expression Language), 格式为 #{…},大括号内为SpEL表达式
在Spring Boot 2.0中增加了新的绑定API来帮助我们更容易的获取配置信息。
假设在propertes配置中有这样一个配置:com.didispace.foo=bar
我们为它创建对应的配置类:
@Data
@ConfigurationProperties(prefix = "com.didispace")
public class FooProperties {
private String foo;
}
接下来,通过最新的Binder就可以这样来拿配置信息了:
@SpringBootApplication
public class Application {
public static void main(String[] args) {
ApplicationContext context = SpringApplication.run(Application.class, args);
Binder binder = Binder.get(context.getEnvironment());
// 绑定简单配置
FooProperties foo = binder.bind("com.didispace", Bindable.of(FooProperties.class)).get();
System.out.println(foo.getFoo());
}
}
Druid中各连接池配置的说明可查阅: