!2 解决自定义字体产生临时文件消耗硬盘的问题,以及解决总分操作系统下无法读到字体文件的问题
Merge pull request !2 from hellozrh/master
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -22,4 +22,5 @@
|
|||||||
/nbbuild/
|
/nbbuild/
|
||||||
/dist/
|
/dist/
|
||||||
/nbdist/
|
/nbdist/
|
||||||
/.nb-gradle/
|
/.nb-gradle/
|
||||||
|
/classes/
|
||||||
2
.idea/compiler.xml
generated
2
.idea/compiler.xml
generated
@@ -10,7 +10,7 @@
|
|||||||
</profile>
|
</profile>
|
||||||
</annotationProcessing>
|
</annotationProcessing>
|
||||||
<bytecodeTargetLevel>
|
<bytecodeTargetLevel>
|
||||||
<module name="EasyCaptcha" target="6" />
|
<module name="EasyCaptcha" target="8" />
|
||||||
</bytecodeTargetLevel>
|
</bytecodeTargetLevel>
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</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"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4">
|
<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 url="file://$MODULE_DIR$/target/classes" />
|
||||||
<output-test url="file://$MODULE_DIR$/target/test-classes" />
|
<output-test url="file://$MODULE_DIR$/target/test-classes" />
|
||||||
<content url="file://$MODULE_DIR$">
|
<content url="file://$MODULE_DIR$">
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
|
<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/test/java" isTestSource="true" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/target" />
|
<excludeFolder url="file://$MODULE_DIR$/target" />
|
||||||
</content>
|
</content>
|
||||||
<orderEntry type="inheritedJdk" />
|
<orderEntry type="inheritedJdk" />
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
<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="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>
|
</component>
|
||||||
</module>
|
</module>
|
||||||
@@ -1,12 +1,11 @@
|
|||||||
package com.wf.captcha.base;
|
package com.wf.captcha.base;
|
||||||
|
|
||||||
|
import com.wf.captcha.utils.FontsUtil;
|
||||||
|
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.awt.geom.CubicCurve2D;
|
import java.awt.geom.CubicCurve2D;
|
||||||
import java.awt.geom.QuadCurve2D;
|
import java.awt.geom.QuadCurve2D;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.*;
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.util.Base64;
|
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 {
|
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() {
|
public int getLen() {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.wf.captcha.servlet;
|
package com.wf.captcha.servlet;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
import javax.servlet.ServletException;
|
import javax.servlet.ServletException;
|
||||||
@@ -7,6 +8,9 @@ import javax.servlet.http.HttpServlet;
|
|||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
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;
|
import com.wf.captcha.utils.CaptchaUtil;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -18,7 +22,16 @@ public class CaptchaServlet extends HttpServlet {
|
|||||||
|
|
||||||
public void doGet(HttpServletRequest request, HttpServletResponse response)
|
public void doGet(HttpServletRequest request, HttpServletResponse response)
|
||||||
throws ServletException, IOException {
|
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)
|
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