Проверка и импорт данных из файла Excel
Недавно я разработал модуль, который будет выполнять массовую загрузку для другого содержимого. В основном пользователь загрузит файл Excel, мне придется читать и проверять заголовки excel, а затем каждое значение ячейки для всех столбцов. Я разработал структуру, пожалуйста, подтвердите.
Ниже приведены vo.
Детали заголовка шаблона: Excel для каждого содержимого определяется как шаблон, который будет иметь идентификатор и будет иметь заголовок (заголовок столбца Excel) для каждого шаблона:
public class TemplateHeaderDetails extends BaseVO {
Integer templateId;
String templateName;
public String headerNames;
String mandatory;
Integer fieldId;
public Integer getTemplateId() {
return templateId;
}
public void setTemplateId(Integer templateId) {
this.templateId = templateId;
}
public String getTemplateName() {
return templateName;
}
public void setTemplateName(String templateName) {
this.templateName = templateName;
}
public String getHeaderNames() {
return headerNames;
}
public void setHeaderNames(String headerNames) {
this.headerNames = headerNames;
}
public String getMandatory() {
return mandatory;
}
public void setMandatory(String mandatory) {
this.mandatory = mandatory;
}
public Integer getFieldId() {
return fieldId;
}
public void setFieldId(Integer fieldId) {
this.fieldId = fieldId;
}
}
Каждому столбцу заголовка присваивается идентификатор поля, как вы можете видеть в vo выше.
Мы определили правила проверки:
public class Rule extends BaseVO {
String ruleName;
Integer ruleId;
String methodName;
String className;
String validationMessage;
List<String> referenceFields;
public String getRuleName() {
return ruleName;
}
public void setRuleName(String ruleName) {
this.ruleName = ruleName;
}
public Integer getRuleId() {
return ruleId;
}
public void setRuleId(Integer ruleId) {
this.ruleId = ruleId;
}
public String getMethodName() {
return methodName;
}
public void setMethodName(String methodName) {
this.methodName = methodName;
}
public String getClassName() {
return className;
}
public void setClassName(String className) {
this.className = className;
}
public String getValidationMessage() {
return validationMessage;
}
public void setValidationMessage(String validationMessage) {
this.validationMessage = validationMessage;
}
public List<String> getReferenceFields() {
return referenceFields;
}
public void setReferenceFields(List<String> referenceFields) {
this.referenceFields = referenceFields;
}
}
Каждый столбец заголовка (идентификатор поля) будет сопоставлен с правилом
public class RulesMapping extends BaseVO {
Integer fieldId;
String referenceField;
Integer ruleId;
public Integer sequenceNumber;
String ruleConfig;
public Integer getRuleId() {
return ruleId;
}
public void setRuleId(Integer ruleId) {
this.ruleId = ruleId;
}
public Integer getSequenceNumber() {
return sequenceNumber;
}
public void setSequenceNumber(Integer sequenceNumber) {
this.sequenceNumber = sequenceNumber;
}
public Integer getFieldId() {
return fieldId;
}
public void setFieldId(Integer fieldId) {
this.fieldId = fieldId;
}
public String getReferenceField() {
return referenceField;
}
public void setReferenceField(String referenceField) {
this.referenceField = referenceField;
}
public String getRuleConfig() {
return ruleConfig;
}
public void setRuleConfig(String ruleConfig) {
this.ruleConfig = ruleConfig;
}
}
Ниже приведен код, который будет читать файл Excel, проверять и обновлять базу данных и обновлять excel с комментариями сообщений проверки и успеха.
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.DateUtil;
import org.apache.poi.ss.usermodel.RichTextString;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
public class BulkUploader {
private static final String BULKUPLOAD_UPDATE_RECORD = "BULKUPLOAD_UPDATE_RECORD";
// This will contain module name plus header details
List<TemplateHeaderDetails> details = new ArrayList<TemplateHeaderDetails>();
// template Name to header details(contians column name ,mandatory columns , sequence)
List<HeaderDetails> headerDetails =null;
// all key value pair mapping ( holding column name and its respective value per row.
Map<String,Object> records = new HashMap<String,Object>();
// field ID to rules mapping
Map<Integer,List<RulesMapping>> rulesMapping = new HashMap<Integer,List<RulesMapping>>();
// Rule id to Rule
Map<Integer,Rule> rules = new HashMap<Integer,Rule>();
Map<Integer,List<String>> errorMessages = new HashMap<Integer,List<String>>();
// List of procedure to be executed
List<SP> procedureList = new ArrayList<SP>();
public void setUpData(){
Map<Integer,String> spColumnNames =new TreeMap<Integer,String>();
spColumnNames.put(1,"BDATE");
spColumnNames.put(2,"ACTION");
spColumnNames.put(3,"BBULLETIN_ID");
spColumnNames.put(4,"BBULLETIN_NO");
spColumnNames.put(5,"DATATitle");
spColumnNames.put(6,"DATAStatus");
spColumnNames.put(7,"DATAIntroduction (Rewritten)");
spColumnNames.put(8,"Summary");
spColumnNames.put(9,"Direct Questions To");
spColumnNames.put(10,"Effective Start Date");
spColumnNames.put(11,"Tags/Keywords");
spColumnNames.put(12,"Created Date");
spColumnNames.put(13,"Creator Name");
SP sp = new SP();
sp.setProcedureName("POC_BULK_UPLOAD");
sp.setColumnSeq(spColumnNames);
procedureList.add(sp);
}
@SuppressWarnings("unchecked")
public void readExcel() throws IOException, IllegalAccessException, InstantiationException, ClassNotFoundException, SecurityException, NoSuchMethodException, IllegalArgumentException, InvocationTargetException{
FileInputStream file = new FileInputStream(new File("C:\\Data.xlsx"));
//Get the workbook instance for XLS file
XSSFWorkbook workbook = new XSSFWorkbook(file);
//Get first sheet from the workbook
XSSFSheet sheet = workbook.getSheetAt(0);
// GET the header row
Row headerRow = sheet.getRow(0);
// LIst of headers from excel
List<String> headers = new ArrayList<String>();
Iterator<Cell> cells = headerRow.cellIterator();
while (cells.hasNext()) {
Cell cell = (Cell) cells.next();
RichTextString value = cell.getRichStringCellValue();
headers.add(value.getString());
}
// validate the template
Object[] headerValidation = validateTempalte(headers );
// if validation fails then write back the message to user.
if((Boolean) headerValidation[0]==false){
List<String> headerValidationMsg = (List<String>) headerValidation[1];
appendHeaderComments(workbook,sheet,headerValidationMsg,headers);
return ;
}
// Assign a number to header.This is done so that when we reading excel value we can identiy the cell value belongs to which column
Map<String,Integer> headerSeqNumber = assignHeaderSeqNumber(headers);
//
//Get iterator to all the rows in current sheet
int rowNumber=0;
Iterator<Row> rowIterator = sheet.iterator();
while (rowIterator.hasNext()) {
Row row = (Row) rowIterator.next();
if(rowNumber==0){
rowNumber++;
continue;
}
System.out.println("Row no "+rowNumber);
Iterator<String> columnsIterator = headerSeqNumber.keySet().iterator();
while (columnsIterator.hasNext()) {
String name = columnsIterator.next();
System.out.println("Read columnName "+name);
int cellType=row.getCell(headerSeqNumber.get(name)).getCellType();
switch (cellType) {
case Cell.CELL_TYPE_STRING:
RichTextString value= row.getCell(headerSeqNumber.get(name)).getRichStringCellValue();
String val=value!=null ?Utils.replaceNonAsciiChar(value.getString().trim()):null;
val=val.replaceAll(":", "");
val=val.replaceAll("'", "");
records.put(name,val);
break;
case Cell.CELL_TYPE_NUMERIC:
if (DateUtil.isCellDateFormatted(row.getCell(headerSeqNumber.get(name)))) {
Date date = row.getCell(headerSeqNumber.get(name)).getDateCellValue();
records.put(name,Utils.convertDateToString(date, "dd-MMM-yyyy"));
}else{
double numericVal= row.getCell(headerSeqNumber.get(name)).getNumericCellValue();
records.put(name,numericVal);
}
break;
case Cell.CELL_TYPE_BLANK:
System.err.println(" blank cell type ");
records.put(name,null);
break;
default:
System.err.println(" NEither string no number "+row.getCell(headerSeqNumber.get(name)).getCellType());
System.err.println(" value "+row.getCell(headerSeqNumber.get(name)).getStringCellValue());
break;
}
}
// once a row is read validate each cell
Object[] validationResults=validateRecords(records);
Boolean isDataValid =(Boolean) validationResults[0];
List<String> vMessages =new ArrayList<String>();
// if data is valid then update the value in db.
if (isDataValid) {
System.out.println(" Valid data sending for upating record");
String msg = executeProcedure(records);
vMessages.add(msg);
}else{
// if there is validation issues then add the messages to list.
if(validationResults[1]!=null){
vMessages = (List<String>) validationResults[1];
}
System.err.println(" data is invalid");
}
errorMessages.put(rowNumber, vMessages);
rowNumber++;
}
// append success or failue to excel.
appendComments(sheet,headers);
String filePath="C:\\Data.xlsx";
FileOutputStream fileOut = new FileOutputStream(filePath);
workbook.write(fileOut);
fileOut.flush();
fileOut.close();
}
@SuppressWarnings("unchecked")
private Object[] validateRecords(Map<String,Object> recordValues) throws IllegalAccessException, InstantiationException, ClassNotFoundException, SecurityException, NoSuchMethodException, IllegalArgumentException, InvocationTargetException{
Object[] values = new Object[2];
List<String> vMessages = new ArrayList<String>();
Boolean isDataUploadedValid = true;
Iterator<TemplateHeaderDetails> columnsIterator = details.iterator();
while (columnsIterator.hasNext()) {
TemplateHeaderDetails headerValue = columnsIterator.next();
String columnName=headerValue.getHeaderNames();
Object value= recordValues.get(columnName);
//System.out.println(" columnName "+columnName);
int fieldId = headerValue.getFieldId();
List<RulesMapping> ruleList= rulesMapping.get(fieldId);
//System.out.println(" ruleList "+ruleList);
if(ruleList!=null){
for (RulesMapping rulesMapping : ruleList) {
String configuration =rulesMapping.getRuleConfig();
int sequence =rulesMapping.sequenceNumber;
Integer ruleId = rulesMapping.getRuleId();
String config = rulesMapping.getRuleConfig();
Rule rule = rules.get(ruleId);
String className=rule.getClassName();
String methodName=rule.getMethodName();
String message = rule.getValidationMessage();
List<String> referenceFields = rule.getReferenceFields();
Object obj=Class.forName(className).newInstance();
//Class<?>[] parameterTypes = Util.getParameterTypes( value,referenceFields,config,message,columnName );
Class<?>[] parameterTypes = new Class<?>[5];
parameterTypes[0]=Object.class;
parameterTypes[1]=List.class;
parameterTypes[2]=String.class;
parameterTypes[3]=String.class;
parameterTypes[4]=String.class;
Object[] validationResults= (Object[]) obj.getClass().getMethod( methodName,parameterTypes).invoke(obj, value,referenceFields,config,message,columnName);
Boolean isValidData = (Boolean) validationResults[0];
if(!isValidData){
isDataUploadedValid=false;
vMessages.addAll((List<String>) validationResults[1]);
}
}
}
}
values[0]=isDataUploadedValid;
values[1]=vMessages;
return values;
}
// checks if headers from excel matches the headers for template from db based on mandaotry filds.
private Object[] validateTempalte(List<String> headers){
Object[] values=new Object[2];
Boolean isTempateProper=true;
List<String> errorMessages = new ArrayList<String>();
//List<HeaderDetails> headerDetails = (List<HeaderDetails>) details.getHeaderDetails();
for (TemplateHeaderDetails headerDetail : details) {
if(headerDetail.getHeaderNames().equalsIgnoreCase("ACTION") ||headerDetail.getHeaderNames().equalsIgnoreCase("DATAID")
||headerDetail.getHeaderNames().equalsIgnoreCase("DATASTATUS ID") ||headerDetail.getHeaderNames().equalsIgnoreCase("Department Name")
||headerDetail.getHeaderNames().equalsIgnoreCase("Status of Record") ||headerDetail.getHeaderNames().equalsIgnoreCase("Description of the Status")
||headerDetail.getHeaderNames().equalsIgnoreCase("Name of the Excel File") ||headerDetail.getHeaderNames().equalsIgnoreCase("Updated By")){
continue;
}
if(headerDetail.getMandatory().equalsIgnoreCase("Y") && !headers.contains(headerDetail.getHeaderNames())){
isTempateProper=false;
errorMessages.add(headerDetail.getHeaderNames() + " column is missing ");
}
}
values[0]=isTempateProper;
values[1]=errorMessages;
return values;
}
private Map<String,Integer> assignHeaderSeqNumber(List<String> headers){
Map<String,Integer> headerSeqNumber = new HashMap<String, Integer>();
int i=0;
for (String columnName : headers) {
headerSeqNumber.put(columnName, i);
i++;
}
return headerSeqNumber;
}
private String executeProcedure(Map<String, Object> recordValues) {
try {
for (SP procedure : procedureList) {
String query = " call " + procedure.getProcedureName() + " ( ";
Map<Integer, String> params = procedure.columnSeq;
Iterator<Integer> keys = params.keySet().iterator();
int i = 1;
while (keys.hasNext()) {
Integer seq = (Integer) keys.next();
if (params.containsKey(seq)) {
String columnName = params.get(seq);
System.out.println(" columName used in SP "
+ columnName);
if (columnName.equalsIgnoreCase("ACTION")) {
query += " 'I' ";
} else if (columnName.equalsIgnoreCase("BBULLETIN_ID")) {
query += " '1' ";
} else if (columnName
.equalsIgnoreCase("Department Name")) {
query += " 'Compliance' ";
} else {
query += " '" + recordValues.get(columnName) + "' ";
}
} else {
query += " null ";
}
if (i <= params.size() - 1) {
query += " ,";
}
i++;
}
query += " ,? ,?)";
ServiceCaller.invokeService(BULKUPLOAD_UPDATE_RECORD, query);
System.out.println(" complete query " + query);
}
return "SUCSSES";
} catch (Exception e) {
e.printStackTrace();
System.err.println(" Errro while upadating record");
return "FAILED";
}
}
private void appendComments(XSSFSheet sheet ,List<String> headers){
int rowNumber=0;
Iterator<Row> rowIterator = sheet.iterator();
while (rowIterator.hasNext()) {
Row row = (Row) rowIterator.next();
if(rowNumber==0){
Cell headerCell = row.createCell(headers.size());
headerCell.setCellValue("Comments");
}else{
List<String> vMessages = errorMessages.get(rowNumber);
StringBuilder builder = new StringBuilder("");
for (String message : vMessages) {
builder.append(message);
}
Cell headerCell = row.createCell(headers.size());
headerCell.setCellValue(builder.toString());
}
rowNumber++;
}
}
private void appendHeaderComments(XSSFWorkbook workbook ,XSSFSheet sheet ,List<String> messages,List<String> headers) throws IOException{
Row headerRow = sheet.getRow(0);
Cell headerCell = headerRow.createCell(headers.size());
headerCell.setCellValue("Comments");
Row firstRow = sheet.getRow(1);
Cell commentCell = firstRow.createCell(headers.size());
String finalMessage=null;
for (String msg : messages) {
finalMessage+=msg;
}
commentCell.setCellValue(finalMessage);
String filePath="C:\\Data.xlsx";
FileOutputStream fileOut = new FileOutputStream(filePath);
workbook.write(fileOut);
fileOut.flush();
fileOut.close();
}
// commnets field for each , combine messages from JAVA,DB.
private void getRecrodStatus(){
}
public List<TemplateHeaderDetails> getDetails() {
return details;
}
public void setDetails(List<TemplateHeaderDetails> details) {
this.details = details;
}
public List<HeaderDetails> getHeaderDetails() {
return headerDetails;
}
public void setHeaderDetails(List<HeaderDetails> headerDetails) {
this.headerDetails = headerDetails;
}
public Map<String, Object> getRecords() {
return records;
}
public void setRecords(Map<String, Object> records) {
this.records = records;
}
public Map<Integer, List<RulesMapping>> getRulesMapping() {
return rulesMapping;
}
public void setRulesMapping(Map<Integer, List<RulesMapping>> rulesMapping) {
this.rulesMapping = rulesMapping;
}
public Map<Integer, Rule> getRules() {
return rules;
}
public void setRules(Map<Integer, Rule> rules) {
this.rules = rules;
}
public Map<Integer, List<String>> getErrorMessages() {
return errorMessages;
}
public void setErrorMessages(Map<Integer, List<String>> errorMessages) {
this.errorMessages = errorMessages;
}
public List<SP> getProcedureList() {
return procedureList;
}
public void setProcedureList(List<SP> procedureList) {
this.procedureList = procedureList;
}
}
Просматривайте дизайн и реализацию.
3 ответа
Конкатенации строк
Иногда вы используете StringBuilder
, а иногда и оператор составного присваивания (+=
). Ключ, чтобы отличать, когда использовать то, что это: если вы знаете количество конкатенаций, вы используете +=
; если вы этого не сделаете, вы используете StringBuilder
(или их слишком много).
Исключения
Вы бросаете много из них, но вы ничего не делаете с этим. Это неправильная обработка ошибок.
Дорожки
Ваш путь к рабочему листу excel жестко запрограммирован, изменив его на то, что пользователь может выбрать (например, передав его в main
аргументы).
итераторы
В ваших итераторах есть следующее:
Iterator<Cell> cells = headerRow.cellIterator();
while (cells.hasNext()) {
Cell cell = (Cell) cells.next();
Так как ваш Iterator
определяется как Iterator<Cell>
, я не думаю, что вам нужно больше его использовать Cell
.
Ошибки ввода
- validateTempalte
- isTempateProper
- SUCSSES
- Errro при записи upadating
- getRecrodStatus
Определенные типы
В ваших методах проверки вы возвращаете что-то вроде этого:
values[0]=isTempateProper;
values[1]=errorMessages;
Это ошибка very (когда я видел результат, я не знал, почему вы вдруг выбрали первое значение для Boolean
). Вместо этого создайте простой класс, содержащий эти поля
class ValidationResult {
private Boolean isTemplateProper;
private List<String> errorMessages;
// Getters + Constructor
}
Впоследствии это позволит вам изменить
if((Boolean) headerValidation[0]==false)
к
if(!validationResult.isProperTemplate())
И вы избавитесь от уродливого типа Object[]
.
Побочное действие
Печать данных внутри метода, который не предполагается, является побочным эффектом, которого вы не хотите; пусть методы придерживаются своей цели. Может быть, это отладка?
Форматирование
Добавьте больше пробелов и белых линий! Вы должны never иметь 30 строк кода без одной нитки между ними: он чувствует себя слишком стесненным. Также не забудьте помещать пробелы между составными операторами "Row no "+rowNumber
и вызовы методов appendHeaderComments(workbook,sheet,headerValidationMsg,headers);
Магические значения
В readExcel()
вы жестко кодируете местоположение файла ("C:\\Data.xlsx
) дважды. Hardcoding сам по себе сомнительный, но это еще более склонно к ошибкам. Определите его один раз и используйте его во всем приложении.
Алмазный оператор
Иногда вы его используете, иногда нет. Имейте в виду, что это
List<String> vMessages = new ArrayList<String>();
может быть записано как
List<String> vMessages = new ArrayList<>();
Промежуточные переменные
Внутри внутреннего цикла validateRecords()
вы объявляете переменную для каждого rule.something()
, но вы используете его только один раз. Это 8 строк кода, которые не нужны, определенно, поскольку вы действительно просто переходите от 2 слов к 1 -> Очень незначительные изменения.
И если я не просмотрю его, я вижу несколько переменных, которые там не используются.
Цикл между значениями
Вы делаете это несколько раз с разными значениями:
headerDetail.getHeaderNames().equalsIgnoreCase("ACTION")
Рассмотрите возможность использования коллекции, которая упростит управление:
String[] headersToSkip = new[] {"ACTION", "DATAID", "DATASTATUS ID", "Department Name" };
for(String header : headersToSkip) {
if(header.equalsIgnoreCase(headerDetail.getHeaderNames())) {
continue;
}
}
Пока мы здесь: почему getHeaderNames()
возвращает один String
? Сделайте это сингулярным.
Нейминг
Сделайте свои методы и переменные как можно более наглядными; часто это означает, что вы не сокращаете их. Например:
- assignHeaderSeqNumber => assignHeaderSequenceNumber
- params => Параметры
- columnSeq => columnSequence
AFAICT этот код не о загрузке ; скорее, речь идет об импорте данных из файлов Excel в базу данных после проверки ее с помощью правил, загружаемых где-то (возможно, в одну и ту же базу данных).
Я игнорирую код отладки print
, код с комментариями и жестко закодированные имена файлов, поскольку они выглядят как артефакты работы в прогресс.
Архитектура
Первые три класса имеют некоторые специфические проблемы:
- У них нет конструкторов.
- У них есть сеттеры и геттеры для каждого поля. Большинство из них, вероятно, не нужны. Сети, в частности, часто бесполезны, потому что многие поля не могут существенно изменить. (
templateId
, например, возможно, никогда не изменится.) - У них нет других методов, хотя части
BulkUploader
должны быть методамиRule
иRulesMapping
. - Все они происходят из
BaseVO
, который, как представляется, не имеет никакого отношения к их значениям.
Ничто из этого обычно не было бы хорошим стилем. Я предполагаю, что это сделано, чтобы они могли храниться в какой-то библиотеке баз данных, которая ожидает этот стиль. В этом случае это может быть необходимым злом, но это все еще раздражает.
Классы с «деталями» в их именах являются плохим знаком. TemplateHeaderDetails
явно представляет либо шаблон (в этом случае его следует называть Template
) или список заголовков, используемых шаблоном (в этом случае его следует называть TemplateHeaders
).
TemplateHeaderDetails.mandatory
должен быть логическим, а не "Y"
/"N"
.
Если Rule
предназначен только для правил проверки, его следует называть ValidationRule
. «Правило» настолько неопределенно, что оно неинформативно.
Запись сообщения об успехе или ошибке в файл Excel является нечетной. Пользователь, вероятно, не увидит его там. Лучше оставить файл немодифицированным и сообщить сообщение пользователю другим способом.
Ошибки
Неэкранированные строки
executeProcedure
не удаляет строки при построении запроса. Это означает, что ввод, содержащий кавычки, символы новой строки и, возможно, другие специальные символы, не будет импортирован правильно и может создать уязвимость SQL-инъекции. readExcel
пытается обойти это, удалив некоторые символы, но это также искажает данные.
Пожалуйста, проверьте данные, содержащие кавычки, символы новой строки, символы, отличные от ASCII, и т. д. Убедитесь, что они импортированы без изменений. Удаление символов неверно.
Данные из предыдущих строк
Если столбец не задан в одной строке (например, поскольку его тип ячейки неизвестен), значение из предыдущей строки (и даже предыдущего файла!) остается. Это связано с тем, что BulkUploader.records
повторно используется: каждая строка представлена одной и той же картой.
records
используется только в readExcel
, поэтому она должна быть локальной переменной. Он представляет собой одну строку, поэтому ее необходимо создать заново для каждой строки.
Упрощения
AFAICT BulkUploader.procedureList
всегда имеет один элемент. Таким образом, он должен быть SP
, а не List<SP>
.
BulkUploader.headerDetails
не используется.
Большинство
BulkUploader
до flush
является избыточным , Просто позвоните close
. (Или используйте блок close
, чтобы он был надежно закрыт.)
В настоящее время методы проверки возвращают массив {success, message message}. Это не дает понять, что вход недействителен и импорт не может продолжаться - вызывающий должен помнить, чтобы проверить результат. Было бы яснее, если бы они бросали исключения при неудаче.
В try (...)
, validateRecords
иconfiguration
не используются.
Некоторые методы должны быть учтены:
- Часть
sequence
, которая преобразует строку в записи вreadExcel
должен быть отдельным методом (records
, называемыйrowMap
?). Часть, которая преобразует ячейку в запись вMap<String, Object> records = rowMap(row);
, также может быть отдельным методом. - Часть
records
, которая находитvalidateRecords
для использования должен быть методRule
. - Часть
RulesMapping
, которая запускает правило, должна быть методомvalidateRecords
. - Часть
Rule
, которая преобразует значение столбца в строку (со специальными случаями для некоторых столбцов), должна быть отдельным методом (executeProcedure
) литий>
Цикл в parameterString
может быть executeProcedure
, который обновляет for
, чтобы было ясно, что он учитывает итерации:
i
Вы можете создавать массивы в одной строке с помощью инициализаторов массива:
for (int i = 1; keys.hasNext(); ++i)
Class<?>[] parameterTypes = {Object.class, List.class, String.class, String.class, String.class};
Object[] values = {isDataUploadedValid, vMessages};
даже не требуется, потому что вы можете передать классы непосредственно в parameterTypes
:
getMethod
Method m = obj.getClass().getMethod(methodName, Object.class, List.class, String.class, String.class, String.class);
принимает строки, поэтому нет необходимости преобразовывать строку в код FileInputStream
. Просто выполните File
.
Только некоторые общие мысли.
Являются ли ваше поле package protected
по назначению? Предотвратите создание плотной связи ваших компонентов, в то время как вы должны начать в основном с помощью private
и только увеличивать видимость там, где это необходимо. С другой стороны, если вы «никогда» не планируете добавлять дополнительные операции к вашему объекту данных, сделайте их общедоступными и пропустите бесполезные геттеры.
Являются ли комментарии только для нас сейчас или являются вашими настоящими комментариями?
// List of procedure to be executed
List<SP> procedureList = new ArrayList<SP>();
В более позднем случае: добавляет ли это значение читателю? Просто найдите подходящее имя переменной, как вы здесь, и пропустите комментарий.
Некоторые из ваших методов довольно длинные, возможно, вы можете извлечь какой-нибудь метод имен, чтобы улучшить читаемость. Кроме того, уменьшая уровень вложенности таким образом, может упростить поддержку кода.