Skip to main content

Spring Boot 框架

Three-Tier architecture 三层架构

1. What is DTO, VO, Payload, DO?

  • DTO: Data Transfer Object
    • A Data Transfer Object is an object that is used to encapsulate data, and send it from one subsystem of an application to another. 通常是前后端的传输, between View layer and Service layer.
  • VO:
    • Value Object in DDD 领域模型
    • View Object in MVC
    • 视图对象,位于 View layer,只要是这个东西是让人看到的,这就叫 VO
    • DTO 的区别:
      • 一个是字段不一样,VO 根据需要会删减一些字段
      • 另一个是值不一样,VO 会根据需要对 DTO 中的值进行展示业务的解释
// DTO 可能是这样
{
"gender": "男",
"age": 35
}
// 业务1只需要展示性别,而且因为是一个古风聊天室,也不能直接展示男
// 因此经过业务解释业务1后的 VO
{
"gender": "公子"
}

// 对于业务2来说只需要年龄,而且不需要精确的年龄
// 因此经过业务解释业务2的 VO 是
{
"age":"30~39"
}
  • Payload:
    • We store DTOs in payload package.
    • Payload is the essential information in a data block that you send to or receive from the server when making API requests. The Payload can be sent or received in a variety of formats, including JSON.
    • 例如有一位客户需要支付一笔费用委托货车司机运送一车钢板,钢板本身的重量、车子的重量、司机的重量等等,这些都属于载重(load)。但是对于该客户来说,他关心的只有钢板的重量,所以钢板的重量是有效载重(payload,也就是付费的重量)。
  • DO: Data Object
    • the same to PO(Persistant Object)持久对象
    • the same to Entity 实体

Spring Boot Core 知识点

1. How can we do Dependecny Injection?

  • Constructor Injection (recommended): In the constructor injection, the injector supplies the service (dependency) through the client class constructor. 在构造函数注入中,注入器通过客户端类构造函数提供服务(依赖)。
    • Constructor injection makes the code more stable and clear, easier to test, and avoids dependency issues.
    • 构造器注入让代码更稳定、易懂,也便于测试,还能避免依赖问题。
  • Property Injection: In the property injection (aka the Setter Injection), the injector supplies the dependency through a public property of the client class.
  • Method Injection: In this type of injection, the client class implements an interface which declares the method(s) to supply the dependency and the injector uses this interface to supply the dependency to the client class.

2. @Autowired How can we inject the specified one?

// If one Interface has 3 implementations, when we do @Autowired, how can we tell the springboot to inject the specified one.
// by using @Qualifier

@Autowired
@Qualifier("yourDataSource")
private DataSource dataSource;

3. What is the @SpringBootApplication?

  • @SpringBootApplication annotation is used to mark a configuration class that declares one or more @Bean methods and also triggers auto-configuration and component scanning.
  • It simply invokes the SpringApplication.run method. This starts the Spring application as a standalone application, runs the embedded servers and loads the beans.
  • 这将 Spring 应用程序作为独立应用程序启动,运行嵌入式服务器并加载 bean。

4. What is application.properties file in a SpringBoot application?

  • application.properties file is used to write the application-related property into that file. This file contains the different configuration which is required to run the application in a different environment, and each environment will have a different property defined by it.

5. 什么是 SpringBoot 中的 Runner?

CommandLineRunner

  • 这个接口用于访问应用程序参数。实现 CommandLineRunner 接口的组件定义了一个 run(String... args)方法
  • Spring Boot 会在应用程序上下文加载完成后自动调用该方法。
@Component
public class CommandLineAppStartupRunner implements CommandLineRunner {
@Override
public void run(String... args) {
System.out.println("Application started with command-line arguments: ");
for (String arg : args) {
System.out.println(arg);
}
}
}

ApplicationRunner

  • 这个接口的工作方式与 CommandLineRunner 类似,但它提供了对参数的更丰富的访问,它使用 ApplicationArguments 对象而不是直接使用字符串数组。
@Component
public class AppStartupRunner implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) {
System.out.println("Application started with option names : " + args.getOptionNames());
if (args.containsOption("myOption")) {
System.out.println("My custom option is present");
}
}
}

