1. Annotation là gì ?
Annotation là một dạng siêu dữ liệu để cung cấp thêm những thông tin bổ sung về chương trình. Nó không ảnh hưởng trực tiếp đến chương trình khi chạy nhưng chúng mang những thông tin quan trọng về cấu trúc và mục đích của đoạn mã nguồn. Annotation được gán cho Class, Method, Parameter, Variable và Package. Annotation không làm thay đổi các hành động trong quá trình biên dịch (Compile time).
2. Annotation của Spring Framework
@Autowired: Áp dụng cho setter, constructor, instance variable. Khi chúng ta gán @Autowired Spring container sẽ tự động tạo ra liên kết tương ứng vơi data-type.
@RestController @RequestMapping("/user") public class UserController { @Autowired private UserService userService; }
@Configuration: Áp dụng cho Class, Khi Class được gán @Configuration cho Spring Boot biết chúng chứa thông tin cấu hình của ứng dụng.
@Configuration public class AppConfig { ... }
@ComponentScan: Nếu như bạn muốn chỉ định Spring Boot quét thông tin một package cho các bean thì có thể dùng kết hợp với @Configuration.
@ComponentScan(basePackages = "vn.tayjava.model") @Configuration public class AppConfig { ... }
@Bean: Áp dụng cho method nằm trong Class được gán @Configuration, Method được gán @Bean sẽ tạo ra một bean và được quản lý bởi Spring Container.
@Configuration public class AppConfig { @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } }
@Component: Áp dụng cho Class, Class được gán @Component cho chúng ta biết bean được tạo ra và quản lý bởi Spring Boot.
@Component public class S3Client { @Autowired private AmazonS3 amazonS3Client; public void createS3Bucket(String bucketName, boolean publicBucket) { .... } }
@Controller: Là một trường hợp đặc biệt của @Component, annotation này nằm trong Spring MVC, module phổ biến được dùng trong ứng dụng web. Mặc định @Controller trả về một string để có thể điều hướng đến một page khác. @Controller có thể được sử dụng kết hợp với @RequestMapping.
@Controller @RequestMapping("/sample") public class SampleController { @GetMapping("/greeting") public String greeting(@RequestParam(name="name", required=false, defaultValue="World") String name, Model model) { model.addAttribute("name", name); return "greeting"; } }
@Service: Là annotation được sử dụng để chỉ rõ Class thuộc tầng business logic.
@Service @Slf4j(topic = "USER-SERVICE") @RequiredArgsConstructor public class UserService { private final UserRepository userRepository; private final SearchRepository searchRepository; }
@Repository: Là annotation được sử dụng để chỉ rõ Class này thuộc tầng DAO, Class được áp dụng @Repository có thể truy cập trực tiếp vào database.
@Repository public interface UserRepository extends JpaRepository<UserEntity, Long>, JpaSpecificationExecutor { UserEntity findByUsername(String username); UserEntity findByEmail(String email); }
3. Annotation của Spring Boot
@EnableAutoConfiguration: Nó cho phép Spring Boot tự động cấu hình application context, Khi áp dụng annotation này Spring Boot sẽ tự động tạo và đăng ký các bean dựa trên tất cả các files jar trong class-path lẫn các bean được chúng ta định nghĩa. Class được gán @EnableAutoConfiguration được hiểu là mặc định nên chúng ta nên gán nó ở root package và điều đó có nghĩa là các package con mặc định được kiểm tra. Cuối cùng do tính lằng nhằng của nó nên từ bản Spring Boot 1.2.0 các nhà thiết kế đã lược bỏ annotation này và tích hợp nó vào @SpringBootApplication.
@SpringBootApplication@EnableAutoConfigurationpublic class SampleApplication { public static void main(String[] args) { SpringApplication.run(SampleApplication.class, args); } }
@SpringBootApplication: Class áp dụng hàm này được hiểu đây là application được xây dựng bởi Spring Boot và nó sẽ được khởi tạo từ hàm main của class này. @SpringBootApplication có thể kết hợp cùng ba annotation khác như: @EnableAutoConfiguration, @ComponentScan, @Configuration.
@RequestMapping: áp dụng cho class hoặc method dùng để định nghĩa các path/url và ánh xạ các request từ client, tức là ứng dụng sẽ nhận request theo các endpoint được định nghĩa rõ ràng tại đây. Chúng ta có thể sử dụng @RequestMapping kết hợp với một số tùy chọn như: consumes, header, method, name, params, path, produces và value.
@RestController @RequestMapping("/users") public class UserController { }
@GetMapping: áp dụng cho các method, method được gán @GetMapping được hiểu là sẽ nhận các request HTTP GET từ phía client và lấy dữ liệu từ database về để hiển thị.
@GetMapping(path = "/list") = @RequestMapping(method = RequestMethod.GET, path = "/list")
@RestController @RequestMapping("/users") public class UserController { @GetMapping(path = "/list", produces = APPLICATION_JSON_VALUE) @ResponseStatus(OK) public List getUsers(Pageable pageable) { return userService.getUsers(pageable); } }
@PostMapping: áp dụng cho method, method được gán @PostMapping cho chúng ta biết rằng đây là method sẽ nhận các request HTTP POST từ client để thêm mới dữ liệu vào database.
@PostMapping(path = "/add") = @RequestMapping(method = RequestMethod.POST, path = "/add")
@RestController @RequestMapping("/users") public class UserController { @PostMapping(path = "/add", produces = APPLICATION_JSON_VALUE, consumes = APPLICATION_JSON_VALUE) @ResponseStatus(CREATED) public long createUser(@Valid @RequestBody UserCreationRequest request) { return userService.addUser(request); } }
@PutMapping: áp dụng cho method, method với @PutMapping được dùng để nhận các request HTTP PUT từ client để cập nhật toàn bộ dữ liệu bản ghi trong database.
@PutMapping(path = "/upd") = @RequestMapping(method = RequestMethod.PUT, path = "/upd")
@RestController @RequestMapping("/users") public class UserController { @PutMapping(path = "/upd", produces = APPLICATION_JSON_VALUE, consumes = APPLICATION_JSON_VALUE) @ResponseStatus(ACCEPTED) public void updateUser(@Valid @RequestBody UserUpdateRequest request) { try { userService.updateUser(request); } catch (Exception e) { throw new InvalidDataException("Update user unsuccessful, Please try again"); } } }
@PatchMapping: áp dụng cho method, method gán @PatchMapping được dùng để nhận các request HTTP PATCH từ client để cập nhật một phần dữ liệu bản ghi trong database.
@PatchMapping(path = "/user/{id}") = @RequestMapping(method = RequestMethod.PATCH, path = "/user/{id}")
@RestController @RequestMapping("/users") public class UserController { @PatchMapping(path = "/user/{id}/change-status", produces = APPLICATION_JSON_VALUE) @ResponseStatus(ACCEPTED) public void changeStatus(@PathVariable long id, @RequestParam @ValueOfEnum(message = "status must be any of enum (ACTIVE,INACTIVE,NONE)", enumClass = UserStatus.class) String status) { try { userService.changeStatus(id, status); } catch (Exception e) { throw new InvalidDataException("Change status unsuccessful, Please try again"); } } }
@DeleteMapping: áp dụng cho method, method gán @DeleteMapping dùng để nhận các request HTTP DELETE từ client với mục đích là xóa bản ghi trong database.
@DeleteMapping(path = "/del/{id}") = @RequestMapping(method = RequestMethod.DELETE, path = "/del/{id}")
@RestController @RequestMapping("/users") public class UserController { @DeleteMapping(path = "/del/{id}", produces = APPLICATION_JSON_VALUE) @ResponseStatus(NO_CONTENT) public void deleteUser(@PathVariable("id") @Min(1) long id) { try { userService.deleteUser(id); } catch (Exception e) { throw new InvalidDataException("Delete user unsuccessful, Please try again"); } } }
@PathVariable: được dùng để trích xuất giá trị từ URL từ các method của RESTful API như GET, PUT, PATCH, DELETE, Chúng ta có thể định nghĩa nhiều @PathVariable trong một method.
@DeleteMapping(path = "/del/{id}", produces = APPLICATION_JSON_VALUE) @ResponseStatus(NO_CONTENT) public void deleteUser(@PathVariable("id") @Min(1) long id) { try { userService.deleteUser(id); } catch (Exception e) { throw new InvalidDataException("Delete user unsuccessful, Please try again"); } }
@RequestBody: thường được dùng để liên kết một đối tượng với một tham số trong HTTP request. @RequestBody thường đường dùng cùng với các RESTful API như POST, PUT.
@PostMapping(path = "/add", produces = APPLICATION_JSON_VALUE, consumes = APPLICATION_JSON_VALUE) @ResponseStatus(CREATED) public long createUser(@Valid @RequestBody UserCreationRequest request) { return userService.addUser(request); }
@RequestParam: được biết đến như là một query parameter được sử dụng phổ biến trong HTTP request (ngoại trừ HTTP POST). Thông qua @RequestParam chúng ta có thể trích xuất thông tin từ URL.
@GetMapping(path = "/list-sorted-paged", produces = APPLICATION_JSON_VALUE) @ResponseStatus(OK) public UserListResponse getUsers(@RequestParam(defaultValue = "0") int pageNo, @RequestParam(defaultValue = "20") int pageSize, @RequestParam(required = false) String... sort) { return userService.getUsers(pageNo, pageSize, sort); }
@RequestHeader: được dùng để lấy thêm thông tin chi tiết về HTTP request header. @RequestHeader cung cấp một số tùy chọn như: name, required, value, defaultValue.
@PostMapping(path = "/add", produces = APPLICATION_JSON_VALUE, consumes = APPLICATION_JSON_VALUE) @ResponseStatus(CREATED) public long createUser(@RequestHeader(HttpHeaders.ACCEPT_LANGUAGE) String language, @Valid @RequestBody UserCreationRequest request) { return userService.addUser(request); }
@RequestAttribute: được dùng để liên kết một parameter trên method đến một thuộc tính phía server-side nhưng trên cùng một HTTP request.
public class CounterInterceptor extends HandlerInterceptorAdapter { private AtomicInteger counter = new AtomicInteger(0); @Override public boolean preHandle (HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { request.setAttribute("visitor", counter.incrementAndGet()); return true; } }
@RestController @RequestMapping("/visitors") public class CounterController { @GetMapping("/view") @ResponseBody public String handle (@RequestAttribute("visitor) Integer counter) { return String.format("Visitor number: %d", counter); } }
@EnableWebMvc @ComponentScan("vn.tayjava.config") public class AppConfig extends WebMvcConfigurerAdapter { @Override public void addInterceptors (InterceptorRegistry registry) { registry.addInterceptor(new CounterInterceptor()); } }
@ResponseBody: được dùng để liên kết dữ liệu trả về với một đối tượng, Spring Boot sẽ serialize đối tượng này để trả về một đối tượng JSON hoặc XML.
@GetMapping("/view")
@ResponseBody
public String handle (@RequestAttribute("visitor") Integer counter) {
return String.format("Visitor number: %d", counter);
}
@RestController: là sự kết hợp giữ @Controller và @ResponseBody. Khi bạn áp dụng @RestController cho class có nghĩa là các RESTful API của chúng ta được trả về kết quả dưới dạng JSON hoặc XML và chúng ta không cần gán thêm @ResponseBody cho các method.