官术网_书友最值得收藏!

4.1.4 Spring WebMVC案例分析

本節將通過一個案例來演示如何通過Spring WebMVC構建RESTful風格的Web API。首先,我們在Maven的pom文件中添加如代碼清單4-36所示的依賴包。

代碼清單4-36 Spring WebMVC依賴包定義代碼

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-mongodb</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

在本案例里,我們采用MongoDB來實現數據存儲,所以這里還引入了一個spring-boot-starter-data-mongodb依賴包。

現在,讓我們來定義業務領域對象。在本案例中,我們設計一個User對象,該對象可以包含該用戶的好友信息以及該用戶所閱讀的文章信息。User對象的字段定義如代碼清單4-37所示,這里的@Document、@Id以及@Field注解都來自MongoDB。

代碼清單4-37 User類定義代碼

@Document("users")
public class User {
    @Id
    private String id;
    @Field("name")
    private String name;
    @Field("age")
    private Integer age;
    @Field("createAt")
    private Date createdAt;
    @Field("nationality")
    private String nationality;
    @Field("friendsIds")
    private List<String> friendsIds;
    @Field("articlesIds")
    private List<String> articlesIds;
    //省略getter/setter方法
}

注意,在這個User對象中存在兩個數組friendsIds和articlesIds,分別用于保存該用戶的好友和所閱讀文章的編號,其中好友信息實際上就是User對象,而文章信息則涉及另一個領域對象Article。

有了領域對象之后,我們就可以設計并實現數據訪問層組件。這里就需要引入Spring家族中的另一個常用框架Spring Data。Spring Data是Spring家族中專門用于實現數據訪問的開源框架,其核心原理是支持對所有存儲媒介進行資源配置從而實現數據訪問。我們知道,數據訪問需要完成領域對象與存儲數據之間的映射,并對外提供訪問入口。Spring Data基于Repository架構模式抽象出了一套統一的數據訪問方式。Spring Data的基本使用過程非常簡單,我們在本書第9章中還會對Spring Data詳細講解。

基于Spring Data,我們可以定義一個UserRepository,如代碼清單4-38所示。

代碼清單4-38 UserRepository接口定義代碼

public interface UserRepository extends PagingAndSortingRepository<User, String> {
    User findUserById(String id);
}

可以看到UserRepository擴展了PagingAndSortingRepository接口,而后者針對User對象提供了一組CRUD以及分頁和排序方法,開發人員可以直接使用這些方法完成對數據的操作。

注意,這里我們還定義了一個findUserById()方法,該方法實際上使用了Spring Data提供的方法名衍生查詢機制。使用方法名衍生查詢是最方便的一種自定義查詢方式,開發人員唯一要做的就是在Repository接口中定義一個符合查詢語義的方法。例如,如果我們希望通過ID來查詢User對象,那么只需要提供findUserById()這一符合常規語義的方法定義即可。

類似地,ArticleRepository的定義也非常簡單,如代碼清單4-39所示。

代碼清單4-39 ArticleRepository接口定義代碼

public interface ArticleRepository extends PagingAndSortingRepository<Article, String> {
    Article findArticleById(String id);
}

基于數據訪問層組件,Service層組件的實現也并不復雜,基本就是對UserRepository和ArticleRepository中的接口方法的合理利用。UserService和ArticleService的實現過程如代碼清單4-40所示。

代碼清單4-40 UserService和ArticleService類實現代碼

@Service
public class UserService {
    private final UserRepository userRepository;

    @Autowired
    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    public User findUserById(String id) {
        return userRepository.findUserById(id);
    }

    public List<User> findByIds(List<String> ids) {
        List<User> list = new ArrayList<>();
        ids.forEach(id -> list.add(userRepository.findUserById(id)));
        return list;
    }

    public List<User> findAllUsers() {
        return (List<User>) userRepository.findAll();
    }
}

@Service
public class ArticleService {
    private final ArticleRepository articleRepository;

    @Autowired
    public ArticleService(ArticleRepository articleRepository) {
        this.articleRepository = articleRepository;
    }

    public List<Article> findAllUserArticles(List<String> articleIds) {
        List<Article> articles = new ArrayList<>();
        articleIds.forEach(id -> articles.add(articleRepository.findArticleById(id)));
        return articles;
    }
}

最后,我們來根據用戶ID獲取其對應的閱讀文章信息。為此,我們實現如代碼清單4-41所示的ArticleController。

代碼清單4-41 ArticleController類實現代碼

@RestController
@RequestMapping("/articles")
public class ArticleController {
    private ArticleService articleService;
    private UserService userService;

     @Autowired
    public ArticleController(ArticleService articleService, UserService userService) {
        this.articleService = articleService;
        this.userService = userService;
    }

    @GetMapping(value = "/{userId}")
    public List<Article> getArticlesByUserId(@PathVariable String userId){
        List<Article> articles = new ArrayList<Article>();

        User user = userService.findUserById(userId);
        if(user != null) {
            articles = articleService.findAllUserArticles(user.getArticlesIds());
        }
        return articles;
    }
}

ArticleController的實現過程充分展現了使用Spring Boot開發RESTful風格Web API的簡便性。完整的案例代碼可以參考:https://github.com/tianminzheng/spring-boot-examples/tree/main/SpringWebMvcExample

在本章4.3節中討論Spring GraphQL框架時,我們還會使用這個案例并對其重構,從而滿足GraphQL的應用場景。

主站蜘蛛池模板: 牡丹江市| 同仁县| 大同县| 水城县| 博罗县| 龙胜| 靖州| 乐昌市| 贞丰县| 改则县| 琼结县| 漳浦县| 丽水市| 高唐县| 闽清县| 扶余县| 乌什县| 张家界市| 达拉特旗| 达尔| 安达市| 大足县| 德阳市| 高淳县| 旺苍县| 新野县| 辉南县| 苍南县| 吉安市| 西充县| 鄯善县| 锡林浩特市| 彭州市| 巨鹿县| 绵竹市| 贵溪市| 深圳市| 德江县| 斗六市| 长兴县| 南城县|