Annotation 注解

1. What is the @Transient, @Temporal, @Enumerated?

  • @Transient
    • It is used to annotate a property or field of an entity class, mapped superclass, or embeddable class which is not persistent.
    • JPA's @Transient annotation is used to indicate that a field is not to be persisted in the database.
  • @Temporal
    • @Temporal annotation must be specified for persistent fields or properties of type java.util.Date and java.util.Calendar.
    • In JPA, @Temporal annotation solves the one of the major issue of converting the date and time values from Java object to compatible database type and retrieving back to the application.
  • @Enumerated
    • Helps map an enum value to and from its database representation. This way, we can instruct a JPA provider to convert an enum to its ordinal or String value.

2. Explain how the below annotaitons specify the table in database?

@Column(columnDefinition = "varchar(255) default
'John Snow'")
private String name;

@Column(name="STUDENT_NAME", length=50,
nullable=false, unique=false)
private String studentName;
  • name: the data type is varchar(255), the default value of name is 'John Snow'.
  • studentName: the column's name is "STUDENT_NAME", the maximum length of the String is 50. Database will reject any values that are more than 50 characters long. The value can be null and duplicated.

3. What is the default record name for @Column?

@Column
private String firstName;

@Column
private String operatingSystem;
  • firstName: first_name
  • operatingSystem: operating_system

@RestController annotation is a combination of 2 annotations, what is that?

List an example how to use the 2 annotations.

  • @RestController combines @Controller and @ResponseBody.
// use `@Controller` and `@ResponseBody`
@Controller
@RequestMapping("books")
public class SimpleBookController {

@GetMapping("/{id}")
public @ResponseBody Book getBook(@PathVariable int id) {
return findBookById(id);
}
}

// use `@RestController`
@RestController
@RequestMapping("books-rest")
public class SimpleBookRestController {

@GetMapping("/{id}")
public Book getBook(@PathVariable int id) {
return findBookById(id);
}

}

4. What is @Pathvariable and @RequestParam?

  • @PathVariable is for parts of the path (i.e. /person/{id})
  • @RequestParam is for the GET query parameters (i.e. /person?name="Bob").
@RequestMapping(value="/user/{userId}/invoices", method = RequestMethod.GET)
public List<Invoice> listUsersInvoices(
@PathVariable("userId") int user,
@RequestParam(value = "date", required = false) Date dateOrNull) {
...
}

5. What is the difference between @Resource, @Autowired and @Inject?

  • @Resource
    • we can only use @Resource annotation on fields or bean property setters.
    • 我们只能在字段或 bean 属性设置器上使用。
    • Order of Execution: Name -> Type -> Qualifiers
  • @Autowired
    • Defined in the package org.springframework.bean.factory and part of Spring framework.
    • The @Autowired can be used on Setter, Field, Constructor or on parameters to do the respective type injections.
    • 可用于 Setter、Field、Constructor 或参数上以执行相应的类型注入。
    • Order of Execution: Type -> Qualifiers -> Name
  • @Inject
    • Defined in the javax.inject package.
    • The @Inject can be used on Setter, Field, or Constructor to do the respective type injections.
    • 可用于 Setter、Field 或 Constructor 来执行相应的类型注入。
    • The Inject annotation does not take any parameter.
    • Order of Execution: Type -> Qualifiers -> Name

6. Difference between @Component, @Controller, @Service, @Repository, @Bean annotations.

  • @Component
    • @Component is a class-level annotation. It is used to denote a class as a Component. We can use @Component across the application to mark the beans as Spring’s managed components.
    • 是一个类级别的注解,用于自动检测和注册 bean。当你将 @Component 注解加到类上时,Spring 在组件扫描时会自动找到这个类,并将其实例作为 bean 注册到 Spring 容器中。
  • @Controller
    • It’s used to mark a class as a web request handler. 注解表明特定类充当控制器的角色。
    • @Controller annotation indicates that a particular class serves the role of a controller.
  • @Service
    • It is used to mark the class as a service provider. 注释与提供某些业务功能的类一起使用。
    • @Service annotation is used with classes that provide some business functionalities.
  • @Repository
    • It is used to mark the interface as DAO (Data Access Object) provider.
    • indicate that the class provides the mechanism for storage, retrieval, update, delete and search operation on objects. 表示该类提供了对对象进行存储、检索、更新、删除和搜索操作的机制。
  • All of them are also the specialization of @Component Annotation.
  • @Bean
    • 是一个方法级别的注解,通常用在标有 @Configuration 的类中。你需要在一个方法上使用 @Bean 注解,并且返回一个对象实例。Spring 容器随后会调用这个方法,并将方法返回的对象注册为 bean
@Configuration
public class AppConfig {

@Bean
public MyBean myBean() {
// 可以在这里配置MyBean的实例
return new MyBean();
}
}

7. Have you created any custom annotations before?

// 1. 带有默认值的自定义注解
public @interface MyAnnotationWithDefaults {
String stringValue() default "defaultString";
int intValue() default 42;
}


// 2. 带有元注解的自定义注解
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME) // 指定注解的保留策略
@Target(ElementType.METHOD) // 指定注解可以应用于的元素类型
public @interface MyMethodAnnotation {
String description() default "A custom method annotation";
}

