H-DTO模式(之二)

前文介绍了基本概念和设计思路,可从UML图看出类关系、组件关系等内容。下文将用JAVA实现第一部分设计,包括实现TransFormData、Field、Record、Table等。最后对H-DTO模式做了简要介绍,欢迎交流。

1、概述

    
前文说明了一些基本的概念和设计思路,从UML图中可以看出很多的内容,比如类关系,组件关系,下文将要使用JAVA实现第一部分的设计

2、实现TransFormData

/*

 * Created on 2004-7-21 by Jem.Lee

 *

 * TransFormData is a part of cn.bs.common.transdata

 * ALL RIGHTS RESERVED.

 * COPYRIGHT (C) 2004. Jem.Lee

 */

 

/* 包路径cn.bs.common.transdata*/

package cn.bs.common.transdata;

 

/*Import包内容*/

import java.util.HashMap;

import java.util.Iterator;

 

 

/**

 * <PRE>

 * History

 * 2004-7-21 21:02:57 created by Jem.Lee

 *

 * 目的

 * 作为视图和控制器之间进行数据传递的主要对象,

 * 它包涵一般的元素对象和Table对象

 * </PRE>

 */

public class TransFormData implements Cloneable{

   

    /*

     * 存放单个元素的Hash表

     */

    private  HashMap trselements = new HashMap();

    /*

     * 存放Table元素的的Hash表

     */

    private  HashMap trstables = new HashMap();

   

    /**

     *  <PRE>

     * 从FormData获得指定元素名称的值

     * @param name 元素名称

     * @return 元素对应的值

     * @throws Exception

     *  </PRE>

     */

    public String getFieldValue(String name) throws Exception {

        return(this.getFieldFromName(name).getValue());

    }

   

    /**

     *  <PRE>

     * 从FormData获得指定元素域名称

     * @param name 元素名称

     * @return 元素对应的域

     * @throws Exception

     *  </PRE>

     */

    public TransFormField getFieldFromName(String name) throws Exception {

        if (name == null) {

            throw (new NullPointerException("输入的域名为空或是null"));

        }

        TransFormField ret = (TransFormField) trselements.get(name);

        if (ret == null) {

            throw (new Exception("找不到对应'" + name + "'域名"));

        }

        return (ret);

    }

     

    /**

     *  <PRE>

     * 给FormData指定一个元素并设置它的值,如果发现该元素已经存在,则覆盖该元素。

     * @param name  元素的名称

     * @param value 元素的值

     *  </PRE>

     */

    public void putFieldValueO(String name, String value){

        TransFormField newElement = new TransFormField(name, value);

        newElement.setParent(this);

        this.putElementsO(newElement);

    }

   

    /**

     *  <PRE>

     * 设置FormData的Elevent域。

     * @param newElement 指定的新域

     *  </PRE>

     */

    public void putElementsO(TransFormField newElement){

        newElement.setParent(this);

        this.trselements.put(newElement.getName(), newElement);

    }

   

    /*------------------------------Table------------------*/

   

    /**

     * <PRE>

     * 增加Table到FormData中,并返回该Table的实例,如果指定的表已经存在,

     * 则抛出Exception例外

     * @param name  Table的名称

     * @return FormTable  所返回的Table类型

     * @throws Exception

     *  </PRE>

     */

    public TransFormTable addTable(String name) throws Exception{

        if(trstables.get(name) != null){

            throw(new Exception());

        }

        return(addTableO(name));

    }

   

    /**

     *  <PRE>

     * 增加Table到FormData中,并返回该Table的实例,如果该指定的表已经存在,

     * 则强行覆盖新的表。

     * @param name  Table的名称

     * @return FormTable  所返回的Table类型

     *  </PRE>

     */

    public TransFormTable addTableO(String tableName){

        TransFormTable newTable = new TransFormTable(tableName);

        newTable.setParent(this);

        trstables.put(tableName, newTable);

        return(newTable);

    }

   

    /**

     *  <PRE>

     * 对Table的内容进行排序

     *  </PRE>

     */

    void sortTable(){

        Iterator iTables = this.trstables.keySet().iterator();

        while(iTables.hasNext()){

            TransFormTable tbl = (TransFormTable) this.trstables.get(iTables.next());

            tbl.sort();

        }

    }

   

    /**

     *  <PRE>

     * 获得指定表名称的实例

     * @param name  表名称

     * @return 指定表名称的实例

     * @throws BsComponentException、NullPointerException、IllegalArgumentException

     *  </PRE>

     */

    public TransFormTable getTable(String name) throws Exception {

        if (name == null) {

            throw (new NullPointerException("输入的表名是null"));

        }

        if (name.equals("")) {

            throw (new IllegalArgumentException("输入的域名为空"));

        }

        TransFormTable ret = (TransFormTable) trstables.get(name);

        if (ret == null) {

            throw (new Exception());

        }

        return(ret);

    }

}

 

 

