学习下识别图片中的文字,找到了Tess4j图文识别的方式,于是就初步探究下,玩下识别验证码。
1、以3.4.2版本为例,下载Tess4j-3.4.2-src.zip。
2、下载中文字库,chi_sim.traineddata。
下载Tess4j参考:
http://sourceforge.net/projects/tess4j/
字库下载参考:
https://github.com/tesseract-ocr/tessdata/tree/3.04.00
api文档参考:
http://tess4j.sourceforge.net/docs/docs-3.4/
1、解压Tess4J-3.4.2-src.zip。
2、把根目录的lib和dist相关jar拷贝到你的项目lib中。
3、再把tessdata目录拷贝到你的项目根目录中。
4、再把中文字库放入tessdata目录。
5、dll不用理,Tess4j.jar已经包含。
6、如果遇到异常,Error: Invalid memory access,Error opening data file ./tessdata/eng.traineddata说明tessdata路径不对。
压缩包目录:
如果是使用maven:
就在pom.xml加入即可。
<dependency>
<groupId>net.sourceforge.tess4j</groupId>
<artifactId>tess4j</artifactId>
<version>3.4.2</version>
</dependency>
我的项目test for java结构:
Tess4j依赖jar参考:
commons-beanutils-1.9.2.jar
commons-io-2.6.jar
commons-logging-1.2.jar
ghost4j-1.0.1.jar
hamcrest-core-1.3.jar
itext-2.1.7.jar
jai-imageio-core-1.3.1.jar
jboss-vfs-3.2.12.Final.jar
jcl-over-slf4j-1.7.25.jar
jna-4.1.0.jar
jul-to-slf4j-1.7.25.jar
junit-4.12.jar
lept4j-1.6.2.jar
log4j-1.2.17.jar
log4j-over-slf4j-1.7.25.jar
logback-classic-1.2.3.jar
logback-core-1.2.3.jar
slf4j-api-1.7.25.jar
xmlgraphics-commons-1.5.jar
官方简单例子:
package net.sourceforge.tess4j.example;
import java.io.File;
import net.sourceforge.tess4j.*;
public class TesseractExample {
public static void main(String[] args) {
File imageFile = new File("eurotext.tif");
ITesseract instance = new Tesseract(); // JNA Interface Mapping
// ITesseract instance = new Tesseract1(); // JNA Direct Mapping
try {
String result = instance.doOCR(imageFile);
System.out.println(result);
} catch (TesseractException e) {
System.err.println(e.getMessage());
}
}
}
我的初探例子:
package com.weizhixi;
import net.sourceforge.tess4j.ITesseract;
import net.sourceforge.tess4j.Tesseract;
import net.sourceforge.tess4j.util.ImageHelper;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
public class Test {
public static void main(String[] args) throws Exception{
testEn();
//testZh();
}
//使用英文字库 - 识别图片
public static void testEn() throws Exception {
File imageFile = new File("C:/Users/XQ/Desktop/en.png");
BufferedImage image = ImageIO.read(imageFile);
//对图片进行处理
image = convertImage(image);
ITesseract instance = new Tesseract();//JNA Interface Mapping
String result = instance.doOCR(image); //识别
System.out.println(result);
}
//使用中文字库 - 识别图片
public static void testZh() throws Exception {
File imageFile = new File("C:/Users/XQ/Desktop/zh.png");
BufferedImage image = ImageIO.read(imageFile);
//对图片进行处理
//image = convertImage(image);
ITesseract instance = new Tesseract();//JNA Interface Mapping
instance.setLanguage("chi_sim");//使用中文字库
String result = instance.doOCR(image); //识别
System.out.println(result);
}
//对图片进行处理 - 提高识别度
public static BufferedImage convertImage(BufferedImage image) throws Exception {
//按指定宽高创建一个图像副本
//image = ImageHelper.getSubImage(image, 0, 0, image.getWidth(), image.getHeight());
//图像转换成灰度的简单方法 - 黑白处理
image = ImageHelper.convertImageToGrayscale(image);
//图像缩放 - 放大n倍图像
image = ImageHelper.getScaledInstance(image, image.getWidth() * 3, image.getHeight() * 3);
return image;
}
}
处理倾斜图片:
如果图片字体倾斜的,可以用下面代码纠正
BufferedImage bi = ImageIO.read(imageFile);
ImageDeskew id = new ImageDeskew(bi);
double imageSkewAngle = id.getSkewAngle(); //获取倾斜角度
if ((imageSkewAngle > 0.05d || imageSkewAngle < -(0.05d))) {
bi = ImageHelper.rotateImage(bi, -imageSkewAngle); //纠偏图像
}
测试1:
测试一张英文截图en.png。
未使用图像简单处理,运行读取图片文字:
发现有几次无法准确识别。
使用convertImage方法对图像简单处理,运行读取图片文字:
发现已经完全识别了。
测试2:
测试一张中文图片zh.png
用不用convertImage,测试结果都正常:
测试3:
来点复杂的图片:
来看看识别输出:
1、未使用图像处理
2、使用图像处理
发现识别度提高了很多,但部分还是未能够识别。
测试4:
识别干扰度比较低的简单验证码
识别结果:已经正确识别了。
经测试多张各种验证码,干扰度比较大的,扭曲字体的验证码不能识别。
训字库能提高中文字库的识别度。
需要下载中文字库:chi_sim.traindata
需要下载tesseract-ocr安装:tesseract-ocr-setup.exe
需要下载jTessBoxEditor用于修改box文件
至于怎么训字库,这里不展开说了。
初探了一天,发现初级简单应用Tess4j:
1、只能识别几乎没有干扰,比较清晰的图片。
2、对图片灰度处理和放大处理,能提高识别度,但不是一定能起作用。
3、如果不准确的识别,可能要去训字库了,如测试识别图中的逗号,已经变成偏上的点了。
4、识别度受字体颜色、大小、清晰度、干扰度、扭曲、倾斜等度影响。
5、官方还提供了一些test例子,还有很多操作和应用。
初级应用只是简单的识别,能识别复杂度很大的图片文字,那是要很多牛B技术和逻辑的大神级操作。
如果想识别度很高很高几乎所有都能识别,又要快速集成、建议还是调用第三方识别API了,有些要收费的有些不用收费但有调用频次限制。
由于资源太大,我就不上传到我网站了。
请到我的网盘下载:
链接:https://pan.baidu.com/s/1dHje9pR
密码:z0bi
内含:
1、项目:基于maven_test4j例子项目.zip
2、官方Tess4j:Tess4J-3.4.2-src.zip
3、中文训字库:chi_sim.traineddata
转自:https://www.weizhixi.com/article/59.html
要功能点:
Spring Boot Web 整合 JasperReports,在浏览器地址栏输入访问地址会直接下载 PDF 报表文件;整合过程中遇到的两个比较费时间的问题:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>net.sf.jasperreports</groupId>
<artifactId>jasperreports</artifactId>
<version>6.19.1</version>
<exclusions>
<exclusion>
<groupId>com.lowagie</groupId>
<artifactId>itext</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>net.sf.jasperreports</groupId>
<artifactId>jasperreports-fonts</artifactId>
<version>6.19.1</version>
</dependency>
<dependency>
<groupId>com.lowagie</groupId>
<artifactId>itext</artifactId>
<version>2.1.7</version>
</dependency>
报表文件名称:employees-details.jrxml
报表文件路径:src\main\resources\employees-details.jrxml
<?xml version="1.0" encoding="UTF-8"?>
<!-- Created with Jaspersoft Studio version 6.19.1.final using JasperReports Library version 6.19.1-867c00bf88cd4d784d404379d6c05e1b419e8a4c -->
<jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd" name="Employee" pageWidth="595" pageHeight="842" columnWidth="555" leftMargin="20" rightMargin="20" topMargin="20" bottomMargin="20" uuid="37175dba-8b89-474d-8341-09d431dce38f">
<style name="Table_TH" mode="Opaque" backcolor="#F0F8FF">
<box>
<pen lineWidth="0.5" lineColor="#000000"/>
<topPen lineWidth="0.5" lineColor="#000000"/>
<leftPen lineWidth="0.5" lineColor="#000000"/>
<bottomPen lineWidth="0.5" lineColor="#000000"/>
<rightPen lineWidth="0.5" lineColor="#000000"/>
</box>
</style>
<style name="Table_TD" mode="Opaque" backcolor="#FFFFFF">
<box>
<pen lineWidth="0.5" lineColor="#000000"/>
<topPen lineWidth="0.5" lineColor="#000000"/>
<leftPen lineWidth="0.5" lineColor="#000000"/>
<bottomPen lineWidth="0.5" lineColor="#000000"/>
<rightPen lineWidth="0.5" lineColor="#000000"/>
</box>
</style>
<style name="Table_CH" mode="Opaque" backcolor="#BFE1FF">
<box>
<pen lineWidth="0.5" lineColor="#000000"/>
<topPen lineWidth="0.5" lineColor="#000000"/>
<leftPen lineWidth="0.5" lineColor="#000000"/>
<bottomPen lineWidth="0.5" lineColor="#000000"/>
<rightPen lineWidth="0.5" lineColor="#000000"/>
</box>
</style>
<subDataset name="Dataset1" uuid="01ae53ec-87c9-41de-867d-bd79f5d4e77c">
<property name="com.jaspersoft.studio.data.defaultdataadapter" value="One Empty Record"/>
<queryString>
<![CDATA[]]>
</queryString>
<field name="id" class="java.lang.Integer"/>
<field name="name" class="java.lang.String"/>
<field name="role" class="java.lang.String"/>
<field name="address" class="java.lang.String"/>
<sortField name="id"/>
<variable name="totalEmployees" class="java.lang.Integer" calculation="DistinctCount">
<variableExpression><![CDATA[$F{id}]]></variableExpression>
</variable>
</subDataset>
<parameter name="CompanyName" class="java.lang.String"/>
<parameter name="employeeData" class="net.sf.jasperreports.engine.data.JRBeanCollectionDataSource"/>
<queryString>
<![CDATA[]]>
</queryString>
<field name="name" class="java.lang.String"/>
<field name="id" class="java.lang.Integer"/>
<field name="role" class="java.lang.String"/>
<field name="address" class="java.lang.String"/>
<background>
<band splitType="Stretch"/>
</background>
<title>
<band height="86" splitType="Stretch">
<frame>
<reportElement mode="Opaque" x="0" y="0" width="555" height="86" backcolor="#3BE3E3" uuid="57f80b95-2c82-4855-8b4f-797057ea6a99"/>
<image scaleImage="FillFrame">
<reportElement x="82" y="0" width="410" height="40" uuid="c21b5d52-4d05-448d-a001-a0cd19a9aeb2"/>
<imageExpression><![CDATA["E:/1.png"]]></imageExpression>
</image>
<textField>
<reportElement style="Table_TH" mode="Transparent" x="90" y="50" width="400" height="30" backcolor="#FFFFFF" uuid="15957312-bfcc-43e7-ad7c-8cdb97c4197b">
<property name="com.jaspersoft.studio.unit.width" value="px"/>
</reportElement>
<box padding="0">
<pen lineWidth="1.0" lineStyle="Solid"/>
<topPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
<leftPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
<bottomPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
<rightPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
</box>
<textElement>
<font fontName="华文宋体" size="20" isBold="true" isItalic="true" isUnderline="true"/>
</textElement>
<textFieldExpression><![CDATA[$P{CompanyName}]]></textFieldExpression>
</textField>
</frame>
</band>
</title>
<pageHeader>
<band height="31" splitType="Stretch">
<line>
<reportElement x="0" y="15" width="555" height="1" uuid="04a9c4d5-af68-4738-b280-249876a779f3">
<property name="com.jaspersoft.studio.unit.height" value="px"/>
</reportElement>
<graphicElement>
<pen lineStyle="Dashed"/>
</graphicElement>
</line>
</band>
</pageHeader>
<detail>
<band height="170" splitType="Stretch">
<property name="com.jaspersoft.studio.unit.height" value="px"/>
<componentElement>
<reportElement x="0" y="0" width="555" height="170" uuid="58650125-3653-4fa6-9154-b9c084419a71">
<property name="com.jaspersoft.studio.layout" value="com.jaspersoft.studio.editor.layout.VerticalRowLayout"/>
<property name="com.jaspersoft.studio.table.style.table_header" value="Table_TH"/>
<property name="com.jaspersoft.studio.table.style.column_header" value="Table_CH"/>
<property name="com.jaspersoft.studio.table.style.detail" value="Table_TD"/>
</reportElement>
<jr:table xmlns:jr="http://jasperreports.sourceforge.net/jasperreports/components" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports/components http://jasperreports.sourceforge.net/xsd/components.xsd">
<datasetRun subDataset="Dataset1" uuid="33e34648-091e-48f9-b2c9-2defadbd03fb">
<dataSourceExpression><![CDATA[$P{employeeData}]]></dataSourceExpression>
</datasetRun>
<jr:column width="100" uuid="fed73b20-211a-48ef-bf45-eb5f50e0d41b">
<property name="com.jaspersoft.studio.components.table.model.column.name" value="Column1"/>
<jr:tableFooter style="Table_TH" height="30" rowSpan="1">
<staticText>
<reportElement x="0" y="0" width="100" height="30" uuid="b219724f-df88-4066-8fc3-db986efed088"/>
<textElement textAlignment="Center" verticalAlignment="Middle"/>
<text><![CDATA[Total Employees=]]></text>
</staticText>
</jr:tableFooter>
<jr:columnHeader style="Table_CH" height="30" rowSpan="1">
<staticText>
<reportElement x="0" y="0" width="100" height="30" uuid="6e4a6eb9-7503-46c2-b199-cb78736d4827"/>
<textElement textAlignment="Center" verticalAlignment="Middle">
<font fontName="华文宋体"/>
</textElement>
<text><![CDATA[ID]]></text>
</staticText>
</jr:columnHeader>
<jr:columnFooter style="Table_CH" height="30" rowSpan="1"/>
<jr:detailCell style="Table_TD" height="30">
<textField>
<reportElement x="0" y="0" width="100" height="30" uuid="e04148fe-4406-4817-bf7c-a75a1837a834"/>
<textElement textAlignment="Center" verticalAlignment="Middle">
<font fontName="华文宋体"/>
</textElement>
<textFieldExpression><![CDATA[$F{id}]]></textFieldExpression>
</textField>
</jr:detailCell>
</jr:column>
<jr:column width="100" uuid="c805b32b-9978-4ad9-93c8-64fb6ebdc310">
<property name="com.jaspersoft.studio.components.table.model.column.name" value="Column2"/>
<jr:tableFooter style="Table_TH" height="30" rowSpan="1">
<textField>
<reportElement x="0" y="0" width="100" height="30" uuid="8b6f3603-5468-4ed8-92d6-2744856cfbec"/>
<textElement textAlignment="Center" verticalAlignment="Middle"/>
<textFieldExpression><![CDATA[$V{totalEmployees}]]></textFieldExpression>
</textField>
</jr:tableFooter>
<jr:columnHeader style="Table_CH" height="30" rowSpan="1">
<staticText>
<reportElement x="0" y="0" width="100" height="30" uuid="ae32a33c-1f5c-4045-b8d6-738226f2881e"/>
<textElement textAlignment="Center" verticalAlignment="Middle">
<font fontName="华文宋体"/>
</textElement>
<text><![CDATA[员工姓名]]></text>
</staticText>
</jr:columnHeader>
<jr:columnFooter style="Table_CH" height="30" rowSpan="1"/>
<jr:detailCell style="Table_TD" height="30">
<textField>
<reportElement x="0" y="0" width="100" height="30" uuid="ce7df570-525d-4bb1-9ed3-a63c0b387bbd"/>
<textElement textAlignment="Center" verticalAlignment="Middle">
<font fontName="华文宋体"/>
</textElement>
<textFieldExpression><![CDATA[$F{name}]]></textFieldExpression>
</textField>
</jr:detailCell>
</jr:column>
<jr:column width="40" uuid="bd04119c-8493-4333-952a-2aeac29db62b">
<property name="com.jaspersoft.studio.components.table.model.column.name" value="Column3"/>
<jr:tableFooter style="Table_TH" height="30" rowSpan="1"/>
<jr:columnHeader style="Table_CH" height="30" rowSpan="1">
<staticText>
<reportElement x="0" y="0" width="40" height="30" uuid="37ee0454-22df-4056-a40e-f52f82d29f95"/>
<textElement textAlignment="Center" verticalAlignment="Middle">
<font fontName="华文宋体"/>
</textElement>
<text><![CDATA[角色]]></text>
</staticText>
</jr:columnHeader>
<jr:columnFooter style="Table_CH" height="30" rowSpan="1"/>
<jr:detailCell style="Table_TD" height="30">
<textField>
<reportElement x="0" y="0" width="40" height="30" uuid="a789a863-4232-4279-8a66-be83206747fe"/>
<textElement textAlignment="Center" verticalAlignment="Middle">
<font fontName="华文宋体"/>
</textElement>
<textFieldExpression><![CDATA[$F{role}]]></textFieldExpression>
</textField>
</jr:detailCell>
</jr:column>
<jr:column width="200" uuid="f32f724a-24c9-4887-ba41-5957dd0fed1d">
<property name="com.jaspersoft.studio.components.table.model.column.name" value="Column4"/>
<jr:tableFooter style="Table_TH" height="30" rowSpan="1"/>
<jr:columnHeader style="Table_CH" height="30" rowSpan="1">
<staticText>
<reportElement x="0" y="0" width="200" height="30" uuid="ced8b636-0cef-488f-89c4-9988b81415db"/>
<textElement textAlignment="Center" verticalAlignment="Middle">
<font fontName="华文宋体"/>
</textElement>
<text><![CDATA[地址]]></text>
</staticText>
</jr:columnHeader>
<jr:columnFooter style="Table_CH" height="30" rowSpan="1">
<property name="com.jaspersoft.studio.unit.width" value="px"/>
</jr:columnFooter>
<jr:detailCell style="Table_TD" height="30">
<textField>
<reportElement x="0" y="0" width="200" height="30" uuid="958c39bd-fd6f-4414-9700-579e0c8ee7d9"/>
<textElement textAlignment="Center" verticalAlignment="Middle">
<font fontName="华文宋体"/>
</textElement>
<textFieldExpression><![CDATA[$F{address}]]></textFieldExpression>
</textField>
</jr:detailCell>
</jr:column>
</jr:table>
</componentElement>
</band>
</detail>
<pageFooter>
<band height="50" splitType="Stretch">
<textField>
<reportElement x="350" y="20" width="100" height="30" uuid="9ab9485d-d510-496f-9dcd-dae944a4ae43"/>
<textElement textAlignment="Right"/>
<textFieldExpression><![CDATA["Page " + $V{PAGE_NUMBER}]]></textFieldExpression>
</textField>
<textField evaluationTime="Report">
<reportElement x="455" y="20" width="100" height="30" uuid="a534e5d1-aa1b-4a87-9149-d7a052cbc01f"/>
<textFieldExpression><![CDATA[" of " + $V{PAGE_NUMBER}]]></textFieldExpression>
</textField>
</band>
</pageFooter>
</jasperReport>
字体文件位置:src\main\resources\static\font\chinese.stsong.ttf
字体配置文件位置:src\main\resources\static\font\fonts.xml
配置文件内容
<?xml version="1.0" encoding="UTF-8"?>
<fontFamilies>
<fontFamily name="华文宋体">
<normal>static/font/chinese.stsong.ttf</normal>
<bold>static/font/chinese.stsong.ttf</bold>
<italic>static/font/chinese.stsong.ttf</italic>
<boldItalic>static/font/chinese.stsong.ttf</boldItalic>
<pdfEncoding>Identity-H</pdfEncoding>
<pdfEmbedded>true</pdfEmbedded>
<exportFonts>
<export key="net.sf.jasperreports.html">'华文宋体', Arial, Helvetica, sans-serif</export>
<export key="net.sf.jasperreports.xhtml">'华文宋体', Arial, Helvetica, sans-serif</export>
</exportFonts>
</fontFamily>
</fontFamilies>
在 classpath 路径下(application.properties 同级)创建 Jasper 拓展文件 jasperreports_extension.properties
net.sf.jasperreports.extension.registry.factory.simple.font.families=net.sf.jasperreports.engine.fonts.SimpleFontExtensionsRegistryFactory
net.sf.jasperreports.extension.simple.font.families.lobstertwo=static/font/fonts.xml
@Data
@NoArgsConstructor
public class Employee {
private int id;
private String name;
private String role;
private String address;
public Employee(int id, String name, String role, String address) {
this.id=id;
this.name=name;
this.role=role;
this.address=address;
}
}
@RestController
public class EmployeeController {
@GetMapping("/employee/records/report")
public ResponseEntity<byte[]> getEmployeeRecordReport() {
try {
// 测试数据
List<Employee> empLst=createTestData();
// 报表需要的动态参数
Map<String, Object> empParams=new HashMap<String, Object>();
empParams.put("CompanyName", "Spring Boot 整合 JasperReports");
empParams.put("employeeData", new JRBeanCollectionDataSource(empLst));
// 编译
JasperReport jasperReport=JasperCompileManager.compileReport(
ResourceUtils.getFile("classpath:employees-details.jrxml").getAbsolutePath()
);
// 填充数据
JasperPrint jasperPrint=JasperFillManager.fillReport(jasperReport, empParams, new JREmptyDataSource());
// 导出报表
HttpHeaders headers=new HttpHeaders();
// 设置响应格式:PDF
headers.setContentType(MediaType.APPLICATION_PDF);
// 设置文件名称
headers.setContentDispositionFormData("filename", "employees-details.pdf");
return new ResponseEntity<byte[]>(JasperExportManager.exportReportToPdf(jasperPrint), headers, HttpStatus.OK);
} catch (Exception e) {
e.printStackTrace();
return new ResponseEntity<byte[]>(HttpStatus.INTERNAL_SERVER_ERROR);
}
}
private List<Employee> createTestData() {
List<Employee> resultList=new ArrayList<>();
resultList.add(new Employee(1, "汪小成", "程序员", "山东省济宁市任城区"));
resultList.add(new Employee(2, "孙小顺", "部门经理", "安徽省合肥市蜀山区"));
return resultList;
}
}
在谷歌浏览器地址栏输入 http://localhost:9000/employee/records/report 会直接弹出保存文件的对话框,实际效果如下:
itext-2.1.7.js8.jar 可以在如下地址下载:
https://jaspersoft.jfrog.io/ui/native/third-party-ce-artifacts/com/lowagie/itext/2.1.7.js8/
这里搜集了用来构建应用程序的工具。
编程操作Java字节码的函数库。
软件度量和质量评估工具。
创建分析器、解释器和编译器的框架。
支持持续集成、测试和应用发布的工具。
简化数据库交互的工具、库。
处理日期和时间的函数库。
帮助代码实现控制反转模式的函数库。
从基础层次上改进开发流程。
用来开发分布式、具有容错性应用程序的函数库和框架。
使用本机格式分发Java应用程序的工具。
用来处理Office格式文档的函数库。
游戏开发框架。
用来创建现代图形用户界面的函数库。
与高性能计算有关的资源,包括集合以及很多具体功能的函数库。
视图简化开发的集成开发环境。
用来帮助创建、评估或操作图形的函数库。
简化JSON处理的函数库。
目前的JVM、JDK实现。
记录应用程序的日志函数库。
提供具体统计算法的工具。其算法可从数据中学习。
在客户端之间进行消息传递,确保协议独立性的工具。
其它资源。
用来专门处理文本的函数库。
网络编程函数库。
处理对象持久化的API。
用来帮助创建PDF文件的资源。
用来创建RESTful 服务的框架。
用于科学计算和分析的函数库。
文档索引引擎,用于搜索和分析。
用于处理安全、认证、授权或会话管理的函数库。
用来高效处理序列化的函数库。
用来部署应用程序的服务器。
对模板中表达式进行替换的工具。
测试内容从对象到接口,涵盖性能测试和基准测试工具。
通用工具类函数库。
用于分析网站内容的函数库。
用于处理Web应用程序不同层次间通讯的框架。
活跃的讨论区。
具有广泛影响且值得阅读的Java经典书籍。
可以一边编程一边听的东西。
值得关注的帐号。
值得阅读的网站。
*请认真填写需求信息,我们会在24小时内与您取得联系。