基于JxBrowser的浏览器控件封装实现Java Swing的浏览器集成

基于JxBrowser的浏览器控件封装实现Java Swing的浏览器集成

  • 背景
  • 实现目标
  • 实现代码
  • 运行效果
  • 完整的代码及依赖jar文件下载

背景

进期客户提出在一个Java Swing项目要集成另外2个系统:
1、集成Fine Report(基于Java Web发布的)要能打印、另存pdf|Excel。
2、集成质检报告系统,主要都是基于Web的图片,要能缩放查看。
基于以上2个要求,我们首先想到的是在JavaSwing中的JFrame中能嵌入一个浏览器控件,再通过浏览器加载Web url实现以上2个需求。经过一番搜索,了解到Java FX有Web View实现了浏览器的基本功能,而Java FX的控件需要以交互模式集成到Java Swing中,经过一番努力终于完成。进行测试才发现Java FX的WebView控件功能太弱了,首先在嵌入Fine Report的报表后能正常显示,但是另存、下载、打印都失效了,而且也不能缩放查看图片。最终智能放弃此方案。又重新从网上搜索发现一个控件JxBrowser(付费的),经过一番集成测试,终于在6.5.1版本上实现了以上2个目标,再高的版本是有问题。下面就把封装实现代码分享一下。

实现目标

1、基于JxBrowser6.5.1封装的浏览器控件(内置破解,仅用于个人学习)。
2、适用于在Java Swing应用中嵌入Web页面,并实现java与javascript的交互。
3、支持嵌入服务器页面,支持页面中的附件下载、报表打印、另存等功能。
4、支持嵌入帆软报表。
5、支持Ctrl+鼠标滚轮实现页面缩放

实现代码

