1. Antecedentes
Apache POI es una API Java que crea y mantiene varias API de Java que cumplen con el estándar de Office Open XML (OOXML) y el formato de documento compuesto OLE 2 de Microsoft (OLE2). Se puede usar para leer y crear y modificar los archivos de MS Excel usando Java. Además, también puede usar Java para leer y crear archivos MS Word y MSpowerPoint. Apache POI proporciona una solución de Operación Java Excel (para Excel97-2008).
Genere el archivo de Excel correspondiente basado en el archivo JSON en el formato especificado. Los requisitos son los siguientes
2. Vista previa del efecto
3. Formato de datos
Dado que es generar archivos de Excel, el valor aquí considera generar un archivo de Excel en formato XLSX. Se considera que el encabezado de la mesa de datos de datos se usa | Por defecto, y Colspan RowsPan no se usa como. Si necesita representar dos columnas y dos filas, el formato de encabezado de combinación de la primera columna es: A | B, A | C Tabla generada es
| A | |
| B | do |
El front-end construye los datos que se generarán como un archivo JSON que cumple con los requisitos y envía y antecedentes a través de la publicación. Defina el formato JSON de acuerdo con los requisitos anteriores de la siguiente manera
{"Savename": "Genere el nombre del archivo Excel.xlsx", "UserStyles": [{"id": "1", // sin duplicación, donde necesita establecer el estilo de celda, puede asignar directamente el estilo a este valor "estilo": {"font": {// establece el formato básico de la fuente "blod": true, // lo está en negrita "italic": verdadero, verdadero, //// "#Ff0000", // font color "nombre": "Microsoft Elegant Black", // Nombre de la fuente "altura": 20 // size}, "fmtstr": "", // format de celda,#, ## 0.00 _);#, ## 0.00; 0 Millimeters "Allign": "", // Horizontal alineación a la izquierda derecha "Valign": "Valign", ",", ",", "," Valign, "Valign", "Valign", "Valign", ",", ",", "Valign", "Valign", "Valign", "," Valign ",", ". Center Bottom "BorderColor": "", // Establezca el color del borde como #FF0000 "BGColor": "" // establece el color de relleno de celda}}], "hojas": [{"hoja": "", // name de hoja "título": [], // COMPACTO Data de área de titular de la hoja "TitleMerger": [], // Compacto de la lámina Merge Merge Información "Información" Información "INFORMA" {{{}, [}, / / / / / / / / / / / /TIPE "TIBLEMERGE": [], // Compac. Información del encabezado "Datos": [], // Información de datos "DataMerge": [], // Información de fusión de datos "Foot": [], // Información final de tabla "Footmerge": [], // Tabla End de información de fusión "IMG": [] // Información de imagen, debe convertir la imagen en base64}]}Descripción breve
El formato del objeto JSON en la matriz de cabecera es
{"Nombre": "A | B", // Nombre del encabezado de la tabla, uso del encabezado de la tabla múltiple | Para dividir "tipo": "str", // Este tipo de datos de columna STR NUM, la fecha también es un tipo numérico en Excel, y se muestra como formato de fecha "campo": "f_field1", // campos alternativos, no puede usar "estilo": {// Datos de columna es el estilo de columna predeterminado, puede ser un objeto de estilo o el valor de ID definido en Userstyles "Align": "} Centre"}}}}}}}}}}}}}}}}}}}}}}}} Centre "}}}}}}}}}}}}}}}}}}}}}}" centro "}}}} centro"}}}}}}}}} centro En el pie de datos del título de la matriz, los datos en la lista pueden ser un valor separado como 1, "a" o un objeto, cuando es un objeto, el formato es
{"valor": "", // El valor específico del cell "tipo": "", // El tipo de celda, el str "estilo" predeterminado: {} // El estilo de la celda puede ser un objeto de estilo o el valor de ID definido en UserStyles. Si no está configurado, el cabezal es el estilo correspondiente de esta columna de forma predeterminada} Los valores de las matrices de TitLemerge, DataMerge y Fulmerge son cadenas separadas por comas, lo que significa "Fila de inicio, fila final, columna de inicio, columna final", y el índice comienza desde 0. Si hay dos filas y tres columnas de datos en el título, ahora debe fusionar los valores correspondientes de una fila y dos columnas de datos que son "0, 0, 0, 1" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" ".
El valor en la matriz IMG es un objeto, formato
{"col": 1, // La columna de inicio de la imagen "fila": 0, // La fila de inicio "colspan": 1, // el tramo de columna, el valor mínimo es 1 "skowspan": 2, // el span de fila, el valor mínimo es 1 "datos": "" // datos de la imagen base64 como: "datos: imagen/png; base64, ib ... ggg =="}}}}} 4. Implementación clave
Los archivos de Excel después de 07 son en realidad un paquete comprimido, con cada hoja un archivo XML, cada hoja es un archivo XML, el estilo es un archivo XML, la imagen es el archivo de imagen correspondiente, y se coloca en la carpeta de medios, por lo que la idea del código es
El portal de funciones es el siguiente
@OverridePublic void buildOutputPutStream () lanza FileProDucerException {// Procese hojas de datos JSON entrantes = this.jsondata.getjsonArray (this.sheets); iterator <S Object> Sheetiter = sheet.iterator (); if (sheets.isEmpty ()) {this.ResponseData.setErrCode (1001); this.responseData.setSuccess (false); this.ResponseData.setErrmsg ("no se pueden generar datos"); tire nuevo fileProDucerException ();} wb = new XSSFWorkBook (); // Creación global de format jsonarray userstyles = = this.jsondata.getjsonArray (this.UserStyles); this.inituserstyles (Userstyles); this.initdefaultheadStyle (); Xssfsheet ws; Hoja JSONObject; JSONArray SheetData; JSONArray Sheettitle; JSONArray Sheethead; Jonerray Sheetfoot; JSONArray Sheetimgs; String sheetName; int sheadinx = 0; while (sheaditer.hasnext ()) {sheet = (jsonObject) sheaditer.next (); // Obtener la hoja de nombre de la hoja = sheet.getString (this.sheet_name); ws = wb.createSheet (); if (stringUtils.isnotblank (sheetname)) {wb.setsheet (sheetet (sheetet, if, if (sheeteN SheetName);} int sheetrowindex = 0; sheettitle = sheet.getjsonArray (this.sheet_title); this.SetMerGeCells (WS, Sheet.getJsonArray (this.sheet_title_merge), SheetrowIndex); SheetrowIndex = this.Createrandom (WS, Sheettitle, Sheetrowindex); sheethead = sheet.getJsonArray (this.sheet_head); SheetrowIndex = this.createheadcolumn (ws, sheethead, sheetrowindex); this.setMerGeCells (ws, sheet.getjsonArray (this.sheet_data_merge), sheetrowindex); sheetData = sheet.getjsonArray (this.sheet_data); sheetrowindex = this.createedata (ws, sheetData, sheetrowindex); sheetfoot = sheet.getJsonArray (this.sheet_foot); this.setMerGeCells (WS, Sheet.getJsonArray (this.sheet_foot_merge), SheetrowIndex); SheetrowIndex = this.Createrandom (WS, Sheetfoot, Sheetrowindex); sheetimgs = sheet.getJsonArray (this.sheet_img); this.setSheetImages (ws, sheetImgs);} // return de salida stream try {bytearRayOutputStream OS = new ByTearRayOutputStream (); wb.write (OS); this.outstreams.add (OS);} Catch (ioException e) {tirar nueva FileProDuceException (E.GetMessage (), E.GetCause ());}}Generar objetos de estilo celular, incluida la alineación de fondo del borde de fuentes
privado xssfcellstyle createCellStyle (JsonObject Style) {XSSFCellStyle CellStyle = wb.createCellStyle (); // set jsonObject font = style.getjsonObject (this.style_font); font Excelfont = this.CreateFont (font); if (Exfall! = null) {CellStyle.SetFont (ExcelFont);} // Border Unification Black CellStyle.SetBorderBottom (BorderStyle.Thin); CellStyle.SetBordertop (Borderstyle.Thin); CellStyle.SetBorderLeft (BorderStyle.Thin); CellStyle.Style.Style.Style (Borderstyle.thin); CellStyle.SetBorderRight (BorderStyle.Thin); String borderColor = style.getString (this.border_color); if (stringUtils.isnotblank (borderColor)) {xssfcolor xfborderColor = new xssfcolor (new Color (Integer.Parseint (borderColor.substring (1), 16))); XfBordERColor); CellStyle.SetBorderColor (Borderside.top, XfBorDerColor); CellStyle.SetBorderColor (Borderside.left, XFBORDERDERColor); CellStyle.SetBordorColor (BorderSide.Right, XfborDercolor);} // Color de fondo de fondo Bgcolor = = = = = = = = style.getString (this.background_color); if (stringUtils.isnotblank (bgcolor)) {xssfcolor cellbgcolor = new xssfcolor (nuevo color (integer.parseInt (bgcolor.substring (1),, 16))); CellStyle.SetFillForeGroundColor (CellBgColor); CellStyle.SetFillPattern (FillPatternType.Solid_Foreground);} // Alineación cadena Halignment = style.getString (this.halignment); If (StringUtils.isnotblank (halignment)) CellStyle.setAlignment (horizontalignment.valueOf (halignment.toupperCase ())); string valignment = style.getString (this.valignment); If (StringUtils.Isnotblank (Valignment)) CellStyle.SetVerticalAlignment (verticalAlignment.ValueOf (Valignment.ToUpperperCase ())); // Línea automática envolvente TrueCellStyle.SetWraptext (verdadero); // Formato de cadena fmt = style.getString (this.fmtString); if (stringUtils.isnotblank (fmt)) cellStyle.setDataFormat (wb.createDataFormat (). getFormat (fmt)); return cellStyle;}Crear estilos de fuentes
privado font createFont (jsonObject fontcfg) {if (fontcfg == null) return null; xssffont font = wb.createFont (); font.setFontName (fontcfg.getString (this.font_name; null) font.setBold (fontboole.booleanValue ()); fontboole = fontcfg.getBoolean (this.font_italic); if (fontboole! = null) font.setitalic (fontboole.booleanValue (); fontboole = fontcfg.getBoolean && fontboole.booleanValue () == true) font.setunderline (fontunderline.single.getByTevalue ()); fontheight = fontcfg.getShort (this.font_height); if (fontheight! = null) font.setfontheightinpoints (fontheight); string colortr = fontcfg.getString (this.font_color); if (colortr! = null) {font.setColor (new xssfcolor (new Color (integer.parseint (colortr.substring (1), 16)));} return font;}Para procesar los encabezados de la tabla, se procesan demasiados encabezados de mesa y se | Se utiliza el método de segmentación. La longitud de la cabeza son datos de columna. Hay varios | En el nombre, y sabrás cuántas filas hay en el encabezado. Por lo tanto, hay varios pasos para el procesamiento de encabezados
private int createHeadColumn (xssfsheet ws, jsonArray sheethead, int sheetrowIndex) {if (sheethead == null) return sheetRowindex; iterator <pectus> headIterator = sheethead.iterator (); jsonObject Curhead = null; int colindex = 0; objeto colsstyle = int colsize = sheethead.ssize () ();) String [colsize]; HeadCellStyleKeys = new String [colsize]; int [] headCollevel = new int [colsize]; string colname = null; string [] colnameary = null; int maxlevel = 0; int collevel = 0; xssfccell Headcell = null; arraylist <grayList <string>> headvaluelist = newvalist = newvalist = new; ArrayList <ArrayList <String> (); while (HeadIter.hasNext ()) {Curhead = (jsonObject) HeadIter.Next (); // Handle el estilo predeterminado if (curead.containskey (this.column_style)) {colstyle = curead.get (this.column_style); if (colstyle instancia de jSonObject)) {HeadCellStyleKeys [colindex] = this.columnstyle_prev+ colindex; this.Userstyles.put (HeadCellStyleKeys [colindex], this.createCellStyle ((jsonObject) colstyle));} else if (this.userstyles.containskey (colsstyle)) {HeadcellStyleKeys [colindex] = (string) colstyle;} // manejar el ancho de la columna predeterminada if si (Curhead.ContainsKey (this.column_width)) {ws.setDefaultColumnWidth (PICIMTOEXCELWDITH (Curhead.getIntValue (this.column_width)));} // Guardar el estilo de columna if (Curhead.ContainSkey (this.column_type)) {Headtypes [colinDex] = = = = = = = Curhead.getString (this.column_type);} else {headTypes [colindex] = this.CellTyPestring;} // manejar el encabezado multi-table colname = curead.getString (this.column_name); colnameary = colnAns.split ("// |"); collevel = colnameLElvel; headcoleLELED Collevel; if (Collevel> MaxLevel) {maxLevel = Collevel;} for (int i = 0; i <collevel; i ++) {if (headValuelist.size () <= i) {headValuelist.add (new ArrayList <String> ());} Headvaluelist.get (i) .add (CILINDEX, COLINDEX, COLNAMEARY [IFRIMY]; ws.getrow (Sheetrowindex + I); if (if (row == null) {row = ws.creatrow (sheetrowindex+i);} hEADCELLEL = ROW.CreateCell (colindex); HeadCell.setCellValue (colnamEary [i]); HeadCell.setCellStyle (this.Usstyles.get (this.headstyle_key));} corindex ++;} /} // horizontalgealgealgealgealLonTalalTalalTalalTalalTalalTalaltalalTalalTalalTalalTalalTalaltalalTalaltalalTalaltalalTalaltalaltalalTalaltalaltalaltalaltalaltalaltalaltalaltals. / / / / / / / / / / HorizeTalles. Iterator <ArrayList <String>> a = HeadValuelist.Iterator (); jSonArray Headmerge = new JSonArray (); String prev = ""; String current = null; int lrowindex = 0; int intoTcol = 0; int permeCol = 0; ArrayList <String> columnInfo = null; while (a.hasnext ()) 0; prev = ""; columnInfo = a.next (); // Solo en la tercera columna podemos saber si se fusionan la primera y segunda columnas. columnInfo.add (""); iterator <String> b = columnInfo.iterator (); xssfcell lastrawcell = null; while (b.hasnext ()) {current = b.next (); if (lrowindex> 0) {lastrawcell = ws.getrow (sheetrowindex + lrowindex - 1). (Prev.equalSignRoCase (actual) && lrowindex == 0) {ws.getrow (sheetrowIndex+lrowindex) .getCell (startCol) .setCellType (cell.cell_type_blank); mergecol ++;} de lo contrario If (preval .equalSignRoCase (actual) && lrowinDex> 0 &&&&&&&& StringUtils.isblank (lastrawcell.getStringCellValue ())) {ws.getrow (sheetrowindex+lrowindex) .getCell (startCol) .setCellType (celular.cell_type_blank); Mergecol ++;} else {if (mercecol> 0 && startcol> 0) {headmerge.add (string.format ("%d,%d,%d,%d", lrowindex, lrowindex, startCol - Mergecol - 1, startCol - 1)); MergEcol = 0;}} startCol ++; prev = actual;} LOROWINDEX ++;} para (int i = 0; i <colssize; i ++) (HeadCollevel [i] <maxlevel) {// columna fusion existe headmerge.add (string.format ("%d,%d,%d,%d", headcollevel [i] - 1, maxlevel - 1, i, i, i)); para (int r = headcollevel [i]; r <maxlevel; r ++) {ws.getrow (sheetrewrow (sheetrewrow+ r) .createCell (i) .setCellStyle (this.Userstyles.get (this.headstyle_key));}}} this.setMerGeCells (ws, headmerge, sheetrowindex); return sheetrowindex + maxlevel;}Agregue imágenes, los puntos de celda se usan de forma predeterminada y la imagen se fija dentro del área de la celda especificada.
Private void addimg (xssfsheet ws, jsonObject img, xssfcreationHelper chelper) {string imgbase64 = img.getString (this.sheet_img_data); if (stringUtils.isblank (imgbase64)) return; string [] imgary = = imgbase64.split (","); system.out.println (imgary [0]); byte [] imgbyte = base64.DecodeBase64 (imgary [1]); int imgidx = wb.addpicture (imgbyte, workbook.picture_type_jpeg); xssfdrawing dibujante ws.CreateDrawingPatriarCh (); xssfclientArCor fastor = chelper.createClientArChor (); int col = img.getIntValue (this.Sheet_img_Col); int fila = img.getIntvalue (this.Sheet_img_row); Anchor.setCol1 (col); Anchor.setRow1 (Row); = drawimg.createPicture (Anchor, imgidx); integer colspan = img.getInteger (this.sheet_img_colspan); if (colspan == null) colsspan = 1; Integer RowsPan = img.getinGeger (this.sheet_img_rowspan); if (rowspan == null) rawspan = 1; Pict.resize (Colspan, Rowspan);} 5. Resumen
Esta vez, generé un archivo de Excel de estilo rico pasando por objetos JSON, y estoy más familiarizado con los documentos de Operación de Operación POI. En comparación con el análisis de los documentos de Excel, el formato de archivo no es necesario para ser considerado al generar, como: compatible con el formato 2003 y se considera el análisis de saxo de archivos grande. En comparación con la generación front-end JS de archivos Excel, se incrementa la posibilidad de procesamiento secundario de los archivos generados, por lo que en la entrada funcional, se adopta el método de generación de flujos binarios. Después de generar el archivo, puede continuar enviando correos electrónicos, cargar FTP y otras operaciones.
Notas clave
De acuerdo, lo anterior es todo el contenido de este artículo. Espero que el contenido de este artículo tenga cierto valor de referencia para el estudio o el trabajo de todos. Si tiene alguna pregunta, puede dejar un mensaje para comunicarse. Gracias por su apoyo a Wulin.com.