使用easyexcel,在服务器上报 java.lang.ArrayIndexOutOfBoundsException: 0
java.lang.ArrayIndexOutOfBoundsException: 0
at sun.font.CompositeFont.getSlotFont(CompositeFont.java:351)
at sun.font.CompositeGlyphMapper.initMapper(CompositeGlyphMapper.java:81)
at sun.font.CompositeGlyphMapper.<init>(CompositeGlyphMapper.java:62)
at sun.font.CompositeFont.getMapper(CompositeFont.java:409)
at sun.font.CompositeFont.canDisplay(CompositeFont.java:435)
at java.awt.Font.canDisplayUpTo(Font.java:2063)
at java.awt.font.TextLayout.singleFont(TextLayout.java:470)
at java.awt.font.TextLayout.<init>(TextLayout.java:531)
at org.apache.poi.ss.util.SheetUtil.getDefaultCharWidth(SheetUtil.java:275)
at org.apache.poi.xssf.streaming.AutoSizeColumnTracker.<init>(AutoSizeColumnTracker.java:117)
at org.apache.poi.xssf.streaming.SXSSFSheet.<init>(SXSSFSheet.java:82)
at org.apache.poi.xssf.streaming.SXSSFWorkbook.createAndRegisterSXSSFSheet(SXSSFWorkbook.java:658)
at org.apache.poi.xssf.streaming.SXSSFWorkbook.createSheet(SXSSFWorkbook.java:679)
at org.apache.poi.xssf.streaming.SXSSFWorkbook.createSheet(SXSSFWorkbook.java:90)
at com.alibaba.excel.util.WorkBookUtil.createSheet(WorkBookUtil.java:66)
在本地测试Excel的导出是正常的,但是上传了服务器,通过Postman 测试发现了返回500
,服务器报错
经过 远程链接服务器的Java程序 Debug 到 报错列表中的 :at sun.font.CompositeFont.getSlotFont(CompositeFont.java:351)
位置
,
根据Debug的提示判断是由 deferredInitialisation[slot]
引起的报错,Debug显示 deferredInitialisation 长度为 0
、slot指为0
deferredInitialisation
这个数组的由来:菜鸡的我 进过了一天的Debug 和 踩坑 终于是Debug到了,下面说重要的地方~~
getFont2D
private Font2D getFont2D() {
// 用于检索当前平台的有效 FontManager 实例的工厂类。为 Linux、Solaris 和 Windows 提供了默认实现。
FontManager fm = FontManagerFactory.getInstance(); // 从此处进入
if (fm.usingPerAppContextComposites() &&
font2DHandle != null &&
font2DHandle.font2D instanceof CompositeFont &&
((CompositeFont)(font2DHandle.font2D)).isStdComposite()) {
return fm.findFont2D(name, style,
FontManager.LOGICAL_FALLBACK);
} else if (font2DHandle == null) {
font2DHandle =
fm.findFont2D(name, style,
FontManager.LOGICAL_FALLBACK).handle;
}
/* Do not cache the de-referenced font2D. It must be explicitly
* de-referenced to pick up a valid font in the event that the
* original one is marked invalid
*/
return font2DHandle.font2D;
}
优先执行静态代码块
)static {
// 根据不同操作系统加载不同的 FontManager
if (FontUtilities.isWindows) {
DEFAULT_CLASS = "sun.awt.Win32FontManager";
} else if (FontUtilities.isMacOSX) {
DEFAULT_CLASS = "sun.font.CFontManager";
} else {
DEFAULT_CLASS = "sun.awt.X11FontManager";
}
}
getInstance()
/**
* Get a valid FontManager implementation for the current platform.
*
* @return a valid FontManager instance for the current platform
*/
public static synchronized FontManager getInstance() {
if (instance != null) {
return instance;
}
AccessController.doPrivileged(new PrivilegedAction<Object>() {
public Object run() {
try {
String fmClassName =
System.getProperty("sun.font.fontmanager",
DEFAULT_CLASS);
ClassLoader cl = ClassLoader.getSystemClassLoader();
// 注册 通过静态代码块得到的 FontManager 看 步骤 4
Class<?> fmClass = Class.forName(fmClassName, true, cl);
// 通过静态代码块得到的 FontManager,反射创建对象
instance =
(FontManager) fmClass.getDeclaredConstructor().newInstance();
} catch (ReflectiveOperationException ex) {
throw new InternalError(ex);
}
return null;
}
});
return instance;
}
由于在远程Debug找到了原因,切远程Debug与本地代码经常对应不上,换至
Windows上进行Debug
,
故步骤 3 创建的FontManager
为Win32FontManager
Win32FontManager
(先执行静态代码块)static {
AccessController.doPrivileged(new PrivilegedAction<Object>() {
public Object run() {
// 获取 EUDC 字体文件
String eudcFile = getEUDCFontFile();
if (eudcFile != null) {
try {
/* Must use Java rasteriser since GDI doesn't
* enumerate (allow direct use) of EUDC fonts.
*/
eudcFont = new TrueTypeFont(eudcFile, null, 0,
true, false);
} catch (FontFormatException e) {
}
}
return null;
}
});
}
SunFontManager()
protected SunFontManager() {
// 这里就是加载系统字体的地方
this.initJREFontMap();
AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
File var1 = new File(SunFontManager.jreFontDirName + File.separator + "badfonts.txt");
String var5;
if (var1.exists()) {
FileInputStream var2 = null;
try {
SunFontManager.this.badFonts = new ArrayList();
var2 = new FileInputStream(var1);
InputStreamReader var3 = new InputStreamReader(var2);
BufferedReader var4 = new BufferedReader(var3);
while(true) {
var5 = var4.readLine();
if (var5 == null) {
break;
}
if (FontUtilities.debugFonts()) {
FontUtilities.getLogger().warning("read bad font: " + var5);
}
SunFontManager.this.badFonts.add(var5);
}
} catch (IOException var8) {
try {
if (var2 != null) {
var2.close();
}
} catch (IOException var7) {
}
}
}
if (FontUtilities.isLinux) {
SunFontManager.this.registerFontDir(SunFontManager.jreFontDirName);
}
SunFontManager.this.registerFontsInDir(SunFontManager.jreFontDirName, true, 2, true, false);
SunFontManager.this.fontConfig = SunFontManager.this.createFontConfiguration();
if (SunFontManager.isOpenJDK()) {
String[] var9 = SunFontManager.this.getDefaultPlatformFont();
SunFontManager.this.defaultFontName = var9[0];
SunFontManager.this.defaultFontFileName = var9[1];
}
String var10 = SunFontManager.this.fontConfig.getExtraFontPath();
boolean var11 = false;
boolean var12 = false;
var5 = System.getProperty("sun.java2d.fontpath");
if (var5 != null) {
if (var5.startsWith("prepend:")) {
var11 = true;
var5 = var5.substring("prepend:".length());
} else if (var5.startsWith("append:")) {
var12 = true;
var5 = var5.substring("append:".length());
}
}
if (FontUtilities.debugFonts()) {
PlatformLogger var6 = FontUtilities.getLogger();
var6.info("JRE font directory: " + SunFontManager.jreFontDirName);
var6.info("Extra font path: " + var10);
var6.info("Debug font path: " + var5);
}
if (var5 != null) {
SunFontManager.this.fontPath = SunFontManager.this.getPlatformFontPath(SunFontManager.noType1Font);
if (var10 != null) {
SunFontManager.this.fontPath = var10 + File.pathSeparator + SunFontManager.this.fontPath;
}
if (var12) {
SunFontManager.this.fontPath = SunFontManager.this.fontPath + File.pathSeparator + var5;
} else if (var11) {
SunFontManager.this.fontPath = var5 + File.pathSeparator + SunFontManager.this.fontPath;
} else {
SunFontManager.this.fontPath = var5;
}
SunFontManager.this.registerFontDirs(SunFontManager.this.fontPath);
} else if (var10 != null) {
SunFontManager.this.registerFontDirs(var10);
}
if (FontUtilities.isSolaris && Locale.JAPAN.equals(Locale.getDefault())) {
SunFontManager.this.registerFontDir("/usr/openwin/lib/locale/ja/X11/fonts/TT");
}
// 初始化 CompositeFont
SunFontManager.this.initCompositeFonts(SunFontManager.this.fontConfig, (ConcurrentHashMap)null);
return null;
}
});
boolean var1 = (Boolean)AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
public Boolean run() {
String var1 = System.getProperty("java2d.font.usePlatformFont");
String var2 = System.getenv("JAVA2D_USEPLATFORMFONT");
return "true".equals(var1) || var2 != null;
}
});
if (var1) {
this.usePlatformFontMetrics = true;
System.out.println("Enabling platform font metrics for win32. This is an unsupported option.");
System.out.println("This yields incorrect composite font metrics as reported by 1.1.x releases.");
System.out.println("It is appropriate only for use by applications which do not use any Java 2");
System.out.println("functionality. This property will be removed in a later release.");
}
}
registerCompositeFont()
protected void registerCompositeFont(String var1, String[] var2, String[] var3, int var4, int[] var5, int[] var6, boolean var7) {
CompositeFont var8 = new CompositeFont(var1, var2, var3, var4, var5, var6, var7, this);
this.addCompositeToFontList(var8, 2);
synchronized(this.compFonts) {
this.compFonts[this.maxCompFont++] = var8;
}
}
CompositeFont()
public CompositeFont(String name, String[] compFileNames,
String[] compNames, int metricsSlotCnt,
int[] exclRanges, int[] maxIndexes,
boolean defer, SunFontManager fm) {
handle = new Font2DHandle(this);
fullName = name;
componentFileNames = compFileNames;
componentNames = compNames;
if (compNames == null) {
numSlots = componentFileNames.length;
} else {
numSlots = componentNames.length;
}
numSlots = (numSlots <= 254) ? numSlots : 254;
numMetricsSlots = metricsSlotCnt;
exclusionRanges = exclRanges;
maxIndices = maxIndexes;
if (fm.getEUDCFont() != null) {
int msCnt = numMetricsSlots;
int fbCnt = numSlots - msCnt;
numSlots++;
if (componentNames != null) {
componentNames = new String[numSlots];
System.arraycopy(compNames, 0, componentNames, 0, msCnt);
componentNames[msCnt] = fm.getEUDCFont().getFontName(null);
System.arraycopy(compNames, msCnt,
componentNames, msCnt+1, fbCnt);
}
if (componentFileNames != null) {
componentFileNames = new String[numSlots];
System.arraycopy(compFileNames, 0,
componentFileNames, 0, msCnt);
System.arraycopy(compFileNames, msCnt,
componentFileNames, msCnt+1, fbCnt);
}
components = new PhysicalFont[numSlots];
components[msCnt] = fm.getEUDCFont();
// 此时已经找到了 那个导致抛出异常数组的赋值
deferredInitialisation = new boolean[numSlots];
if (defer) {
for (int i=0; i<numSlots-1; i++) {
deferredInitialisation[i] = true;
}
}
} else {
components = new PhysicalFont[numSlots];
deferredInitialisation = new boolean[numSlots];
if (defer) {
for (int i=0; i<numSlots; i++) {
deferredInitialisation[i] = true;
}
}
}
fontRank = Font2D.FONT_CONFIG_RANK;
int index = fullName.indexOf('.');
if (index>0) {
familyName = fullName.substring(0, index);
if (index+1 < fullName.length()) {
String styleStr = fullName.substring(index+1);
if ("plain".equals(styleStr)) {
style = Font.PLAIN;
} else if ("bold".equals(styleStr)) {
style = Font.BOLD;
} else if ("italic".equals(styleStr)) {
style = Font.ITALIC;
} else if ("bolditalic".equals(styleStr)) {
style = Font.BOLD | Font.ITALIC;
}
}
} else {
familyName = fullName;
}
}
fc-list :lang=zh
yum -y install fontconfig #安装字体库
yum -y install ttmkfdir mkfontscale #安装字体索引信息
可拷贝Windows的字体目录:C:\Windows\Fonts
/usr/share/fonts
,建议创建一个目录mkdir chinese 放中文字体/usr/share/fonts/chinese
目录/usr/share/fonts/chinese
执行命令,生成字库索引信息mkfontscale
mkfontdir
fc-cache