// 3. 要使用自定义注解,请将它们应用于 Java 代码中的类、方法或其他元素。例如:
public class MyClass {

@MyAnnotation
public void myAnnotatedMethod() {
// ...
}

@MyAnnotationWithDefaults(stringValue = "customString", intValue = 24)
public void myMethodWithDefaults() {
// ...
}

@MyMethodAnnotation(description = "This is a custom method annotation example")
public void myMethodWithMethodAnnotation() {
// ...
}
}

// 4. 要处理自定义注解,可以使用 Java 反射 API 在运行时访问它们。例如:
import java.lang.reflect.Method;

public class AnnotationProcessor {

public static void main(String[] args) {
Method[] methods = MyClass.class.getDeclaredMethods();

for (Method method : methods) {
if (method.isAnnotationPresent(MyMethodAnnotation.class)) {
MyMethodAnnotation annotation = method.getAnnotation(MyMethodAnnotation.class);
System.out.println("Method: " + method.getName() + " | Annotation description: " + annotation.description());
}
}
}
}

Spring JPA

1. What is JPA, what is Hibernate?

  • JPA (Java Persistence API)
    • It describes the handling of relational data in Java applications.
    • It is not an implementation. It is only a Java specification. 它只是一个 Java 规范。
    • It is a standard API that permits to perform database operations. 它是一个标准的 API,允许执行数据库操作。
  • Hibernate
    • Hibernate is an Object-Relational Mapping (ORM) tool that is used to save the Java objects in the relational database system. 它是一个对象关系映射工具,用于将 Java 对象保存到关系数据库系统中。
    • Hibernate is an implementation of JPA. Hence, the common standard which is given by JPA is followed by Hibernate.
    • It is used in mapping Java data types with SQL data types and database tables. 它用于将 Java 数据类型与 SQL 数据类型和数据库表进行映射。

2. @Entity Why annotations should be imported from JPA and not from Hibernate?

import javax.persistence.*; (JPA) (we usually import this one)
import org.hibernate.annotations; (Hibernate)
  • JPA annotations are used in mapping java objects to the database tables, columns etc.
  • The @Entity annotation marks this class as an entity bean, so the class must have a no-argument constructor that is visible with at least protected scope (JPA specific). 当你为一个类添加 @Entity 注解时,你需要确保该类有一个无参数的构造函数,这样 JPA 才能正常工作。如果你的构造函数设置为 private,那么 JPA 将无法访问它,所以至少要将其设置为 protected 或者 public。

3. What is the @OneToMany, @ManyToOne, @ManyToMany?

  • @OneToMany: one object in this table can have many relationships to another table. 一个对象可以有多个关系到另一个表。
  • @ManyToOne: used combined with one to many. 与一对多一起使用。
  • @ManyToMany: set up a table to hold @ManyToOne && @OneToMany. 设置一个表来保存 @ManyToOne 和 @OneToMany。

4. What are CascadeType and their features?