3、实现TransFormField

/*

 * Created on 2004-7-21 by Jem.Lee

 *

 * TransFormField is a part of cn.bs.common.transdata

 * ALL RIGHTS RESERVED.

 * COPYRIGHT (C) 2004. Jem.Lee

 */

 

/* 包路径cn.bs.common.transdata*/

package cn.bs.common.transdata;

 

/**

 * <PRE>

 * History

 * 2004-7-21 21:03:26 created by Jem.Lee

 *

 * 目的

 * 作为视图和控制器之间进行数据传递的主要对象,

 * 它作为一般的元素对象

 * </PRE>

 */

public class TransFormField {

 

    /*

     * 元素名称

     */

    private String name;

 

    /*

     * 元素值

     */

    private String value;

 

    /*

     * 存放该元素得父目录

     */

    private TransFormData parent;

   

    /**

     *  构造函数

     * @param initName 元素名称

     * @param initValue 元素值

     */

    public TransFormField(String initName, String initValue) {

       

        /*如果提供的元素名称为null则抛出NullPointerException例外*/

        if (initName == null)

            throw (new NullPointerException("初始化FormField时提供的参数错误,比如其中initName为null"));

       

        /*如果提供的元素名称为空则抛出IllegalArgumentException例外*/

        if (initName.equals(""))

            throw (new IllegalArgumentException("初始化FormField时提供的参数错误,initName为空"));

       

        /*如果提供的元素值为null则抛出NullPointerException例外*/

        if (initValue == null)

            throw (new NullPointerException("初始化FormField时提供的参数错误,initValue为null"));

       

        this.name = initName;

        this.value = initValue;

    }

    /**

     * <PRE>

     * 获得元素名称

     * @return 元素名称

     * </PRE>

     */

    public String getName(){

        return(this.name);

    }

   

    /**

     * <PRE>

     * 获得元素的值

     * @return 元素的值

     * </PRE>

     */

    public String getValue(){

        return(this.value);

    }

   

    /**

     * <PRE>

     * 设置元素的父目录

     * @param newParent 父目录

     * </PRE>

     */

    public void setParent(TransFormData newParent){

        /*如果父目录为null,则抛出NullPointerException例外*/

        if(newParent == null)

            throw (new NullPointerException("设置FormField的包容类FormData错误,比如为null"));

        this.parent = newParent;

    }

 

 

}

 

 

4、实现TransFormRecord

/*

 * Created on 2004-7-21 by Jem.Lee

 *

 * TransFormRecord is a part of cn.bs.common.transdata

 * ALL RIGHTS RESERVED.

 * COPYRIGHT (C) 2004. Jem.Lee

 */

 

/* 包路径cn.bs.common.transdata*/

package cn.bs.common.transdata;

 

/**

 * <PRE>

 * History

 * 2004-7-21 21:03:44 created by Jem.Lee

 *

 * 目的

 * 作为视图和控制器之间进行数据传递的主要对象,

 * 它作为Table对象的元素对象

 * </PRE>

 */

public class TransFormRecord  extends TransFormData implements Comparable{

   

    /*

     * 记录 ID

     */

    private int rec_Id;

 

    /*

     * 存放该元素得父目录

     */

    private TransFormTable parent;

   

 

    public int compareTo(Object target) {

        if(target instanceof TransFormRecord)

            return(rec_Id-((TransFormRecord)target).getRecId());

        return(0);

    }

    /**

     * <PRE>

     * 设置元素的父目录

     * @param newParent 父目录

     * </PRE>

     */

    void setParent(TransFormTable newParent){

        parent = newParent;

    }

    /**

     * <PRE>

     * 获得元素的父目录

     * @return FormTable 父目录

     * </PRE>

     */

    TransFormTable getParent(){

        return(parent);

    }

   

    /**

     *

     * <PRE>

     * 设置 新的记录ID

     * @param newId 记录ID

     * </PRE>

     */

    void setRecId(int new_Id){

        rec_Id = new_Id;

    }

   

    /**

     *

     * <PRE>

     * 获得的记录ID

     * @return 记录ID

     * </PRE>

     */

    int getRecId(){

        return(rec_Id);

    }

}

 

 

5、实现TransFormTable

/*

 * Created on 2004-7-21 by Jem.Lee

 *

 * FormTable.java is a part of cn.bs.common.transdata

 * ALL RIGHTS RESERVED.

 * COPYRIGHT (C) 2004. Jem.Lee */

 

/* 包路径cn.bs.common.transdata*/

package cn.bs.common.transdata;

 

/*Import包内容*/

