[javafx] 多源翻译工具 05.有道翻译

有道翻译返回的结果是 json,为了处理json,需要引入 jackson(当然,如果你喜欢别的json工具也可以,参考本篇,将你用的json 工具类处理一下即可)

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>dev.guu</groupId>
    <artifactId>fx-translate-box</artifactId>
    <version>1.0</version>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.openjfx</groupId>
            <artifactId>javafx-controls</artifactId>
            <version>17.0.2</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.13.3</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.22</version>
        </dependency>

    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>17</source>
                    <target>17</target>
                    <encoding>utf-8</encoding>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-assembly-plugin</artifactId>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>single</goal>
                        </goals>
                        <configuration>
                            <archive>
                                <manifest>
                                    <mainClass>
                                        dev.guu.fx.translate.box.AppStarter
                                    </mainClass>
                                </manifest>
                            </archive>
                            <descriptorRefs>
                                <descriptorRef>jar-with-dependencies</descriptorRef>
                            </descriptorRefs>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

json 处理工具类

package dev.guu.kit.string;

import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.core.json.JsonReadFeature;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.json.JsonMapper;
import lombok.SneakyThrows;

/**
 * @author guweichao json相关工具集
 * @since
 *  2019年6月28日
 */
public class JsonKit {
    private final static String lineSeparator = System.lineSeparator();
    private final static ThreadLocal<ObjectMapper> mapper = ThreadLocal
            .withInitial(() -> JsonMapper.builder().disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
                    .enable(JsonReadFeature.ALLOW_UNESCAPED_CONTROL_CHARS).build()
                    .setSerializationInclusion(Include.NON_EMPTY));

    @SneakyThrows
    public static String toJson(Object obj) {
        return mapper.get().writeValueAsString(obj);
    }
    @SneakyThrows
    public static String toJsonFormat(Object obj) {
        return mapper.get().writerWithDefaultPrettyPrinter().writeValueAsString(obj);
    }

    @SneakyThrows
    public static <T> T toBean(String json, Class<T> clz) {
        return mapper.get().readValue(json, clz);
    }
 
}

AppStarter

package dev.guu.fx.translate.box;

import javafx.application.Application;


public class AppStarter {


    public static void main(String[] args) {
        Application.launch(BoxMain.class,args);
    }

}

MainBox

package dev.guu.fx.translate.box;

import dev.guu.fx.translate.box.youdao.YoudaoV3;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.stage.Stage;


public class BoxMain extends Application {


    private Stage primaryStage;
    private TextArea inputTextArea;

    @Override
    public void start(Stage primaryStage) throws Exception {
        this.primaryStage = primaryStage;
        Pane root = new VBox();
        Scene scene = new Scene(root, 800, 600);
        primaryStage.setTitle("翻译工具箱");
        primaryStage.setScene(scene);
        primaryStage.show();
        createInputTextArea(root);
        createOutput(root);
    }

    private void createInputTextArea(Pane root) {
        inputTextArea = new TextArea();
        inputTextArea.setPromptText("请输入要翻译的文本...");
        inputTextArea.setPrefHeight(200);
        VBox box = new VBox(inputTextArea);
        root.getChildren().add(box);
        primaryStage.widthProperty().addListener((obs, oldV, newV) -> inputTextArea.setPrefWidth(newV.doubleValue()));
    }

    private void createOutput(Pane root) {

        HBox box = new HBox();
        root.getChildren().add(box);
        createYoudao(box);
    }


    private void createYoudao(HBox parent) {
        Label label = new Label("有道翻译:");
        Button btn = new Button("翻译");

        label.setFont(Font.font("微软雅黑", 24));
        TextArea output = new TextArea();
        output.setPromptText("等待输入...");
        output.setEditable(false);
        output.setFont(Font.font("宋体", 20));
        parent.getChildren().add(new VBox(label,btn, output));
        btn.setOnMouseClicked(e -> {
            String text = inputTextArea.getText();
            if (isBlank(text)) {
                output.setText("请输入");
            } else {
                output.setText("翻译中...");
                // fx的多线程 ,
                Platform.runLater(() -> {
                    String trans = YoudaoV3.translate(text);
                    output.setText(trans);
                });

            }
        });

    }