What is the cascade = CascadeType.ALL, orphanRemoval = true? and what are the other CascadeType and their features? In which situation we choose which one?

  • The meaning of CascadeType.ALL is that the persistence will propagate (cascade) all EntityManager operations (PERSIST, REMOVE, REFRESH, MERGE, DETACH) to the relating entities. 持久性会将所有 EntityManager 操作(PERSIST、REMOVE、REFRESH、MERGE、DETACH)传播(级联)到相关实体。
  • orphanRemoval = true is to delete orphaned entities from the database. 从数据库中删除孤立的实体。
  • JPA Cascade Types
    • CascadeType.PERSIST: cascade type presist means that save() or persist() operations cascade to related entities.
    • CascadeType.MERGE: cascade type merge means that related entities are merged when the owning entity is merged. 级联类型合并是指当所属实体合并时,相关实体也被合并。
    • CascadeType.REFRESH: cascade type refresh does the same thing for the refresh() operation.
    • CascadeType.REMOVE: cascade type remove removes all related entities association with this setting when the owning entity is deleted.
    • CascadeType.DETACH: cascade type detach detaches all related entities if a “manual detach” occurs.
    • CascadeType.ALL: cascade type all is shorthand for all of the above cascade operations.

5. What is the fetch = FetchType.LAZY, fetch = FetchType.EAGER?

  • FetchType.EAGER: tells Hibernate to get all elements of a relationship when selecting the root entity. 告诉 Hibernate 在选择根实体时获取关系的所有元素。
  • FetchType.LAZY: tells Hibernate to only fetch the related entities from the database when you use the relationship. 告诉 Hibernate 在使用关系时仅从数据库中获取相关实体。
@Entity
public class User {

/*
当你加载一个 User 实体时,并不会立即加载所有相关的 Order 实体。
只有当你访问 user.getOrders() 并且需要使用这些 Order 实体时,它们才会被加载。
*/
@OneToMany(fetch = FetchType.LAZY)
private List<Order> orders;

/*
当User实体被查询时,与之关联的所有 Address 实体都会立即被加载到内存中。
*/
@OneToMany(mappedBy = "user", fetch = FetchType.EAGER)
private List<Address> addresses;
}

6. What is the rule of JPA naming convention? 命名规范

  • Spring uses lower snake case by default, which means it uses only lower case letters and separates words with underscores. Spring默认使用小写蛇形字母,这意味着它只使用小写字母并用下划线分隔单词。
  • Person class -> person
  • firstName -> first_name

7. How to define the query using SQL in repository?

@Query("SELECT u FROM User u WHERE u.status = 1")
Collection<User> findAllActiveUsers();
@Query(
value = "SELECT * FROM USERS u WHERE u.status = 1",
nativeQuery = true)
Collection<User> findAllActiveUsersNative();
@Query(value = "SELECT u FROM User u")
List<User> findAllUsers(Sort sort);

8. SprintBoot JPA 如何实现分页功能?

Repository Layer

@Repository
public interface OrderRepository extends CrudRepository<Order, Long> {
Page<Order> findAllByUserId(Long userId, Pageable pageable);
}

Service Layer

@Service
public class OrderService {

@Autowired
private OrderRepository orderRepository;

public Page<Order> getOrdersByUser(Long userId, Pageable pageable) {
return orderRepository.findAllByUserId(userId, pageable);
}
}

Controller Layer

@RestController
@RequestMapping("/users/{userId}/orders")
public class OrderController {

@Autowired
private OrderService orderService;

@GetMapping
public Page<Order> getUserOrders(@PathVariable Long userId,
@RequestParam Optional<String> sort,
@RequestParam Optional<String> direction,
Pageable pageable) {
// 创建Sort对象,根据请求参数决定排序方向,默认为降序
Sort sortObj = Sort.by(direction.isPresent() && direction.get().equalsIgnoreCase("asc") ?
Sort.Direction.ASC : Sort.Direction.DESC,
sort.orElse("id")); // 默认按'id'属性排序

// 根据页码、页面大小和Sort对象创建PageRequest对象
pageable = PageRequest.of(pageable.getPageNumber(), pageable.getPageSize(), sortObj);

// 调用服务层方法,获取排序后的分页结果
return orderService.getOrdersByUser(userId, pageable);
}
}