diff --git a/.gitignore b/.gitignore index 0e13eeb..e5dba25 100644 --- a/.gitignore +++ b/.gitignore @@ -4,8 +4,5 @@ pom.xml.releaseBackup pom.xml.versionsBackup pom.xml.next release.properties -dependency-reduced-pom.xml -buildNumber.properties -.mvn/timing.properties -# https://github.com/takari/maven-wrapper#usage-without-binary-jar -.mvn/wrapper/maven-wrapper.jar +*.iml +.idea/ diff --git a/README.md b/README.md new file mode 100644 index 0000000..99d9792 --- /dev/null +++ b/README.md @@ -0,0 +1,20 @@ +## 大屏客户端 + +### 介绍 +一体机、大屏、展示屏等终端设备需要全屏展示H5应用或统计大屏客户端; +本程序采用java编写,内核采用jcef java版本,目前支持直接打包为exe,其他系统支持需要二次开发 + +### 开发环境 +jdk 11+ + +### 构建工具 +Maven 3+ + +##### 版本说明 +###### v0.0.1-SNAPSHOT +1. 开机自启 +2. 自动全屏 +3. 支持本地静态文件和在线地址 + +### 联系方式 +E-Mail:wangbing@wbsite.xyz diff --git a/ScreenClient.ico b/ScreenClient.ico new file mode 100644 index 0000000..b46159a Binary files /dev/null and b/ScreenClient.ico differ diff --git a/default.config b/default.config new file mode 100644 index 0000000..8ed8058 --- /dev/null +++ b/default.config @@ -0,0 +1,8 @@ +#标题,默认ScreenClient +title=ScreenClient + +#启动打开地址,不写默认html/index.html +url=html/index.html + +#默认大小,full全屏,normal正常 +size=full diff --git a/html/index.html b/html/index.html new file mode 100644 index 0000000..884cadd --- /dev/null +++ b/html/index.html @@ -0,0 +1,38 @@ + + + +Welcome to ScreenClient! + + + +

Welcome to ScreenClient!

+

If you see this page, the ScreenClient server is successfully installed and +working. Further configuration is required.

+ +

Config

+ +

To modify the configuration please refer to 【default.config】

+ + + +

Shortcut

+ + + +

Thank you for using ScreenClient.

+ + diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..6d399b1 --- /dev/null +++ b/pom.xml @@ -0,0 +1,163 @@ + + + 4.0.0 + + xyz.wbsite + ScreenClient + 0.0.1-SNAPSHOT + jar + ScreenClient + ScreenClient + + + UTF-8 + UTF-8 + 11 + true + 2.3.7.RELEASE + Hoxton.SR8 + + + + + + central + Central Repository + default + https://maven.aliyun.com/repository/public + + + + + + central + Central Repository + https://maven.aliyun.com/repository/public + default + + + + + + me.friwi + jcefmaven + 110.0.25.1 + + + + cn.hutool + hutool-all + 5.8.0.M2 + + + + + me.friwi + jcef-natives-windows-amd64 + jcef-87476e9+cef-110.0.25+g75b1c96+chromium-110.0.5481.78 + + + + + + + + + + + + + + + + + com.melloware + jintellitype + 1.4.0 + + + + + + ${artifactId}-${version} + + src/main/java + + src/test/java + + + src/main/resources + + + + + org.springframework.boot + spring-boot-maven-plugin + + + org.apache.maven.plugins + maven-compiler-plugin + + ${java.version} + ${java.version} + + + + + org.apache.maven.plugins + maven-war-plugin + + + + ${project.basedir}/src/main/resources/lib + WEB-INF/lib + + *.jar + + + + + + + + io.github.fvarrui + javapackager + 1.7.1 + + + package + + package + + + + xyz.wbsite.screen.Starter + + true + true + false + windows + ${artifactId} + ${version} + + ${project.basedir}/html + ${project.basedir}/log + ${project.basedir}/default.config + ${project.basedir}/service.bat + + + + + ${project.basedir}/ScreenClient.ico + false + false + false + + + + + + + + diff --git a/src/main/java/xyz/wbsite/screen/Starter.java b/src/main/java/xyz/wbsite/screen/Starter.java new file mode 100644 index 0000000..52eb005 --- /dev/null +++ b/src/main/java/xyz/wbsite/screen/Starter.java @@ -0,0 +1,63 @@ +package xyz.wbsite.screen; + +import cn.hutool.core.io.FileUtil; +import cn.hutool.log.StaticLog; +import cn.hutool.setting.dialect.Props; +import me.friwi.jcefmaven.CefInitializationException; +import me.friwi.jcefmaven.UnsupportedPlatformException; +import xyz.wbsite.screen.client.ShortCutUtil; +import xyz.wbsite.screen.client.WebClient; + +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.io.File; +import java.io.IOException; + +public class Starter { + + public void run() throws InterruptedException, UnsupportedPlatformException, CefInitializationException, IOException { + // 检查配置文件 + File configFile = new File("default.config"); + System.out.println(configFile.getAbsolutePath()); + if (!FileUtil.exist(configFile)) { + throw new IllegalArgumentException("default.config not exist!"); + } + // 初始化配置 + Props props = new Props(configFile); + // 初始化客户端 + WebClient webClient = new WebClient(props); + // 焦点事件监听 + webClient.addFocusListener(new FocusListener() { + @Override + public void focusGained(FocusEvent e) { + StaticLog.debug("获得焦点事件"); + } + + @Override + public void focusLost(FocusEvent e) { + StaticLog.debug("丢失焦点事件"); + } + }); + + // 添加一个鼠标点击监听 + webClient.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + StaticLog.debug("鼠标点击事件"); + } + }); + + // 调用脚本 + webClient.executeJavaScript("console.log('java 调用 JavaScript')"); + + // 创建快捷方式使用 + File targetFile = new File("ScreenClient.exe"); + ShortCutUtil.createShortCutForDesktop(targetFile); + } + + public static void main(String[] args) throws InterruptedException, UnsupportedPlatformException, CefInitializationException, IOException { + new Starter().run(); + } +} diff --git a/src/main/java/xyz/wbsite/screen/client/KeyEnum.java b/src/main/java/xyz/wbsite/screen/client/KeyEnum.java new file mode 100644 index 0000000..6ab038c --- /dev/null +++ b/src/main/java/xyz/wbsite/screen/client/KeyEnum.java @@ -0,0 +1,58 @@ +package xyz.wbsite.screen.client; + +public enum KeyEnum { + + F1(112), + F2(113), + F3(114), + F4(115), + F5(116), + F6(117), + F7(118), + F8(119), + F9(120), + F10(121), + F11(122), + F12(123), + ESC(27), + TAB(9), + CAPSLOCK(20), + SHIFT(16), + CTRL(17), + START_LEFT(91), + START_RIGHT(92), + CONTEXT_MENU(93), + ALT(18), + SPACE(32), + CARRIAGE_RETURN(13), + LINE_FEED(10), + BACK_SLASH(220), + BACK_SPACE(8), + INSERT(45), + DEL(46), + HOME(36), + END(35), + PAGE_UP(33), + PAGE_DOWN(34), + PRINT_SCREEN(44), + SCR_LK(145), + PAUSE(19), + LEFT_ARROW_KEY(37), + UP_ARROW_KEY(38), + RIGHT_ARROW_KEY(39), + DOWN_ARROW_KEY(40), + MOD_ALT(1), + MOD_CONTROL(2), + MOD_SHIFT(4), + MOD_WIN(8); + + private int value; + + KeyEnum(int value) { + this.value = value; + } + + public int value() { + return value; + } +} diff --git a/src/main/java/xyz/wbsite/screen/client/ShortCutUtil.java b/src/main/java/xyz/wbsite/screen/client/ShortCutUtil.java new file mode 100644 index 0000000..88fea45 --- /dev/null +++ b/src/main/java/xyz/wbsite/screen/client/ShortCutUtil.java @@ -0,0 +1,177 @@ +package xyz.wbsite.screen.client; + +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.io.IoUtil; +import cn.hutool.system.SystemUtil; + +import javax.swing.filechooser.FileSystemView; +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.channels.FileChannel; + +public class ShortCutUtil { + + /** + * 文件头,固定字段 + */ + private static byte[] headFile = {0x4c, 0x00, 0x00, 0x00, + 0x01, 0x14, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, + (byte) 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46 + }; + /** + * 文件头属性 + */ + private static byte[] fileAttributes = {(byte) 0x93, 0x00, 0x08, 0x00,//可选文件属性 + 0x20, 0x00, 0x00, 0x00,//目标文件属性 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,//文件创建时间 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,//文件修改时间 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,//文件最后一次访问时间 + 0x00, 0x00, 0x00, 0x00,//文件长度 + 0x00, 0x00, 0x00, 0x00,//自定义图标个数 + 0x01, 0x00, 0x00, 0x00,//打开时窗口状态 + 0x00, 0x00, 0x00, 0x00,//热键 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00//未知 + }; + /** + * 固定字段1 + */ + static byte[] fixedValueOne = { + (byte) 0x83, 0x00, 0x14, 0x00 + , 0x1F, 0x50, (byte) 0xE0, 0x4F + , (byte) 0xD0, 0x20, (byte) 0xEA + , 0x3A, 0x69, 0x10, (byte) 0xA2 + , (byte) 0xD8, 0x08, 0x00, 0x2B + , 0x30, 0x30, (byte) 0x9D, 0x19, 0x00, 0x2f + }; + /** + * 固定字段2 + */ + static byte[] fixedValueTwo = { + 0x3A, 0x5C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + , 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + , 0x00, 0x54, 0x00, 0x32, 0x00, 0x04 + , 0x00, 0x00, 0x00, 0x67, 0x50, (byte) 0x91, 0x3C, 0x20, 0x00 + }; + + /** + * 复制文件 + * + * @param source + * @param dest + * @throws IOException + */ + private static void copyFileUsingFileChannels(File source, File dest) throws IOException { + FileChannel inputChannel = null; + FileChannel outputChannel = null; + try { + inputChannel = new FileInputStream(source).getChannel(); + outputChannel = new FileOutputStream(dest).getChannel(); + outputChannel.transferFrom(inputChannel, 0, inputChannel.size()); + } finally { + inputChannel.close(); + outputChannel.close(); + } + } + + /** + * 创建快捷方式 + * + * @param lnk 快捷方式文件路径 + * @param target 目标文件(exe,path,bat...) + */ + public static void createShortCut(File lnk, File target) { + if (!SystemUtil.getOsInfo().isWindows()) { + System.out.println("当前系统不是window系统,无法创建快捷方式!!"); + return; + } + + try { + File touch = FileUtil.touch(lnk); + BufferedOutputStream stream = FileUtil.getOutputStream(touch); + stream.write(headFile); + stream.write(fileAttributes); + stream.write(fixedValueOne); + stream.write((target.getAbsolutePath().toCharArray()[0] + "").getBytes()); + stream.write(fixedValueTwo); + stream.write(target.getAbsolutePath().substring(3).getBytes("gbk")); + stream.flush(); + IoUtil.close(stream); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * 在目标位置创建快捷方式 + * + * @param target 目标 + */ + public static File createShortCut(File target) { + File lnk = new File(target.getParentFile(), FileUtil.mainName(target) + ".lnk"); + createShortCut(lnk, target); + return lnk; + } + + /** + * 在桌面创建快捷方式 + * + * @param target 目标 + */ + public static File createShortCutForDesktop(File target) { + File lnk = new File(FileSystemView.getFileSystemView().getHomeDirectory(), FileUtil.mainName(target) + ".lnk"); + createShortCut(lnk, target); + return lnk; + } + + /** + * 设置某软件开启启动 + * + * @param targetFile 源文件 + * @return 是否设置成功 + */ + public static boolean setStartup(File targetFile, boolean forAllUser) { + File shortCut = createShortCut(targetFile); + // 用户启动目录 + String userStartup = System.getProperty("user.home") + "\\AppData\\Roaming\\Microsoft\\Windows\\Start Menu\\Programs\\Startup\\"; + // 系统启动目录 + String sysStartup = "C:\\ProgramData\\Microsoft\\Windows\\Start Menu\\Programs\\Startup"; + String startup = forAllUser ? sysStartup : userStartup; + // 快捷方式复制到启动目录 + FileUtil.copy(shortCut, new File(startup, shortCut.getName()), true); + return true; + } + + public static boolean delStartup(File targetFile, boolean forAllUser) { + File shortCut = createShortCut(targetFile); + // 用户启动目录 + String userStartup = System.getProperty("user.home") + "\\AppData\\Roaming\\Microsoft\\Windows\\Start Menu\\Programs\\Startup\\"; + // 系统启动目录 + String sysStartup = "C:\\ProgramData\\Microsoft\\Windows\\Start Menu\\Programs\\Startup"; + String startup = forAllUser ? sysStartup : userStartup; + FileUtil.del(new File(startup, shortCut.getName())); + return true; + } + + /** + * 设置软件开机启动 + * + * @param targetFile 源文件 + * @return 是否设置成功 + */ + public static boolean setStartup(File targetFile) { + return setStartup(targetFile, false); + } + + /** + * 删除软件开机启动 + * + * @param targetFile 源文件 + * @return 是否设置成功 + */ + public static boolean delStartup(File targetFile) { + return delStartup(targetFile, false); + } +} diff --git a/src/main/java/xyz/wbsite/screen/client/WebClient.java b/src/main/java/xyz/wbsite/screen/client/WebClient.java new file mode 100644 index 0000000..5b0ebe3 --- /dev/null +++ b/src/main/java/xyz/wbsite/screen/client/WebClient.java @@ -0,0 +1,268 @@ +package xyz.wbsite.screen.client; + +import cn.hutool.core.convert.Convert; +import cn.hutool.core.img.ImgUtil; +import cn.hutool.core.io.resource.ResourceUtil; +import cn.hutool.log.StaticLog; +import com.melloware.jintellitype.HotkeyListener; +import com.melloware.jintellitype.JIntellitype; +import me.friwi.jcefmaven.CefAppBuilder; +import me.friwi.jcefmaven.CefBuildInfo; +import me.friwi.jcefmaven.CefInitializationException; +import me.friwi.jcefmaven.MavenCefAppHandlerAdapter; +import me.friwi.jcefmaven.UnsupportedPlatformException; +import org.cef.CefApp; +import org.cef.CefClient; +import org.cef.browser.CefBrowser; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.FocusListener; +import java.awt.event.KeyListener; +import java.awt.event.MouseListener; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.util.Properties; + +public class WebClient extends JFrame { + + // 退出 + private final int KEY_MARK_ESC = 1; + // 最小化 + private final int KEY_MARK_SWITCH = 2; + // 刷新 + private final int KEY_MARK_RELOAD = 3; + // 添加自启 + private final int KEY_MARK_SET_START = 4; + // 移除自启 + private final int KEY_MARK_DEL_START = 5; + + private CefClient cefClient; + private CefApp cefApp; + private CefBrowser cefBrowser; + private String lastUrl = "about:blank"; + private Properties config; + + private final HotkeyListener hotkeyListener = new HotkeyListener() { + @Override + public void onHotKey(int i) { + switch (i) { + case KEY_MARK_ESC: { + StaticLog.info("exit."); + JIntellitype.getInstance().unregisterHotKey(KEY_MARK_ESC); + JIntellitype.getInstance().removeHotKeyListener(hotkeyListener); + close(); + } + break; + case KEY_MARK_SWITCH: { + StaticLog.info("screen switch."); + if (getExtendedState() == Frame.NORMAL) { + removeNotify(); + setUndecorated(true); + setExtendedState(JFrame.MAXIMIZED_BOTH); + } else { + setExtendedState(Frame.NORMAL); + removeNotify(); + setUndecorated(false); + } + setVisible(true); + } + break; + case KEY_MARK_RELOAD: { + StaticLog.info("screen reload."); + reload(); + } + break; + case KEY_MARK_SET_START: { + StaticLog.info("screen setStartup."); + setStartup(); + } + break; + case KEY_MARK_DEL_START: { + StaticLog.info("screen delStartup."); + delStartup(); + } + break; + } + } + }; + + public WebClient(Properties config) { + this.config = config; + try { + initCef(new String[]{}); + initClient(); + } catch (Exception e) { + StaticLog.error(e); + } + } + + private void initClient() { + setTitle(getProp("title", "ScreenClient")); + getContentPane().add(cefBrowser.getUIComponent(), BorderLayout.CENTER); + setSize(800, 600);//初始大小 + setLocation(0, 0);//位置 + // 设置全屏模式 + if ("full".equals(getProp("size", "full"))) { + setExtendedState(JFrame.MAXIMIZED_BOTH); + setUndecorated(true); + setAlwaysOnTop(true); + } + + addWindowListener(new WindowAdapter() { + @Override + public void windowClosing(WindowEvent e) { + // 关闭应用时要释放资源 + CefApp.getInstance().dispose(); + dispose(); + System.exit(0);//0正常退出,1非正常退出 + } + }); + + // 添加热键 + JIntellitype.getInstance().registerHotKey(KEY_MARK_ESC, 0, KeyEnum.ESC.value()); + JIntellitype.getInstance().registerHotKey(KEY_MARK_SET_START, 0, KeyEnum.F1.value()); + JIntellitype.getInstance().registerHotKey(KEY_MARK_DEL_START, 0, KeyEnum.F2.value()); + JIntellitype.getInstance().registerHotKey(KEY_MARK_RELOAD, 0, KeyEnum.F5.value()); + JIntellitype.getInstance().registerHotKey(KEY_MARK_SWITCH, 0, KeyEnum.F11.value()); + JIntellitype.getInstance().addHotKeyListener(hotkeyListener); + + //设置图标 + URL resource = ResourceUtil.getResource("ScreenClient.png"); + BufferedImage read = ImgUtil.read(resource); + setIconImage(read); + + // 显示 + setVisible(true); + } + + /** + * 初始化 CefBrowser + * + * @param args + */ + private void initCef(String[] args) throws InterruptedException, UnsupportedPlatformException, CefInitializationException, IOException { + CefAppBuilder builder = new CefAppBuilder(); + // window下不需要OSR + boolean useOSR = false; + builder.getCefSettings().windowless_rendering_enabled = useOSR; + builder.setAppHandler(new MavenCefAppHandlerAdapter() { + @Override + public void stateHasChanged(org.cef.CefApp.CefAppState state) { + // 关闭应用时退出jvm运行 + if (state == CefApp.CefAppState.TERMINATED) System.exit(0); + } + }); + + // 设置cef运行参数,这里为空 + builder.addJcefArgs(args); + + // 这边不设置,程序会自动解压 + // 设置 cef chrome实例的目录,关键,若不设置他会默认从网络中下载,国外网络可能下载不稳定导致失败 + // 我的 cef chrome 位于项目的chrome目录下 C:\Users\Administrator\Desktop\project\java\demo-desktop\chrome + // builder.setInstallDir(new File(System.getProperty("user.dir") + File.separator + "chrome")); + // 由于是手动设置cef的chrome,我们要跳过ins检查,防止版本不一致导致从镜像站下载 + // builder.setSkipInstallation(true); + + // 全局的 CefApp 每个程序只能有一个,线程安全 + cefApp = builder.build(); + // 显示一些版本信息 + CefBuildInfo buildInfo = CefBuildInfo.fromClasspath(); + StaticLog.info(buildInfo.toString()); + CefApp.CefVersion cefVersion = cefApp.getVersion(); + StaticLog.info(cefVersion.toString()); + + // 创建一个浏览器客户端实例 + cefClient = cefApp.createClient(); + + // 创建一个浏览器实例 + lastUrl = getProp("url", "html/index.html"); + // 处理非http时的相对路径 + if (!lastUrl.startsWith("http")) { + lastUrl = new File(lastUrl).getAbsolutePath(); + } + + cefBrowser = cefClient.createBrowser(lastUrl, useOSR, true); + } + + /** + * 加载地址 + * + * @param url 地址 + * @throws InterruptedException + */ + public void loadUrl(String url) throws InterruptedException { + // 必须延迟,否则可能因为切换太快无法加载成功 + Thread.sleep(300); + lastUrl = url; + // 处理非http时的相对路径 + if (!lastUrl.startsWith("http")) { + lastUrl = new File(lastUrl).getAbsolutePath(); + } + cefBrowser.loadURL(url); + } + + /** + * 刷新 + */ + public void reload() { + // 创建一个浏览器实例 + cefBrowser = cefClient.createBrowser(lastUrl, false, true); + getContentPane().remove(0); + getContentPane().add(cefBrowser.getUIComponent(), BorderLayout.CENTER); + setVisible(true); + } + + /** + * 开机自启 + */ + public void setStartup() { + if (ShortCutUtil.setStartup(new File("ScreenClient.exe"))) { + executeJavaScript("alert('set startup success')"); + } else { + executeJavaScript("alert('set startup failed')"); + } + } + + /** + * 删除自启 + */ + public void delStartup() { + if (ShortCutUtil.delStartup(new File("ScreenClient.exe"))) { + executeJavaScript("alert('del startup success')"); + } else { + executeJavaScript("alert('del startup failed')"); + } + } + + private String getProp(String key, String defaultValue) { + return Convert.toStr(config.getProperty(key), defaultValue); + } + + public void addFocusListener(FocusListener listener) { + cefBrowser.getUIComponent().addFocusListener(listener); + } + + public void addMouseListener(MouseListener listener) { + cefBrowser.getUIComponent().addMouseListener(listener); + } + + public void addKeyListener(KeyListener listener) { + cefBrowser.getUIComponent().addKeyListener(listener); + } + + public void executeJavaScript(String javascript) { + cefBrowser.executeJavaScript(javascript, null, 1); + } + + public void close() { + // 关闭应用时要释放资源 + CefApp.getInstance().dispose(); + dispose(); + System.exit(0); + } +} diff --git a/src/main/resources/ScreenClient.png b/src/main/resources/ScreenClient.png new file mode 100644 index 0000000..4b0f312 Binary files /dev/null and b/src/main/resources/ScreenClient.png differ diff --git a/src/main/resources/logging.properties b/src/main/resources/logging.properties new file mode 100644 index 0000000..f5e15b6 --- /dev/null +++ b/src/main/resources/logging.properties @@ -0,0 +1,34 @@ +#----------------------------------------------------------------------------------------------------------- +# == JDK Logging ļ == +#Levelȼ +# SEVERE +# WARNING +# INFO +# CONFIG +# FINE +# FINER +# FINEST +# +#----------------------------------------------------------------------------------------------------------- +# ־ʽ +#java.util.logging.SimpleFormatter.format=%4$s: %5$s [%1$tc]%n +#ָRoot Logger +.level=ALL +#Ϊ Handler ָĬϵļĬΪ Level.INFO +java.util.logging.ConsoleHandler.level=ALL +# ָҪʹõ Formatter ƣĬΪ java.util.logging.SimpleFormatter +java.util.logging.ConsoleHandler.formatter=logging.formatter.MySimpleFormatter +# Ϊ Handler ָĬϵļĬΪ Level.ALL +java.util.logging.FileHandler.level=INFO +# ָҪʹõ Formatter ƣĬΪ java.util.logging.XMLFormatter +java.util.logging.FileHandler.formatter=java.util.logging.SimpleFormatter +# ָҪд뵽ļĽֽΪλΪ 0ûƣĬΪƣ +java.util.logging.FileHandler.limit=1024000 +# ָжļѭĬΪ 1 +java.util.logging.FileHandler.count=1 +# ΪɵļָһģʽйϸμݣĬΪ "%h/java%u.log" +java.util.logging.FileHandler.pattern=log/info.log +# ָǷӦý FileHandler ׷ӵκļϣĬΪ false +java.util.logging.FileHandler.append=true +# ִеLogHandlerʹöŸ +handlers=java.util.logging.ConsoleHandler,java.util.logging.FileHandler