今天在eclipse中运行ant时,碰到一个诡异问题:执行javac之后,console就没有任何输出了,没有任何错误信息,同时编译是成功的。
经过一番搜索,终于找到这篇文章,又是字符集的问题。
具体原因就不去深究了,经过我的试验,只要保证workspace、javac和console都使用同一种encoding(比如UTF-8),就能确保ant能在console正常输出日志。
今天在eclipse中运行ant时,碰到一个诡异问题:执行javac之后,console就没有任何输出了,没有任何错误信息,同时编译是成功的。
经过一番搜索,终于找到这篇文章,又是字符集的问题。
具体原因就不去深究了,经过我的试验,只要保证workspace、javac和console都使用同一种encoding(比如UTF-8),就能确保ant能在console正常输出日志。
根据html来生成图片很多时候都会被用到,最常见的就是网页截图。通过html模板技术,可以让用户自定义一段html,然后为用户实时生成图片。
以下就是使用java 2D实现的html生成图片的方法,需要用到两个开源的jar包。core-renderer.jar,jtidy-r938.jar,这两个jar包是用来渲染html页面的,但是不支持执行javasrcipt。另外还需要xmlgraphics-commons-1.4.jar,这是用来生成PNG图片的。
为了支持中文显示自动换行,需要修改org.xhtmlrenderer.layout.Breaker类。
因为xhtmlrenderer是外国人写的,默认是根据空格来决定是否可以换行的,但是中文语句都是没有空格的,修改后的行为就像样式word-break:break-all。core-renderer-repack.jar是我重新打的包,包含了Breaker.java的源代码。
以下是代码:
public class ImageGenerator { private float jpgQuality = 0.9F; private boolean useHighScaleQuality = true; private ImageFormat imageFormat = ImageFormat.JPG; private ChineseFontResolver fontResolver; private static final Logger logger = Logger.getLogger(ImageGenerator.class); public void init() { XRLog.init("init log..."); initTidy(); } private Tidy tidy = null; private static HashMap
为了使用中文字体,需要手工加载中文字体,这里都是用truetype字体:
/** * 中文字体支持,默认使用微软雅黑 * */ public class ChineseFontResolver extends AWTFontResolver { private static Font DEFAULT_FONT; private String fontPath; public ChineseFontResolver() { super(); } public void init() { try { InputStream input = new FileInputStream(new File(getFontPath() + "msyh.ttf")); Font font = Font.createFont(Font.TRUETYPE_FONT, input); font = font.deriveFont(12.0F); setFontMapping("微软雅黑", font); DEFAULT_FONT = font; setFontMapping("arial", font); setFontMapping("serif", font); setFontMapping("SansSerif", font); setFontMapping("Monospaced", font); } catch (FontFormatException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } protected Font resolveFont(SharedContext ctx, String font, float size, IdentValue weight, IdentValue style, IdentValue variant) { Font result = super.resolveFont(ctx, "微软雅黑", size, weight, style, variant); if (result == null) { result = DEFAULT_FONT; } return result; } public void setFontPath(String fontPath) { this.fontPath = fontPath; } public String getFontPath() { return fontPath; } }
truetype的微软雅黑结合ImageGenerator中的RENDER_HINT,渲染出来的中文字体质量还是相当不错的。
使用方法就像这样,为了不出现乱码,最好全部都是用UTF-8编码:
ByteArrayOutputStream output = null; try { Map data = new HashMap(); String html = getTemplateParser().parse("template.ftl", data);//使用freemarker填充数据 InputStream input = new ByteArrayInputStream(html.getBytes(Charset.forName("UTF-8"))); output = getImageGenerator().html2Image(input, 1260, 64); //for test // FileOutputStream file = new FileOutputStream(new File("d://images//result.jpg")); // file.write(output.toByteArray()); // file.flush(); // file.close(); } catch (TemplateException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }
以上代码是使用模板来生成图片,网站截图只要稍微修改一下代码即可,以下是个简单的例子:
public class Main { public static void main(String[] args) { try { Tidy tidy = new Tidy(); tidy.setQuiet(true); tidy.setXHTML(true); tidy.setHideComments(true); tidy.setInputEncoding("UTF-8"); tidy.setOutputEncoding("UTF-8"); tidy.setShowErrors(0); tidy.setShowWarnings(false); //for test start FileOutputStream output = new FileOutputStream(new File("d:/1234.png")); URL url=new URL("http://www.baidu.com"); URLConnection conn=url.openConnection(); conn.connect(); InputStream is=conn.getInputStream(); BufferedReader br=new BufferedReader(new InputStreamReader(is,"gbk")); String s = ""; StringBuffer sb = new StringBuffer(""); while ((s = br.readLine()) != null) { sb.append(s + "\r\n"); } ByteArrayInputStream bis = new ByteArrayInputStream(sb.toString().getBytes("UTF-8")); //for test end Document doc = tidy.parseDOM(bis, null); Graphics2DRenderer g2r = new Graphics2DRenderer(); g2r.setDocument(doc,""); //这里其实还是使用固定的width、height去渲染网页,但是可以设置一个较大的值 Dimension dim = new Dimension(1024, 2000); BufferedImage buff = new BufferedImage((int)dim.getWidth(), (int)dim.getHeight(), BufferedImage.TYPE_INT_RGB); Graphics2D g = (Graphics2D)buff.getGraphics(); g2r.layout(g, new Dimension(1024, 2000)); g.dispose(); //这里获取真正的网页大小,如果页面有背景图设了repeat,会导致无法获取真实大小 Rectangle rect = g2r.getMinimumSize(); buff = new BufferedImage((int)rect.getWidth(), (int)rect.getHeight(), BufferedImage.TYPE_INT_RGB); g = (Graphics2D)buff.getGraphics(); g2r.render(g); g.dispose(); PNGEncodeParam param = PNGEncodeParam.RGB.getDefaultEncodeParam(buff); PNGImageEncoder imageEncoder = new PNGImageEncoder(output, param); imageEncoder.encode(buff); output.flush(); output.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }
如果提交的参数包含中文,只要实用post方式提交请求即可。但是使用post的话,每次刷新页面,浏览器都会弹出对话框提示用户,对于搜索功能就显得不可接受了。
通常一次搜索请求都是通过get方式提交的。但是在tomcat里,直接使用request的getParameter方法得到的参数总是会乱码。
对于这个问题的原因,从源代码级剖析tomcat乱码问题(如果这个链接失效,也可以访问这里)这篇文章已经解释的很清楚了,并且也提供解决方法。但是直接修改tomcat-util.jar显然不是很好。
以下是我现在采用的方法:
String queryString = request.getQueryString();//get raw query string if (queryString != null && queryString.length() > 0) { queryString = new String(queryString.getBytes("ISO-8859-1"), "GBK");//process url which is not urlencoded queryString = URLDecoder.decode(queryString, "GBK");//decode url Pattern pattern = Pattern.compile("q=([^]*)"); Matcher matcher = pattern.matcher(queryString); if (matcher.find()) { query = matcher.group(1); } }
通常来讲,判断两个时间是否属于同一个月,只要判断year相等并且month相等即可,但是这样判断在某些情况下会失败。
前两天就碰到了这个问题,服务器上统计访问量时在判断当前时刻是否属于本月时,就使用了上述逻辑,但是每台服务器的系统时间都不尽相同,导致在同一时刻,两台服务器在做这个判断时得到不同结果。 所造成的结果就是上个月的记录被当前月的统计覆盖。
其实两个系统时间不同的服务器在判断两个时间是否属于某个区间(同天/同月/同年)时,都存在类似问题。 保险起见,应该减弱判断条件:如果系统时间小于等于输入时间,就可以认为相等。