1. 程式人生 > >Spring Data REST不完全指南(三)

Spring Data REST不完全指南(三)

上一篇我們介紹了使用Spring Data REST時的一些高階特性,以及使用程式碼演示瞭如何使用這些高階的特性。本文將繼續講解前面我們列出來的七個高階特性中的後四個。至此,這些特效能滿足我們大部分的介面開發場景。

需要滿足的一些要求:
1.針對欄位級別,方法級別,類級別進行限制(禁止某些欄位,方法,介面的對外對映)。
2.對資料增刪改查的限制(禁止某些請求方法的訪問)。
3.能個性化定義請求的路徑。
4.對所傳引數進行值校驗。
5.響應統一處理。
6.異常處理。
7.資料處理的切面。

➡️本文,將演示7個要求中的其餘四個要求。


對所傳引數進行值校驗

對於值校驗,Spring 提供了Validator介面,Spring Data REST提供了使用Validator來進行值校驗的功能。

首先我們通過實現Validator介面來建立一個校驗器,然後在實現RepositoryRestConfigurer或Spring Data REST的RepositoryRestConfigurerAdapter的子類的配置中,重寫configureValidatingRepositoryEventListener方法,並在ValidatingRepositoryEventListener上呼叫addValidator,傳遞要觸發此校驗器的事件和校驗器的例項。以下示例顯示瞭如何執行此操作:

public class SaveTenantValidator implements Validator {
    @Override
    public boolean supports(Class<?> clazz) {
        return Tenant.class.isAssignableFrom(clazz);
    }

    @Override
    public void validate(Object target, Errors errors) {
        Tenant tenant = (Tenant) target;
        if (StringUtils.isEmpty(tenant.getMobile())) {
            errors.rejectValue("mobile", "1001", "手機號不能為空");
        }
    }
}

如上,我們聲明瞭一個Validator類,作為對手機號校驗的Validator。接著我們通過以下程式碼註冊我們的校驗器。

@Component
public class SpringDataRestCustomization implements RepositoryRestConfigurer {
    @Override
    public void configureValidatingRepositoryEventListener(ValidatingRepositoryEventListener validatingListener) {
        validatingListener.addValidator("beforeCreate", new SaveTenantValidator());
    }
}

validatingListener.addValidator("beforeCreate", new SaveTenantValidator());我們使用validatingListener.addValidator()來註冊我們的校驗器。該方法傳入兩個引數,第一個代表著要校驗的事件,"beforeCreate"即代表著在插入新紀錄之前,對插入資料進行校驗。spring Data REST還提供了其他的事件:

  • BeforeCreateEvent
  • AfterCreateEvent
  • BeforeSaveEvent
  • AfterSaveEvent
  • BeforeLinkSaveEvent
  • AfterLinkSaveEvent
  • BeforeDeleteEvent
  • AfterDeleteEvent

我們都可以從字面意思進行理解。

方法中的第二個引數,就是指定我們要註冊的校驗器,如上程式碼中,我們對我們剛剛建立的校驗器進行註冊。

如下為驗證效果:


響應統一處理

有時候我們需要對響應結果進行統一處理,比如,我們希望我們的響應結果中包含當前時間的時間戳又或者我們希望我們的HAL格式的響應資料中增加其他的連結。這時候,我們可以通過響應統一處理來完成這種看似重複性的工作。但是Spring Data REST並沒有提供現成的功能,不過我們可以通過覆蓋Spring Data REST響應處理程式,來實現這一目標。

@RepositoryRestController
public class TenantController {
    private final TenantRepository tenantRepository;
		@Resource
    private RepositoryEntityLinks entityLinks;
    @Autowired
    public TenantController(TenantRepository tenantRepository) {
        this.tenantRepository = tenantRepository;
    }

