zdsong 2 ヶ月 前
コミット
bfb6b7dc94

+ 779 - 0
farm-common-biz/src/main/java/jp/yamoto/farm/common/dev/ExcelToJavaGenerator.java

@@ -0,0 +1,779 @@
+package jp.yamoto.farm.common.dev;
+
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.ss.usermodel.*;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+import java.io.FileInputStream;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class ExcelToJavaGenerator {
+	public static void main(String[] args) {
+        // 文件路径配置
+        String excelFilePath = "/Users/apple/mywork-gs/svn/ds-yamoto-farm/20_設計/02_DB設計書/テーブル設計書_ヤマト運輸様|農家(農業法人)支援システム_v1.0.xlsx"; // 输入的Excel文件路径
+        String outputSqlPath = "/Users/apple/mywork-gs/svn/ds-yamoto-farm/20_設計/02_DB設計書/codes"; // 输出的SQL文件路径
+        generateMapperL(excelFilePath,outputSqlPath);
+    }
+
+	public static void generateMapperL(String excelFilePath,String outputSqlPath) {
+		
+	    List<String> fieldGenerateLst = new ArrayList<String>();
+	    fieldGenerateLst.add(excelFilePath);
+	    fieldGenerateLst.add("create_time");
+	    fieldGenerateLst.add("create_by");
+	    fieldGenerateLst.add("create_pg_id");
+	    fieldGenerateLst.add("update_time");
+	    fieldGenerateLst.add("update_by");
+	    fieldGenerateLst.add("update_pg_id");
+	    fieldGenerateLst.add("version");
+	    
+	    try (FileInputStream fis = new FileInputStream(excelFilePath);
+	         Workbook workbook = getWorkbook(fis, excelFilePath)) {
+	        
+	        // 创建输出目录(如果不存在)
+	        Path outputDir = Paths.get(outputSqlPath);
+	        if (!Files.exists(outputDir)) {
+	            Files.createDirectories(outputDir);
+	        }
+	        
+	        // 遍历每个Sheet,每个Sheet生成一个文件
+	        for (int sheetIndex = 2; sheetIndex < workbook.getNumberOfSheets(); sheetIndex++) {
+//	            if (sheetIndex > 6) {
+//	                continue;
+//	            }
+	            
+	            Sheet sheet = workbook.getSheetAt(sheetIndex);
+	            Row rowTable = sheet.getRow(1);
+	            
+	            if (rowTable == null || rowTable.getCell(27) == null) {
+	                System.out.println("Sheet " + sheetIndex + " 没有找到表名信息,跳过");
+	                continue;
+	            }
+	            // 表名
+	            String tableName = rowTable.getCell(27).getStringCellValue();
+	            String tablrNameHanzi = sheet.getRow(0).getCell(27).getStringCellValue();
+	            // 驼峰表名
+	            String camelTableName = convertToCamelCase(tableName);
+	            // 首字母大些驼峰表名
+	            String camelTableName2 = convertToPascalCase(tableName);
+	            
+	            Map<String,StringBuilder> generateBuilder = generateCodes(sheet, tableName, 
+		                camelTableName, camelTableName2, tablrNameHanzi , fieldGenerateLst);
+	            
+	            for(String key : generateBuilder.keySet()) {
+	            	
+	            	StringBuilder outTempPathBuilder = new StringBuilder();
+	            	outTempPathBuilder.append(outputSqlPath + "/" + key);
+	            	// 创建输出目录(如果不存在)
+	            	String fileOutTempPath = outTempPathBuilder.toString();
+	    	        outputDir = Paths.get(fileOutTempPath);
+	    	        if (!Files.exists(outputDir)) {
+	    	            Files.createDirectories(outputDir);
+	    	        }
+	    	        
+	            	outTempPathBuilder.append( "/" + camelTableName2);
+	            	if("mapper".equals(key)) {
+	            		outTempPathBuilder.append( "Mapper.xml" );
+	            	}else if("entity".equals(key)) {
+	            		outTempPathBuilder.append(".java" );
+	            	} else if("inteface".equals(key)) {
+	            		outTempPathBuilder.append("Mapper.java" );
+	            	} else if("json".equals(key)) {
+	            		outTempPathBuilder.append("Json.txt" );
+	            	} else if("message".equals(key)) {
+	            		outTempPathBuilder.append("Message.txt" );
+	            	}else if("entityVo".equals(key)) {
+	            		outTempPathBuilder.append("Vo").append(".java" );
+	            	} else if("entityBo".equals(key)) {
+	            		outTempPathBuilder.append("Bo").append(".java" );
+	            	}
+	            	// 为每个Sheet创建独立的文件
+		            Path filePath = Paths.get(outTempPathBuilder.toString());
+		            
+		            // 删除已存在的文件[6,7](@ref)
+		            if (Files.exists(filePath)) {
+		                try {
+		                    Files.deleteIfExists(filePath);
+		                    System.out.println("文件已删除: " + filePath);
+		                } catch (IOException e) {
+		                    System.err.println("删除文件时发生错误: " + e.getMessage());
+		                }
+		            }
+		            
+		            // 为当前Sheet构建Mapper内容
+		            StringBuilder sheetMapperContent = generateBuilder.get(key);
+		            
+		            // 为每个Sheet单独写入文件[6,8](@ref)
+		            try (FileWriter writer = new FileWriter(filePath.toFile())) {
+		                writer.write(sheetMapperContent.toString());
+		                System.out.println("Mapper已生成: " + filePath);
+		            } catch (IOException e) {
+		                System.err.println("写入文件时发生错误: " + e.getMessage());
+		                e.printStackTrace();
+		            }
+	            }
+	            
+	        }
+	        
+	    } catch (Exception e) {
+	        e.printStackTrace();
+	    }
+	}
+
+	/**
+	 * 为单个Sheet构建Mapper内容
+	 */
+	private static Map<String,StringBuilder> generateCodes(Sheet sheet, String tableName,String camelTableName, String camelTableName2, String tablrNameHanzi, List<String> fieldGenerateLst) {
+	    
+		
+		Map<String,StringBuilder> generateBuilder =new HashMap<String,StringBuilder>();
+		
+		// Mapper
+	    StringBuilder mapperContent = new StringBuilder();
+	    // Result列Builder
+	    StringBuilder resultMapColumnSb = new StringBuilder();
+	    // Select field Builder
+	    StringBuilder selectFieldMapColumnSb = new StringBuilder();
+	    // Select List Builder
+	    StringBuilder selectListMapColumnSb = new StringBuilder();
+	    // Select By Id Builder
+	    StringBuilder selectByIdMapColumnSb = new StringBuilder();
+	    // Insert Builder
+	    StringBuilder insertBeforeMapColumnSb = new StringBuilder();
+	    StringBuilder insertAfterMapColumnSb = new StringBuilder();
+	    // Update Builder
+	    StringBuilder updateMapColumnSb = new StringBuilder();
+	    
+	    // Entity
+	    StringBuilder entityContent = new StringBuilder();
+	    StringBuilder entityFieldMapSb = new StringBuilder();
+	    StringBuilder entityContentVo = new StringBuilder();
+	    StringBuilder entityContentBo = new StringBuilder();
+	    StringBuilder entityFieldMapSbBo = new StringBuilder();
+	    // Json
+	    StringBuilder jsonFieldMapSb = new StringBuilder();
+	    
+	    // Message
+	    StringBuilder jsonMessageMapSb = new StringBuilder();
+	    
+	    // Inteface
+	    StringBuilder intefaceContent = new StringBuilder();
+	   
+	    boolean hasPrimaryKey = false;
+        String primaryKeyColumn = null;
+
+        int startRow = 8; // 通常第1行 (索引0) 是标题行,数据从第2行开始
+        for (int rowIndex = startRow; rowIndex <= sheet.getLastRowNum(); rowIndex++) {
+            Row row = sheet.getRow(rowIndex);
+            if (row == null || isEmptyRow(row)) continue;
+
+            // 解析单元格,假设列顺序为:字段名, 类型, 长度, 是否主键, 是否允许空, 默认值, 注释
+            String fieldName = getCellValueSafe(row.getCell(12));
+            if(fieldName == null || fieldName =="") {
+            	continue;
+            } 
+            
+            String camelFieldName = convertToCamelCase(fieldName);
+            
+            String fieldType = getCellValueSafe(row.getCell(21));
+            String fieldLength = getCellValueSafe(row.getCell(24));
+            String fieldDit = getCellValueSafe(row.getCell(26));
+            String isPrimaryKey = getCellValueSafe(row.getCell(33));
+            String searchField = "";
+            String isSeachCode = getCellValueSafe(row.getCell(34));
+            String isNullable = getCellValueSafe(row.getCell(28));
+            String defaultValue = getCellValueSafe(row.getCell(30));
+            String fieldComment = getCellValueSafe(row.getCell(2));
+
+            if (fieldName == null || fieldName.trim().isEmpty()) {
+                break; // 遇到空行则结束当前表的解析
+            }
+            
+            if(!fieldGenerateLst.contains(fieldName)) {
+            	// 开始拼接单个字段定义
+                entityFieldMapSb.append("    /**").append("\n");
+                entityFieldMapSb.append("     * ").append(fieldComment) .append("\n");
+                entityFieldMapSb.append("     */").append("\n");
+                entityFieldMapSb.append("    private ");
+
+                // 处理数据类型和长度
+                if (("varchar".equalsIgnoreCase(fieldType) 
+                		|| ("text".equalsIgnoreCase(fieldType)) && !fieldLength.isEmpty()) ) {
+                	entityFieldMapSb.append("String");
+
+                } else if ("DECIMAL".equalsIgnoreCase(fieldType) && !fieldLength.isEmpty()) {
+                	entityFieldMapSb.append("BigDecimal");
+                } else if ("timestamp".equalsIgnoreCase(fieldType) && !fieldLength.isEmpty()) {
+                	entityFieldMapSb.append("Date");
+                }  else if ("integer".equalsIgnoreCase(fieldType) && !fieldLength.isEmpty()) {
+                	entityFieldMapSb.append("Integer");
+                }   else {
+                	entityFieldMapSb.append("String");
+                }
+                entityFieldMapSb.append(" ");
+                entityFieldMapSb.append(camelFieldName).append(";") .append("\n");
+                entityFieldMapSb.append("\n");
+                
+               // 开始拼接单个字段定义
+                entityFieldMapSbBo.append("    /**").append("\n");
+                entityFieldMapSbBo.append("     * ").append(fieldComment) .append("\n");
+                entityFieldMapSbBo.append("     */").append("\n");
+                
+                if(isNullable.equals("NO") && "varchar".equalsIgnoreCase(fieldType) ) {
+                	entityFieldMapSbBo.append("    @LmNotBlank(params = {\"{").append(camelFieldName).append("}\"}, groups = {ValidatorGroup.AddGroup.class, ValidatorGroup.UpdateGroup.class})") .append("\n");;
+                }
+                
+                if ("varchar".equalsIgnoreCase(fieldType) ) {
+                	entityFieldMapSbBo.append("    @LmLength(min = 1, max = ").append(fieldLength).append(", params = {\"{")
+                	.append(camelFieldName).append("}\", \"").append(fieldLength).append("\"}, groups = {ValidatorGroup.AddGroup.class, ValidatorGroup.UpdateGroup.class})") .append("\n");;
+                }
+                
+                entityFieldMapSbBo.append("    private ");
+                // 处理数据类型和长度
+                if (("varchar".equalsIgnoreCase(fieldType) 
+                		|| ("text".equalsIgnoreCase(fieldType)) && !fieldLength.isEmpty()) ) {
+                	entityFieldMapSbBo.append("String");
+
+                } else if ("DECIMAL".equalsIgnoreCase(fieldType) && !fieldLength.isEmpty()) {
+                	entityFieldMapSbBo.append("BigDecimal");
+                } else if ("timestamp".equalsIgnoreCase(fieldType) && !fieldLength.isEmpty()) {
+                	entityFieldMapSbBo.append("Date");
+                }  else if ("integer".equalsIgnoreCase(fieldType) && !fieldLength.isEmpty()) {
+                	entityFieldMapSbBo.append("Integer");
+                }   else {
+                	entityFieldMapSbBo.append("String");
+                }
+                entityFieldMapSbBo.append(" ");
+                entityFieldMapSbBo.append(camelFieldName).append(";") .append("\n");
+                entityFieldMapSbBo.append("\n");
+                
+            }
+            
+            
+            
+            // COMMENT ON COLUMN "public"."mast_user"."user_cd" IS '111';
+            // 处理是否为主键
+            if ("1".equalsIgnoreCase(isPrimaryKey)) {
+                hasPrimaryKey = true;
+                primaryKeyColumn = fieldName;
+            }
+            
+            // 处理是否为查询code
+            if ("1".equalsIgnoreCase(isSeachCode)) {
+            	searchField = fieldName;
+            }
+
+            // 处理是否允许为空 (PostgreSQL 中 NOT NULL 约束)
+            if ("NO".equalsIgnoreCase(isNullable)) {
+               
+            }
+
+            // 处理默认值
+            if (defaultValue != null && !defaultValue.trim().isEmpty()) {
+                // 对字符串类型默认值加单引号,数字和函数不加
+                if (needsQuotesForDefault(fieldType)) {
+//                    fieldDefinition.append(" DEFAULT '").append(defaultValue).append("'");
+                } else {
+//                    fieldDefinition.append(" DEFAULT ").append(defaultValue);
+                }
+            }
+
+            // ResultMap构建
+            resultMapColumnSb.append("        <result property=") .append("\"").append(camelFieldName).append("\"").append(" column=") .append("\"").append(fieldName).append("\"").append("/>\n");
+            
+            // Select Filed 构建
+            if(!fieldGenerateLst.contains(fieldName)) {
+            	
+                selectFieldMapColumnSb.append("          ").append(fieldName).append(",\n");
+                if ("varchar".equalsIgnoreCase(fieldType) && !fieldLength.isEmpty()) {
+                    // Select List 构建
+                    selectListMapColumnSb.append("            <if test=") .append("\"").append(camelFieldName).append(" != null  and ").append(camelFieldName).append(" != ").append("\'").append("\'") .append("\"").append(">\n");
+                } else {
+                	 selectListMapColumnSb.append("            <if test=") .append("\"").append(camelFieldName).append(" != null ").append("\"").append(">\n");
+                }
+
+                selectListMapColumnSb.append("                and ").append(fieldName).append(" = #{").append(camelFieldName).append("}\n");
+                selectListMapColumnSb.append("            </if>\n");
+            }
+            if(primaryKeyColumn.equals(fieldName)) {
+            	  selectByIdMapColumnSb.append(fieldName).append(" = #{").append(camelFieldName).append("}\n");
+            }
+            // Insert 构建
+            insertBeforeMapColumnSb.append("            <if test=") .append("\"").append(camelFieldName).append(" != null").append("\"").append(">\n");
+            insertBeforeMapColumnSb.append("                ").append(fieldName).append(",\n");;
+            insertBeforeMapColumnSb.append("            </if>\n");
+            insertAfterMapColumnSb.append("            <if test=") .append("\"").append(camelFieldName).append(" != null").append("\"").append(">\n");
+            insertAfterMapColumnSb.append("                #{").append(camelFieldName).append("},\n");;
+            insertAfterMapColumnSb.append("            </if>\n");
+            // Update 构建
+            updateMapColumnSb.append("            <if test=") .append("\"").append(camelFieldName).append(" != null").append("\"").append(">\n");
+            updateMapColumnSb.append("                ") .append(fieldName).append(" = #{").append(camelFieldName).append("},\n");;
+            updateMapColumnSb.append("            </if>\n");
+            
+    
+            
+            jsonFieldMapSb.append("\"").append(camelFieldName).append("\"").append(":");
+            if (("integer".equalsIgnoreCase(fieldType)|| "decimal".equalsIgnoreCase(fieldType)) &&  !fieldLength.isEmpty()) {
+            	jsonFieldMapSb.append(0).append(",\n");
+            } else {
+            	jsonFieldMapSb.append("\"").append("\"").append(",\n");
+            }
+            
+            jsonMessageMapSb.append("label.").append(camelFieldName).append("=").append(fieldComment).append("\n");
+        }
+
+        // 构建完整的 Mapper 语句
+        if (resultMapColumnSb.length() > 0) {
+        	// 创建MapBuilder类
+            StringBuilder  createMapperSb= new StringBuilder();
+            
+			String tableReslut = camelTableName2 + "Result";
+            // 创建Result类
+            StringBuilder resultMapSb = new StringBuilder();
+            createMapperSb.append("<?xml version=") .append("\"").append("1.0").append("\"").append(" encoding=").append("\"").append("UTF-8").append("\"").append(" ?>").append("\n");
+            createMapperSb.append("<!DOCTYPE mapper").append("\n");
+            createMapperSb.append("        PUBLIC ") .append("\"").append("-//mybatis.org//DTD Mapper 3.0//EN").append("\"").append("\n");
+            createMapperSb.append("        ") .append("\"").append("http://mybatis.org/dtd/mybatis-3-mapper.dtd").append("\"").append(">\n");
+            createMapperSb.append("<mapper namespace=") .append("\"").append("jp.yamoto.farm.xxx.xxx.xxx.mapper.").append(camelTableName2).append("Mapper").append("\"").append(">\n");
+            
+            // 创建Result类
+            resultMapSb.append("   <resultMap type=") .append("\"").append(camelTableName2).append("\"").append(" id=") .append("\"").append(tableReslut).append("\"").append(">\n");
+            resultMapSb.append(resultMapColumnSb.toString()).append("\n");
+            // Result结尾
+            resultMapSb.append("    </resultMap>");
+            // 添加Result结构
+            createMapperSb.append(resultMapSb.toString()).append("\n");
+            
+            // Select Field
+            StringBuilder selectFieldMapSb = new StringBuilder();
+            StringBuilder selectFieldVoSb  = new StringBuilder();
+            selectFieldVoSb.append("select").append(camelTableName2).append("Vo");
+            selectFieldMapSb.append("    <sql id=") .append("\"").append(selectFieldVoSb.toString()).append("\"").append(">\n");
+            selectFieldMapSb.append("        select").append("\n");;
+            // 移除最后一个逗号
+            String selectFieldDefs = selectFieldMapColumnSb.toString();
+			if (selectFieldDefs.endsWith(",\n")) {
+				selectFieldDefs = selectFieldDefs.substring(0, selectFieldDefs.length() - 2);
+			}
+			selectFieldMapSb.append(selectFieldDefs).append("\n");;
+			selectFieldMapSb.append("        from ").append(tableName).append("\n");
+			selectFieldMapSb.append("    </sql>");
+			// 添加Select Field 结构
+            createMapperSb.append(selectFieldMapSb.toString()).append("\n");
+            
+            // Select List
+            StringBuilder selectListMapSb = new StringBuilder();
+            selectListMapSb.append("    <select id=\"selectList\" parameterType=") .append("\"").append(camelTableName2).append("\"").append(" resultMap=") .append("\"").append(tableReslut).append("\"").append(">\n");
+            selectListMapSb.append("        <include refid=") .append("\"").append(selectFieldVoSb.toString()).append("\"").append("/>\n");
+            selectListMapSb.append("        <where>") .append("\n");
+            selectListMapSb.append(selectListMapColumnSb.toString()).append("\n");
+            selectListMapSb.append("        </where>") .append("\n");
+            selectListMapSb.append("    </select>") .append("\n");
+            // 添加Select List 结构
+            createMapperSb.append(selectListMapSb.toString()).append("\n");
+            
+            // Select By Id
+            StringBuilder selectByIdMapSb = new StringBuilder();
+            selectByIdMapSb.append("    <select id=\"selectById\" parameterType=\"String\" ") .append(" resultMap=") .append("\"").append(tableReslut).append("\"").append(">\n");
+            selectByIdMapSb.append("        <include refid=") .append("\"").append(selectFieldVoSb.toString()).append("\"").append("/>\n");
+            selectByIdMapSb.append("        where ").append(selectByIdMapColumnSb.toString()).append("\n");
+            selectByIdMapSb.append("    </select>") .append("\n");
+            // 添加Select By Id 结构
+            createMapperSb.append(selectByIdMapSb.toString()).append("\n");
+            
+            // Insert
+            StringBuilder insertMapSb = new StringBuilder();
+            insertMapSb.append("    <insert id=\"insert\" parameterType=\"").append(camelTableName2).append("\"").append(">\n");
+            insertMapSb.append("        insert into ").append(tableName) .append("\n");
+            insertMapSb.append("        <trim prefix=\"(\" suffix=\")\" suffixOverrides=\",\">") .append("\n");
+            insertMapSb.append(insertBeforeMapColumnSb.toString()).append("\n");
+            insertMapSb.append("        </trim>") .append("\n");
+            insertMapSb.append("        <trim prefix=\"values (\" suffix=\")\" suffixOverrides=\",\">") .append("\n");
+            insertMapSb.append(insertAfterMapColumnSb.toString()).append("\n");
+            insertMapSb.append("        </trim>") .append("\n");
+            insertMapSb.append("    </insert>") .append("\n");
+            // 添加Insert 结构
+            createMapperSb.append(insertMapSb.toString()).append("\n");
+            
+            // Insert
+            StringBuilder updateMapSb = new StringBuilder();
+            updateMapSb.append("    <update id=\"update\" parameterType=\"").append(camelTableName2).append("\"").append(">\n");
+            updateMapSb.append("        update ").append(tableName) .append("\n");
+            updateMapSb.append("        <trim prefix=\"SET\" suffixOverrides=\",\">") .append("\n");
+            updateMapSb.append(updateMapColumnSb.toString()).append("\n");
+            updateMapSb.append("        </trim>") .append("\n");
+            updateMapSb.append("        where") .append("\n");
+            updateMapSb.append("        ").append(selectByIdMapColumnSb.toString()).append("\n");
+            updateMapSb.append("        and version = #{version}") .append("\n");
+            updateMapSb.append("    </update>") .append("\n");
+            // 添加Update 结构
+            createMapperSb.append(updateMapSb.toString()).append("\n");
+
+            // Delete
+            StringBuilder deleteMapSb = new StringBuilder();
+            deleteMapSb.append("    <delete id=\"deleteById\" parameterType=\"String\"").append(">\n");
+            deleteMapSb.append("        delete") .append("\n");
+            deleteMapSb.append("        from") .append("\n");
+            deleteMapSb.append("        ").append(tableName) .append("\n");
+            deleteMapSb.append("        where") .append("\n");
+            deleteMapSb.append("        ").append(selectByIdMapColumnSb.toString()).append("\n");
+            deleteMapSb.append("    </delete>") .append("\n");
+            // 添加Delete 结构
+            createMapperSb.append(deleteMapSb.toString()).append("\n");
+            
+            
+            
+            // 文件结尾
+            createMapperSb.append(" </mapper>");
+            
+            mapperContent.append(createMapperSb);
+            
+        }
+        
+        // 构建完整的 Mapper 语句
+        if (entityFieldMapSb.length() > 0) {
+        	 StringBuilder  createSb= new StringBuilder();
+        	 createSb.append("package jp.yamoto.farm.xx.xxx.xxxx.domain.entity;").append("\n");
+        	 createSb.append("\n");
+             createSb.append("import jp.yamoto.farm.common.core.domain.BaseEntity;").append("\n");
+             createSb.append("import lombok.Data;").append("\n");
+             createSb.append("import lombok.EqualsAndHashCode;").append("\n");
+             createSb.append("\n");
+             createSb.append("import java.io.Serial;").append("\n");
+             
+             createSb.append("import java.math.BigDecimal;").append("\n");
+             createSb.append("\n");
+             
+             createSb.append("/**").append("\n");
+             createSb.append(" * ").append(tablrNameHanzi).append(" (").append(tableName).append(")")  .append("\n");
+             createSb.append(" *").append("\n");
+             createSb.append(" * @author nextosd").append("\n");
+             createSb.append(" */").append("\n");
+             createSb.append("@EqualsAndHashCode(callSuper = true)").append("\n");
+             createSb.append("@Data").append("\n");
+             createSb.append("public class ").append(camelTableName2);
+             createSb.append(" extends BaseEntity {").append("\n");
+             createSb.append("\n");
+
+             createSb.append("    @Serial").append("\n");
+             createSb.append("    private static final long serialVersionUID = 1L;").append("\n");
+             createSb.append("\n");
+             
+             createSb.append(entityFieldMapSb.toString());
+             
+             createSb.append("    /**").append("\n");
+             createSb.append("     * ").append("リビジョン") .append("\n");
+             createSb.append("     */").append("\n");
+             createSb.append("    private Integer version;").append("\n");;
+             
+             createSb.append("}").append("\n");
+             entityContent.append(createSb);
+             
+             StringBuilder  createSb1= new StringBuilder();
+             createSb1.append("package jp.yamoto.farm.xx.xxx.xxxx.domain.entity;").append("\n");
+             createSb1.append("\n");
+             createSb1.append("import jp.yamoto.farm.common.core.domain.BaseEntity;").append("\n");
+             createSb1.append("import lombok.Data;").append("\n");
+             createSb1.append("import lombok.EqualsAndHashCode;").append("\n");
+             createSb1.append("\n");
+             createSb1.append("import java.io.Serial;").append("\n");
+             
+             createSb1.append("import java.math.BigDecimal;").append("\n");
+             createSb1.append("\n");
+             
+             createSb1.append("/**").append("\n");
+             createSb1.append(" * ").append(tablrNameHanzi).append("詳細情報Vo")  .append("\n");
+             createSb1.append(" *").append("\n");
+             createSb1.append(" * @author nextosd").append("\n");
+             createSb1.append(" */").append("\n");
+             createSb1.append("@Data").append("\n");
+             createSb1.append("public class ").append(camelTableName2).append("Vo");
+             createSb1.append(" extends BaseEntity {").append("\n");
+             createSb1.append("\n");
+
+             
+             createSb1.append(entityFieldMapSb.toString());
+             
+             createSb1.append("    /**").append("\n");
+             createSb1.append("     * ").append("リビジョン") .append("\n");
+             createSb1.append("     */").append("\n");
+             createSb1.append("    private Integer version;").append("\n");;
+             
+             createSb1.append("}").append("\n");
+             entityContentVo.append(createSb1);
+             
+             StringBuilder  createSbBo= new StringBuilder();
+        	 createSbBo.append("package jp.yamoto.farm.xx.xxx.xxxx.domain.entity;").append("\n");
+        	 createSbBo.append("\n");
+             createSbBo.append("import jp.yamoto.farm.common.validator.annotation.*;").append("\n");
+             createSbBo.append("import jp.yamoto.farm.common.validator.enums.CheckTypeEnum;").append("\n");
+             createSbBo.append("import jp.yamoto.farm.common.validator.utils.ValidatorGroup;").append("\n");
+             createSbBo.append("import lombok.Data;").append("\n");
+             createSbBo.append("\n");
+             createSbBo.append("import java.io.Serial;").append("\n");
+             createSbBo.append("import java.io.Serializable;").append("\n");
+             createSbBo.append("import java.math.BigDecimal;").append("\n");
+             createSbBo.append("\n");
+             
+             createSbBo.append("/**").append("\n");
+             createSbBo.append(" * ").append(tablrNameHanzi).append(" サービスパラメータ対象")  .append("\n");
+             createSbBo.append(" *").append("\n");
+             createSbBo.append(" * @author nextosd").append("\n");
+             createSbBo.append(" */").append("\n");
+             createSbBo.append("@Data").append("\n");
+             createSbBo.append("public class ").append(camelTableName2);
+             createSbBo.append("Bo implements Serializable {").append("\n");
+             createSbBo.append("\n");
+
+             createSbBo.append("    @Serial").append("\n");
+             createSbBo.append("    private static final long serialVersionUID = 1L;").append("\n");
+             createSbBo.append("\n");
+             
+             createSbBo.append(entityFieldMapSbBo.toString());
+             
+             createSbBo.append("    /**").append("\n");
+             createSbBo.append("     * ").append("リビジョン") .append("\n");
+             createSbBo.append("     */").append("\n");
+             createSbBo.append("    private Integer version;").append("\n");;
+             
+             createSbBo.append("}").append("\n");
+             entityContentBo.append(createSbBo);
+             
+             
+             
+             
+        }
+        
+        // 构建完整的 Inteface 语句
+        if (resultMapColumnSb.length() > 0) {
+        	
+        	 StringBuilder  createSb= new StringBuilder();
+        	 createSb.append("package jp.yamoto.farm.xx.xxx.xxxx.mapper;").append("\n");
+        	 createSb.append("\n");
+             createSb.append("import jp.yamoto.farm.xx.xxx.xxxx.domain.entity.").append(camelTableName2).append(";\n");
+             createSb.append("import jp.yamoto.farm.xx.xxx.xxxx.domain.vo.").append(camelTableName2).append("Vo").append(";\n");
+             
+             createSb.append("import java.util.List;").append("\n");
+             createSb.append("import lombok.EqualsAndHashCode;").append("\n");
+             createSb.append("\n");
+ 
+             createSb.append("\n");
+             
+             createSb.append("/**").append("\n");
+             createSb.append(" * ").append(tablrNameHanzi).append(" Mapperインタフェース")  .append("\n");
+             createSb.append(" *").append("\n");
+             createSb.append(" * @author nextosd").append("\n");
+             createSb.append(" */").append("\n");
+
+             createSb.append("public interface ").append(camelTableName2);
+             createSb.append("Mapper {").append("\n");
+             createSb.append("\n");
+
+             // 检索byID
+             createSb.append("     /**").append("\n");
+             createSb.append("     *").append(tablrNameHanzi).append("を検索")  .append("\n");
+             createSb.append("     *").append("\n");
+             createSb.append("     * @param id ").append(tablrNameHanzi).append("プライマリ・キー")  .append("\n");
+             createSb.append("     * @return ").append(tablrNameHanzi) .append("\n");
+             createSb.append("     */").append("\n");
+             createSb.append("    public ").append(camelTableName2).append("Vo");
+             createSb.append(" selectById(String id);").append("\n");
+             createSb.append("\n");
+             
+             // 检索List by entity
+             createSb.append("     /**").append("\n");
+             createSb.append("     *").append(tablrNameHanzi).append("を検索リスト")  .append("\n");
+             createSb.append("     *").append("\n");
+             createSb.append("     * @param ").append(camelTableName).append(" ").append(tablrNameHanzi)  .append("\n");
+             createSb.append("     * @return ").append(tablrNameHanzi).append("リスト") .append("\n");
+             createSb.append("     */").append("\n");
+             createSb.append("    public List<").append(camelTableName2).append("Vo");
+             createSb.append("> selectList(").append(camelTableName2).append(" ").append(camelTableName) .append(");\n");
+             createSb.append("\n");
+             
+             // Insert
+             createSb.append("     /**").append("\n");
+             createSb.append("     *").append(tablrNameHanzi).append("を登録")  .append("\n");
+             createSb.append("     *").append("\n");
+             createSb.append("     * @param ").append(camelTableName).append(" ").append(tablrNameHanzi)  .append("\n");
+             createSb.append("     * @return ").append(" 結果") .append("\n");
+             createSb.append("     */").append("\n");
+             createSb.append("    public int insert(").append(camelTableName2);
+             createSb.append(" ").append(camelTableName) .append(");\n");
+             createSb.append("\n");
+             
+             // Update
+             createSb.append("     /**").append("\n");
+             createSb.append("     *").append(tablrNameHanzi).append("を修正")  .append("\n");
+             createSb.append("     *").append("\n");
+             createSb.append("     * @param ").append(camelTableName).append(" ").append(tablrNameHanzi)  .append("\n");
+             createSb.append("     * @return ").append(" 結果") .append("\n");
+             createSb.append("     */").append("\n");
+             createSb.append("    public int update(").append(camelTableName2);
+             createSb.append(" ").append(camelTableName) .append(");\n");
+             createSb.append("\n");
+             
+             
+             createSb.append("}").append("\n");
+             intefaceContent.append(createSb.toString());
+        }
+	    
+        generateBuilder.put("mapper", mapperContent);
+        generateBuilder.put("entity", entityContent);
+        generateBuilder.put("entityVo", entityContentVo);
+        generateBuilder.put("entityBo", entityContentBo);
+        generateBuilder.put("inteface", intefaceContent);
+        
+        generateBuilder.put("json", jsonFieldMapSb);
+        generateBuilder.put("message",jsonMessageMapSb);
+	    return generateBuilder;
+	}
+	
+	
+
+    /**
+     * 根据文件扩展名创建合适的Workbook对象
+     */
+    private static Workbook getWorkbook(FileInputStream fis, String filePath) throws IOException {
+        if (filePath.endsWith(".xlsx")) {
+            return new XSSFWorkbook(fis);
+        } else if (filePath.endsWith(".xls")) {
+            return new HSSFWorkbook(fis);
+        } else {
+            throw new IllegalArgumentException("不支持的文件格式");
+        }
+    }
+
+    /**
+     * 安全获取单元格的字符串值,处理不同类型单元格[6,7](@ref)
+     */
+    private static String getCellValueSafe(Cell cell) {
+        if (cell == null) {
+            return ""; // 如果单元格为空,返回空字符串
+        }
+
+        switch (cell.getCellType()) {
+            case STRING:
+                return cell.getStringCellValue().trim();
+            case NUMERIC:
+                // 判断是否为日期
+                if (DateUtil.isCellDateFormatted(cell)) {
+                    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+                    return sdf.format(cell.getDateCellValue());
+                } else {
+                    // 处理数字,避免显示为科学计数法
+                    double num = cell.getNumericCellValue();
+                    if (num == (long) num) {
+                        return String.valueOf((long) num); // 整数去除小数点
+                    } else {
+                        return String.valueOf(num);
+                    }
+                }
+            case BOOLEAN:
+                return String.valueOf(cell.getBooleanCellValue());
+            case FORMULA:
+                // 对于公式单元格,尝试计算公式结果,然后递归调用本方法
+                try {
+                    FormulaEvaluator evaluator = cell.getSheet().getWorkbook().getCreationHelper().createFormulaEvaluator();
+                    CellValue cellValue = evaluator.evaluate(cell);
+                    // 根据公式计算结果类型再次处理
+                    switch (cellValue.getCellType()) {
+                        case STRING:
+                            return cellValue.getStringValue();
+                        case NUMERIC:
+                            return String.valueOf(cellValue.getNumberValue()).replace(".0", "");
+                        case BOOLEAN:
+                            return String.valueOf(cellValue.getBooleanValue());
+                        default:
+                            return "FORMULA_RESULT_UNKNOWN";
+                    }
+                } catch (Exception e) {
+                    // 如果公式计算失败,退回直接读取公式字符串或缓存值
+                    return cell.getCellFormula();
+                }
+            case BLANK:
+                return "";
+            default:
+                return "";
+        }
+    }
+
+    /**
+     * 辅助方法:处理公式单元格的计算值[6](@ref)
+     */
+    private static Cell getCellValueFromFormula(Cell cell) {
+        // 这里可以引入 FormulaEvaluator 来计算公式结果[6](@ref)
+        // 简化处理:返回单元格的缓存值或尝试计算
+        return cell; // 实际应用中应使用 FormulaEvaluator
+    }
+
+    private static boolean isEmptyRow(Row row) {
+        for (int i = 0; i < row.getLastCellNum(); i++) {
+            Cell cell = row.getCell(i);
+            if (cell != null && cell.getCellType() != CellType.BLANK) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * 判断该数据类型的默认值是否需要引号(字符串、日期等需要)
+     */
+    private static boolean needsQuotesForDefault(String fieldType) {
+        if (fieldType == null) return false;
+        String typeLower = fieldType.toLowerCase();
+        return typeLower.contains("char") || typeLower.contains("text") || 
+                typeLower.contains("date") ;
+    }
+    
+    public static String convertToCamelCase(String input) {
+        if (input == null || input.isEmpty()) {
+            return input;
+        }
+        StringBuilder result = new StringBuilder();
+        // 使用标志位判断是否需要大写下一个字符[7](@ref)
+        boolean nextUpperCase = false;
+
+        for (int i = 0; i < input.length(); i++) {
+            char currentChar = input.charAt(i);
+            if (currentChar == '_') {
+                nextUpperCase = true; // 遇到下划线,标记下一个字符大写
+            } else {
+                if (nextUpperCase) {
+                    result.append(Character.toUpperCase(currentChar));
+                    nextUpperCase = false;
+                } else {
+                    result.append(currentChar);
+                }
+            }
+        }
+        return result.toString();
+    }
+    
+    public static String convertToPascalCase(String input) {
+        if (input == null || input.isEmpty()) {
+            return input;
+        }
+        StringBuilder result = new StringBuilder();
+        String[] words = input.split("_");
+        
+        for (String word : words) {
+            if (!word.isEmpty()) { // 避免连续下划线导致空字符串
+                // 将每个单词的首字母大写,其余字母小写
+                result.append(Character.toUpperCase(word.charAt(0)))
+                      .append(word.substring(1).toLowerCase());
+            }
+        }
+        return result.toString();
+    }
+}

+ 279 - 0
farm-common-biz/src/main/java/jp/yamoto/farm/common/dev/ExcelToSQLGenerator.java

@@ -0,0 +1,279 @@
+package jp.yamoto.farm.common.dev;
+
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.ss.usermodel.*;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+import java.io.FileInputStream;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.text.SimpleDateFormat;
+
+public class ExcelToSQLGenerator {
+	public static void main(String[] args) {
+        // 文件路径配置
+        String excelFilePath = "/Users/apple/mywork-gs/svn/ds-yamoto-farm/20_設計/02_DB設計書/テーブル設計書_ヤマト運輸様|農家(農業法人)支援システム_v1.0.xlsx"; // 输入的Excel文件路径
+        String outputSqlPath = "/Users/apple/mywork-gs/svn/ds-yamoto-farm/20_設計/02_DB設計書/create_table_sql.sql"; // 输出的SQL文件路径
+       
+
+        generatePostgresqlDDL(excelFilePath, outputSqlPath);
+    }
+
+	public static void generatePostgresqlDDL(String excelFilePath, String outputSqlPath) {
+        StringBuilder finalSQL = new StringBuilder();
+        Path path = Paths.get(outputSqlPath);
+        if (Files.exists(path)) {
+            try {
+                // 如果文件存在,则删除它
+                boolean deleted = Files.deleteIfExists(path);
+                if (deleted) {
+                    System.out.println("文件已成功删除: " + path);
+                } else {
+                    System.out.println("尝试删除文件但失败: " + path);
+                }
+            } catch (IOException e) {
+                // 处理可能发生的IO异常
+                System.err.println("删除文件时发生错误: " + e.getMessage());
+            }
+        } else {
+            System.out.println("文件不存在: " + path);
+        }
+        
+        try (FileInputStream fis = new FileInputStream(excelFilePath);
+             Workbook workbook = getWorkbook(fis, excelFilePath);
+             FileWriter writer = new FileWriter(outputSqlPath)) {
+        	
+
+            // 遍历每个Sheet,假设每个Sheet定义一张表
+            for (int sheetIndex = 2; sheetIndex < workbook.getNumberOfSheets(); sheetIndex++) {
+         
+                Sheet sheet = workbook.getSheetAt(sheetIndex);
+                
+                Row rowTable = sheet.getRow(1);
+                
+                String tableName = rowTable.getCell(27).getStringCellValue(); // 使用工作表名作为表名
+
+                // 获取列定义(假设数据从第2行开始,第1行是标题)
+                StringBuilder columnDefinitions = new StringBuilder();
+                StringBuilder columnComments = new StringBuilder();
+                boolean hasPrimaryKey = false;
+                String primaryKeyColumn = null;
+
+                int startRow = 8; // 通常第1行 (索引0) 是标题行,数据从第2行开始
+                for (int rowIndex = startRow; rowIndex <= sheet.getLastRowNum(); rowIndex++) {
+                    Row row = sheet.getRow(rowIndex);
+                    if (row == null || isEmptyRow(row)) continue;
+
+                    // 解析单元格,假设列顺序为:字段名, 类型, 长度, 是否主键, 是否允许空, 默认值, 注释
+                    String fieldName = getCellValueSafe(row.getCell(12));
+                    if(fieldName == null || fieldName =="") {
+                    	continue;
+                    } 
+                    
+                    String fieldType = getCellValueSafe(row.getCell(21));
+                    String fieldLength = getCellValueSafe(row.getCell(24));
+                    String fieldDit = getCellValueSafe(row.getCell(26));
+                    String isPrimaryKey = getCellValueSafe(row.getCell(33));
+                    String isNullable = getCellValueSafe(row.getCell(28));
+                    String defaultValue = getCellValueSafe(row.getCell(30));
+                    String fieldComment = getCellValueSafe(row.getCell(2));
+
+                    if (fieldName == null || fieldName.trim().isEmpty()) {
+                        break; // 遇到空行则结束当前表的解析
+                    }
+
+                    // 开始拼接单个字段定义
+                    StringBuilder fieldDefinition = new StringBuilder();
+                    fieldDefinition.append("    \"").append(fieldName).append("\" "); // PostgreSQL 通常使用双引号
+
+                    // 处理数据类型和长度
+                    if ("varchar".equalsIgnoreCase(fieldType) && !fieldLength.isEmpty()) {
+                        fieldDefinition.append("VARCHAR(").append(fieldLength).append(")");
+                    } else if ("DECIMAL".equalsIgnoreCase(fieldType) && !fieldLength.isEmpty()) {
+                        fieldDefinition.append("DECIMAL(").append(fieldLength).append(",").append(fieldDit).append(")");
+                    } else {
+                        fieldDefinition.append(fieldType); // 直接使用类型,如 INT, TEXT, DATE, TIMESTAMP
+                    }
+                    columnComments.append("    COMMENT ON COLUMN ");
+                    columnComments.append("\"").append("public").append("\"");
+                    columnComments.append(".");
+                    columnComments.append("\"").append(tableName).append("\"");
+                    columnComments.append(".");
+                    columnComments.append("\"").append(fieldName).append("\"").append(" IS '").append(fieldComment).append("';");; // PostgreSQL 通常使用双引号
+                    columnComments.append("\n");
+                    // COMMENT ON COLUMN "public"."mast_user"."user_cd" IS '111';
+                    // 处理是否为主键
+                    if ("1".equalsIgnoreCase(isPrimaryKey)) {
+                        hasPrimaryKey = true;
+                        primaryKeyColumn = fieldName;
+                    }
+
+                    // 处理是否允许为空 (PostgreSQL 中 NOT NULL 约束)
+                    if ("NO".equalsIgnoreCase(isNullable)) {
+                        fieldDefinition.append(" NOT NULL");
+                    }
+
+                    // 处理默认值
+                    if (defaultValue != null && !defaultValue.trim().isEmpty()) {
+                        // 对字符串类型默认值加单引号,数字和函数不加
+                        if (needsQuotesForDefault(fieldType)) {
+                            fieldDefinition.append(" DEFAULT '").append(defaultValue).append("'");
+                        } else {
+                            fieldDefinition.append(" DEFAULT ").append(defaultValue);
+                        }
+                    }
+
+                    columnDefinitions.append(fieldDefinition).append(",\n");
+                   
+                }
+
+                // 构建完整的 CREATE TABLE 语句
+                if (columnDefinitions.length() > 0) {
+                    StringBuilder createTableSQL = new StringBuilder();
+                    
+                    createTableSQL.append("\n");
+                    createTableSQL.append("DROP TABLE  IF EXISTS ").append(tableName).append(";\n");
+                    createTableSQL.append("-- 创建表: ").append(tableName).append("\n");
+                    createTableSQL.append("CREATE TABLE ").append(tableName).append(" (\n");
+                    
+                    // 添加列定义(移除最后一个逗号)
+                    String columnDefs = columnDefinitions.toString();
+                    if (columnDefs.endsWith(",\n")) {
+                        columnDefs = columnDefs.substring(0, columnDefs.length() - 2);
+                    }
+                    createTableSQL.append(columnDefs).append("\n");
+
+                    // 添加表级主键约束
+                    if (hasPrimaryKey && primaryKeyColumn != null) {
+                        createTableSQL.append("    ,CONSTRAINT pk_").append(tableName)
+                                     .append(" PRIMARY KEY (\"").append(primaryKeyColumn).append("\")\n");
+                    }
+
+                    createTableSQL.append(");\n\n");
+                    createTableSQL.append("ALTER TABLE ");
+                    createTableSQL.append("\"").append("public").append("\"");
+                    createTableSQL.append(".");
+                    createTableSQL.append("\"").append(tableName).append("\"");
+                    createTableSQL.append(" OWNER TO ");
+                    createTableSQL.append("\"").append("postgres").append("\"");
+                    
+                    createTableSQL.append(";\n");
+                    createTableSQL.append(columnComments.toString());
+                    createTableSQL.append("COMMENT ON TABLE ");
+                    //COMMENT ON TABLE "public"."mast_user" IS 'ユーザーマスタ';
+                    createTableSQL.append("\"").append("public").append("\"");
+                    createTableSQL.append(".");
+                    createTableSQL.append("\"").append(tableName).append("\"");
+                    createTableSQL.append(" IS '").append(sheet.getSheetName()).append("';");
+                    finalSQL.append(createTableSQL);
+                }
+            }
+
+            // 将生成的SQL写入文件
+            writer.write(finalSQL.toString());
+            System.out.println("PostgreSQL 建表语句已生成至: " + outputSqlPath);
+
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     * 根据文件扩展名创建合适的Workbook对象
+     */
+    private static Workbook getWorkbook(FileInputStream fis, String filePath) throws IOException {
+        if (filePath.endsWith(".xlsx")) {
+            return new XSSFWorkbook(fis);
+        } else if (filePath.endsWith(".xls")) {
+            return new HSSFWorkbook(fis);
+        } else {
+            throw new IllegalArgumentException("不支持的文件格式");
+        }
+    }
+
+    /**
+     * 安全获取单元格的字符串值,处理不同类型单元格[6,7](@ref)
+     */
+    private static String getCellValueSafe(Cell cell) {
+        if (cell == null) {
+            return ""; // 如果单元格为空,返回空字符串
+        }
+
+        switch (cell.getCellType()) {
+            case STRING:
+                return cell.getStringCellValue().trim();
+            case NUMERIC:
+                // 判断是否为日期
+                if (DateUtil.isCellDateFormatted(cell)) {
+                    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+                    return sdf.format(cell.getDateCellValue());
+                } else {
+                    // 处理数字,避免显示为科学计数法
+                    double num = cell.getNumericCellValue();
+                    if (num == (long) num) {
+                        return String.valueOf((long) num); // 整数去除小数点
+                    } else {
+                        return String.valueOf(num);
+                    }
+                }
+            case BOOLEAN:
+                return String.valueOf(cell.getBooleanCellValue());
+            case FORMULA:
+                // 对于公式单元格,尝试计算公式结果,然后递归调用本方法
+                try {
+                    FormulaEvaluator evaluator = cell.getSheet().getWorkbook().getCreationHelper().createFormulaEvaluator();
+                    CellValue cellValue = evaluator.evaluate(cell);
+                    // 根据公式计算结果类型再次处理
+                    switch (cellValue.getCellType()) {
+                        case STRING:
+                            return cellValue.getStringValue();
+                        case NUMERIC:
+                            return String.valueOf(cellValue.getNumberValue()).replace(".0", "");
+                        case BOOLEAN:
+                            return String.valueOf(cellValue.getBooleanValue());
+                        default:
+                            return "FORMULA_RESULT_UNKNOWN";
+                    }
+                } catch (Exception e) {
+                    // 如果公式计算失败,退回直接读取公式字符串或缓存值
+                    return cell.getCellFormula();
+                }
+            case BLANK:
+                return "";
+            default:
+                return "";
+        }
+    }
+
+    /**
+     * 辅助方法:处理公式单元格的计算值[6](@ref)
+     */
+    private static Cell getCellValueFromFormula(Cell cell) {
+        // 这里可以引入 FormulaEvaluator 来计算公式结果[6](@ref)
+        // 简化处理:返回单元格的缓存值或尝试计算
+        return cell; // 实际应用中应使用 FormulaEvaluator
+    }
+
+    private static boolean isEmptyRow(Row row) {
+        for (int i = 0; i < row.getLastCellNum(); i++) {
+            Cell cell = row.getCell(i);
+            if (cell != null && cell.getCellType() != CellType.BLANK) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * 判断该数据类型的默认值是否需要引号(字符串、日期等需要)
+     */
+    private static boolean needsQuotesForDefault(String fieldType) {
+        if (fieldType == null) return false;
+        String typeLower = fieldType.toLowerCase();
+        return typeLower.contains("char") || typeLower.contains("text") || 
+                typeLower.contains("date") ;
+    }
+}