    boolean isBlank(String s) {
        return s == null || s.isBlank();
    }


}

有道翻译结果 json 处理需要的文件

package dev.guu.fx.translate.box.youdao;

import lombok.Data;
import lombok.experimental.Accessors;

import java.util.List;

@Data
@Accessors(chain = true)
public class YoudaoRoot {
    private List<String> translation;

    private List<YoudaoKeyValue> web;

}

package dev.guu.fx.translate.box.youdao;

import lombok.Data;

import java.util.List;

@Data

public class YoudaoKeyValue {
    private String key;
    private List<String> value;
}

有道翻译工具类(注意,个人API id和secret为私人信息,你需要自行申请)

有道智云控制台 (youdao.com) ai.youdao.com/console/#/

package dev.guu.fx.translate.box.youdao;

import dev.guu.kit.string.JsonKit;
import dev.guu.kit.string.StringKit;
import lombok.SneakyThrows;

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Map;
import java.util.StringJoiner;


public class YoudaoV3 {



    private static final String APP_KEY = "替换成你的appId";
    private static final String APP_SECRET = "替换为你的 appSecret";















    private static final String YOUDAO_URL = "https://openapi.youdao.com/api?";
    public static String translate(String text) {

        Map<String, String> params = new HashMap<>();
        long ms = System.currentTimeMillis();
        String salt = String.valueOf(ms);
        params.put("from", "auto");
        params.put("to", StringKit.isEn(text) ? "zh-CHS":"en");
        params.put("signType", "v3");
        String curtime = String.valueOf(ms / 1000);
        params.put("curtime", curtime);
        String signStr = APP_KEY + truncate(text) + salt + curtime + APP_SECRET;
        String sign = getDigest(signStr);
        params.put("appKey", APP_KEY);
        params.put("q", text);
        params.put("salt", salt);
        params.put("sign", sign);
//        params.put("vocabId", "您的用户词表ID");
        /** 处理结果 */
        return requestForHttp(YOUDAO_URL, params);
    }


    @SneakyThrows
    public static String requestForHttp(String url, Map<String, String> params)  {
        StringJoiner sj = new StringJoiner("&");
        params.forEach((k, v) -> sj.add(k + "=" + StringKit.encode(v)));

        url += sj.toString();
        HttpClient client = HttpClient.newHttpClient();
        HttpRequest request = HttpRequest.newBuilder()
                .POST(HttpRequest.BodyPublishers.ofString("a"))
                .setHeader("Content-type", "application/json; charset=UTF-8")
                .uri(URI.create(url)).build();
        HttpResponse<String> send = client.send(request, HttpResponse.BodyHandlers.ofString());
        String body = send.body();
        System.out.println(body);
        YoudaoRoot root = JsonKit.toBean(body, YoudaoRoot.class);
        System.out.println(root);
        return JsonKit.toJsonFormat(root);
    }

    /**
     * 生成加密字段
     */
      static String getDigest(String string) {
        if (string == null) {
            return null;
        }
        char hexDigits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
        byte[] btInput = string.getBytes(StandardCharsets.UTF_8);
        try {
            MessageDigest mdInst = MessageDigest.getInstance("SHA-256");
            mdInst.update(btInput);
            byte[] md = mdInst.digest();
            int j = md.length;
            char str[] = new char[j * 2];
            int k = 0;
            for (byte byte0 : md) {
                str[k++] = hexDigits[byte0 >>> 4 & 0xf];
                str[k++] = hexDigits[byte0 & 0xf];
            }
            return new String(str);
        } catch (NoSuchAlgorithmException e) {
            return null;
        }
    }


    public static String truncate(String q) {
        if (q == null) {
            return null;
        }
        int len = q.length();
        return len <= 20 ? q : (q.substring(0, 10) + len + q.substring(len - 10, len));
    }
}