笔者近期开发eclipse插件时,需要用到中译英的功能,所以就研究了一下百度翻译. 百度翻译开放平台为广大开发者提供了开发服务的平台,但是并不是免费的.百度翻译是按字符计费的,每个月200万字符内是免费的, 超过200万字符之后,以单价49元/百万字符收费.
1. 注册开发者账号
使用百度翻译API之前,需要自助注册百度-翻译开放平台的API, 注册只需要使用手机号注册即可.笔者注册的是个人开发者, 注册完之后可以在开发者信息页面查看百度翻译平台为你分配的个人账号及秘钥.
- 注册地址: http://api.fanyi.baidu.com/api/trans/product/apiapply
- 开发者信息: http://api.fanyi.baidu.com/api/trans/product/desktop?req=developer
- 通用API文档: http://api.fanyi.baidu.com/api/trans/product/apidoc#joinFile
2. API 简介
2.1 API 地址
百度翻译API 提供了Http 或Https 地址, 可以通过GET 或 POST 方式进行访问, 其中https 使用的是非强制证书方式.
- http地址: http://api.fanyi.baidu.com/api/trans/vip/translate
- https地址: https://fanyi-api.baidu.com/api/trans/vip/translate
2.2 请求参数
百度翻译请求参数拼接方式为普通get请求参数拼接方式.但是需要注意的是,参数q必须是UTF8编码,否则翻译会报错.而且发送http请求之前需要做URL 编码.
字段 | 描述 |
---|---|
q | 请求翻译原文,必须是UTF-8编码,否则报错 |
from | 翻译原文语种 |
to | 翻译目标语种 |
appid | 开发平台注册APPID |
salt | 随机数 |
sign | 数字签名, md5(appid+q+salt+秘钥) |
2.3 响应参数
当翻译报错时,会返回error_code 和 error_msg 字段; 当翻译正确时,返回正确的翻译内容.
字段 | 描述 |
---|---|
error_code | 错误编码,当翻译报错时有值 |
error_msg | 错误原因, 当翻译报错时有值 |
from | 翻译原文语种 |
to | 翻译目标语种 |
trans_result | 翻译列表, 数组类型 |
src | 原文 |
dst | 译文 |
3. Java Demo
笔者使用Java 创建的Maven 项目, 项目源码地址: https://download.csdn.net/download/zongf0504/10835043
3.1 核心工具类
核心类为BDTransApiUtil, 其中依赖的HttpUtil 可以自定义实现.
import java.util.List;
import org.apache.commons.codec.digest.DigestUtils;
import org.zongf.learn.baidu.translate.vo.BDTransRequest;
import org.zongf.learn.baidu.translate.vo.BDTransResponse;
import org.zongf.learn.baidu.translate.vo.BDTransResult;
import com.alibaba.fastjson.JSONObject;
/**
* 百度翻译工具类
* @ClassName: BDTransApiUtil.java
* @author zongf
* @date 2018年12月7日-上午11:42:26
*/
public class BDTransApiUtil {
// 百度翻译地址
private static final String TRANS_API_HOST = "https://api.fanyi.baidu.com/api/trans/vip/translate";
// 百度翻译注册应用id
private static final String APPID = "xxxxx";
// 百度翻译注册秘钥
private static final String SECURITYKEY = "xxxxx";
/**
* @Description 中文翻译成中文
* @param chineseQuery 中文
* @return 英文
* @author zongf
* @date 2018年12月7日-下午1:35:31
*/
public static String chinese2English(String chineseQuery){
// 随机数
long salt = System.currentTimeMillis();
// 签名
String src = APPID + chineseQuery + salt + SECURITYKEY; // 加密前的原文
String sign = DigestUtils.md5Hex(src);
// 构造请求参数
BDTransRequest request = new BDTransRequest();
request.setFrom("zh");
request.setTo("en");
request.setAppid(APPID);
request.setQ(chineseQuery);
request.setSalt("" + salt);
request.setSign(sign);
// 调用翻译API
String result = HttpUtil.get(TRANS_API_HOST, request.toMap());
// 解析响应结果
BDTransResponse response = JSONObject.parseObject(result, BDTransResponse.class);
// 判断错误码
if(response.getError_code() != null){
return "翻译报错-错误码:" + response.getError_code() + ",错误原因:" + response.getError_msg();
}
// 返回结果
List<BDTransResult> transResults = response.getTrans_result();
if(null != transResults && transResults.size() > 0){
return transResults.get(0).getDst();
}
return null;
}
}
3.2 请求响应类
笔者将百度翻译的请求响应都封装成java 对象, 使用JSONObject 进行解析, 这样便于操作.
public class BDTransRequest {
// 翻译源语种, 默认为中文
private String from = "zh";
// 目标语种, 默认为英文
private String to = "en";
// 百度翻译平台注册id
private String appid;
// 随机数
private String salt;
// 翻译原文, UTF-8编码
private String q;
// 数字签名=md5(appid+q+salt+密钥)
private String sign;
public Map<String, String> toMap(){
Map<String, String> map = new HashMap<String, String>();
map.put("q", this.q);
map.put("sign", this.sign);
map.put("appid", this.appid);
map.put("from", this.from);
map.put("to", this.to);
map.put("salt", this.salt);
return map;
}
// 省略 setter/getter 方法
}
public class BDTransResponse {
// 原文语种
private String from;
// 目标语种
private String to;
// 翻译结果
private List<BDTransResult> trans_result;
// 错误编码, 当报错时才有值
private String error_code;
// 错误信息, 当报错时才有值
private String error_msg;
// 省略setter/getter...
}
public class BDTransResult {
// 原文
private String src;
// 翻译
private String dst;
// 省略setter/getter...
}
3.3 http 工具类
http 工具类主要是为了发送http get 请求, 可以替换为自己的http 工具类.
import java.io.BufferedReader;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Map;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
/**
* http 工具类
* @ClassName: HttpUtil.java
* @author zongf
* @date 2018年12月7日-下午1:37:03
*/
public class HttpUtil {
// 网络代理ip
private static final String PROXY_HOST = "xxx.xxx.xxx.xxx";
// 网络代理端口号
private static final Integer PROXY_PORT = 8080;
// 网络超时时间
protected static final int SOCKET_TIMEOUT = 10000; // 10S
// http 请求方式
protected static final String HTTP_METHOD = "GET";
// x509 证书
private static TrustManager myX509TrustManager = new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
};
/**
* @Description http 发送get 请求
* @param host 请求地址
* @param params 请求参数
* @return 响应结果
* @author zongf
* @date 2018年12月7日-下午1:42:26
*/
public static String get(String host, Map<String, String> params) {
try {
// 设置SSLContext
SSLContext sslcontext = SSLContext.getInstance("TLS");
sslcontext.init(null, new TrustManager[] { myX509TrustManager }, null);
String uri = connectUrlAndParams(host, params);
HttpURLConnection conn = (HttpURLConnection) openConnection(uri);
if (conn instanceof HttpsURLConnection) {
((HttpsURLConnection) conn).setSSLSocketFactory(sslcontext.getSocketFactory());
}
conn.setConnectTimeout(SOCKET_TIMEOUT); // 设置相应超时
conn.setRequestMethod("GET"); // 设置请求方式
int statusCode = conn.getResponseCode();
if (statusCode != HttpURLConnection.HTTP_OK) {
System.out.println("Http错误码:" + statusCode);
}
// 读取服务器的数据
InputStream is = conn.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
StringBuilder builder = new StringBuilder();
String line = null;
while ((line = br.readLine()) != null) {
builder.append(line);
}
String text = builder.toString();
close(br); // 关闭数据流
close(is); // 关闭数据流
conn.disconnect(); // 断开连接
return text;
} catch ( Exception e) {
e.printStackTrace();
}
return null;
}
/**
* @Description 获取
* @param url
* @return
* @throws IOException
* @author zongf
* @date 2018年12月7日-下午1:33:27
*/
private static URLConnection openConnection(String uri) throws IOException {
URLConnection connection;
URL url = new URL(uri); // 创建URL对象
if (PROXY_HOST != null && PROXY_PORT != null) {
Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(PROXY_HOST, PROXY_PORT));
connection = url.openConnection(proxy);
} else {
connection = url.openConnection();
}
return connection;
}
/**
* @Description 拼接url和请求参数
* @param url 请求地址
* @param params 请求参数
* @return String
* @author zongf
* @date 2018年12月7日-下午1:43:12
*/
public static String connectUrlAndParams(String url, Map<String, String> params) {
if (params == null) {
return url;
}
StringBuilder builder = new StringBuilder(url);
if (url.contains("?")) {
builder.append("&");
} else {
builder.append("?");
}
int i = 0;
for (String key : params.keySet()) {
String value = params.get(key);
if (value == null) { // 过滤空的key
continue;
}
if (i != 0) {
builder.append('&');
}
builder.append(key);
builder.append('=');
builder.append(encode(value));
i++;
}
return builder.toString();
}
/**
* @Description 对输入的字符串进行URL编码, 即转换为%20这种形式
* @param input 原文
* @return URL编码. 如果编码失败, 则返回原文
* @author zongf
* @date 2018年12月7日-下午1:28:28
*/
public static String encode(String input) {
if (input == null) {
return "";
}
try {
return URLEncoder.encode(input, "utf-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return input;
}
/**
* @Description 关闭流
* @param closeable
* @author zongf
* @date 2018年12月7日-下午1:28:08
*/
private static void close(Closeable closeable) {
if (closeable != null) {
try {
closeable.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
3.4 pom 核心依赖
demo 主要依赖于apache 的加解密工具包, 和阿里巴巴的json 工具包.
<dependencies>
<!-- 提供单元测试 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!-- 提供json 解析工具 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.54</version>
</dependency>
<!-- 提供md5 加密工具 -->
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.11</version>
</dependency>
</dependencies>
4. 测试
写成静态工具类之后,直接通过类名.方法名调用即可.
public class BDTransUtilTest {
@Test
public void test() {
String result = BDTransApiUtil.chinese2English("你好");
System.out.println(result); // 输出: hello
}
}
附
由于笔者是在开发eclipse插件时用到了百度翻译, 在windows平台下,eclipse启动时默认jvm 编码为GBK ,也就是说eclipse中表单中输入的字符串都是GBK编码的,而GBK编码又不能转化为UTF8编码,因此需要修改eclipse的启动参数. 编辑eclipse.ini 文件, 添加如下配置:
-Dfile.encoding=UTF-8