!2 解决自定义字体产生临时文件消耗硬盘的问题,以及解决总分操作系统下无法读到字体文件的问题
Merge pull request !2 from hellozrh/master
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -22,4 +22,5 @@
|
||||
/nbbuild/
|
||||
/dist/
|
||||
/nbdist/
|
||||
/.nb-gradle/
|
||||
/.nb-gradle/
|
||||
/classes/
|
||||
2
.idea/compiler.xml
generated
2
.idea/compiler.xml
generated
@@ -10,7 +10,7 @@
|
||||
</profile>
|
||||
</annotationProcessing>
|
||||
<bytecodeTargetLevel>
|
||||
<module name="EasyCaptcha" target="6" />
|
||||
<module name="EasyCaptcha" target="8" />
|
||||
</bytecodeTargetLevel>
|
||||
</component>
|
||||
</project>
|
||||
13
.idea/libraries/Maven__junit_junit_4_7.xml
generated
13
.idea/libraries/Maven__junit_junit_4_7.xml
generated
@@ -1,13 +0,0 @@
|
||||
<component name="libraryTable">
|
||||
<library name="Maven: junit:junit:4.7">
|
||||
<CLASSES>
|
||||
<root url="jar://$USER_HOME$/.m2/repository/junit/junit/4.7/junit-4.7.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC>
|
||||
<root url="jar://$USER_HOME$/.m2/repository/junit/junit/4.7/junit-4.7-javadoc.jar!/" />
|
||||
</JAVADOC>
|
||||
<SOURCES>
|
||||
<root url="jar://$USER_HOME$/.m2/repository/junit/junit/4.7/junit-4.7-sources.jar!/" />
|
||||
</SOURCES>
|
||||
</library>
|
||||
</component>
|
||||
@@ -1,16 +1,34 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_6">
|
||||
<component name="FacetManager">
|
||||
<facet type="web" name="Web">
|
||||
<configuration>
|
||||
<descriptors>
|
||||
<deploymentDescriptor name="web.xml" url="file://$MODULE_DIR$/web/WEB-INF/web.xml" />
|
||||
</descriptors>
|
||||
<webroots>
|
||||
<root url="file://$MODULE_DIR$/web" relative="/" />
|
||||
</webroots>
|
||||
<sourceRoots>
|
||||
<root url="file://$MODULE_DIR$/src/main/java" />
|
||||
<root url="file://$MODULE_DIR$/src/main/resources" />
|
||||
</sourceRoots>
|
||||
</configuration>
|
||||
</facet>
|
||||
</component>
|
||||
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8">
|
||||
<output url="file://$MODULE_DIR$/target/classes" />
|
||||
<output-test url="file://$MODULE_DIR$/target/test-classes" />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/target" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" scope="PROVIDED" name="Maven: javax.servlet:javax.servlet-api:3.1.0" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: junit:junit:4.7" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: junit:junit:4.12" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: org.hamcrest:hamcrest-core:1.3" level="project" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -1,12 +1,11 @@
|
||||
package com.wf.captcha.base;
|
||||
|
||||
import com.wf.captcha.utils.FontsUtil;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.geom.CubicCurve2D;
|
||||
import java.awt.geom.QuadCurve2D;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.*;
|
||||
import java.util.Base64;
|
||||
|
||||
/**
|
||||
@@ -275,7 +274,7 @@ public abstract class Captcha extends Randoms {
|
||||
}
|
||||
|
||||
public void setFont(int font, int style, float size) throws IOException, FontFormatException {
|
||||
this.font = Font.createFont(Font.TRUETYPE_FONT, new File(getClass().getResource("/" + FONT_NAMES[font]).getFile())).deriveFont(style, size);
|
||||
this.font = FontsUtil.getFont(FONT_NAMES[font], style, size);
|
||||
}
|
||||
|
||||
public int getLen() {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.wf.captcha.servlet;
|
||||
|
||||
import java.awt.*;
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
@@ -7,6 +8,9 @@ import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import com.wf.captcha.GifCaptcha;
|
||||
import com.wf.captcha.SpecCaptcha;
|
||||
import com.wf.captcha.base.Captcha;
|
||||
import com.wf.captcha.utils.CaptchaUtil;
|
||||
|
||||
/**
|
||||
@@ -18,7 +22,16 @@ public class CaptchaServlet extends HttpServlet {
|
||||
|
||||
public void doGet(HttpServletRequest request, HttpServletResponse response)
|
||||
throws ServletException, IOException {
|
||||
CaptchaUtil.out(request, response);
|
||||
// SpecCaptcha captcha = new SpecCaptcha(130, 48, 6);
|
||||
GifCaptcha captcha = new GifCaptcha(130, 48, 6);
|
||||
|
||||
// 设置内置字体
|
||||
try {
|
||||
captcha.setFont(Captcha.FONT_10);
|
||||
} catch (FontFormatException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
CaptchaUtil.out(captcha, request, response);
|
||||
}
|
||||
|
||||
public void doPost(HttpServletRequest request, HttpServletResponse response)
|
||||
|
||||
107
src/main/java/com/wf/captcha/utils/FileUtil.java
Normal file
107
src/main/java/com/wf/captcha/utils/FileUtil.java
Normal file
@@ -0,0 +1,107 @@
|
||||
package com.wf.captcha.utils;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 文件操作工具类,此类源码从org.apache.commons.io.FileUtils中复制
|
||||
*
|
||||
* @author zrh 455741807@qq.com
|
||||
* @date 2022-05-07
|
||||
*/
|
||||
public class FileUtil {
|
||||
public static final int DEFAULT_BUFFER_SIZE = 8192;
|
||||
public static final int EOF = -1;
|
||||
|
||||
/**
|
||||
* 文件流复制
|
||||
* @param inputStream
|
||||
* @param file
|
||||
* @throws IOException
|
||||
*/
|
||||
public static void copyToFile(final InputStream inputStream, final File file) throws IOException {
|
||||
try (OutputStream out = openOutputStream(file)) {
|
||||
copy(inputStream, out);
|
||||
}
|
||||
}
|
||||
|
||||
public static FileOutputStream openOutputStream(final File file) throws IOException {
|
||||
return openOutputStream(file, false);
|
||||
}
|
||||
|
||||
public static FileOutputStream openOutputStream(final File file, final boolean append) throws IOException {
|
||||
Objects.requireNonNull(file, "file");
|
||||
if (file.exists()) {
|
||||
requireFile(file, "file");
|
||||
requireCanWrite(file, "file");
|
||||
} else {
|
||||
createParentDirectories(file);
|
||||
}
|
||||
return new FileOutputStream(file, append);
|
||||
}
|
||||
|
||||
private static File requireFile(final File file, final String name) {
|
||||
Objects.requireNonNull(file, name);
|
||||
if (!file.isFile()) {
|
||||
throw new IllegalArgumentException("Parameter '" + name + "' is not a file: " + file);
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
private static void requireCanWrite(final File file, final String name) {
|
||||
Objects.requireNonNull(file, "file");
|
||||
if (!file.canWrite()) {
|
||||
throw new IllegalArgumentException("File parameter '" + name + " is not writable: '" + file + "'");
|
||||
}
|
||||
}
|
||||
|
||||
public static File createParentDirectories(final File file) throws IOException {
|
||||
return mkdirs(getParentFile(file));
|
||||
}
|
||||
|
||||
private static File mkdirs(final File directory) throws IOException {
|
||||
if ((directory != null) && (!directory.mkdirs() && !directory.isDirectory())) {
|
||||
throw new IOException("Cannot create directory '" + directory + "'.");
|
||||
}
|
||||
return directory;
|
||||
}
|
||||
|
||||
private static File getParentFile(final File file) {
|
||||
return file == null ? null : file.getParentFile();
|
||||
}
|
||||
|
||||
public static int copy(final InputStream inputStream, final OutputStream outputStream) throws IOException {
|
||||
final long count = copyLarge(inputStream, outputStream);
|
||||
if (count > Integer.MAX_VALUE) {
|
||||
return EOF;
|
||||
}
|
||||
return (int) count;
|
||||
}
|
||||
|
||||
public static long copyLarge(final InputStream inputStream, final OutputStream outputStream)
|
||||
throws IOException {
|
||||
return copy(inputStream, outputStream, DEFAULT_BUFFER_SIZE);
|
||||
}
|
||||
|
||||
public static long copy(final InputStream inputStream, final OutputStream outputStream, final int bufferSize)
|
||||
throws IOException {
|
||||
return copyLarge(inputStream, outputStream, byteArray(bufferSize));
|
||||
}
|
||||
|
||||
public static long copyLarge(final InputStream inputStream, final OutputStream outputStream, final byte[] buffer)
|
||||
throws IOException {
|
||||
Objects.requireNonNull(inputStream, "inputStream");
|
||||
Objects.requireNonNull(outputStream, "outputStream");
|
||||
long count = 0;
|
||||
int n;
|
||||
while (EOF != (n = inputStream.read(buffer))) {
|
||||
outputStream.write(buffer, 0, n);
|
||||
count += n;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
public static byte[] byteArray(final int size) {
|
||||
return new byte[size];
|
||||
}
|
||||
}
|
||||
75
src/main/java/com/wf/captcha/utils/FontsUtil.java
Normal file
75
src/main/java/com/wf/captcha/utils/FontsUtil.java
Normal file
@@ -0,0 +1,75 @@
|
||||
package com.wf.captcha.utils;
|
||||
|
||||
import sun.security.action.GetPropertyAction;
|
||||
|
||||
import java.awt.*;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
import static java.security.AccessController.doPrivileged;
|
||||
|
||||
/**
|
||||
* 解决自定义字体读取时,产生.tmp临时文件耗磁盘的问题。
|
||||
*
|
||||
* 解决思路:
|
||||
* Font类的createFont有个重载方法–>java.awt.Font#createFont(int, java.io.File),
|
||||
* 不产生临时文件获取字体代码实现
|
||||
* <code>
|
||||
* URL url = FontLoader.class.getResource("font/SourceHanSansCN-Regular.otf");
|
||||
* String pathString = url.getFile();
|
||||
* Font selfFont = Font.createFont(Font.TRUETYPE_FONT, new File(pathString));
|
||||
* </code>
|
||||
* 上面的解决方案会导致另一个问题,字体文件在生产环境是在jar包里,部分操作系统环境下,直接读取读取不到,只能通过流的方式获取。
|
||||
*
|
||||
* 因此,本方案采用的办法是把jar包中的字体文件复制到java.io.tmpdir临时文件夹中
|
||||
* ,再采用<code>java.awt.Font#createFont(int, java.io.File)</code>的方式产生字体,既解决了临时文件tmp消耗磁盘的问题,也解决了
|
||||
* 部分操作系统下读不到文件的问题。
|
||||
*
|
||||
* @author zrh 455741807@qq.com
|
||||
* @date 2022-05-07
|
||||
*
|
||||
*/
|
||||
public class FontsUtil {
|
||||
private static final Path tmpdir = Paths.get(doPrivileged(new GetPropertyAction("java.io.tmpdir")));
|
||||
|
||||
/**
|
||||
* 手动复制字体文件到临时目录. 调用传文件的构造方法创建字体
|
||||
* @param fontName 字体文件名称
|
||||
* @return
|
||||
*/
|
||||
public static Font getFont(String fontName, int style, float size) {
|
||||
Font font = null;
|
||||
|
||||
File tempFontFile = new File(tmpdir.toUri().getPath() + fontName);
|
||||
if(!tempFontFile.exists()){
|
||||
//临时文件不存在
|
||||
copyTempFontFile(fontName, tempFontFile);
|
||||
}
|
||||
if(tempFontFile.exists()) {
|
||||
try {
|
||||
font = Font.createFont(Font.TRUETYPE_FONT, tempFontFile).deriveFont(style, size);;
|
||||
} catch (FontFormatException | IOException e) {
|
||||
e.printStackTrace();
|
||||
tempFontFile.delete();
|
||||
}
|
||||
}
|
||||
return font;
|
||||
}
|
||||
|
||||
/**
|
||||
* 复制字体文件到临时文件目录
|
||||
* @param fontName
|
||||
* @param tempFontFile
|
||||
*/
|
||||
private static synchronized void copyTempFontFile(String fontName, File tempFontFile){
|
||||
try(InputStream is = FontsUtil.class.getResourceAsStream("/" + fontName)){
|
||||
FileUtil.copyToFile(is, tempFontFile);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
15
web/WEB-INF/web.xml
Normal file
15
web/WEB-INF/web.xml
Normal file
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
|
||||
version="4.0">
|
||||
<!-- 图形验证码servlet -->
|
||||
<servlet>
|
||||
<servlet-name>CaptchaServlet</servlet-name>
|
||||
<servlet-class>com.wf.captcha.servlet.CaptchaServlet</servlet-class>
|
||||
</servlet>
|
||||
<servlet-mapping>
|
||||
<servlet-name>CaptchaServlet</servlet-name>
|
||||
<url-pattern>/captcha</url-pattern>
|
||||
</servlet-mapping>
|
||||
</web-app>
|
||||
10
web/index.html
Normal file
10
web/index.html
Normal file
@@ -0,0 +1,10 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>验证码测试</title>
|
||||
</head>
|
||||
<body>
|
||||
<img src="/captcha" width="130px" height="48px" />
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user