    @GetMapping(value = "/tenantPath/search/mobile")
    public ResponseEntity<?> getByMobile(@RequestParam String mobile) {
        Tenant tenant = tenantRepository.findFirstByMobile(mobile);
        EntityModel<Tenant> resource = new EntityModel<>(tenant);
        resource.add(linkTo(methodOn(TenantController.class).getByMobile(mobile)).withSelfRel());
      resource.add(entityLinks.linkToSearchResource(Tenant.class, LinkRelation.of("findAllByIdCardContaining")));
        return ResponseEntity.ok(resource);
    }
}

如上程式碼,我們使用了@RepositoryRestController註解來建立了一個控制器,並定義了一個路徑的請求,以此我們覆蓋了之前Spring Data REST自動為我們提供的相同路徑的介面。我們給介面的響應增加了兩個連結。

注意:上述程式碼中用到了Spring HATEOAS的庫,所以我們需要增加Spring HATEOAS的依賴。

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-hateoas</artifactId>
</dependency>
<dependency>
  <groupId>org.atteo</groupId>
  <artifactId>evo-inflector</artifactId>
</dependency>

現在我們訪問http://localhost:8080/tenantPath/search/mobile?mobile=186****3331,看到響應結果:

{
  "name": "王一",
  "mobile": "186****3331",
  "rentDateTime": "2020-04-22 17:48:40",
  "_links": {
    "self": {
      "href": "http://localhost:8080/tenantPath/search/mobile?mobile=186****3331"
    },
    "findAllByIdCardContaining": {
      "href": "http://localhost:8080/tenantPath/search/findAllByIdCardContaining{?idCard,page,size,sort,projection}",
      "templated": true
    }
  }
}

可以看到,links屬性中連結已經變成我們指定的連結了。


異常統一處理

Spring Data REST中並沒有提供異常處理的功能,但是我們可以使用Springboot中自帶的異常處理功能來實現我們的要求。

@Slf4j
@ControllerAdvice
public class ExceptionTranslator {
    @ExceptionHandler
    public ResponseEntity<Object> handleEmailAlreadyUsedException(NullPointerException ex, NativeWebRequest request) {
        log.info("遇到空指標");
        return ResponseEntity.ok(List.of("攔截到空指標異常"));
    }
}

如上,我們聲明瞭一個異常處理器。接下來我人為製造一個錯誤。

@RepositoryRestController
public class TenantController {
    private final TenantRepository tenantRepository;

    @Autowired
    public TenantController(TenantRepository tenantRepository) {
        this.tenantRepository = tenantRepository;
    }

    @GetMapping(value = "/tenantPath/search/mobile")
    public ResponseEntity<?> getByMobile(@RequestParam String mobile) {
      	if (1 == 1) {
           throw new NullPointerException();
        }
        Tenant tenant = tenantRepository.findFirstByMobile(mobile);
        EntityModel<Tenant> resource = new EntityModel<>(tenant);
        resource.add(linkTo(methodOn(TenantController.class).getByMobile(mobile)).withSelfRel());
        return ResponseEntity.ok(resource);
    }
}

此時,我們請求此介面:

[
  "攔截到空指標異常"
]

可以看到,我們的異常被我們的異常處理器攔截掉了。


資料切面處理

Spring Data REST提供了類似的Aop切面操作,雖然不能和Spring的原生aop相比,但是其簡潔性也能滿足需求。Spring Data REST提供的是基於事件的切面。如下我們聲明瞭一個切面。

@Component
@Slf4j
@RepositoryEventHandler
public class TenantEventHandler {
    @HandleBeforeDelete
    protected void onBeforeDelete(Tenant entity) {
        log.info("現在要開始刪除操作了,刪除物件:{}", entity);
    }
    @HandleAfterDelete
    protected void onAfterDelete(Tenant entity) {
        log.info("刪除物件完成,刪除物件:{}", entity);
    }

}

如上,我們聲明瞭一個切面,我們可以在刪除操作之前和之後進行額外的邏輯處理,示例中很簡單,我們使用日誌記錄事件的發生。

