JSR 303全解析:如何在Java項目中實施高效數據校驗

1. JSR 303是什么?

JSR 303(Java Specification Request 303),也稱為Bean Validation,是Java中的一個規范,用于定義Java對象的校驗規則。

1.1 JSR 303的主要功能

  • 注解驅動:通過注解直接在Java類上定義校驗規則。
  • 內置約束:如@NotNull、@Size、@Min、@Max等。
  • 自定義約束:可以定義自定義的校驗注解和邏輯。
  • 分組校驗:支持對不同場景(如創建和更新)進行分組校驗。

1.2 常用注解

  • @NotNull:驗證注解的元素值不是null。
  • @Size:驗證注解的元素的大小在指定范圍內。
  • @Min和@Max:驗證注解的元素值在指定范圍內。
  • @Email:驗證注解的元素是一個合法的電子郵件地址。

2. 使用步驟

JSR 303 是一個規范,所以需要具體的實現。Hibernat Bean Validator 就是Bean Validator的實現

2.1.引入庫

        <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId></dependency><dependency><groupId>javax.validation</groupId><artifactId>validation-api</artifactId><version>2.0.1.Final</version></dependency><dependency><groupId>org.hibernate</groupId><artifactId>hibernate-validator</artifactId><version>8.0.1.Final</version></dependency>

2.2 實體類編寫校驗規則

代碼如下(示例):

@Data
public class BrandEntity implements Serializable {/*** 品牌ID,用于標識品牌。* * 此字段通過注解進行了不同的驗證邏輯配置,以適應不同的業務場景。* 在更新操作(UpdateGroup)中,要求此字段不為空,確保了更新操作有明確的目標品牌ID。* 在新增操作(AddGroup)中,要求此字段為空,因為新增品牌時不應該預先指定ID。* 這種通過注解進行驗證的方式,提高了代碼的靈活性和可維護性,避免了在業務邏輯中硬編碼驗證邏輯。*/@NotNull(message = "修改必須指定品牌id",groups = {UpdateGroup.class})@Null(message = "新增不能指定id",groups = {AddGroup.class})private Long brandId;/*** 品牌名稱字段。* * 該字段是必填的,不允許為空字符串,這在添加和更新品牌信息時都必須遵守。* 使用@NotBlank注解來強制驗證品牌名的非空性,如果為空,則會觸發驗證失敗,* 返回相應的錯誤消息。*/@NotBlank(message = "品牌名必須提交",groups = {AddGroup.class,UpdateGroup.class})private String name;/*** 品牌logo地址* * 此字段在添加(AddGroup)和更新(UpdateGroup)時都必須是一個合法的URL地址,* 以確保公司徽標的鏈接是有效和可訪問的。使用@URL注解進行驗證,* 如果不符合URL格式,則會提示指定的錯誤信息。* * 使用@NotBlank注解確保在添加時該字段不為空,為空則認為是無效的輸入。* 這是因為在更新時,如果用戶沒有提供新的徽標URL,可以保留舊的URL,* 所以在更新組(UpdateGroup)中,@NotBlank約束被移除,允許為空。*/@NotBlank(groups = {AddGroup.class})@URL(message = "logo必須是一個合法的url地址",groups={AddGroup.class,UpdateGroup.class})private String logo;/*** 展示狀態字段,用于標記對象的展示狀態。* 顯示狀態[0-不顯示;1-顯示]* * 此字段受到兩個驗證組(AddGroup, UpdateStatusGroup)的約束。* 在這兩個組中,該字段不能為空(@NotNull)且其值必須在預定義的列表中(@ListValue)。* 這樣的設計確保了在添加對象和更新狀態操作時,展示狀態的值是有效且受控的。* * @NotNull(groups = {AddGroup.class, UpdateStatusGroup.class})* 表明在AddGroup和UpdateStatusGroup驗證組中,此字段不能為空。* @ListValue(vals={0,1},groups = {AddGroup.class, UpdateStatusGroup.class})* 表明在AddGroup和UpdateStatusGroup驗證組中,此字段的值必須是0或1。*/@NotNull(groups = {AddGroup.class, UpdateStatusGroup.class})@ListValue(vals={0,1},groups = {AddGroup.class, UpdateStatusGroup.class})private Integer showStatus;/*** 字段firstLetter用于存儲實體的首字母。* 該字段的驗證有以下規則:* 1. 在添加(AddGroup)時,不能為空,確保數據完整性。* 2. 在添加(AddGroup)和更新(UpdateGroup)時,必須是一個字母,確保數據的格式符合預期。* 這些驗證規則通過注解的方式進行聲明,以在運行時對數據進行校驗。*/@NotEmpty(groups={AddGroup.class})@Pattern(regexp="^[a-zA-Z]$",message = "檢索首字母必須是一個字母",groups={AddGroup.class,UpdateGroup.class})private String firstLetter;/*** 排序字段,用于控制元素的顯示順序。* * @NotNull 標注指示該字段在添加(AddGroup)時不能為空,確保了排序值的有效性。* @Min 標注指定了排序值必須大于等于0,適用于添加(AddGroup)和更新(UpdateGroup)操作,保證了排序的邏輯正確性。*/@NotNull(groups={AddGroup.class})@Min(value = 0,message = "排序必須大于等于0",groups={AddGroup.class,UpdateGroup.class})private Integer sort;}

