概要
前回リクエスト情報を DTO に変換して安全にデータベースの情報を取得する方法を紹介しました
今回はレスポンスでも DTO を導入してみます
環境
- macOS 26.4.1
- openjdk 26.0.1
- SpringBoot 4.0.6
- jasypt-spring-boot 4.0.4
- gradle 9.5.1
- VSCode 1.121.0
- MySQL 9.6.0
レスポンス用 DTO の作成
レスポンス用の DTO には返却したい情報だけを定義します
今回はテストなので name だけ返却するようにします
- vim src/main/java/com/example/demo/dto/UserResponse.java
package com.example.demo.dto;
import jakarta.validation.constraints.NotBlank;
public class UserResponse {
@NotBlank
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
UserService の修正
getAllUsers を先ほど作成した UserResponse が帰るように修正します
stream を使ってクロージャっぽく変換しています
- vim src/main/java/com/example/demo/service/UserService.java
package com.example.demo.service;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.example.demo.dto.UserRequest;
import com.example.demo.dto.UserResponse;
import com.example.demo.entity.User;
import com.example.demo.repository.UserRepository;
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
public void createUser(UserRequest req) {
// 例:ビジネスルール
if (userRepository.existsByEmail(req.getEmail())) {
throw new IllegalArgumentException("既に登録されています");
}
User user = new User();
user.setName(req.getName());
user.setEmail(req.getEmail());
userRepository.save(user);
}
public List<UserResponse> getAllUsers() {
List<User> users = new ArrayList<>();
userRepository.findAll().forEach(users::add);
return users.stream().map(this::toResponse).toList();
}
private UserResponse toResponse(User user) {
UserResponse response = new UserResponse();
response.setName(user.getName());
return response;
}
}
コントローラの修正
コントローラからは Service レイヤーのみを扱うように修正します
これでコントローラが直接 Repository を扱うことはなくなりました
- vim src/main/java/com/example/demo/MainController.java
package com.example.demo;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
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.ResponseBody;
import com.example.demo.dto.UserRequest;
import com.example.demo.dto.UserResponse;
import com.example.demo.service.UserService;
import jakarta.validation.Valid;
@Controller
@RequestMapping(path = "/demo")
public class MainController {
@Autowired
private UserService userService;
@PostMapping(path = "/add")
public @ResponseBody String addNewUser(@Valid @RequestBody UserRequest req) {
userService.createUser(req);
return "Saved";
}
@GetMapping(path = "/all")
public @ResponseBody List<UserResponse> getAllUsers() {
return userService.getAllUsers();
}
}
動作確認
-
./gradlew bootRun --args='--jasypt.encryptor.password=xxx'
curl で GET し UserResponse に定義されている値だけ返ってくることを確認しましょう
-
curl -XGET http://localhost:8080/demo/all
[{"name":"First"}]
最後に
SpringBoot でレスポンスに DTO を導入してみました
レスポンスに DTO を導入するメリットとしては以下のようなものがあります
- 予期せぬデータベース情報の返却を防ぐ
- データベースの情報を加工してレスポンスを生成する
基本的にはレスポンスにも DTO を含めるのがベストプラクティスにはなります
0 件のコメント:
コメントを投稿