- @SpringBootAppliaction
- 相当于下面三个注解:
- @EnableAutoConfiguration:启动自动装配。
- @ComponentScan:在当前包启动组件扫描。
- @SpringBootConfiguration:@Configuration的特例,将该类声明为配置类。
- @Controller
- @Component的特例
- 用于表明该类为控制器类,@Controller注解的类会自动被扫描并检测到,通常与@RequestMapping搭配来表明该类处理Web请求。
- Spring会扫描所有带@Controller注解的类,并在其中寻找@RequestMapping注解,以便映射请求到这些类的方法当中。
- @RequestMapping
- 可用于类或者方法
- 当用于类时,用于表明该类接收Web请求,并可指明该类负责的URL范围,其所有方法都接收该范围内的特定请求。
- 当用于方法时,通常会使用下面几个对应HTTP动作的特定注解:
- @GetMapping
- @DeleteMapping
- @PostMapping
- @PutMapping
- @PatchMapping
- @Slf4j
- Slf4j的全称:Simple Logging Facade for Java
- Slf4j是一个日志解决方案规范。它本身是不提供日志功能的具体实现的,而是提供了日志功能的一种API规范。具体的实现可以是log4j、log4j2等日志组件,默认实现是logback。
- Slf4j使用统一的接口屏蔽了具体日志组件的差异,在项目中使用Slf4j可以自由切换日志功能的实现而无需更改日志输出的代码。
- @Slf4j注解是由Lombok提供的,可以在当前类自动生成一个Slf4j的Logger静态属性。
- @SessionAttributes
- 该注解用于类型级别,声明一个将在Serlet HTTP对话中保持的模型属性,通常和@ModelAttribute搭配使用。
- @ModelAttribute
- 该注解用于绑定模型属性到某个方法或者方法参数中,这些属性会可以在View层中访问。
- 当用于注解方法时,表示该方法将创建并添加模型属性。Spring会保证@ModelAttribute注解的方法一定会在@RequestMapping注解的方法调用之前被调用。
- 当用于注解方法参数时,表示应当从模型属性中检索来获取该参数。如果没有使用该注解,那么方法参数将尝试从请求属性中检索。
- @Valid
- 该注解由JavaBean Validation API提供(JSR-303)
- 当用于注解方法参数时,表示该参数需要进行校验,校验的时机是数据绑定之后,请求处理的方法被调用之前,若校验不通过,请求将响应HTTP 400 Bad Request。
- @Repository
- @Component的特例
- 该注解用于声明一个数据访问层(持久层)对象,即DAO。
- 使用该注解,Spring会将特定的数据访问组件抛出的异常转换为DataAccessException并重新抛出,这是通过PersistenceExceptionTranslationPostProcessor实现的。
- JDBC
- 全称:Java Database Connectivity
- 广义上说,JDBC是JAVA中用于连接和读写数据库的一种解决方案。狭义上说,JDBC是指SUM公司为JAVA语言提供的一套用于读写数据库的标准接口(即API规范),数据库厂商可以按照JDBC API编写适用于本家数据库的JDBC驱动,程序员通过加载驱动即可使用JDBC API读写特定的数据库了。
- JDBC是一个比较底层的数据库读写的方式(类似于ADO.NET),它依旧需要在代码中编写SQL语句并手动进行数据和对象之间的映射。
- JdbcTemplate
- JdbcTemplate类是Spring在原生JDBC上的一层封装,它简化了使用JDBC时要编写的重复性代码,包括异常处理等。同时它也作为Spring JDBC中最基础的类。
- JPA
- 全称:Java Persistence API
- 与JDBC一样,JPA其实是一种标准,不同的是它是为ORM框架定制的持久化标准,JPA有许多实现,比如Hiberenate。
- JPA标准在JDBC标准之上规定了很多新的内容,包括对象数据映射、读缓存、实体导航等。
- Spring Data
- Spring Data是Spring技术栈中的用于简化数据访问层(DAO)代码编写的模块,它的主要目的是为了将程序员从琐碎的样板代码中解放出来。
- Spring Data在JDBC或JPA之上定义了一层新的抽象接口,这些接口可以让程序员很方便地编写Spring下的Repository,甚至不需要编写实现,Spring Data内置了一组领域特定语言,可以根据存储库的方法名自动在编译期生成实现。
- Spring Data不仅提供了对关系型数据库,还包括了对非关系型数据库以及NoSQL数据库的支持。
- Spring Security
- Spring技术栈的一个重要模块,用于提供安全性解决方案。
- 引入Spring Security依赖后,自动配置功能会初始化一些安全配置
- 所有HTTP请求路径都需要认证,认证是通过默认的登录页实现的
- 此时没有特定的角色和权限,只有唯一用户User
- 使用@Configuration注解修饰配置类,在配置类中使用@Bean方法可以对Spring Security进行配置。
- PasswordEncoder Bean
- 用于配置密码加密方式
@Bean public PasswordEncoder PpasswordEncoder(){ return new BCryptPasswordEncoder(); }
- 用于配置密码加密方式
- UserDetailsService Bean
- 用于配置用户服务,Spring Security本身内置了几个关于UserDetailsService接口的实现,包括基于内存的和基于JDBC等。也可以自己实现该接口,只需实现一个方法loadUserByUsername
@Bean public UserDetailsService userDetailsService(UserRepository userRepo){ return username -> { User user = userRepo.findByUsername(username); if(user != null) return user; throw new UsernameNotFoundException(username); }; }
- 用于配置用户服务,Spring Security本身内置了几个关于UserDetailsService接口的实现,包括基于内存的和基于JDBC等。也可以自己实现该接口,只需实现一个方法loadUserByUsername
- UserDetails 接口
- 可用于实现用户实体类,它定义了一些常用的关于用户状态的方法。
其中的getAuthorities方法用于设定用户的权限。@Entity @Data @NoArgsConstructor(access = AccessLevel.PRIVATE, force = true) @RequiredArgsConstructor @Table(name = "MyUser") public class User implements UserDetails { private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; private final String username; private final String password; @Override public Collection<? extends GrantedAuthority> getAuthorities() { return Arrays.asList(new SimpleGrantedAuthority("ROLE_USER")); } @Override public boolean isAccountNonExpired() { return true; } @Override public boolean isAccountNonLocked() { return true; } @Override public boolean isCredentialsNonExpired() { return true; } @Override public boolean isEnabled() { return true; } }
- 可用于实现用户实体类,它定义了一些常用的关于用户状态的方法。
- SecurityFilterChain Bean
- 用于配置Web请求相关的权限。HttpSecurity作为其构造器,使用Builder模式配置。
@Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception{ return http .authorizeRequests() .antMatchers("/design", "/orders").hasRole("USER") .antMatchers("/","/**").permitAll() .and() .formLogin() .loginPage("/login") .loginProcessingUrl("/login") .usernameParameter("username") .passwordParameter("password") .defaultSuccessUrl("/design", true) .and() .build(); }
其中authorizeRequests可以根据URL模式来配置安全需求,前面的安全规则比后面的安全规则有更高优先级。
formLogin表示自定义登录页,而loginPage表示登录页的路径(用于Spring Security重定向)。loginProcessingUrl表示接受登录请求(一般是POST请求)的路径,Spring Security会监视该路径,并通过usernameParameter和passwordParameter指定的字段来获取请求参数中的用户名和密码。
如果登录成功,则会根据defaultSuccessUrl跳转页面,否则会跳转到用户登录前浏览的页面,如果登录失败,则会跳转到登录页,并指定query参数error。
Spring Security默认启动CSRF,可以通过如下方法关闭:
.and() .csrf().disable() .build();
使用thymeleaf时,规定th:action属性后,表单会自动生成CSRF令牌。
- 用于配置Web请求相关的权限。HttpSecurity作为其构造器,使用Builder模式配置。
- @PreAuthorize和@PostAuthorize
- 用于方法级别的安全配置,它们可以接受一个SpEL表达式,并在不满足时抛出AccessDeniedException。
- 需要启用@EnableMethodSecurity注解标记安全配置类才能使用这两个注解。
- 区别在于PreAuthorize在方法执行前校验,而PostAuthorize在方法执行后校验,后者可以通过在SpEL表达式中使用returnObject来引用方法返回值,例如:
@GetMapping @PostAuthorize("hasRole('USER') && returnObject.user.username == authentication.name") public TacoOrder getOrder(Long id){ return orderRepo.findById(id).orElse(null); }
- 获取当前登录用户的方法
- 注入参数 java.security.Principal,getName方法返回用户名。
- 注入参数 org.springframework.security.core.Authentication,其getPrincipal返回用户对象,返回的是Object类型,需要作类型转换。Authentication对象也可以通过
SecurityContextHolder.getContext().getAuthentication()
得到。 - @AuthenticationPrincipal注解方法参数,直接得到强类型对象。
- Spring Boot的配置属性
- 配置属性本质就是Spring应用上下文(Bean)中带有@ConfigurationProperties注解的属性
- 配置属性可以通过application.properties或application.yml来配置。除了配置文件,Spring环境会从JVM系统属性、操作系统环境变量、命令行参数等属性源拉取配置值,这些值会被注入到Bean当中。
- 例如,可以在application.yml配置服务器端口:
server: port: 4567
如果将server.port属性设置为0,它会任选一个端口,可用于集成化测试中防止端口冲突。
实际上这个配置属性是由下面的JAVA代码定义的:
@ConfigurationProperties( prefix = "server", ignoreUnknownFields = true ) public class ServerProperties { private Integer port; //... }
使用@ConfigrationProperties注解,并用prefix指定配置前缀,便可以把类的属性值映射到某个配置属性上,Spring从属性源拉取值后,通过注入的方式为类的属性赋值。
注意到这里的类ServerProperties是一个专门用于存放服务器相关属性的类,这是因为可能存在很多功能类都会使用到其中的属性,所以可以单独设定一个配置类来持有这些属性,而消费这些属性的功能类只需通过Bean注入该配置类即可。
- Spring Profile
- profile是一种条件化配置,用于解决不同环境下需要多套配置的需求。
- 可以通过application-{profile_name}.properties或application-{profile_name}.yml来为名为{profile_name}的profile设置配置属性,只有当profile属于激活状态时这些配置才会生效。而application.properties或application.yml则总是生效。
- 如何激活profile:
- 通过application.properties或application.yml中设置spring.profiles.active配置属性
- 通过环境变量SPRING_PROFILES_ACTIVE
- @RestController
- 类似于@Controller,但多了一个@ResponseBody注解的效果,它告诉Spring该控制器的处理方法的返回值都要经过序列化后直接写入响应体,而不是渲染某个视图。
- 当使用@RestController时,需要指定@RequestMapping中的produces参数,它指定该控制器生成的Content-type,同时该控制器的所有处理方法只会处理Accept头信息包含produces参数的请求。
@RestController @RequestMapping(path = "/api/tacos", produces = "application/json") @CrossOrigin(origins = "*") public class TacoController {
@CrossOrigin用于指定允许跨域资源共享(CORS)的域名
@PostMapping(consumes = "application/json") @ResponseStatus(HttpStatus.CREATED) public Taco postTaco(@RequestBody Taco taco){ return tacoRepo.save(taco); }
当使用@RestController时,PostMapping的consumes参数可以指定请求输入的类型,这表示该方法只会处理Content-type为consumes参数的请求。
-
@RequestBody注解表明请求体应该被转换(反序列化)为一个对象并绑定到所注解的参数上。如果不使用@RequestBody注解,Spring会试图将查询参数或者表单参数绑定到该参数上。
- @ResponseStatus注解用于指定响应的HTTP状态码,正常情况下所有响应的HTTP状态码都是200,通过该注解可以指定语义更明确的状态码。
- @PathVariable
- 该注解用于获取路径中的参数,参数的占位符在路径中使用{XX}来指定。
@GetMapping("/{id}") public ResponseEntity<Taco> tacoById(@PathVariable("id") Long id){ Optional<Taco> taco = tacoRepo.findById(id); if(taco.isPresent()) return new ResponseEntity<>(taco.get(), HttpStatus.OK); else return new ResponseEntity<>(null, HttpStatus.NOT_FOUND); }
- @PathVariable可以指定参数名,也可以不指定,不指定时会使用变量名作为参数名。@PathVariable可以注解一个Map<string, string>类型的参数,用于将所有路径参数填充到该Map中。
- 该注解用于获取路径中的参数,参数的占位符在路径中使用{XX}来指定。
- ResponseEntity<T>
- 继承于HttpEntity<T>,可以用于接收RestTemplate.getForEntity的返回值,也可以用于Controller方法的返回值。
- 返回ResponseEntity<T>可以通过HttpStatus指定HTTP状态码。
- Spring Data REST
- 使用Spring Data REST可以自动为Spring Data创建的所有存储库创建REST API
- 依赖:spring-boot-starter-data-rest
- 可以通过spring.data.rest.base-path参数来调整自动生成的API的基础路径
- Spring Data REST会根据Repository的接口来生成REST API,当接口包含参数为Pageable、返回值为Page<T>的方法时,生成的REST API就会包含分页和排序功能。
@Repository public interface TacoRepository extends CrudRepository<Taco, Long> { Page<Taco> findAll(Pageable page); }
分页和排序功能通过URL的size、page、sort参数来启用。
- RestTemplate
- 用于发起REST请求的类,由Spring核心框架提供的简单、同步REST客户端。
- getForEntity方法发起GET请求,返回一个ResponseBody
- getForObject方法发起GET请求,返回一个对象,对象的类型在参数中指定
- execute方法用于发起特定的HTTP方法,它是最通用的请求方法,可以自定义所有的细节。RestTemplate的所有请求方法都是在execute方法的基础上实现的。
public <T> T execute(String url, HttpMethod method, @Nullable RequestCallback requestCallback, @Nullable ResponseExtractor<T> responseExtractor, Object... uriVariables) throws RestClientException
其requestCallback参数是一个函数式接口,其中可以通过ClientHttpRequest在请求发出前进行配置。其ResponseExtractor<T>参数也是一个函数式接口,其中可以通过ClienthttpResponse对响应进行反序列化,返回值是Object类型。
- exchange方法用于发起特定的HTTP方法,但可以直接传递HttpEntity,并且会根据传递的responseType对响应进行反序列化,返回值是具体的类类型。
public <T> ResponseEntity<T> exchange(String url, HttpMethod method, @Nullable HttpEntity<?> requestEntity, Class<T> responseType, Object... uriVariables)
test