2.3 自定義約束

通過上面的代碼可以看出,如果要指定注解作用的范圍,就要自己添加分組。

AddGroup

public interface AddGroup {
}

UpdateGroup

public interface UpdateGroup {
}

UpdateStatusGroup

public interface UpdateStatusGroup {
}

上述代碼中為了對狀態取值進行驗證,我們采用了自定義驗證器的方式

ListValue

@Documented
@Constraint(validatedBy = { ListValueConstraintValidator.class })
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
public @interface ListValue {String message() default "{com.xunqi.common.valid.ListValue.message}";Class<?>[] groups() default { };Class<? extends Payload>[] payload() default { };int[] vals() default { };
}

ListValueConstraintValidator

/*** 實現了ListValue注解的驗證器,用于驗證一個整數是否在預定義的整數列表中。* 該驗證器在驗證階段檢查給定的整數是否存在于初始化時指定的整數集合中。*/
public class ListValueConstraintValidator implements ConstraintValidator<ListValue, Integer> {/*** 用于存儲驗證器初始化時指定的整數列表的集合。*/private Set<Integer> set = new HashSet<>();/*** 初始化驗證器,加載注解中指定的整數列表到集合中。** @param constraintAnnotation ListValue注解實例,其中包含需要驗證的整數列表。*/@Overridepublic void initialize(ListValue constraintAnnotation) {int[] value = constraintAnnotation.vals();for (int val : value) {set.add(val);}}/*** 驗證給定的整數是否在集合中。** @param value 待驗證的整數。* @param context 驗證上下文,提供關于驗證操作的上下文信息。* @return 如果給定的整數存在于集合中,則返回true;否則返回false。*/@Overridepublic boolean isValid(Integer value, ConstraintValidatorContext context) {return set.contains(value);}
}

3. 業務層使用