1、破解文件(src/META-INF/teamdev.licenses),仅供个人学习,力所能及请付费购买(https://www.teamdev.com/jxbrowser)

Product: JxBrowser
Version: 6.x
Licensed to:
License type: Enterprise
License info: JxBrowser License
Expiration date: 01-01-9999
Support expiration date: NO SUPPORT
Generation date: 01-01-1970
Platforms: win32/x86;win32/x64;mac/x86;mac/x64;linux/x86;linux/x64
Company name: TeamDev Ltd.
SigB: 1
SigA: 1

2、封装号的浏览器控件(com.controls.WebBrowser.java)

package com.controls;

import java.awt.BorderLayout;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.math.BigInteger;

import javax.swing.JOptionPane;
import javax.swing.JPanel;

import com.teamdev.jxbrowser.chromium.Browser;
import com.teamdev.jxbrowser.chromium.CloseStatus;
import com.teamdev.jxbrowser.chromium.UnloadDialogParams;
import com.teamdev.jxbrowser.chromium.swing.BrowserView;
import com.teamdev.jxbrowser.chromium.swing.DefaultDialogHandler;

/**
 * 功能说明:基于jxBrowser的自定义浏览器控件 修改说明:
 * 
 * @author zhenglibing
 * @date 2019年7月5日 下午1:58:32
 * @version 0.1
 */
public class WebBrowser extends JPanel {
	private static final long serialVersionUID = 1L;
	private String url = "http://www.baidu.com";
	private boolean ZoomingFlag = false; // 是否正在缩放,按下Ctrl键变为true,释放Ctrl键变为false
	// 25% : "default_zoom_level": -7.6035680338478615,
	// 33% : "default_zoom_level": -6.0311726618503405,
	// 50% : "default_zoom_level": -3.8017840169239308,
	// 67% : "default_zoom_level": -2.2293886449264093,
	// 75% : "default_zoom_level": -1.5778829311823859,
	// 90% : "default_zoom_level": -0.5778829311823857,
	// 100% : "default_zoom_level": 0.0,
	// 110% : "default_zoom_level": 0.5227586988632231,
	// 125% : "default_zoom_level": 1.2239010857415449,
	// 150% : "default_zoom_level": 2.223901085741545,
	// 175% : "default_zoom_level": 3.069389038663465,
	// 200% : "default_zoom_level": 3.8017840169239308,
	// 250% : "default_zoom_level": 5.025685102665476,
	// 300% : "default_zoom_level": 6.025685102665476,
	// 400% : "default_zoom_level": 7.6035680338478615,
	// 500% : "default_zoom_level": 8.827469119589406

	// 定义缩放级别值数组
	private double[] levels = { -7.6035680338478615, -6.0311726618503405, -3.8017840169239308, -2.2293886449264093,
			-1.5778829311823859, -0.5778829311823857, 0.0, 0.5227586988632231, 1.2239010857415449, 2.223901085741545,
			3.069389038663465, 3.8017840169239308, 5.025685102665476, 6.025685102665476, 7.6035680338478615,
			8.827469119589406 };
	private String[] strLevels = { "25%", "33%", "50%", "67%", "75%", "90%", "100%", "110%", "125%", "150%", "175%",
			"200%", "250%", "300%", "400%", "500%" };
	private long lastWheelTime = 0; // 最后滚动鼠标滚轮的时间

	private Browser browser; // 浏览器对象,需引用jxbrowser
	private BrowserView view; // 浏览器视图对象,需引擎jxbrowser

	// 以下代码用于破解jxbrowser
	static {
		try {
			Class claz = null;
			//6.5.1版本破解 兼容xp
			claz = Class.forName("com.teamdev.jxbrowser.chromium.aq");
			// 6.21版本破解 默认使用最新的6.21版本
			// claz = Class.forName("com.teamdev.jxbrowser.chromium.ba");
			// 6.23版本破解
			//claz = Class.forName("com.teamdev.jxbrowser.chromium.bb");

			Field e = claz.getDeclaredField("e");
			Field f = claz.getDeclaredField("f");

			e.setAccessible(true);
			f.setAccessible(true);
			Field modifersField = Field.class.getDeclaredField("modifiers");
			modifersField.setAccessible(true);
			modifersField.setInt(e, e.getModifiers() & ~Modifier.FINAL);
			modifersField.setInt(f, f.getModifiers() & ~Modifier.FINAL);
			e.set(null, new BigInteger("1"));
			f.set(null, new BigInteger("1"));
			modifersField.setAccessible(false);
		} catch (Exception e) {
			e.printStackTrace();
			System.out.println("执行jxbrowser破解程序时出现异常" + e.getMessage());
		}
	}

	/**
	 * 默认构造方法
	 */
	public WebBrowser() {
		this.init();
	}

	/**
	 * 构造方法重载
	 * 
	 * @param url
	 *            浏览器默认加载的url地址
	 */
	public WebBrowser(String url) {
		this.url = url.startsWith("http://") ? url : "http://" + url;
		this.init();
	}

	/**
	 * 功能说明:初始化jxBrowser 修改说明:
	 * 
	 * @author zhenglibing
	 * @date 2019年7月5日 下午2:28:27
	 */
	private void init() {
		this.browser = new Browser();
		this.view = new BrowserView(browser);
		this.setLayout(new BorderLayout());
		this.add(view, BorderLayout.CENTER);
		this.browser.loadURL(this.url);
		
		// 以下代码支持鼠标拖拽超链接内容
		this.browser.setDialogHandler(new DefaultDialogHandler(view) {
			@Override
			public CloseStatus onBeforeUnload(UnloadDialogParams params) {
				String title = "Confirm Navigation";
				String message = params.getMessage();
				int returnValue = JOptionPane.showConfirmDialog(view, message, title, JOptionPane.OK_CANCEL_OPTION);
				if (returnValue == JOptionPane.OK_OPTION) {
					return CloseStatus.OK;
				} else {
					return CloseStatus.CANCEL;
				}
			}
		});
		
		this.browser.loadHTML(""
				+ "Click here to leave"
				+ "");

		// 以下代码支持Ctrl + 鼠标滚轮实现页面放大缩小
		// 注册键盘按下事件
		this.view.addKeyListener(new KeyListener() {

			@Override
			public void keyTyped(KeyEvent e) {
				// TODO Auto-generated method stub
			}

			/**
			 * 键盘按下
			 */
			@Override
			public void keyPressed(KeyEvent e) {
				// TODO Auto-generated method stub
				if (e.getKeyCode() == 17) {
					ZoomingFlag = true;
				}

			}

			/**
			 * 键盘释放
			 */
			@Override
			public void keyReleased(KeyEvent e) {
				// TODO Auto-generated method stub
				System.out.println("keyReleased");
				ZoomingFlag = false;
			}

		});
		// 注册鼠标滚轮事件
		this.view.addMouseWheelListener(new MouseWheelListener() {
			@Override
			public void mouseWheelMoved(MouseWheelEvent e) {
//				System.out.println(e.getScrollAmount());
				if (e.getScrollAmount() != 3 || e.getWhen() - lastWheelTime < 20) {
					// 滚动太快则过滤一下
					// System.out.println("过滤...");
					return;
				}
//				System.out.println("getWhen = " + e.getWhen());
//				System.out.println("lastWheelTime = " + lastWheelTime);
				if (e.getScrollAmount() == 3 && ZoomingFlag) {
					double currZoomLevel = browser.getZoomLevel();
					if (e.getWheelRotation() == -1) {
						// 加
						for (int i = 0; i < levels.length; i++) {
							if (currZoomLevel == levels[i]) {
								if (i < levels.length - 1) {
									browser.setZoomLevel(levels[i + 1]);
									System.out.println("当前缩放级别:" + strLevels[i + 1]);
								}
								break;
							}
						}
						System.out.println("放大");
					} else if (e.getWheelRotation() == 1) {
						// 减
						for (int i = 1; i < levels.length; i++) {
							if (currZoomLevel == levels[i]) {
								if (i > 0) {
									browser.setZoomLevel(levels[i - 1]);
									System.out.println("当前缩放级别:" + strLevels[i - 1]);
								}
								break;
							}
						}
						System.out.println("缩小");
					}

					// 记录最后一次滚轮时间
					if (lastWheelTime != e.getWhen()) {
						lastWheelTime = e.getWhen();
					}
				}
			}
		});
	}

	/**
	 * 功能说明:获取浏览器访问的url地址
	 * 修改说明:
	 * @author zhenglibing
	 * @date 2019年7月9日 下午2:32:39
	 * @return
	 */
	public String getURL() {
		if (null != this.browser) {
			return this.browser.getURL();
		}
		else
		{
			return "";
		}
	}
	/**
	 * 功能说明:swing方法,设置浏览器访问的url地址 修改说明:
	 * 
	 * @author zhenglibing
	 * @date 2019年7月5日 下午2:30:13
	 * @param urlString
	 */
	public void setURL(final String urlString) {
		if (null == urlString || "".equals(urlString)) {
			this.browser.loadURL("");
			this.browser.loadHTML("");
		} else {
			String oldUrl = this.browser.getURL();
			if (!urlString.equals(oldUrl)) {
				this.browser.loadURL(urlString);
			} else {
				this.browser.reload();
			}
		}
	}

	/**
	 * 功能说明:swing方法,设置浏览器的html内容 修改说明:
	 * 
	 * @author zhenglibing
	 * @date 2019年7月5日 下午5:34:12
	 * @param htmlContent
	 */
	public void setContent(final String htmlContent) {
		this.browser.loadHTML(htmlContent);
	}

	/**
	 * 功能说明:swing方法,清空浏览器的内容 修改说明:
	 * 
	 * @author zhenglibing
	 * @date 2019年7月5日 下午5:33:42
	 */
	public void clear() {
		this.setURL("");
	}

	/**
	 * 功能说明:获取浏览器类型信息 修改说明:
	 * 
	 * @author zhenglibing
	 * @date 2019年7月5日 下午5:32:54
	 * @return
	 */
	public String getBrowserType() {
		return "jxBrowser" + "v6.23.1";
	}

	/**
	 * 功能说明:资源释放方法 修改说明:
	 * 
	 * @author zhenglibing
	 * @date 2019年7月5日 下午5:33:21
	 */
	public void dispose() {

	}
}

3、测试启动类(com.controls.Start.java)

package com.controls;

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;

public class Start {

	private static String title = "浏览器测试";
	private static String url = "https://www.baidu.com";
	public static void main(String[] args) {
		if (args.length >= 2) {
			title = args[0];
			url = args[1];
		}
		else if (args.length == 1) {
			url = args[0];
		}

		JFrame frm = new JFrame(title);
		frm.setSize(800,600);
		frm.setExtendedState(JFrame.MAXIMIZED_BOTH);
		WebBrowser browser = new WebBrowser();
		browser.setSize(800, 600);
		browser.setVisible(true);
		frm.add(browser, BorderLayout.CENTER);
		frm.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frm.setVisible(true);
		browser.setURL(url);
	}

}

运行效果

基于JxBrowser的浏览器控件封装实现Java Swing的浏览器集成_第1张图片

完整的代码及依赖jar文件下载

完整的代码及依赖jar文件下载

你可能感兴趣的:(控件)