代码拉取完成,页面将自动刷新
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.time.Instant;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
public class RedInvoiceExample {
private static final String BASE_URL = "https://api.fa-piao.com";
/**
* 示例入口,演示POST multipart/form-data请求
*/
public static void main(String[] args) throws Exception {
try {
String appKey = "";
String appSecret = "";
String nsrsbh = "";//统一社会信用代码
String title = "";//名称(营业执照)
String username = "";//手机号码(电子税务局)
String password = "";//密码(电子税务局)
String type = "7";//6基础版 7标准
String token = "";
String fphm = "26502000000536415466";
String kprq = "";
System.setOut(new PrintStream(System.out, true, "UTF-8"));
System.out.println("java " + System.getProperty("java.version"));
if(token.isEmpty()) {// 获取token 建议redis缓存 30天
/*
* 获取授权Token文档
* @see https://fa-piao.com/doc.html#api1?source=github
*/
Map<String, Object> formData = new LinkedHashMap<>();
formData.put("nsrsbh", nsrsbh);
formData.put("type", type);
// formData.put("username", username);
// formData.put("password", password);
/*
* 获取授权Token文档
* @see https://fa-piao.com/doc.html#api1?source=github
*/
ApiResponse tokenResponse = postRequest("/v5/enterprise/authorization",formData,"" ,appKey, appSecret);
token = tokenResponse.getTokenString();
if (token == null || token.isEmpty()) {
System.out.println("获取授权失败:" + tokenResponse.getMsg());
return;
}
}
Map<String, Object> queryParams = new LinkedHashMap<>();
queryParams.put("nsrsbh", nsrsbh);
queryParams.put("fphm", fphm);
queryParams.put("username", username);
queryParams.put("sqyy", "2");
if (kprq != null && !kprq.isEmpty()) {
queryParams.put("kprq", kprq);
}
/*
* 1. 数电申请红字前查蓝票信息接口
* @link https://fa-piao.com/doc.html#api8?source=github
*/
ApiResponse queryResponse = postRequest("/v5/enterprise/retMsg", queryParams, token, appKey, appSecret);
if (queryResponse.getCode() != 200) {
System.out.println(queryResponse.getCode() + " 查询蓝票失败:" + queryResponse.getMsg());
System.out.println(queryResponse.getBody());
return;
}
System.out.println("1 可以申请红字");
Map<String, Object> applyParams = new LinkedHashMap<>();
applyParams.put("xhdwsbh", nsrsbh);
applyParams.put("yfphm", fphm);
applyParams.put("username", username);
applyParams.put("sqyy", "2");
applyParams.put("chyydm", "01");
/*
* 2. 申请红字信息表
* @link https://fa-piao.com/doc.html#api9?source=github
*/
ApiResponse applyResponse = postRequest("/v5/enterprise/hzxxbsq", applyParams, token, appKey, appSecret);
if (applyResponse.getCode() != 200) {
System.out.println(applyResponse.getCode() + " 申请红字信息表失败:" + applyResponse.getMsg());
System.out.println(applyResponse.getBody());
return;
}
String xxbbh = applyResponse.getDataString("xxbbh");
if (xxbbh == null || xxbbh.isEmpty()) {
System.out.println("红字信息表缺少字段: xxbbh");
System.out.println(applyResponse.getBody());
return;
}
System.out.println("2 申请红字信息表成功");
Map<String, Object> redParams = new LinkedHashMap<>();
redParams.put("fpqqlsh", "red" + fphm);
redParams.put("username", username);
redParams.put("xhdwsbh", nsrsbh);
redParams.put("tzdbh", xxbbh);
redParams.put("yfphm", fphm);
/*
* 3. 开具红字发票
* @link https://fa-piao.com/doc.html#api10?source=github
*/
ApiResponse redResponse = postRequest("/v5/enterprise/hzfpkj", redParams, token, appKey, appSecret);
if (redResponse.getCode() == 200) {
System.out.println("3 负数开具成功");
} else {
System.out.println(redResponse.getCode() + " 数电票负数开具失败:" + redResponse.getMsg());
System.out.println(redResponse.getBody());
}
} catch (Exception e) {
System.out.println("请求异常:" + e.getMessage());
e.printStackTrace();
}
}
/**
* post 请求
*/
public static ApiResponse postRequest(String path,Map<String, Object> formData, String token, String appKey, String appSecret) throws Exception {
String randomString = generateRandomString(20);
String timestamp = String.valueOf(Instant.now().getEpochSecond());
String signature = calculateSignature("POST", path, randomString, timestamp,appKey,appSecret);
Map<String, String> headers = new LinkedHashMap<>();
headers.put("AppKey", appKey);
headers.put("Sign", signature);
headers.put("TimeStamp", timestamp);
headers.put("RandomString", randomString);
if (token != null && !token.isEmpty()) {
headers.put("Authorization", "Bearer " + token);
}
return postMultipart(path, headers, formData);
}
/**
* 发送POST multipart/form-data请求
*/
public static ApiResponse postMultipart(String path, Map<String, String> headers, Map<String, Object> formData)
throws IOException {
String boundary = "----JavaFormBoundary" + generateRandomString(24);
byte[] body = buildMultipartBody(formData, boundary);
String urlString = BASE_URL + path;
HttpURLConnection connection = openConnection(urlString, "POST", headers);
connection.setDoOutput(true);
connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
connection.setRequestProperty("Content-Length", String.valueOf(body.length));
connection.getOutputStream().write(body);
connection.getOutputStream().flush();
connection.getOutputStream().close();
return readResponse(connection);
}
/**
* 生成随机字符串
*/
private static String generateRandomString(int length) {
SecureRandom random = new SecureRandom();
String chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
StringBuilder sb = new StringBuilder();
for(int i=0; i<length; i++) {
int index = random.nextInt(chars.length());
sb.append(chars.charAt(index));
}
return sb.toString();
}
/**
* 计算签名
*/
private static String calculateSignature(String method, String path,
String randomString, String timestamp,
String appKey, String appSecret)
throws Exception {
String content = String.format(
"Method=%s&Path=%s&RandomString=%s&TimeStamp=%s&AppKey=%s",
method, path, randomString, timestamp, appKey
);
Mac sha256 = Mac.getInstance("HmacSHA256");
SecretKeySpec secretKey = new SecretKeySpec(appSecret.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
sha256.init(secretKey);
byte[] hash = sha256.doFinal(content.getBytes(StandardCharsets.UTF_8));
return bytesToHex(hash).toUpperCase();
}
/**
* 字节转十六进制字符串
*/
private static String bytesToHex(byte[] hash) {
StringBuilder hexString = new StringBuilder();
for (byte b : hash) {
String hex = Integer.toHexString(0xff & b);
if (hex.length() == 1) hexString.append('0');
hexString.append(hex);
}
return hexString.toString();
}
public static class ApiResponse {
private final int statusCode;
private final String body;
private final Map<String, List<String>> headers;
private final Object json;
public ApiResponse(int statusCode, String body, Map<String, List<String>> headers) {
this.statusCode = statusCode;
this.body = body;
this.headers = headers;
this.json = parseJson(body);
}
public int getStatusCode() {
return statusCode;
}
public String getBody() {
return body;
}
public Map<String, List<String>> getHeaders() {
return headers;
}
public boolean isJson() {
return json != null;
}
public int getCode() {
Object value = getJsonValue("code");
if (value instanceof Number) {
return ((Number) value).intValue();
}
return 0;
}
public String getMsg() {
Object value = getJsonValue("msg");
if (value == null) {
value = getJsonValue("message");
}
return value == null ? null : String.valueOf(value);
}
public Object getData() {
return getJsonValue("data");
}
public Object getDataValue(String key) {
Object data = getData();
if (!(data instanceof Map)) {
return null;
}
return ((Map<?, ?>) data).get(key);
}
public String getDataString(String key) {
Object value = getDataValue(key);
return value == null ? null : String.valueOf(value);
}
public String getDataAsString() {
Object data = getData();
if (data == null) {
return null;
}
if (data instanceof String || data instanceof Number || data instanceof Boolean) {
return String.valueOf(data);
}
return null;
}
public String getTokenString () {
Object data = getData();
if (data instanceof Map) {
Object token = ((Map<?, ?>) data).get("token");
return token == null ? "" : String.valueOf(token);
}
return "";
}
public Object getJson() {
return json;
}
private Object getJsonValue(String key) {
if (!(json instanceof Map)) {
return null;
}
return ((Map<?, ?>) json).get(key);
}
private static Object parseJson(String text) {
if (text == null) {
return null;
}
String trimmed = text.trim();
if (trimmed.isEmpty()) {
return null;
}
if (trimmed.charAt(0) != '{' && trimmed.charAt(0) != '[') {
return null;
}
try {
return new JsonParser(trimmed).parse();
} catch (Exception e) {
return null;
}
}
}
private static class JsonParser {
private final String text;
private int index;
JsonParser(String text) {
this.text = text;
this.index = 0;
}
Object parse() {
skipWhitespace();
Object value = parseValue();
skipWhitespace();
return value;
}
private Object parseValue() {
skipWhitespace();
if (index >= text.length()) {
return null;
}
char c = text.charAt(index);
if (c == '{') {
return parseObject();
}
if (c == '[') {
return parseArray();
}
if (c == '"') {
return parseString();
}
if (c == 't' || c == 'f' || c == 'n') {
return parseLiteral();
}
return parseNumber();
}
private Map<String, Object> parseObject() {
Map<String, Object> map = new LinkedHashMap<>();
index++;
skipWhitespace();
if (peek('}')) {
index++;
return map;
}
while (index < text.length()) {
skipWhitespace();
String key = parseString();
skipWhitespace();
expect(':');
Object value = parseValue();
map.put(key, value);
skipWhitespace();
if (peek(',')) {
index++;
continue;
}
if (peek('}')) {
index++;
break;
}
}
return map;
}
private List<Object> parseArray() {
List<Object> list = new java.util.ArrayList<>();
index++;
skipWhitespace();
if (peek(']')) {
index++;
return list;
}
while (index < text.length()) {
Object value = parseValue();
list.add(value);
skipWhitespace();
if (peek(',')) {
index++;
continue;
}
if (peek(']')) {
index++;
break;
}
}
return list;
}
private String parseString() {
expect('"');
StringBuilder sb = new StringBuilder();
while (index < text.length()) {
char c = text.charAt(index++);
if (c == '"') {
break;
}
if (c == '\\') {
if (index >= text.length()) {
break;
}
char esc = text.charAt(index++);
switch (esc) {
case '"':
sb.append('"');
break;
case '\\':
sb.append('\\');
break;
case '/':
sb.append('/');
break;
case 'b':
sb.append('\b');
break;
case 'f':
sb.append('\f');
break;
case 'n':
sb.append('\n');
break;
case 'r':
sb.append('\r');
break;
case 't':
sb.append('\t');
break;
case 'u':
sb.append(parseUnicode());
break;
default:
sb.append(esc);
break;
}
} else {
sb.append(c);
}
}
return sb.toString();
}
private char parseUnicode() {
if (index + 4 > text.length()) {
return '?';
}
String hex = text.substring(index, index + 4);
index += 4;
try {
return (char) Integer.parseInt(hex, 16);
} catch (Exception e) {
return '?';
}
}
private Object parseLiteral() {
if (text.startsWith("true", index)) {
index += 4;
return Boolean.TRUE;
}
if (text.startsWith("false", index)) {
index += 5;
return Boolean.FALSE;
}
if (text.startsWith("null", index)) {
index += 4;
return null;
}
return null;
}
private Number parseNumber() {
int start = index;
boolean dot = false;
boolean exp = false;
if (peek('-')) {
index++;
}
while (index < text.length()) {
char c = text.charAt(index);
if (c >= '0' && c <= '9') {
index++;
continue;
}
if (c == '.' && !dot) {
dot = true;
index++;
continue;
}
if ((c == 'e' || c == 'E') && !exp) {
exp = true;
index++;
if (peek('+') || peek('-')) {
index++;
}
continue;
}
break;
}
String num = text.substring(start, index);
try {
if (dot || exp) {
return Double.parseDouble(num);
}
return Long.parseLong(num);
} catch (Exception e) {
return 0;
}
}
private void skipWhitespace() {
while (index < text.length()) {
char c = text.charAt(index);
if (c == ' ' || c == '\n' || c == '\r' || c == '\t') {
index++;
continue;
}
break;
}
}
private void expect(char c) {
if (index < text.length() && text.charAt(index) == c) {
index++;
}
}
private boolean peek(char c) {
return index < text.length() && text.charAt(index) == c;
}
}
/**
* 构建multipart/form-data请求体
*/
private static byte[] buildMultipartBody(Map<String, Object> data, String boundary) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
for (Map.Entry<String, Object> entry : data.entrySet()) {
writeString(out, "--" + boundary + "\r\n");
writeString(out, "Content-Disposition: form-data; name=\"" + entry.getKey() + "\"\r\n\r\n");
Object value = entry.getValue();
writeString(out, value == null ? "" : String.valueOf(value));
writeString(out, "\r\n");
}
writeString(out, "--" + boundary + "--\r\n");
return out.toByteArray();
}
/**
* 创建并初始化HTTP连接
*/
private static HttpURLConnection openConnection(String urlString, String method, Map<String, String> headers)
throws IOException {
HttpURLConnection connection = (HttpURLConnection) new URL(urlString).openConnection();
connection.setRequestMethod(method);
connection.setUseCaches(false);
if (headers != null) {
for (Map.Entry<String, String> entry : headers.entrySet()) {
connection.setRequestProperty(entry.getKey(), entry.getValue());
}
}
return connection;
}
/**
* 读取HTTP响应内容
*/
private static ApiResponse readResponse(HttpURLConnection connection) throws IOException {
int statusCode = connection.getResponseCode();
byte[] bytes;
if (statusCode >= 200 && statusCode < 400) {
bytes = readAllBytes(connection.getInputStream());
} else {
bytes = readAllBytes(connection.getErrorStream());
}
String body = bytes == null ? "" : new String(bytes, StandardCharsets.UTF_8);
return new ApiResponse(statusCode, body, connection.getHeaderFields());
}
/**
* 读取输入流为字节数组
*/
private static byte[] readAllBytes(java.io.InputStream in) throws IOException {
if (in == null) {
return null;
}
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte[] buffer = new byte[4096];
int len;
while ((len = in.read(buffer)) != -1) {
out.write(buffer, 0, len);
}
in.close();
return out.toByteArray();
}
/**
* 按UTF-8写入字符串
*/
private static void writeString(ByteArrayOutputStream out, String value) throws IOException {
out.write(value.getBytes(StandardCharsets.UTF_8));
}
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。