/*** <p>* 商品品牌 前端控制器* </p>** @author shiqi* @version 1.0.0* @createTime 2024-06-26*/
@RestController
@RequestMapping("product/brand")
public class BrandController {/*** 保存品牌信息。* <p>* 該方法通過@RequestMapping注解映射了"/save"的HTTP請求,用于保存BrandEntity對象。* 使用@Validated注解對brandEntity參數進行驗證,確保添加或修改品牌時數據的合法性。* BindingResult參數用于接收驗證后的錯誤信息,可以進一步處理和反饋給前端。* <p>* 方法返回一個R對象,通常表示操作的成功或失敗狀態。** @param brandEntity 品牌實體對象,包含待保存的品牌信息。* @param bindingResult 驗證結果對象,用于存儲brandEntity驗證過程中產生的錯誤信息。* @return 返回一個表示操作結果的對象,通常是一個包含成功狀態和相關消息的R對象。*/@RequestMapping("/save")public R save(@Validated({AddGroup.class}) @RequestBody BrandEntity brandEntity, BindingResult bindingResult) {// 方法體中應包含保存品牌信息的具體邏輯,此處省略。return R.ok();}}

4. 封裝統一異常

4.1 業務異常狀態枚舉類

/*** <p>* 描述:業務異常枚舉類* </p>** @author shiqi* @version 1.0.0* @createTime 2024-06-26*/
public enum BizCodeEnum {UNKNOWN_EXCEPTION(10000,"系統未知異常"),VALID_EXCEPTION(10001,"參數格式校驗失敗"),TO_MANY_REQUEST(10002,"請求流量過大,請稍后再試"),SMS_CODE_EXCEPTION(10002,"驗證碼獲取頻率太高,請稍后再試"),PRODUCT_UP_EXCEPTION(11000,"商品上架異常"),USER_EXIST_EXCEPTION(15001,"存在相同的用戶"),PHONE_EXIST_EXCEPTION(15002,"存在相同的手機號"),NO_STOCK_EXCEPTION(21000,"商品庫存不足"),LOGIN_ACCOUNT_PASSWORD_EXCEPTION(15003,"賬號或密碼錯誤");private int code;private String message;BizCodeEnum(int code, String message) {this.code = code;this.message = message;}public int getCode() {return code;}public String getMessage() {return message;}
}

4.2 封裝統一返回結果


/*** <p>*  統一返回結果* </p>** @author shiqi* @version 1.0.0* @createTime 2024-06-26*/public class R extends HashMap<String, Object> {private static final long serialVersionUID = 1L;public R setData(Object data) {put("data",data);return this;}//利用fastjson進行反序列化public <T> T getData(TypeReference<T> typeReference) {Object data = get("data");	//默認是mapString jsonString = JSON.toJSONString(data);T t = JSON.parseObject(jsonString, typeReference);return t;}//利用fastjson進行反序列化public <T> T getData(String key,TypeReference<T> typeReference) {Object data = get(key);	//默認是mapString jsonString = JSON.toJSONString(data);T t = JSON.parseObject(jsonString, typeReference);return t;}public R() {put("code", 0);put("msg", "success");}public static R error() {return error(HttpStatus.SC_INTERNAL_SERVER_ERROR, "未知異常,請聯系管理員");}public static R error(String msg) {return error(HttpStatus.SC_INTERNAL_SERVER_ERROR, msg);}public static R error(int code, String msg) {R r = new R();r.put("code", code);r.put("msg", msg);return r;}public static R ok(String msg) {R r = new R();r.put("msg", msg);return r;}public static R ok(Map<String, Object> map) {R r = new R();r.putAll(map);return r;}public static R ok() {return new R();}public R put(String key, Object value) {super.put(key, value);return this;}public Integer getCode() {return (Integer) this.get("code");}}

自定義校驗異常處理器

/*** <p>*  集中處理所有異常* </p>** @author shiqi* @version 1.0.0* @createTime 2024-06-26*/@Slf4j
@RestControllerAdvice(basePackages = {"com.shiqi.jsr303demo"})
public class CustomExceptionControllerAdvice {/*** 處理方法參數不合法異常。* 當方法參數不滿足驗證條件時,Spring MVC會拋出MethodArgumentNotValidException異常。* 該異常處理器專門捕獲此類異常,以統一的方式處理參數驗證失敗的情況。** @param e MethodArgumentNotValidException異常實例,包含驗證失敗的詳細信息。* @return 返回一個包含錯誤信息的響應對象。*/@ExceptionHandler(value = MethodArgumentNotValidException.class)public R handleMethodArgumentNotValidException(MethodArgumentNotValidException e){// 獲取驗證結果對象,其中包含了具體的驗證錯誤信息。BindingResult bindingResult = e.getBindingResult();// 初始化一個映射,用于存儲字段名和對應的錯誤信息。HashMap<String,String> errMap=new HashMap<String,String>();// 檢查是否有驗證錯誤,如果有,則遍歷所有字段錯誤,并將字段名和錯誤信息添加到errMap中。if (bindingResult.hasErrors()){bindingResult.getFieldErrors().forEach((item)->{errMap.put(item.getField(),item.getDefaultMessage());});}// 返回一個包含錯誤代碼、錯誤消息和具體錯誤詳情的響應對象。// 錯誤代碼為400,表示客戶端請求錯誤,錯誤消息為"參數校驗不合法"。// errMap作為數據部分的一部分,包含了所有驗證失敗的字段和對應的錯誤信息。return R.error(400,"參數校驗不合法").put("data",errMap);}/*** 處理所有異常的控制器異常處理器。* <p>* 該方法旨在捕獲控制器層拋出的任何異常,無論是預期的業務異常還是未預期的運行時異常。* 它的目的是統一異常的處理方式,向客戶端返回一個標準的響應體,而不是直接暴露服務器內部錯誤信息。** @param throwable 拋出的異常對象,無論異常類型為何。* @return 返回一個表示錯誤響應的R對象。這個響應體可以幫助客戶端識別請求處理過程中發生了什么錯誤。*/@ExceptionHandler(value = Throwable.class)private R handleValidException(Throwable throwable) {// 記錄異常信息到日志系統,以便后續的問題排查和分析。log.error("出現異常{},異常類型{}", throwable.getMessage(), throwable.getClass());// 返回一個通用的錯誤響應體,通知客戶端請求處理過程中發生了錯誤。return R.error();}}

5. 實際業務中的應用

  1. 表單校驗:確保用戶輸入的數據合法,如用戶注冊、登錄、表單提交等。
  2. 數據傳輸對象(DTO)校驗:在進行數據傳輸時,確保傳輸的數據符合預期,如API請求和響應。
  3. 領域對象校驗:確保業務邏輯中的對象狀態合法,如訂單處理、支付處理等。

使用JSR 303可以有效減少手動校驗代碼,簡化代碼結構,提高代碼可讀性和維護性。在實際應用中,常結合Spring框架和Hibernate Validator一起使用

6. 擴展知識

6.1 PO(Persistence Object)

定義:持久化對象,通常對應數據庫中的一張表,每個實例對應表中的一行。
應用場景:用于數據持久化層,與數據庫的表結構一一對應,通過ORM(如Hibernate)進行數據操作。
使用時機:當需要將數據持久化到數據庫,或者從數據庫中讀取數據時使用。
示例:

public class UserPO {private Long id;private String username;private String password;// Getters and Setters
}

具體使用場景

  • 在需要進行數據庫操作(CRUD)時使用。
  • 與DAO一起使用,以實現數據持久化邏輯。

簡單來說就是Java Bean 對應的是數據庫中的一張表

6.2. BO(Business Object)

定義:業務對象,封裝業務邏輯的Java對象,通常包含業務操作方法。
應用場景:在業務層使用,用于處理業務邏輯,可能會調用多個DAO或與多個PO交互。
使用時機:當需要處理復雜的業務邏輯或操作多個數據對象時使用。
示例:

public class UserBO {private Long id;private String username;private String password;public void changePassword(String newPassword) {// 業務邏輯:更新密碼this.password = newPassword;}// Getters and Setters
}

具體使用場景

  • 在業務層需要進行復雜業務邏輯處理時。
  • 需要將多個數據對象(PO)進行組合或處理時。

6.3. VO(Value Object)

定義:值對象,用于在應用層傳遞數據,通常是只讀的。
應用場景:在視圖層(如MVC中的View)使用,用于展示數據,不包含業務邏輯。
使用時機:當需要在視圖層展示數據,而不需要修改數據時使用。
示例:

public class UserVO {private Long id;private String username;// 只包含展示所需的字段// Getters and Setters
}

具體使用場景

  • 在需要將數據傳遞給前端進行展示時。
  • 在只讀數據場景下使用,如顯示用戶信息。

簡單來說就是對PO進行閹割或者強化,比如我們需要查詢用戶列表的時候,需要對敏感信息進行加密,不太關心的數據我們也不必返回給前端,造成帶寬的浪費。

6.4 DTO(Data Transfer Object)

定義:數據傳輸對象,用于在不同層之間傳輸數據,通常是無狀態的。
應用場景:在數據傳輸層使用,如在服務接口之間傳遞數據,減少遠程調用次數。
使用時機:當需要在不同系統或不同層之間傳遞數據時使用。
示例:

public class UserDTO {private Long id;private String username;private String email;// Getters and Setters
}

具體使用場景

  • 在服務之間的遠程調用中傳輸數據。
  • 在Controller與Service之間傳遞數據。

這個怎么理解了,就是我們進行表單提交的時候,或者更新查詢操作時,需要前端傳遞很多參數,如果每個參數都寫在Controller層的參數列表中就很不優雅,而且如果需新增參數的話就需要改動很多地方,會導致容易遺漏,這個時候我們就把這些請求參數封裝成一個請求對象,這就是DTO。

6.5. POJO(Plain Old Java Object)

定義:簡單的Java對象,不依賴任何特定框架或庫。
應用場景:用于定義普通的Java對象,通常作為PO、BO、VO、DTO的基礎。
使用時機:在需要創建簡單的數據容器而不依賴任何特定框架時使用。
示例:

public class User {private Long id;private String username;private String password;// Getters and Setters
}

具體使用場景

  • 創建簡單的Java對象用于數據封裝。
  • 作為其他對象(PO、BO、VO、DTO)的基礎類。

也就是我們自己編寫的業務類,無需與數據庫打交道的。上述的統一返回結果類,我們就可以理解為POJO

6.6. DAO(Data Access Object)

定義:數據訪問對象,提供對數據庫的抽象和封裝,包含CRUD操作。
應用場景:在數據訪問層使用,負責與數據庫進行交互。
使用時機:當需要對數據庫進行操作(如查詢、插入、更新、刪除)時使用。
示例:

    public void save(UserPO user) {// 保存用戶到數據庫}public UserPO findById(Long id) {// 根據ID查詢用戶return new UserPO();}// 其他CRUD操作
}

具體使用場景

  • 在需要與數據庫進行直接交互時。
  • 在業務邏輯中需要持久化或檢索數據時。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/35837.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/35837.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/35837.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

多家國產大模型提供OpenAI API服務替代方案,谷歌將推出明星網紅AI聊天機器人

ChatGPT狂飆160天&#xff0c;世界已經不是之前的樣子。 更多資源歡迎關注 1、OpenAI終止對中國提供服務 6月25日凌晨&#xff0c;多個用戶收到OpenAI的推送郵件&#xff0c;信中稱&#xff0c;自今年7月9日起&#xff0c;將開始阻止來自非支持國家和地區的API&#xff08;應…

3.任務的創建與刪除

1.什么是任務&#xff1f; 任務可以理解為進程/線程&#xff0c;創建一個任務&#xff0c;就會在內存開辟一個空間。 任務通常都含有while(1)死循環 2.任務創建與刪除相關的函數 3.CUBEMAX相關配置 編輯一個led1閃爍的任務

小程序使用echarts和echarts配置項總結(全網最簡單詳細)

文章目錄 概要小程序中使用echarts1. ec-canvas2. 下載項目3. 去echarts官網定制&#xff1a;4.點擊下載5.引入使用 echarts的option配置知識點歸納整理&#xff08;還在更新&#xff09;&#xff1a;小結 概要 小程序中使用echarts&#xff08;簡單詳細&#xff09; 小程序中…

解密城市酷選為何異軍突起!打造消費新潮流的排隊免單模式

一、城市酷選平臺簡介 在數字化浪潮席卷全球的今天&#xff0c;城市酷選作為一個前沿的消費平臺&#xff0c;憑借其獨特的排隊免單模式&#xff0c;成功吸引了眾多消費者和商家的目光。該平臺不僅整合了線上線下的資源&#xff0c;更通過數字化手段&#xff0c;為消費者提供了…

云計算 | 期末梳理(中)

1. 經典虛擬機的特點 多態(Polymorphism):支持多種類型的OS。重用(Manifolding):虛擬機的鏡像可以被反復復制和使用。復用(Multiplexing):虛擬機能夠對物理資源時分復用。2. 系統接口 最基本的接口是微處理器指令集架構(ISA)。應用程序二進制接口(ABI)給程序提供使用硬件資源…

C3P0數據庫連接池

目錄 一&#xff1a;連接池介紹 1.1連接池解決的問題 2.常用的數據庫連接池 二&#xff1a;c3p0介紹 2.1C3P0介紹&#xff1a; 2.2C3P0快速入門 1.常用參數說明 2.API介紹 3.使用步驟 1.導入jar包c3p0-0.9.1.2.jar 2.編寫c3p0-config.xml配置文件&#xff0c;配置對…

Python 中字符串修飾符

1. 原始字符串 (Raw String) - r 或 R 使用 r 或 R 前綴&#xff0c;可以告訴 Python 字符串中的所有反斜杠都是普通字符&#xff0c;而不是轉義字符。這在處理文件路徑、正則表達式等情況下非常有用。 path rC:\new_folder\test.txt # 原始字符串2. 格式化字符串 (Formatt…

第十九條:要么為繼承而設計并提供文檔說明,要么就禁止繼承

在前面一條中&#xff0c;我們已經知道了David寫了A類被Tom拿去繼承了&#xff0c;導致了A類的封裝性遭到了破壞&#xff0c;那么有沒有可能做點事情避免此事發生呢&#xff1f;第十九條孕育而生&#xff01;David在創建A類的時候寫上文檔說明&#xff0c;說Al類不允許任何類來…

node 實現導出, 在導出excel中包含圖片(附件)

如果想查看 node mySql 實現數據的導入導出&#xff0c;以及導入批量插入的sql語句&#xff0c;連接如下 node mySql 實現數據的導入導出&#xff0c;以及導入批量插入的sql語句-CSDN博客https://blog.csdn.net/snows_l/article/details/139998373 一、效果如圖&#xff1a; 二…

中介子方程三十四

XXFXXuXXWXXuXXdXXrXXαXXuXpXXKXηXiXXαXXiXηXKXXpXuXXαXXrXXdXXuXWXπXXWXeXyXeXbXπXpXXNXXqXeXXrXXαXXuXpXXKXηXiXXαXXiXηXKXXpXuXXαXXrXXeXqXXNXXpXπXbXeXyXeXWXXπXWXuXXdXXrXXαXXuXpXXKXηXiXXαXXiXηXKXXpXuXXαXXrXXdXXuXXWXXuXXFXXEXXyXXEXXrXXαXXuXpXXK…

paraview跨節點并行渲染

參考&#xff1a; https://cloud.tencent.com/developer/ask/sof/101483588 ParaView 支持使用其內置的網絡拓撲來進行跨節點的并行渲染。以下是一個簡單的步驟來設置和運行跨節點的并行渲染&#xff1a; 確保你的計算環境支持多節點計算&#xff0c;比如通過SSH、MPI或其他集…

阿里云擴容

官網&#xff1a;https://help.aliyun.com/zh/ecs/user-guide/extend-the-partitions-and-file-systems-of-disks-on-a-linux-instance?spm5176.ecs-console-storage_disk.help.dexternal.72d24df5QOL4ss 博客&#xff1a;http://t.csdnimg.cn/cUykr

Android APP通過View修改鼠標樣式

app view上修改鼠標樣式比較簡單&#xff0c;使用如下方法修改為自定義圖片&#xff1a; getWindow().getDecorView().setPointerIcon(PointerIcon.load(getResources(), R.drawable.pointer_spot_touch_icon)); 設置鼠標樣式setPointerIcon的調用棧 frameworks/base/core/jav…

C語言:流量控制

前言 流量控制可以讓發送端根據接收端的實際接受能力控制發送的數據量。它的具體操作是&#xff0c;接收端主機向發送端主機通知自己可以接收數據的大小&#xff0c;于是發送端會發送不會超過該大小的數據&#xff0c;該限制大小即為窗口大小&#xff0c;即窗口大小由接收端主…

【Linux詳解】進程的狀態 | 運行 阻塞 掛起 | 僵尸和孤兒狀態

目錄 操作系統中 運行狀態 阻塞狀態 進程狀態轉換 Linux系統中 查看進程狀態 深度睡眠狀態 T 暫停狀態 Z 僵尸狀態 孤兒狀態 文章手稿 xmind: 引言 介紹系統中的進程狀態及其管理方式。將通過結合操作系統原理和實際代碼示例&#xff0c;詳細說明進程的各種狀態、轉換…

鴻蒙開發Ability Kit(程序框架服務):【FA模型切換Stage模型指導】 app和deviceConfig的切換

app和deviceConfig的切換 為了便于開發者維護應用級別的屬性配置&#xff0c;Stage模型將config.json中的app和deviceConfig標簽提取到了app.json5中進行配置&#xff0c;并對部分標簽名稱進行了修改&#xff0c;具體差異見下表。 表1 配置文件app標簽差異對比 配置項FA模型…

Excel中的“點選輸入”——次級下拉列表創建

在Excel中&#xff0c;用“數據驗證”功能可以設置下拉列表&#xff0c;二級下拉列表需要設置公式。 (筆記模板由python腳本于2024年06月16日 18:36:37創建&#xff0c;本篇筆記適合經常使用Excel處理數據的coder翻閱) 【學習的細節是歡悅的歷程】 Python 官網&#xff1a;http…

基于 Spring AOP 實現安全檢查

在現代應用程序中&#xff0c;安全性是一個至關重要的方面。通過對系統中的關鍵操作進行安全檢查&#xff0c;可以有效防止未授權的訪問和操作。Spring AOP&#xff08;面向切面編程&#xff09;提供了一種優雅的方式來實現安全檢查&#xff0c;而無需修改業務邏輯代碼。本文將…

后端之路第三站(Mybatis)——入門配置

一、Mybatis是啥&#xff1f; 就是一個用java來操控數據庫的框架語言 之前學的datagrip或者navicat這些軟件里我們操作數據庫&#xff0c;原理是我們編寫完的操作語句發送到服務器傳送到數據庫系統&#xff0c;然后數據庫執行完之后再發送給服務器返回給datagrip或者navicat顯…

【linux/shell案例實戰】shell界面命令快捷鍵

快捷鍵及含義&#xff1a; Ctrl&#xff0b;u剪切光標之前的內容。Ctul&#xff0b;k剪切光標之后的內容。Ctrl&#xff0b;e讓光標移動到命令最前&#xff0c;Ctrl&#xff0b;a讓光標移動到命令最后Ctrl&#xff0b;y 粘貼剛才所刪除的內容。Ctrl&#xff0b;d 刪除光標所在…