此時,我們訪問專案的刪除介面curl --location --request DELETE 'http://localhost:8080/tenantPath/1'

我們可以看到控制輸出了相應的日誌:

2020-04-23 17:26:29.950 INFO 38077 --- [nio-8080-exec-1] c.e.d.configuration.TenantEventHandler : 現在要開始刪除操作了,刪除物件:Tenant(id=1, name=王一, idCard=3305221, mobile=1863331, rentDateTime=2020-04-22T17:24:46.105897, house=House(id=2, houseNumber=1101, owner=張三, idCard=3305211))

2020-04-23 17:26:30.035 INFO 38077 --- [nio-8080-exec-1] c.e.d.configuration.TenantEventHandler : 刪除物件完成,刪除物件:Tenant(id=1, name=王一, idCard=3305221, mobile=1863331, rentDateTime=2020-04-22T17:24:46.105897, house=House(id=2, houseNumber=1101, owner=張三, idCard=3305211))

此時,我們的資料切面處理生效了,除此之外,Spring Data REST還提供瞭如下幾個基於事件的切面:


總結

至此,我們先前列出的所有功能特性三篇文章中都有涉及到,通過引入這些功能特性,我們能更加輕鬆的使用Spring Data REST,並且也能滿足我們大部分介面開發的場景。當然三篇文章不能涉及Spring Data REST的全部,有興趣的小夥伴可以訪問Spring Data REST的官方文件檢視更多關於Spring Data REST的特性及資訊。


關注筆者公眾號,推送各類原創/優質技術文章 ⬇️

相關推薦

Spring Data REST完全指南

