使用CSV Parser根据多个约束验证每个字段

时间:2015-12-20 09:03:36

标签: java csv supercsv

我正在制定一项要求,我需要针对多个验证解析CSV记录字段。我正在使用supercsv,它支持现场级处理器来验证数据。

我的要求是针对多个验证验证每个记录/行字段,并将它们保存到具有成功/失败状态的数据库。对于失败记录,我必须使用一些代码显示所有失败的验证。

超级CSV是工作文件,但它只检查字段的第一次验证,如果失败,则忽略同一字段的第二次验证。请查看下面的代码并帮助我。

package com.demo.supercsv;

import java.io.FileReader;
import java.io.IOException;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;

import org.supercsv.cellprocessor.Optional;
import org.supercsv.cellprocessor.constraint.NotNull;
import org.supercsv.cellprocessor.constraint.StrMinMax;
import org.supercsv.cellprocessor.constraint.StrRegEx;
import org.supercsv.cellprocessor.constraint.UniqueHashCode;
import org.supercsv.cellprocessor.ift.CellProcessor;
import org.supercsv.exception.SuperCsvCellProcessorException;
import org.supercsv.io.CsvBeanReader;
import org.supercsv.io.CsvBeanWriter;
import org.supercsv.io.ICsvBeanReader;
import org.supercsv.io.ICsvBeanWriter;
import org.supercsv.prefs.CsvPreference;

public class ParserDemo {

    public static void main(String[] args) throws IOException {

        List<Employee> emps = readCSVToBean();
        System.out.println(emps);
        System.out.println("******");
        writeCSVData(emps);
    }

    private static void writeCSVData(List<Employee> emps) throws IOException {
        ICsvBeanWriter beanWriter = null;
        StringWriter writer = new StringWriter();
        try{
            beanWriter = new CsvBeanWriter(writer, CsvPreference.STANDARD_PREFERENCE);
            final String[] header = new String[]{"id","name","role","salary"};
            final CellProcessor[] processors = getProcessors();

            // write the header
            beanWriter.writeHeader(header);

            //write the beans data
            for(Employee emp : emps){
                beanWriter.write(emp, header, processors);
            }
        }finally{
            if( beanWriter != null ) {
                beanWriter.close();
            }
        }
        System.out.println("CSV Data\n"+writer.toString());
    }

    private static List<Employee> readCSVToBean() throws IOException {
        ICsvBeanReader beanReader = null;
        List<Employee> emps = new ArrayList<Employee>();
        try {
            beanReader = new CsvBeanReader(new FileReader("src/employees.csv"),
                    CsvPreference.STANDARD_PREFERENCE);

            // the name mapping provide the basis for bean setters 
            final String[] nameMapping = new String[]{"id","name","role","salary"};
            //just read the header, so that it don't get mapped to Employee object
            final String[] header = beanReader.getHeader(true);
            final CellProcessor[] processors = getProcessors();

            Employee emp;

            while ((emp = beanReader.read(Employee.class, nameMapping,
                    processors)) != null) {
                emps.add(emp);


                if (!CaptureExceptions.SUPPRESSED_EXCEPTIONS.isEmpty()) {
                    System.out.println("Suppressed exceptions for row "
                                        + beanReader.getRowNumber() + ":");
                    for (SuperCsvCellProcessorException e :
                        CaptureExceptions.SUPPRESSED_EXCEPTIONS) {
                        System.out.println(e);
                    }
                    // for processing next row clearing validation list
                    CaptureExceptions.SUPPRESSED_EXCEPTIONS.clear();
                }

            }

        } finally {
            if (beanReader != null) {
                beanReader.close();
            }
        }
        return emps;
    }

    private static CellProcessor[] getProcessors() {

        final CellProcessor[] processors = new CellProcessor[] { 

                new CaptureExceptions(new NotNull(new StrRegEx("\\d+",new StrMinMax(0, 2)))),//id must be in digits and should not be more than two charecters
                new CaptureExceptions(new Optional()), 
                new CaptureExceptions(new Optional()), 
                new CaptureExceptions(new NotNull()), 
                 // Salary
        };
        return processors;
    }

}

异常处理程序:

package com.demo.supercsv;

import java.util.ArrayList;
import java.util.List;
import org.supercsv.cellprocessor.CellProcessorAdaptor;
import org.supercsv.cellprocessor.ift.CellProcessor;
import org.supercsv.exception.SuperCsvCellProcessorException;
import org.supercsv.util.CsvContext;

public class CaptureExceptions extends CellProcessorAdaptor {

    public static List<SuperCsvCellProcessorException> SUPPRESSED_EXCEPTIONS = 
            new ArrayList<SuperCsvCellProcessorException>();

    public CaptureExceptions(CellProcessor next) {
        super(next);
    }

    public Object execute(Object value, CsvContext context) {
        try {
            return next.execute(value, context);

        } catch (SuperCsvCellProcessorException e) {
            // save the exception
            SUPPRESSED_EXCEPTIONS.add(e);
            if(value!=null)
                return value.toString();
                else
                    return "";
        }
    }
}

示例csv文件

ID,Name,Role,Salary
a123,kiran,CEO,"5000USD"
2,Kumar,Manager,2000USD
3,David,developer,1000USD

当我运行程序supercsv异常处理程序时,为第一行中的ID值显示此消息

Suppressed exceptions for row 2:
org.supercsv.exception.SuperCsvConstraintViolationException: 'a123' does not match the regular expression '\d+'
processor=org.supercsv.cellprocessor.constraint.StrRegEx
context={lineNo=2, rowNo=2, columnNo=1, rowSource=[a123, kiran, CEO, 5000USD]}
[com.demo.supercsv.Employee@23bf011e, com.demo.supercsv.Employee@50e26ae7, com.demo.supercsv.Employee@40d88d2d]

对于字段Id长度不应该为空且超过两个且它应该是neumeric ...我已经定义了这样的字段处理器。

new CaptureExceptions(new NotNull(new StrRegEx("\\d+",new StrMinMax(0, 2))))

但超级csv忽略第二次验证(maxlenght 2)如果给定的输入不是neumeric ...如果我的输入是100那么它的验证最大长度...但是如何得到两个错误输入的验证。请帮助我这个< / p>

1 个答案:

答案 0 :(得分:1)

SuperCSV细胞处理器将按顺序工作。因此,如果它通过了先前的约束验证,那么它将检查下一个。

为了实现您的目标,您需要编写一个自定义CellProcessor,它将检查输入是否为数字(数字),长度介于0到2之间。 因此,这两项检查都是一步完成的。