SpringBoot(1)---常用注解
【一】SpringBoot介绍
(1)先从Spring谈起
我们知道Spring是重量级企业开发框架 Enterprise JavaBean(EJB) 的替代品,Spring为企业级Java开发提供了一种相对简单的方法,通过 DI依赖注入 和 AOP面向切面编程 ,用简单的 Java对象(Plain Old Java Object,POJO) 实现了EJB的功能
虽然Spring的组件代码是轻量级的,但它的配置却是重量级的(需要大量XML配置) 。Spring 2.5引入了基于注解的组件扫描,这消除了大量针对应用程序自身组件的显式XML配置。Spring 3.0引入了基于Java的配置,这是一种类型安全的可重构配置方式,可以代替XML。
尽管如此,我们依旧没能逃脱配置的魔爪。开启某些Spring特性时,比如事务管理和Spring MVC,还是需要用XML或Java进行显式配置。启用第三方库时也需要显式配置,比如基于Thymeleaf的Web视图。配置Servlet和过滤器(比如Spring的DispatcherServlet)同样需要在web.xml或Servlet初始化代码里进行显式配置。组件扫描减少了配置量,Java配置让它看上去简洁不少,但Spring还是需要不少配置。
光配置这些XML文件都够我们头疼的了,占用了我们大部分时间和精力。除此之外,相关库的依赖非常让人头疼,不同库之间的版本冲突也非常常见。
不过,好消息是:Spring Boot让这一切成为了过去。
(2)再来谈谈 Spring Boot
官方的介绍:
Spring Boot makes it easy to create stand-alone, production-grade Spring based Applications that you can “just run”…Most Spring Boot applications need very little Spring configuration.(Spring Boot可以轻松创建独立的生产级基于Spring的应用程序,只要通过 “just run”(可能是run ‘Application’或java -jar 或 tomcat 或 maven插件run 或 shell脚本)便可以运行项目。大部分Spring Boot项目只需要少量的配置即可)
简而言之,从本质上来说,Spring Boot就是Spring,它做了那些没有它你自己也会去做的Spring Bean配置。
为什么需要 Spring Boot?
Spring Framework旨在简化J2EE企业应用程序开发。Spring Boot Framework旨在简化Spring开发。
Spring Boot的主要优点
- 开发基于 Spring 的应用程序很容易。
- Spring Boot 项目所需的开发或工程时间明显减少,通常会提高整体生产力。
- Spring Boot不需要编写大量样板代码、XML配置和注释。
- Spring引导应用程序可以很容易地与Spring生态系统集成,如Spring JDBC、Spring ORM、Spring Data、Spring Security等。
- Spring Boot遵循“固执己见的默认配置”,以减少开发工作(默认配置可以修改)。
- Spring Boot 应用程序提供嵌入式HTTP服务器,如Tomcat和Jetty,可以轻松地开发和测试web应用程序。(这点很赞!普通运行Java程序的方式就能运行基于Spring Boot web 项目,省事很多)
- Spring Boot提供命令行接口(CLI)工具,用于开发和测试Spring Boot应用程序,如Java或Groovy。
- Spring Boot提供了多种插件,可以使用内置工具(如Maven和Gradle)开发和测试Spring Boot应用程序。
【二】常用注解
代码示例
@RestController
@RequestMapping("/api")
public class BookController {
private List<Book> books = new ArrayList<>();
@PostMapping("/book")
public ResponseEntity<List<Book>> addBook(@RequestBody Book book) {
books.add(book);
return ResponseEntity.ok(books);
}
@DeleteMapping("/book/{id}")
public ResponseEntity deleteBookById(@PathVariable("id") int id) {
books.remove(id);
return ResponseEntity.ok(books);
}
@GetMapping("/book")
public ResponseEntity getBookByName(@RequestParam("name") String name) {
List<Book> results = books.stream().filter(book -> book.getName().equals(name)).collect(Collectors.toList());
return ResponseEntity.ok(results);
}
}
(1)@SpringBootApplication
看作是 @Configuration、@EnableAutoConfiguration、@ComponentScan 注解的集合。根据 SpringBoot官网,这三个注解的作用分别是:
- @EnableAutoConfiguration:启用 SpringBoot 的自动配置机制
- @ComponentScan: 扫描被@Component (@Service,@Controller)注解的bean,注解默认会扫描该类所在的包下所有的类。
- @Configuration:允许在上下文中注册额外的bean或导入其他配置类。
(2)@RestController
将返回的对象数据直接以 JSON 或 XML 形式写入 HTTP 响应(Response)中。绝大部分情况下都是直接以 JSON 形式返回给客户端,很少的情况下才会以 XML 形式返回。转换成 XML 形式还需要额为的工作,直接将对象数据直接以 JSON 形式写入 HTTP 响应(Response)中。关于@Controller和@RestController 的对比,(@Controller +@ResponseBody= @RestController)。
(3)@RequestMapping
上面的示例中没有指定 GET 与 PUT、POST 等,因为**@RequestMapping默认映射所有HTTP Action**,你可以使用@RequestMapping(method=ActionType)来缩小这个映射。例如@RequestMapping(method=GET)
(4)@PostMapping
实际上就等价于 @RequestMapping(method = RequestMethod.POST),同样的 @DeleteMapping ,@GetMapping也都一样,常用的 HTTP Action 都有一个这种形式的注解所对应。
(5)@PathVariable
可以将 HttpRequest body 中的 JSON 类型数据反序列化为合适的 Java 类型。
(6)@RequestBody
可以将 HttpRequest body 中的 JSON 类型数据反序列化为合适的 Java 类型。
(7)ResponseEntity
表示整个HTTP Response:状态码,标头和正文内容。我们可以使用它来自定义HTTP Response 的内容。
(8)@RestController vs @Controller
(8.1)Controller 返回一个页面(前后端不分离,返回的string是视图的名称)
单独使用 @Controller 不加 @ResponseBody的话一般使用在要返回一个视图的情况,这种情况属于比较传统的Spring MVC 的应用,对应于前后端不分离的情况。
当我们需要直接在后端返回一个页面的时候,Spring 推荐使用 Thymeleaf 模板引擎。Spring MVC中@Controller中的方法可以直接返回模板名称,接下来 Thymeleaf 模板引擎会自动进行渲染,模板中的表达式支持Spring表达式语言(Spring EL)。如果需要用到 Thymeleaf 模板引擎,注意添加依赖!不然会报错。
@Controller
public class HelloController {
@GetMapping("/hello")
public String greeting(@RequestParam(name = "name", required = false, defaultValue = "World") String name, Model model) {
model.addAttribute("name", name);
return "hello";
}
}
Spring 会去 resources 目录下 templates 目录下找,所以建议把页面放在 resources/templates 目录下
(8.2)@RestController 返回JSON 或 XML 形式数据
但@RestController只返回对象,对象数据直接以 JSON 或 XML 形式写入 HTTP 响应(Response)中,这种情况属于 RESTful Web服务,这也是目前日常开发所接触的最常用的情况(前后端分离)。
如果你需要在Spring4之前开发 RESTful Web服务的话,你需要使用@Controller 并结合@ResponseBody注解,也就是说@Controller +@ResponseBody= @RestController(Spring 4 之后新加的注解)。
@ResponseBody 注解的作用是将 Controller 的方法返回的对象通过适当的转换器转换为指定的格式之后,写入到HTTP 响应(Response)对象的 body 中,通常用来返回 JSON 或者 XML 数据,返回 JSON 数据的情况比较多。
SpringBoot 默认集成了 jackson ,对于此需求你不需要添加任何相关依赖。
@Controller
public class HelloController {
@PostMapping("/hello")
@ResponseBody
public Person greeting(@RequestBody Person person) {
return person;
}
}
使用 post 请求访问 http://localhost:8080/hello ,body 中附带以下参数,后端会以json 格式将 person 对象返回。
{
“name”: “teamc”,
“age”: 1
}
(9)@PostConstruct与@PreDestroy
@PostConstruct和@PreDestroy 是两个作用于 Servlet 生命周期的注解,被这两个注解修饰的方法可以保证在整个 Servlet 生命周期只被执行一次,即使 Web 容器在其内部中多次实例化该方法所在的 bean。
这两个注解分别有什么作用呢?
- @PostConstruct : 用来修饰方法,标记在项目启动的时候执行这个方法,一般用来执行某些初始化操作比如全局配置。PostConstruct 注解的方法会在构造函数之后执行,Servlet 的init()方法之前执行。
- @PreDestroy : 当 bean 被 Web 容器的时候被调用,一般用来释放 bean 所持有的资源。。@PreDestroy 注解的方法会在Servlet 的destroy()方法之前执行。
被这个注解修饰的方法需要满足下面这些基本条件:
- 非静态
- 该方法必须没有任何参数,除非在拦截器的情况下,在这种情况下,它接受一个由拦截器规范定义的InvocationContext对象
- void()也就是没有返回值
- 该方法抛出未检查的异常
- …
我们新建一个 Spring 程序,其中有一段代码是这样的,输出结果会是什么呢?
@Configuration
public class MyConfiguration {
public MyConfiguration() {
System.out.println("构造方法被调用");
}
@PostConstruct
private void init() {
System.out.println("PostConstruct注解方法被调用");
}
@PreDestroy
private void shutdown() {
System.out.println("PreDestroy注解方法被调用");
}
}
替换方案
但是 J2EE已在Java 9中弃用 @PostConstruct和@PreDestroy这两个注解 ,并计划在Java 11中将其删除。我们有什么更好的替代方法吗?当然有!
@Configuration
public class MyConfiguration2 implements InitializingBean, DisposableBean {
public MyConfiguration2() {
System.out.println("构造方法被调用");
}
@Override
public void afterPropertiesSet() {
System.out.println("afterPropertiesSet方法被调用");
}
@Override
public void destroy() {
System.out.println("destroy方法被调用");
}
}
输出结果如下,可以看出实现Spring 提供的 InitializingBean和 DisposableBean接口的效果和使用**@PostConstruct和@PreDestroy** 注解的效果一样。
但是,Spring 官方不推荐使用上面这种方式,如果你还是非要使用 Java 9 及以后的版本使用 @PostConstruct和@PreDestroy 这两个注解的话,你也可以手动添加相关依赖。
Maven:
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.2</version>
</dependency>
Gradle:
compile group: ‘javax.annotation’, name: ‘javax.annotation-api’, version: ‘1.3.2’
【三】其他注解
【1】@ConfigurationProperties
在 SpringBoot 中,当想需要获取到配置文件数据时,除了可以用 Spring 自带的 @Value 注解外,SpringBoot 还提供了一种更加方便的方式:@ConfigurationProperties。只要在 Bean 上添加上了这个注解,指定好配置文件的前缀,那么对应的配置文件数据就会自动填充到 Bean 中。
比如在application.properties文件中有如下配置文件
config.username=jay.zhou
config.password=3333
那么按照如下注解配置,SpringBoot项目中使用@ConfigurationProperties的Bean,它的username与password就会被自动注入值了。就像下面展示的那样
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Component
@ConfigurationProperties(prefix = "config")
public class TestBean{
private String username;
private String password;
}
【2】@Data
@Data注解的主要作用是提高代码的简洁,使用这个注解可以省去实体类中大量的get()、 set()、 toString()等方法。
属于lombok插件的注解。其他的一些注解有:
- @Data : 注在类上,提供类的get、set、equals、hashCode、toString等方法
- @AllArgsConstructor :注在类上,提供类的全参构造 @NoArgsConstructor :注在类上,提供类的无参构造
- @Setter :注在属性上,提供 set 方法
- @Getter :注在属性上,提供 get 方法
- @EqualsAndHashCode
:注在类上,提供对应的 equals 和 hashCode 方法 - @Log4j/@Slf4j :注在类上,提供对应的 Logger
对象,变量名为 log
【3】@TableField
(1)@TableField(value = “email”)//指定数据库表中字段名
如果数据库和实体类的字段名不一致,可以使用@TableField注解指定数据库表中字段名。
(2)@TableField(exist = “false”)//数据库表中不存在的数据,在实体类中指定。
如果数据库表中不存在字段,在实体类中使用@TableField注解指定。
例如:数据库表中没有address字段,可以在该字段上方使用@TableField(exist = “false”)来指定。
(3)@TableField(select = “false”)//查询时不返回该字段的值
如果不想被查询出来该字段,可以使用@TableField注解来隐藏该字段的查询结果。
例如:不想被查出来password字段的值,就可以使用@TableField注解。