导出效果:
完整代码:
Controller层:
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;@Api(value = "TestController",description="TestController")
@RestController
@RequestMapping("/test")
public class TestController {@Autowiredprivate IMetadataService metadataService;@IgnoreSecurity@ApiOperation(value = "DDL2WordTable")@GetMapping(value = "/DDL2WordTable")public void DDL2WordTable(HttpServletRequest request, HttpServletResponse response){try {this.metadataService.DDL2WordTable( response );}catch ( Exception e ){e.printStackTrace();}}
}
service 层:
IMetadataService.java:
import javax.servlet.http.HttpServletResponse;
import java.util.List;public interface IMetadataService {void DDL2WordTable(HttpServletResponse response);List<MySqlTableInfo> collectTableInfos();
}
MetadataServiceImpl.java:
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;import javax.servlet.http.HttpServletResponse;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;@Service
@Slf4j
public class MetadataServiceImpl implements IMetadataService {@Autowiredprivate MetadataMapper metadataMapper;@Value( "${spring.datasource.url}" )private String url;@Overridepublic void DDL2WordTable(HttpServletResponse response) {try {List<MySqlTableInfo> tableInfos = this.collectTableInfos();if( tableInfos == null || tableInfos.size() == 0 ){return;}for( MySqlTableInfo tableInfo:tableInfos ){System.out.println( tableInfo.getTableName() + " " + tableInfo.getFieldInfos().size() );}response.setContentType("application/msword");String filename = URLEncoder.encode( "xxxx数据库表结构.docx","UTF-8" );response.setHeader("Content-Disposition", "attachment; filename=" + filename);POIWordUtils.writeMysqlTables2Word( tableInfos,response.getOutputStream() );}catch ( Exception e ){e.printStackTrace();}}@Overridepublic List<MySqlTableInfo> collectTableInfos() {List<String> tableNames = this.metadataMapper.showTableNames();if( tableNames == null || tableNames.size() == 0 ){return null;}// todo 从 jdbc url 中提取???String databaseName = "xxxxxxxxxxxxxx";List<MySqlTableInfo> tableInfos = new ArrayList<>();for( String tableName:tableNames ){List<InformationSchemaCOLUMNS> columnsList = this.metadataMapper.queryInformationSchemaCOLUMNS( databaseName,tableName );if( columnsList == null || columnsList.size() == 0 ){continue;}MySqlTableInfo tableInfo = new MySqlTableInfo();List<MySqlTableFieldInfo> fieldInfos = new ArrayList<>();for( InformationSchemaCOLUMNS columns:columnsList ){MySqlTableFieldInfo fieldInfo = new MySqlTableFieldInfo();fieldInfo.setName( columns.getColumnName() );fieldInfo.setType( columns.getDataType() );Long character_maximum_length = columns.getCharacterMaximumLength();if( character_maximum_length != null ){fieldInfo.setLength( character_maximum_length.toString() );}String is_nullable = columns.getIsNullable();if( "YES".equals( is_nullable ) ){fieldInfo.setNullable( true );}else if( "NO".equals( is_nullable ) ){fieldInfo.setNullable( false );}fieldInfo.setComment( columns.getColumnComment() );String column_key = columns.getColumnKey();if( "PRI".equals( column_key ) ){fieldInfo.setPrimaryKey( true );}else if( "UNI".equals( column_key ) ){// todo 唯一索引fieldInfo.setIndexType( "唯一索引" );}else if( "MUL".equals( column_key ) ){fieldInfo.setIndexType( "普通索引" );}else {// todo 其他索引返回什么}fieldInfo.setDefaultValue( columns.getColumnDefault() );fieldInfos.add( fieldInfo );}tableInfo.setTableName( tableName );tableInfo.setFieldInfos( fieldInfos );tableInfos.add( tableInfo );}// set titlesList<String> titles = new ArrayList<>();titles.add( "字段名称" );titles.add( "类型" );titles.add( "长度" );titles.add( "允许为空" );titles.add( "字段说明" );titles.add( "键" );titles.add( "默认值" );titles.add( "索引类型" );for( MySqlTableInfo tableInfo:tableInfos ){tableInfo.setTitles( titles );}return tableInfos;}
}
Mapper 层:
MetadataMapper.java:
import org.apache.ibatis.annotations.Param;import java.util.List;@DataSource("dataSource")
public interface MetadataMapper extends BaseMapper {List<String> showTableNames();List<InformationSchemaCOLUMNS> queryInformationSchemaCOLUMNS(@Param( "databaseName" ) String databaseName,@Param( "tableName" ) String tableName);
}
MetadataMapper.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.xxx.mapper.MetadataMapper"><select id="showTableNames" resultType="java.lang.String">SHOW TABLES</select><select id="queryInformationSchemaCOLUMNS" resultType="com.xxx.vo.InformationSchemaCOLUMNS">SELECTTABLE_CATALOG AS tableCatalog,TABLE_SCHEMA tableSchema,TABLE_NAME AS tableName,COLUMN_NAME AS columnName,ORDINAL_POSITION AS ordinalPosition,COLUMN_DEFAULT AS columnDefault,IS_NULLABLE AS isNullable,DATA_TYPE AS dataType,CHARACTER_MAXIMUM_LENGTH AS characterMaximumLength,CHARACTER_OCTET_LENGTH AS characterOctetLength,NUMERIC_PRECISION AS numericPrecision,NUMERIC_SCALE AS numericScale,DATETIME_PRECISION AS datetimePrecision,CHARACTER_SET_NAME AS characterSetName,COLLATION_NAME AS collationName,COLUMN_TYPE AS columnType,COLUMN_KEY AS columnKey,EXTRA AS extra,PRIVILEGES AS privileges,COLUMN_COMMENT AS columnComment,GENERATION_EXPRESSION AS generationExpressionFROMinformation_schema.COLUMNSWHEREtable_name = #{tableName}ANDtable_schema = #{databaseName}</select>
</mapper>
用到的 VO 类:InformationSchemaCOLUMNS.java:
import lombok.Getter;
import lombok.Setter;@Getter
@Setter
public class InformationSchemaCOLUMNS {private Long ordinalPosition;/*** 字段长度*/private Long characterMaximumLength;private Long characterOctetLength;private Long numericPrecision;private Long numericScale;private Long datetimePrecision;private String tableCatalog;private String tableSchema;private String tableName;/*** 字段名称,如:username*/private String columnName;/*** 默认值*/private String columnDefault;/*** 字段是否允许空值,'YES'、'NO'*/private String isNullable;/*** 字段的数据类型,如:varchar、datetime ...*/private String dataType;private String characterSetName;private String collationName;private String columnType;/*** 该字段的索引类型( 'PRI':主键索引,'UNI':唯一索引,'MUL':普通索引 )*/private String columnKey;private String extra;private String privileges;/*** 字段的注释*/private String columnComment;private String generationExpression;
}
MySqlTableInfo.java:
import lombok.Getter;
import lombok.Setter;import java.util.List;@Getter
@Setter
public class MySqlTableInfo {private String tableName;private List<String> titles;private List<MySqlTableFieldInfo> fieldInfos;
}
MySqlTableFieldInfo.java:
import lombok.Getter;
import lombok.Setter;@Getter
@Setter
public class MySqlTableFieldInfo {/*** 字段名称,如:username*/private String name;/*** 字段的数据类型*/private String type;/*** 字段长度*/private String length;/*** 字段是否允许空值*/private boolean nullable;/*** 字段的注释*/private String comment;/*** 该字段是否是主键*/private boolean primaryKey;/*** 默认值*/private String defaultValue;private String indexType;
}
POI 工具类:POIWordUtils.java:
import org.apache.poi.xwpf.usermodel.*;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTP;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTc;import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;public class POIWordUtils {public static void writeMysqlTables2Word(List<MySqlTableInfo> tableInfos, OutputStream outputStream){XWPFDocument xwpfDocument = null;try {xwpfDocument = new XWPFDocument();// 创建1行3列的表格for( MySqlTableInfo tableInfo:tableInfos ){appendMysqlTable2Word( xwpfDocument,tableInfo );}xwpfDocument.write( outputStream );}catch ( Exception e ){e.printStackTrace();}finally {if( xwpfDocument != null ){try {xwpfDocument.close();}catch ( Exception e ){e.printStackTrace();}}}}private static void appendMysqlTable2Word(XWPFDocument xwpfDocument, MySqlTableInfo tableInfo) {xwpfDocument.createParagraph().createRun().setText( "" );xwpfDocument.createParagraph().createRun().setText( "" );xwpfDocument.createParagraph().createRun().setText( "" );XWPFRun run = xwpfDocument.createParagraph().createRun();run.setFontSize( 12 );run.setText( tableInfo.getTableName() );List<String> titles = tableInfo.getTitles();List<MySqlTableFieldInfo> fieldInfos = tableInfo.getFieldInfos();int colCount = titles.size();int rowCount = 1 + tableInfo.getFieldInfos().size();XWPFTable table = xwpfDocument.createTable(rowCount,colCount );table.setWidth(10000);// table.setTableAlignment( TableRowAlign.CENTER );XWPFTableRow row_title = table.getRow(0);// 设置标题行for( int colIndex = 0;colIndex<colCount;colIndex++ ){XWPFTableCell cell = row_title.getCell(colIndex);cell.setWidthType( TableWidthType.PCT );cell.setWidth( "12.5%" );String title = titles.get(colIndex);setTextForCell( cell,title );cell.setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER);}for( int rowIndex=1;rowIndex<rowCount;rowIndex++ ){XWPFTableRow row = table.getRow(rowIndex);row.setHeight( 500 );MySqlTableFieldInfo fieldInfo = fieldInfos.get(rowIndex - 1);XWPFTableCell cell0 = row.getCell(0);XWPFTableCell cell1 = row.getCell(1);XWPFTableCell cell2 = row.getCell(2);XWPFTableCell cell3 = row.getCell(3);XWPFTableCell cell4 = row.getCell(4);XWPFTableCell cell5 = row.getCell(5);XWPFTableCell cell6 = row.getCell(6);XWPFTableCell cell7 = row.getCell(7);cell0.setWidthType( TableWidthType.PCT );cell1.setWidthType( TableWidthType.PCT );cell2.setWidthType( TableWidthType.PCT );cell3.setWidthType( TableWidthType.PCT );cell4.setWidthType( TableWidthType.PCT );cell5.setWidthType( TableWidthType.PCT );cell6.setWidthType( TableWidthType.PCT );cell7.setWidthType( TableWidthType.PCT );/* cell0.setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER);cell1.setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER);cell2.setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER);cell3.setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER);cell4.setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER);cell5.setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER);cell6.setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER);cell7.setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER);*/cell0.setWidth( "12.5%" );cell1.setWidth( "12.5%" );cell2.setWidth( "12.5%" );cell3.setWidth( "12.5%" );cell4.setWidth( "12.5%" );cell5.setWidth( "12.5%" );cell6.setWidth( "12.5%" );cell7.setWidth( "12.5%" );setTextForCell( cell0,fieldInfo.getName() );setTextForCell( cell1,fieldInfo.getType() );String length = fieldInfo.getLength();if( length == null ){setTextForCell( cell2,"" );}else {setTextForCell( cell2,String.valueOf( fieldInfo.getLength() ) );}if( fieldInfo.isNullable() ){setTextForCell( cell3,"YES" );}else {setTextForCell( cell3,"NO" );}setTextForCell( cell4,fieldInfo.getComment() );if( fieldInfo.isPrimaryKey() ){setTextForCell( cell5,"主键" );}setTextForCell( cell6,fieldInfo.getDefaultValue() );setTextForCell( cell7,fieldInfo.getIndexType() );}}private static void setTextForCell(XWPFTableCell cell,String text) {// cell.setText( text );CTTc ctTc = cell.getCTTc();CTP ctP = (ctTc.sizeOfPArray() == 0) ?ctTc.addNewP() : ctTc.getPArray(0);XWPFParagraph paragraph = cell.getParagraph(ctP);XWPFRun run = paragraph.createRun();paragraph.setAlignment( ParagraphAlignment.CENTER );paragraph.setVerticalAlignment( TextAlignment.CENTER );// 即小四run.setFontSize( 12 );run.setText( text );}
}