上一篇我們介紹了使用Spring Data REST時的一些高階特性,以及使用程式碼演示瞭如何使用這些高階的特性。本文將繼續講解前面我們列出來的七個高階特性中的後四個。至此,這些特效能滿足我們大部分的介面開發場景。 需要滿足的一些要求: 1.針對欄位級別,方法級別,類級別進行限制(禁止某些欄位,方法,介面的

Spring Data REST完全指南

上一篇文章介紹了Spring Data REST的功能及特徵,以及演示瞭如何在專案中引入Spring Data REST並簡單地啟動演示了Spring Data REST專案。在本文中,我們將深入瞭解Spring Data REST的特性,以此來滿足我們日常api開發工作的要求。 如果僅僅是上一篇文章中對Sp

Chrome開發者工具完全指南四、效能進階篇

前言   Profiles面板功能的作用主要是監控網頁中各種方法執行時間和記憶體的變化,簡單來說它就是Timeline的數字化版本。它的功能選項卡不是很多(只有三個),操作起來比較前面的幾塊功能版本來說簡單,但是裡面的資料確很多,很雜,要弄懂它們需要花費一些時間。尤其是在記憶體快照中的各種龐雜的資料。在這篇

Chrome開發者工具完全指南五、移動篇

  前面介紹了Chrome開發者工具的大部分內容工具,現在介紹最後兩塊功能Audits和Console面板。一、Audits  Audits面板會針對目前網頁提出若干條優化的建議,這些建議分為兩大類,一類是網路載入效能,另一類是介面效能。首先開下它的主介面。  Audits面板的網路優化建議參照的是雅虎前端工

Chrome開發者工具完全指南一、基礎功能篇

  就算你不是一名前端開發工程師,相信你也不會對Chrome瀏覽器感到陌生。根據最新的一份(2015/06)的瀏覽器市場佔有率報告,Chrome近乎佔有瀏覽器天下的半壁江山。簡單、快捷使它成為了新時代人們的新寵。如果你是一名web開發人員,我推薦你使用Chrome。作為前端開發的"IDE",你只需要搭配一個編

Chrome開發者工具完全指南二、進階篇

function a () { b(); } function b() { c(); } function c() { //在該處斷點,檢視call stack } a->b->c. call stack 從上到下的順序就是 c

Spring Cloud Alibaba遷移指南:極簡的 Config

自 Spring Cloud 官方宣佈 Spring Cloud Netflix

Java多線程編程模式實戰指南:Two-phase Termination模式

增加 row throws mgr 額外 finally join table 還需 停止線程是一個目標簡單而實現卻不那麽簡單的任務。首先,Java沒有提供直接的API用於停止線程。此外,停止線程時還有一些額外的細節需要考慮,如待停止的線程處於阻塞(等待鎖)或者等待狀態(等

Redis 小白指南- 事務、過期、消息通知、管道和優化內存空間

如何 入門 系列 code 場景 消息 運算 封裝 c# Redis 小白指南(三)- 事務、過期、消息通知、管道和優化內存空間 簡介   《Redis 小白指南(一)- 簡介、安裝、GUI 和 C# 驅動介紹》 講的是 Redis 的介紹,以及如何在 Windows

C語言攻略指南流程控制篇

... cpp 流程控制 printf 循環結構 多重 -a 1-43 continue 流程控制語句,或者說控制流語句,是用於控制程序計算操作執行的次序,使我們能實現判斷,選擇,循環等操作。本篇將逐一描述 C語言中的流程控制語句。 選擇結構 if 語句 if(表達式

JNI/NDK開發指南——JNI數據類型及與Java數據類型的映射關系

ons 轉換 類型 art return http 異常 array src 轉載請註明出處:http://blog.csdn.net/xyang81/article/details/42047899 當我們在調用一個

spring boot 登錄註冊 demo -- 前後端傳遞

lin 表單提交 www col log ref rec put 內容 前端頁面通過thymeleaf渲染     <dependency> <groupId>org.springframework.boot</gro

Spring Data 關於Repository的介紹

聲明 except int pre dcl import type esc return Repository類的定義: public interface Repository<T, ID extends Serializable> { } 1)Rep

android源碼編譯——從此走上Liunx的歸路

article down 安裝git https ani 同步 版本 bsp rep 下載android源碼: 1.安裝git和curl: sudo apt-get install git-core sudo apt-get install git-core curl 2

Android Gradle Plugin指南——依賴關系、android庫和多項目配置

tool 全部 ocs 共享 項目路徑 多項目配置 path 用戶 so文件 原文地址:http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Dependencies-Android-L

Spring IOC容器的初始化-BeanDefinition的註冊

store erro pan customize 註冊 failed mono def override ---恢復內容開始--- 前言 在上一篇中有一處代碼是BeanDefiniton註冊的入口,我們回顧一下。 1.BeanDefiniton在IOC容器註冊 首先我

【轉】Spring Boot幹貨系列:啟動原理解析

無法 time exp 記得 started 打印 ping 正文 exclude 前言 前面幾章我們見識了SpringBoot為我們做的自動配置,確實方便快捷,但是對於新手來說,如果不大懂SpringBoot內部啟動原理,以後難免會吃虧。所以這次博主就跟你們一起一步步揭開

Qt與FFmpeg聯合開發指南——編碼1:代碼流程演示

開啟 fault 原因 上下 sizeof ffmpeg 不同步 目前 直接 前兩講演示了基本的解碼流程和簡單功能封裝,今天我們開始學習編碼。編碼就是封裝音視頻流的過程,在整個編碼教程中,我會首先在一個函數中演示完成的編碼流程,再解釋其中存在的問題。下一講我們會將編碼功能進

小橙書閱讀指南——插入排序

stat 指定 improve @override n) alt img 解釋 style 算法描述:通常人們在整理撲克的方法是一張一張的來,將每一張牌插入到其他已經有序的牌中的適當位置。在算法的實現中,為了給要插入的元素騰出1個空間,我們需要將其余所有元素在插入之前都向右

Spring整合Struts2和Hibernate+Maven之請求的處理

關於請求的處理,即涉及前面提到Struts2。 具體流程:頁面發出請求->攔截action->處理action->具體到那個類的哪個方法處理。 頁面發出請求: fm.action="/Login_register"; fm.subm