import java.util.ArrayList;

import java.util.Collections;

import java.util.Iterator;

 

/**

 * <PRE>

 * History

 * 2004-7-21 21:04:00 created by Jem.Lee

 *

 * 目的

 * 作为视图和控制器之间进行数据传递的主要对象,

 * 它作为FormData对象的元素对象

 * </PRE>

 */

public class TransFormTable {

   

    /*

     * Table 名称

     */

    private String name;

 

 

    /*

     * 记录数组

     */

    private ArrayList records = new ArrayList();

 

    /*

     * 存放该元素得父目录

     */

    private TransFormData parent;

   

    /**

     *  <PRE>

     * 构造函数 提供表名称

     * @param initName 表名称

     *  </PRE>

     */

    public TransFormTable(String initName) {

        /*如果提供的表名为null,则抛出NullPointerException例外*/

        if (initName == null)

            throw (new NullPointerException("构造FormTable时错误,比如表名为null"));

       

         /*如果提供的表名为空,则抛出NullPointerException例外*/

        if (initName.equals(""))

            throw (new IllegalArgumentException("构造FormTable时错误,比如表名为空"));

       

        this.name = initName;

    }

    /**

     * <PRE>

     * 设置元素的父目录

     * @param newParent 父目录

     * </PRE>

     */

    void setParent(TransFormData newParent) throws NullPointerException {

        /*如果提供的父目录为null,则抛出NullPointerException例外*/

        if (newParent == null)

            throw (new NullPointerException("设置ForFormTablemField的包容类FormData错误,比如为null"));

       

        this.parent = newParent;

    }

    /**

     *

     * <PRE>

     * 加入一条记录到Table

     * @return 返回该条记录的实例,以便进行赋值操作

     * </PRE>

     */

    public TransFormData add() {

        TransFormRecord newRec = new TransFormRecord();

        newRec.setParent(this);

        records.add(newRec);

        reIndex();

        sort();

        return (newRec);

    }

    /**

     *

     * <PRE>

     * 排序函数,对表的记录进行排序

     * </PRE>

     */

    void sort() {

        Collections.sort(records);

        Iterator iRecs = records.iterator();

        while(iRecs.hasNext()){

            TransFormData rec = (TransFormData) iRecs.next();

            rec.sortTable();

        }

    }

   

    /**

     *

     * <PRE>

     * 记录索引

     * </PRE>

     */

    void reIndex() {

        int index = 0;

        //Collections.sort(recs);

        Iterator i = records.iterator();

        while (i.hasNext()) {

            TransFormRecord rec = (TransFormRecord) i.next();

            rec.setRecId(index);

            index++;

        }

    }

   

    /**

     *

     * <PRE>

     * 通过记录号获得一条记录

     * @param recNo 记录号

     * @return 一条记录

     * </PRE>

     */

    public TransFormData get(int recNo) {

        return ((TransFormData) records.get(recNo));

    }

   

    /**

     *

     * <PRE>

     * 获得表的长度

     * @return 表的长度

     * </PRE>

     */

    public int size() {

        return (records.size());

    }

 

 

}

 

6、总结
  
  到这里,我把HDTO模式做了简要介绍,希望对你的设计有些帮助,如果发现错误之处还请批评指正,如果有疑问或是不明之处欢迎讨论。

 

 

