在企业应用中,我们使用RESTful服务来建立客户端和服务器之间的通信。总体思路是客户端将请求发送到服务器,服务器用一些响应来响应该请求。一般来说,我们大多数应用程序都具有三个不同的层:Web层、业务层和数据库层。这些层中的对象大多彼此不同。例如,Web层对象与数据库层中的同一对象完全不同。由于数据库对象可能包含 Web 层对象中不需要的字段,例如自动生成的字段、密码字段等。
DTO 代表数据传输对象,这些对象从一层移动到另一层。DTO 还可用于隐藏数据库层对象的实现细节。将实体暴露给 Web 层而不正确处理响应可能会成为安全问题。例如,如果我们有一个端点公开名为 User 的实体类的详细信息。端点处理GET请求。如果未使用 GET 端点正确处理响应,则可以获取 User 类的所有字段,甚至密码,这对于编写静态服务来说不是一种好的做法。为了克服这些问题,DTO 应运而生,通过 DTO,我们可以选择需要向 Web 层公开哪些字段。
ModelMapper是一个 Maven 库,用于将实体对象转换为 DTO,反之亦然。
在此示例中,我们将为用户服务创建一个 Restful 应用程序,该应用程序使用模型映射器库将实体转换为 DTO。
创建Spring Boot项目
在这一步中,我们将创建一个 Spring Boot 项目。要了解如何创建 Spring Boot 项目,请参阅如何在 Eclipse IDE 中创建和设置 Spring Boot 项目?
在此步骤中,我们将向项目添加依赖项。我们将添加以下依赖项。
图 1 – 添加依赖项
创建数据库架构
我们将在我们的应用程序中使用 MySQL 作为数据库。我们需要创建一个数据库模式。在这里,我们将使用 MySQL Workbench 创建数据库架构。为此,打开 MySQL Workbench > Schemas > 右键单击 > Create Schema。
图 2 – 创建架构
这将打开一个弹出窗口,我们需要在其中填写模式的名称。在这里,我们将模式命名为model_mapper_db。
图 3 – 数据库架构名称
一旦我们添加了模式的名称,我们需要单击“应用”按钮,它将弹出一个窗口,我们需要在其中再次单击“应用”按钮。这将创建我们的模式。
图 4 – 数据库架构
配置数据库
在此步骤中,我们将在 Spring Boot 应用程序中配置数据库。我们需要在application.properties文件中写入以下属性。
server.port = 9090
#database configuration
spring.datasource.url=jdbc:mysql://localhost:3306/model_mapper_db
spring.datasource.username=root
spring.datasource.password=root
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL57Dialect
#the ddl-auto=update : It will create the entity schema and map it to db automatically
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
之后,我们将运行我们的应用程序以查看我们的应用程序是否配置到数据库。为此,请转到Spring Boot 中的主类(此处为 ModelMapperApplication.java)右键单击 > Run As > Java Application。
图 5 – 运行应用程序
一旦我们将应用程序作为 Java Application 运行,我们就可以在控制台中看到我们的应用程序已启动并设置了与数据库的连接。
图 6 – 数据库连接设置
现在,我们需要创建实体类。对于我们的应用程序,我们将使用User 类作为我们的实体类。它将包含以下字段id、名称、电子邮件和密码。
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name="user-id")
private int id;
@Column(name="user-name")
private String name;
@Column(name="user-email")
private String email;
@Column(name="user-password")
private String password;
// NoArgsConstructor
public User() {
super();
}
// Getters & Setters
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
我们已经编写了实体类。我们将运行我们的应用程序,当我们完成数据库配置时,JPA 将使用我们添加到实体类中的注释自动在数据库中创建 User 表。
图 7 – 用户表
在此步骤中,我们将创建一个接口并将其命名为UserRepository并将此类扩展至JPA存储库。因此,我们可以轻松进行 CRUD 操作。
UserRepository.java
import org.springframework.data.jpa.repository.JpaRepository;
import com.geeksforgeeks.ModelMapper.data.User;
// 在参数中,我们需要传递我们的模型类和第二个参数是我们使用的 id 类型在我们的模型类中
public interface UserRepository extends JpaRepository<User, Integer> {
}
创建用户服务
现在,我们将创建一个服务接口并将其命名为 UserService。我们将只添加两个方法。一个用于添加用户,另一个用于获取用户。
UserService.java
import com.geeksforgeeks.ModelMapper.data.User;
public interface UserService {
public User createUser(User user);
public User getUser(int userId);
}
之后,我们将添加用户服务接口的实现。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.geeksforgeeks.ModelMapper.data.User;
import com.geeksforgeeks.ModelMapper.repository.UserRepository;
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserRepository userRepository;
@Override
public User createUser(User user) {
User userSavedToDB = this.userRepository.save(user);
return userSavedToDB;
}
@Override
public User getUser(int userId) {
User user = this.userRepository.getById(userId);
return user;
}
}
在此步骤中,我们将创建一个用户控制器来处理和映射我们的请求。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.geeksforgeeks.ModelMapper.data.User;
import com.geeksforgeeks.ModelMapper.repository.UserRepository;
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserRepository userRepository;
@Override
public User createUser(User user) {
User userSavedToDB = this.userRepository.save(user);
return userSavedToDB;
}
@Override
public User getUser(int userId) {
User user = this.userRepository.findById(userId).get();
return user;
}
}
运行应用程序
在此步骤中,我们将使用邮递员运行我们的应用程序并测试我们的 Restful 服务。
图 8 – 创建请求
我们发送了我们的请求。我们将得到以下输出。
图 9 – 响应
我们还可以检查数据库中的新用户条目。
图 10 – 添加到数据库的用户
我们将使用 GET 端点和用户 ID 从数据库中检索用户。
图 11 – 获取用户
正如我们在上面的响应中看到的,我们还将收到密码,这不是编写 Restful API 的好习惯。为了解决这个问题,我们将使用 DTO。
在此步骤中,我们将创建 UserDTO 类,该类仅包含 Web 层必需的字段。
public class UserDto {
private String name;
private String email;
// NoArgsConstructor
public UserDto() {
super();
}
// Getters & Setters
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
我们需要在 pom.xml 文件中添加以下依赖项。
<dependency>
<groupId>org.modelmapper</groupId>
<artifactId>modelmapper</artifactId>
<version>3.1.1</version>
</dependency>
修改类
现在,要使用 UserDto,我们需要修改 UserService、UserServiceImpl 和 UserController 类。
import com.geeksforgeeks.ModelMapper.data.User;
import com.geeksforgeeks.ModelMapper.dto.UserDto;
public interface UserService {
public User createUser(User user);
// updated it with UserDto
public UserDto getUser(int userId);
}
import org.modelmapper.ModelMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.geeksforgeeks.ModelMapper.data.User;
import com.geeksforgeeks.ModelMapper.dto.UserDto;
import com.geeksforgeeks.ModelMapper.repository.UserRepository;
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserRepository userRepository;
@Autowired
private ModelMapper modelMapper;
@Override
public User createUser(User user) {
User userSavedToDB = this.userRepository.save(user);
return userSavedToDB;
}
// update it with UserDto
@Override
public UserDto getUser(int userId) {
User user = this.userRepository.findById(userId).get();
UserDto userDto = this.modelMapper.map(user, UserDto.class);
return userDto;
}
}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.geeksforgeeks.ModelMapper.data.User;
import com.geeksforgeeks.ModelMapper.dto.UserDto;
import com.geeksforgeeks.ModelMapper.service.UserServiceImpl;
@RestController
@RequestMapping("/api/user")
public class UserController {
@Autowired
private UserServiceImpl userServiceImpl;
@PostMapping("/create")
public ResponseEntity<User> createUser(@RequestBody User user){
User userCreated = this.userServiceImpl.createUser(user);
return new ResponseEntity<User>(userCreated, HttpStatus.CREATED);
}
// update it with UserDto
@GetMapping("/get/{id}")
public ResponseEntity<UserDto> getUser(@PathVariable("id") int userId){
UserDto userDto = this.userServiceImpl.getUser(userId);
return new ResponseEntity<UserDto>(userDto, HttpStatus.OK);
}
}
添加模型映射器 Bean
在此步骤中,我们将把模型映射器 bean 添加到我们的主 Spring Boot 类中。
import org.modelmapper.ModelMapper;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
public class ModelMapperApplication {
public static void main(String[] args) {
SpringApplication.run(ModelMapperApplication.class, args);
}
@Bean
public ModelMapper getModelMapper() {
return new ModelMapper();
}
}
运行应用程序
现在,我们将再次运行我们的应用程序并使用 GET 端点来查看响应。
图 12 – 响应
正如我们在上面的响应中看到的,我们只获得了 Web 层所需的必要字段。尽管如此,我们将创建一个包含所有字段的新用户,但只会将必需的字段发送到 Web 层。