diff --git a/.gitignore b/.gitignore index 82eca33..d99f4ff 100644 --- a/.gitignore +++ b/.gitignore @@ -22,4 +22,5 @@ /nbbuild/ /dist/ /nbdist/ -/.nb-gradle/ \ No newline at end of file +/.nb-gradle/ +/classes/ \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml index 0a3aa2a..968b4f9 100644 --- a/.idea/compiler.xml +++ b/.idea/compiler.xml @@ -10,7 +10,7 @@ - + \ No newline at end of file diff --git a/.idea/libraries/Maven__junit_junit_4_7.xml b/.idea/libraries/Maven__junit_junit_4_7.xml deleted file mode 100644 index 1c50f8b..0000000 --- a/.idea/libraries/Maven__junit_junit_4_7.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/EasyCaptcha.iml b/EasyCaptcha.iml index f1dd1f9..4e0729f 100644 --- a/EasyCaptcha.iml +++ b/EasyCaptcha.iml @@ -1,16 +1,34 @@ - + + + + + + + + + + + + + + + + + + - + + \ No newline at end of file diff --git a/src/main/java/com/wf/captcha/base/Captcha.java b/src/main/java/com/wf/captcha/base/Captcha.java index e9565e3..712c5a4 100644 --- a/src/main/java/com/wf/captcha/base/Captcha.java +++ b/src/main/java/com/wf/captcha/base/Captcha.java @@ -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() { diff --git a/src/main/java/com/wf/captcha/servlet/CaptchaServlet.java b/src/main/java/com/wf/captcha/servlet/CaptchaServlet.java index e273a03..2117759 100644 --- a/src/main/java/com/wf/captcha/servlet/CaptchaServlet.java +++ b/src/main/java/com/wf/captcha/servlet/CaptchaServlet.java @@ -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) diff --git a/src/main/java/com/wf/captcha/utils/FileUtil.java b/src/main/java/com/wf/captcha/utils/FileUtil.java new file mode 100644 index 0000000..41900dc --- /dev/null +++ b/src/main/java/com/wf/captcha/utils/FileUtil.java @@ -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]; + } +} diff --git a/src/main/java/com/wf/captcha/utils/FontsUtil.java b/src/main/java/com/wf/captcha/utils/FontsUtil.java new file mode 100644 index 0000000..29ae619 --- /dev/null +++ b/src/main/java/com/wf/captcha/utils/FontsUtil.java @@ -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), + * 不产生临时文件获取字体代码实现 + * + * URL url = FontLoader.class.getResource("font/SourceHanSansCN-Regular.otf"); + * String pathString = url.getFile(); + * Font selfFont = Font.createFont(Font.TRUETYPE_FONT, new File(pathString)); + * + * 上面的解决方案会导致另一个问题,字体文件在生产环境是在jar包里,部分操作系统环境下,直接读取读取不到,只能通过流的方式获取。 + * + * 因此,本方案采用的办法是把jar包中的字体文件复制到java.io.tmpdir临时文件夹中 + * ,再采用java.awt.Font#createFont(int, java.io.File)的方式产生字体,既解决了临时文件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(); + } + } + +} diff --git a/web/WEB-INF/web.xml b/web/WEB-INF/web.xml new file mode 100644 index 0000000..ebe475a --- /dev/null +++ b/web/WEB-INF/web.xml @@ -0,0 +1,15 @@ + + + + + CaptchaServlet + com.wf.captcha.servlet.CaptchaServlet + + + CaptchaServlet + /captcha + + \ No newline at end of file diff --git a/web/index.html b/web/index.html new file mode 100644 index 0000000..607f9de --- /dev/null +++ b/web/index.html @@ -0,0 +1,10 @@ + + + + + 验证码测试 + + + + + \ No newline at end of file