Trong quá trình phát triển ứng dụng Java, việc tương tác với các dịch vụ web bên ngoài thông qua giao thức HTTP là một trong những tác vụ cơ bản và thường gặp nhất. Bài viết này sẽ hướng dẫn bạn cách xây dựng và gửi các yêu cầu HTTP GET và POST, minh họa bằng các ví dụ cụ thể liên quan đến việc gọi các API của WeChat Mini Program (小程序).
1. Thực hiện yêu cầu HTTP GET để truy xuất dữ liệu
Yêu cầu GET được sử dụng để lấy thông tin từ một tài nguyên được chỉ định. Dưới đây là ví dụ minh họa cách truy vấn access_token từ API WeChat, sử dụng lớp HttpURLConnection có sẵn trong Java. Đoạn mã này sẽ xây dựng URL với các tham số cần thiết và xử lý phản hồi JSON để trích xuất token.
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.text.MessageFormat;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
public class DichVuTruyCapAPI {
private static final ObjectMapper boChuyenDoiJson = new ObjectMapper();
/**
* Lấy access_token của WeChat Mini Program.
*
* @param maUngDung ID ứng dụng Mini Program.
* @param maBiMat Khóa bí mật của ứng dụng Mini Program.
* @return Chuỗi access_token.
* @throws Exception Nếu có lỗi trong quá trình gửi yêu cầu hoặc xử lý phản hồi.
*/
public String layAccessTokenWechat(String maUngDung, String maBiMat) throws Exception {
String diaChiAPI = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={0}&secret={1}";
String urlHoanChinh = MessageFormat.format(diaChiAPI, maUngDung, maBiMat);
URL urlDichVu = new URL(urlHoanChinh);
HttpURLConnection ketNoi = null;
StringBuilder duLieuPhanHoi = new StringBuilder();
try {
ketNoi = (HttpURLConnection) urlDichVu.openConnection();
ketNoi.setRequestMethod("GET");
ketNoi.setRequestProperty("Accept", "application/json"); // Đảm bảo nhận phản hồi JSON
ketNoi.setConnectTimeout(5000); // Thiết lập thời gian chờ kết nối
ketNoi.setReadTimeout(5000); // Thiết lập thời gian chờ đọc
int maTrangThai = ketNoi.getResponseCode();
if (maTrangThai != HttpURLConnection.HTTP_OK) {
// Đọc thông báo lỗi từ luồng lỗi nếu có
try (BufferedReader docLoi = new BufferedReader(new InputStreamReader(ketNoi.getErrorStream()))) {
String dongLoi;
while ((dongLoi = docLoi.readLine()) != null) {
duLieuPhanHoi.append(dongLoi);
}
}
throw new RuntimeException("Lỗi khi gửi yêu cầu GET, mã phản hồi: " + maTrangThai + ". Chi tiết: " + duLieuPhanHoi.toString());
}
// Đọc phản hồi từ luồng đầu vào
try (BufferedReader docDuLieu = new BufferedReader(new InputStreamReader(ketNoi.getInputStream()))) {
String dong;
while ((dong = docDuLieu.readLine()) != null) {
duLieuPhanHoi.append(dong);
}
}
JsonNode nutGoc = boChuyenDoiJson.readTree(duLieuPhanHoi.toString());
if (nutGoc.has("errmsg")) {
throw new RuntimeException("API WeChat trả về lỗi: " + nutGoc.get("errmsg").asText());
}
return nutGoc.get("access_token").asText();
} finally {
if (ketNoi != null) {
ketNoi.disconnect();
}
}
}
}
2. Thực hiện yêu cầu HTTP POST để gửi dữ liệu
Yêu cầu POST được sử dụng để gửi dữ liệu tới máy chủ, thường là để tạo một tài nguyên mới hoặc cập nhật tài nguyên hiện có. Ví dụ dưới đây minh họa cách tạo mã QR không giới hạn cho Mini Program WeChat bằng cách gửi dữ liệu JSON thông qua yêu cầu POST, sử dụng java.net.http.HttpClient (có sẵn từ Java 11 trở lên).
2.1. Định nghĩa cấu trúc dữ liệu yêu cầu
Để gửi dữ liệu JSON, chúng ta cần một lớp POJO (Plain Old Java Object) để ánh xạ các trường dữ liệu. Lớp này sẽ được chuyển đổi thành chuỗi JSON trước khi gửi đi.
package com.example.wechat.dto;
import com.fasterxml.jackson.annotation.JsonProperty;
/**
* Đối tượng đại diện cho dữ liệu yêu cầu tạo mã QR Mini Program.
*/
public class YeuCauTaoMaQR {
private String canhHienThi; // Tương ứng với 'scene'
private String trangHienThi = "pages/shop/shop"; // Tương ứng với 'page'
private int chieuRong = 300; // Tương ứng với 'width'
@JsonProperty("auto_color")
private Boolean tuDongChonMau; // Tương ứng với 'auto_color'
@JsonProperty("line_color")
private CauHinhMauSac duongVienMau; // Tương ứng với 'line_color'
// Constructors
public YeuCauTaoMaQR() {}
public YeuCauTaoMaQR(String canhHienThi, String trangHienThi, int chieuRong, Boolean tuDongChonMau, CauHinhMauSac duongVienMau) {
this.canhHienThi = canhHienThi;
this.trangHienThi = trangHienThi;
this.chieuRong = chieuRong;
this.tuDongChonMau = tuDongChonMau;
this.duongVienMau = duongVienMau;
}
// Getters and Setters
public String getCanhHienThi() {
return canhHienThi;
}
public void setCanhHienThi(String canhHienThi) {
this.canhHienThi = canhHienThi;
}
public String getTrangHienThi() {
return trangHienThi;
}
public void setTrangHienThi(String trangHienThi) {
this.trangHienThi = trangHienThi;
}
public int getChieuRong() {
return chieuRong;
}
public void setChieuRong(int chieuRong) {
this.chieuRong = chieuRong;
}
public Boolean getTuDongChonMau() {
return tuDongChonMau;
}
public void setTuDongChonMau(Boolean tuDongChonMau) {
this.tuDongChonMau = tuDongChonMau;
}
public CauHinhMauSac getDuongVienMau() {
return duongVienMau;
}
public void setDuongVienMau(CauHinhMauSac duongVienMau) {
this.duongVienMau = duongVienMau;
}
}
/**
* Đối tượng đại diện cho cấu hình màu sắc RGB.
*/
class CauHinhMauSac {
public int r = 0;
public int g = 0;
public int b = 0;
// Constructors
public CauHinhMauSac() {}
public CauHinhMauSac(int r, int g, int b) {
this.r = r;
this.g = g;
this.b = b;
}
// Getters and Setters
public int getR() { return r; }
public void setR(int r) { this.r = r; }
public int getG() { return g; }
public void setG(int g) { this.g = g; }
public int getB() { return b; }
public void setB(int b) { this.b = b; }
}
2.2. Gửi yêu cầu POST để tạo mã QR
Sử dụng HttpClient của Java 11 để gửi yêu cầu POST. Dữ liệu từ POJO YeuCauTaoMaQR sẽ được chuyển đổi thành chuỗi JSON và gửi trong phần thân yêu cầu.
package com.example.wechat.service;
import java.io.InputStream;
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 com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.JsonNode;
import com.example.wechat.dto.YeuCauTaoMaQR;
import com.example.wechat.dto.CauHinhMauSac;
import com.example.wechat.DichVuTruyCapAPI; // Import the GET service
public class DichVuTaoMaQR {
private static final HttpClient trinhKhachHTTP = HttpClient.newBuilder().build();
private static final ObjectMapper boChuyenDoiJson = new ObjectMapper();
private final DichVuTruyCapAPI dichVuAccessToken;
public DichVuTaoMaQR(DichVuTruyCapAPI dichVuAccessToken) {
this.dichVuAccessToken = dichVuAccessToken;
}
/**
* Tạo mã QR không giới hạn cho Mini Program.
*
* @param maNhaHang ID nhà hàng.
* @param soBan Số bàn.
* @param maSoBan ID số bàn.
* @return InputStream chứa dữ liệu hình ảnh mã QR.
* @throws Exception Nếu có lỗi trong quá trình tạo hoặc gửi yêu cầu.
*/
public InputStream taoMaQRKhongGioiHan(Integer maNhaHang, String soBan, Integer maSoBan) throws Exception {
// Giả định rằng maUngDung và maBiMat được quản lý ở đâu đó.
String tokenTruyCap = dichVuAccessToken.layAccessTokenWechat("your_appid", "your_secret"); // Sử dụng dịch vụ GET
YeuCauTaoMaQR yeuCauMaQR = new YeuCauTaoMaQR();
String chuoiCanhHienThi = String.format("%d*%d*%s", maNhaHang, maSoBan, soBan);
yeuCauMaQR.setCanhHienThi(chuoiCanhHienThi);
yeuCauMaQR.setTuDongChonMau(true);
yeuCauMaQR.setDuongVienMau(new CauHinhMauSac(0, 0, 0)); // Thiết lập màu đen cho đường viền
String duLieuJson = boChuyenDoiJson.writeValueAsString(yeuCauMaQR);
String diaChiAPIQRCode = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=" + tokenTruyCap;
HttpRequest yeuCauHTTP = HttpRequest.newBuilder()
.uri(URI.create(diaChiAPIQRCode))
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(duLieuJson, StandardCharsets.UTF_8))
.build();
HttpResponse<InputStream> phanHoiHTTP = trinhKhachHTTP.send(yeuCauHTTP, HttpResponse.BodyHandlers.ofInputStream());
int maTrangThai = phanHoiHTTP.statusCode();
if (maTrangThai != 200) {
// Đọc phản hồi lỗi để biết chi tiết nếu có
try (InputStream errorStream = phanHoiHTTP.body()) {
String errorBody = new String(errorStream.readAllBytes(), StandardCharsets.UTF_8);
JsonNode errorJson = boChuyenDoiJson.readTree(errorBody);
if (errorJson.has("errmsg")) {
throw new RuntimeException("Lỗi từ API WeChat khi tạo mã QR: " + errorJson.get("errmsg").asText());
} else {
throw new RuntimeException("Lỗi không xác định khi tạo mã QR, mã trạng thái: " + maTrangThai + ", phản hồi: " + errorBody);
}
}
}
return phanHoiHTTP.body(); // Trả về InputStream chứa hình ảnh mã QR
}
}