<think>我们正在分析一段Java代码:`validator.stream().flatMap(f -> f.apply(dto).stream()).collect(Collectors.toList())` 结合引用内容,这段代码可能用于服务层的参数校验(如批量导入场景)。下面逐步解析: 1. **组件分析**: - `validator`:一个包含多个校验函数的集合(可能是`List<Function<T, List<String>>>`类型),每个函数接收一个DTO对象,返回错误信息列表(无错误返回空列表) - `stream()`:将集合转换为流以便进行函数式操作 - `flatMap(f -> f.apply(dto).stream())`: - 对每个校验函数`f`,应用`f.apply(dto)`得到错误列表`List<String>` - 通过`.stream()`将每个错误列表转换为流 - `flatMap`将多个错误流合并为一个连续的流 - `collect(Collectors.toList())`:将合并后的流转为一个错误列表 2. **数学表达**: 设校验器集合为 $V = \{f_1, f_2, \dots, f_n\}$,其中每个校验函数 $f_i$ 满足: $$ f_i: D \to E_i \quad (E_i \subseteq \mathbb{S}^*, \mathbb{S} \text{为字符串集合}) $$ 则整个表达式可表示为: $$ \text{result} = \bigcup_{i=1}^{n} f_i(d) $$ 其中 $d$ 为输入DTO对象。 3. **用途场景**: 用于集中收集DTO对象的全部校验错误(如批量导入时),返回所有错误的扁平化列表(引用[1]提到服务层校验需求)[^1]。 4. **示例模拟**: ```java // 定义校验器集合(实际可能通过依赖注入) List<Function<UserDTO, List<String>>> validators = new ArrayList<>(); // 添加校验器1:用户名规则 validators.add(dto -> { List<String> errors = new ArrayList<>(); if (dto.getUsername() == null) errors.add("用户名缺失"); else if (dto.getUsername().length() < 6) errors.add("用户名过短"); return errors; }); // 添加校验器2:邮箱规则(参考引用[3]) validators.add(dto -> { List<String> errors = new ArrayList<>(); if (!Pattern.matches("^[\\w-]+(\\.[\\w-]+)*@[\\w-]+(\\.[\\w-]+)+$", dto.getEmail())) { errors.add("邮箱格式错误"); } return errors; }); // 执行校验 UserDTO user = new UserDTO("Tom", "invalid-email"); List<String> errorList = validators.stream() .flatMap(f -> f.apply(user).stream()) .collect(Collectors.toList()); // 输出:["用户名过短", "邮箱格式错误"] ``` 5. **工程优势**: - **解耦**:每个校验规则独立实现(符合单一职责) - **可扩展**:新增校验只需添加新函数 - **复用性**:校验器可组合用于不同场景(如单对象/批量) 6. **对比传统校验**: 区别于引用[3]中直接在DTO字段加注解的方式,此方法适用于: - 跨字段校验(如密码与确认密码) - 动态规则(如不同用户类型不同规则) - 非注解场景(如遗留系统改造) 7. **关联引用**: - 校验结果可整合到统一响应对象(如引用[2]中的`R`类)[^2]: ```java if (!errorList.isEmpty()) { return R.error().data("errors", errorList); } ``` §§相关问题§§ 1. 如何实现校验器的动态加载(如根据数据库配置启用不同规则)? 2. 这种流式校验与Spring Validation的`@Valid`注解在性能上有何差异? 3. 在多层级校验(如DTO内嵌套对象)时如何扩展此模式? 4. 如何将错误信息按字段归类(而非扁平列表)? </think>### Java校验代码解析:`validator.stream().flatMap(f -> f.apply(dto).stream()).collect(Collectors.toList())` #### 1. **代码结构分解** | 代码片段 | 功能说明 | |---------|---------| | `validator.stream()` | 将校验器集合转为流(Stream)处理 | | `.flatMap(f -> f.apply(dto).stream())` | 核心操作:展开嵌套校验结果 | | `.collect(Collectors.toList())` | 合并所有错误到单一列表 | #### 2. **核心逻辑说明** $$ \text{result} = \bigcup_{i=1}^{n} f_i(\text{dto}) $$ 其中: - $f_i$ 表示单个校验器函数 - $\text{dto}$ 是待校验对象 - 输出为所有校验错误的并集 #### 3. **执行流程** ```mermaid graph TD A[validator集合] --> B[转换为Stream] B --> C[遍历每个校验器f] C --> D[应用f校验dto对象] D --> E[获得错误列表List<String>] E --> F[转换为新Stream] F --> G[合并所有错误Stream] G --> H[收集为单一错误列表] ``` #### 4. **典型应用场景** 1. **批量校验**(如Excel导入) - 同时校验多个DTO对象中的字段规则(参考引用[1])[^1] 2. **复杂规则校验** - 实现跨字段校验(如“密码”与“确认密码”一致性) 3. **服务层校验** - 在Controller层无法覆盖的场景使用(如异步批量更新)[^1] #### 5. **对比传统校验方式** | 方式 | 特点 | 适用场景 | |------|------|---------| | **Hibernate注解校验**<br>(`@NotBlank`等) | 声明式校验,简单直接 | 简单字段规则(引用[3][4])[^3][^4] | | **本代码的流式校验** | 编程式校验,灵活度高 | 动态规则/跨字段校验/批量处理 | #### 6. **扩展应用示例** ```java // 定义校验器集合(参考引用[1]的ValidatorUtil3) List<Function<UserDTO, List<String>>> validators = Arrays.asList( dto -> validateUsername(dto.getUsername()), // 用户名规则校验 dto -> validatePassword(dto.getPassword()) // 密码强度校验 ); // 执行批量校验 UserDTO user = new UserDTO("admin", "123456"); List<String> errors = validators.stream() .flatMap(f -> f.apply(user).stream()) .collect(Collectors.toList()); // 输出:["用户名过短", "密码需包含大写字母"] ``` #### 7. **工程优势** 1. **解耦性**:校验规则可独立管理和扩展 2. **可组合性**:自由组合不同校验器(如基础规则+业务规则) 3. **复用性**:相同校验逻辑可用于DTO/Entity等不同对象 ---
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值