HttpClient
用來提供高效的、最新的、功能豐富的支持HTTP協議的客戶端編程工具包
作用:
發送HTTP請求
接受響應數據
應用場景:
當我們在使用掃描支付、查看地圖、獲取驗證碼、查看天氣等功能時
其實,應用程序本身并未實現這些功能,都是在應用程序里訪問提供這些功能的服務,訪問這些服務需要發送HTTP請求,并且接收響應數據,可通過HttpClient來實現。
核心API:
HttpClient:Http客戶端對象類型,用該類型對象可發起Http請求
HttpClients:構建器,可創建HttpClient對象
CloseableHttpClient:實現類實現了HttpClinet接口
HttpGet:Get方式請求類型
HttpPost:Post方式請求類型
發送請求步驟:
創建HttpClient對象
創建Http請求對象
調用HttpClient的execute方法發送請求對象
入門案例
GET請求
@Test
public void testGET() throws Exception{ CloseableHttpClient httpClient = HttpClients.createDefault(); HttpGet httpGet = new HttpGet("http://localhost:8080/user/shop/status"); CloseableHttpResponse response = httpClient.execute(httpGet); int statusCode = response.getStatusLine().getStatusCode(); System.out.println("statusCode = " + statusCode); HttpEntity entity = response.getEntity(); String body = EntityUtils.toString(entity); System.out.println("body = " + body); response.close(); httpClient.close();
}
創建HttpClient對象
創建請求對象httpGet
通過httpClient.execute發送請求,接收響應結果
解析結果
關閉資源!
POST請求
@Test public void testPOST() throws Exception { CloseableHttpClient httpClient = HttpClients.createDefault(); HttpPost httpPost = new HttpPost("http://localhost:8080/admin/employee/login"); JSONObject jsonObject = new JSONObject(); jsonObject.put("username","admin"); jsonObject.put("password","123456"); StringEntity entity = new StringEntity(jsonObject.toString()); entity.setContentEncoding("utf-8"); entity.setContentType("application/json"); httpPost.setEntity(entity); CloseableHttpResponse response = httpClient.execute(httpPost); int statusCode = response.getStatusLine().getStatusCode(); System.out.println("statusCode = " + statusCode); HttpEntity entity1 = response.getEntity(); String body = EntityUtils.toString(entity1); System.out.println("body = " + body); response.close(); httpClient.close(); }
}
先創建JSON對象存儲鍵值對形式的數據
然后將JSON對象轉換為字符串,并創建一個StringEntity對象entity,并為其設置內容編碼和內容類型,并將entity對象設置為httpPost請求的請求體
通過httpPost將這個對象發送出去
使用 JSONObject
再轉換為 StringEntity
而非直接拼接 JSON 字符串,是因為JSON 對語法要求嚴格(例如引號必須是雙引號、鍵必須用雙引號包裹、特殊字符需轉義等)。如果直接手動拼接字符串(例如 "{\"username\":\"admin\",\"password\":\"123456\"}"
),雖然簡單,但存在以下風險:
- 容易出錯:如果鍵值對較多、嵌套復雜,或值中包含特殊字符(如
"
、\
、換行符等),手動拼接時容易遺漏轉義,導致生成的 JSON 格式不合法。 - 類型處理麻煩:如果值是數字、布爾值或其他對象(如日期),手動拼接需要額外處理類型轉換(例如將
123
寫成數字而非字符串),而JSONObject
會自動根據值的類型生成正確的 JSON 表示(例如數字不加引號,布爾值為true
/false
)。
JSONObject
的put
方法會自動處理這些問題,確保生成的字符串是符合 JSON 規范的格式。
微信小程序開發
使用微信開發者工具 Stable 1.06.2204250
在本地設置中選擇 調試基礎庫3.5.8可正常運行小程序,使用太新的庫可能出現白屏
微信登錄流程
@PostMapping("/login")
@ApiOperation("微信登錄")
public Result<UserLoginVO> login(@RequestBody UserLoginDTO userLoginDTO) { User user = userService.wxLogin(userLoginDTO); Map<String, Object> claims = new HashMap<>(); claims.put(JwtClaimsConstant.USER_ID, user.getId()); String token = JwtUtil.createJWT(jwtProperties.getUserSecretKey(), jwtProperties.getUserTtl(), claims); UserLoginVO userLoginVO = UserLoginVO.builder() .id(user.getId()) .token(token) .openid(user.getOpenid()) .build(); return Result.success(userLoginVO);
}
String token = JwtUtil.createJWT(jwtProperties.getUserSecretKey(), jwtProperties.getUserTtl(), claims);
:
調用JwtUtil
工具類的createJWT
方法來創建一個 JWT。傳入三個參數,第一個是jwtProperties.getUserSecretKey()
,即從jwtProperties
獲取用于簽名的用戶密鑰;第二個是jwtProperties.getUserTtl()
,從jwtProperties
獲取該 JWT 的過期時間(TTL,Time To Live);第三個參數是前面構建好的claims
,包含用戶 ID 等聲明信息。最后將創建好的 JWT 賦值給token
變量。 整體來看,這段代碼主要是在構建 JWT 相關的聲明信息,并使用特定工具類創建一個包含用戶 ID 且有過期時間設定的 JWT。 例如,假設JwtClaimsConstant.USER_ID
的值為 “user_id”,user.getId()
返回值為 12345,jwtProperties.getUserSecretKey()
返回 “my_secret_key”,jwtProperties.getUserTtl()
返回 3600(表示 1 小時過期),那么claims
就會包含 {“user_id”: 12345},最終創建的 JWT 就是基于這個聲明信息、密鑰以及 1 小時過期時間生成的。
@Component
@ConfigurationProperties(prefix = "sky.jwt")
@Data
public class JwtProperties { /** * 管理端員工生成jwt令牌相關配置 */ private String adminSecretKey; private long adminTtl; private String adminTokenName; /** * 用戶端微信用戶生成jwt令牌相關配置 */ private String userSecretKey; private long userTtl; private String userTokenName; }
sky: jwt: # 設置jwt簽名加密時使用的秘鑰 admin-secret-key: itcast # 設置jwt過期時間 admin-ttl: 7200000 # 設置前端傳遞過來的令牌名稱 admin-token-name: token user-secret-key: itheima user-ttl: 7200000 user-token-name: authentication
屬性名的自動映射規則
配置文件中的屬性名(如 admin-secret-key
)與 JwtProperties
類的字段名(如 adminSecretKey
)遵循 “寬松綁定”(Relaxed Binding) 規則:
- 配置文件中的屬性名支持多種格式(如
kebab-case
、snake_case
、camelCase
、UPPER_CASE
),最終會映射到類的camelCase
字段。 - 具體映射規則:
- 配置中的
-
(kebab-case,如admin-secret-key
) → 類字段的camelCase
(如adminSecretKey
)。 - 配置中的
_
(snake_case,如admin_secret_key
) → 類字段的camelCase
(如adminSecretKey
)。 - 配置中的全大寫(如
ADMIN_SECRET_KEY
) → 類字段的camelCase
(如adminSecretKey
)。
- 配置中的
攔截器
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {//判斷當前攔截到的是Controller的方法還是其他資源if (!(handler instanceof HandlerMethod)) {//當前攔截到的不是動態方法,直接放行return true;}//1、從請求頭中獲取令牌String token = request.getHeader(jwtProperties.getUserTokenName());//2、校驗令牌try {log.info("jwt校驗:{}", token);Claims claims = JwtUtil.parseJWT(jwtProperties.getUserSecretKey(), token);Long userId = Long.valueOf(claims.get(JwtClaimsConstant.USER_ID).toString());log.info("當前用戶的id:", userId);BaseContext.setCurrentId(userId);//3、通過,放行return true;} catch (Exception ex) {//4、不通過,響應401狀態碼response.setStatus(401);return false;}}
使用JwtUtil用密鑰解密token得到userId,將userId保存到本地
并在WebMvcConfiguration中注冊user的攔截器
商品瀏覽功能
返回前端左側的分類,點擊一下前端會將category_id發送到后端請求,通過分類id查詢菜品的功能實現顯示右側的菜品或套餐
service
/*** 條件查詢菜品和口味* @param dish* @return*/public List<DishVO> listWithFlavor(Dish dish) {List<Dish> dishList = dishMapper.list(dish);List<DishVO> dishVOList = new ArrayList<>();for (Dish d : dishList) {DishVO dishVO = new DishVO();BeanUtils.copyProperties(d,dishVO);//根據菜品id查詢對應的口味List<DishFlavor> flavors = dishFlavorMapper.getByDishId(d.getId());dishVO.setFlavors(flavors);dishVOList.add(dishVO);}return dishVOList;}
根據菜品查詢出每一道菜的不同口味,其中口味通過dishFlavorMapper的getByDishId方法查詢
總結
1.HttpClient
用于發送HTTP請求以及接收響應數據
主要用HttpGet和HttpPost
2.HttpClient流程
創建HttpClient對象
創建請求對象HttpGet(HttpPost)
通過httpClient.execute發送請求,并接受響應結果
解析結果
關閉資源
3.在使用Post請求時先創建JSON對象存儲鍵值對形式的數據
JsonObject會自動根據值的類型生成正確的JSON表達式,使用put方法能夠保證JSON規范,然后通過StringEntity(jsonObject.toString())將json轉換為stirng類型的"json",設置編碼和類型然后通過HttpClient.execute傳輸出去
4.微信登錄流程:
前端發送用戶的openid(每次都變)給后端,后端拿到后將小程序的appid的secret一起通過HttpClient發送給微信官方的服務器,官方服務器通過openid會返回這個用戶的openid(不變的),然后在數據庫查詢是否為新用戶,是的話創建一下,然后將token和id一起返回給前端,下次直接拿token和id給后端就好了
5.Jwt工具生成token的方式
通過JwtUtil工具類的createJWT方法創建,傳入三個參數:
getUserSecretKey()從配置文件中獲取用戶密鑰
getUserTtl()設置token過期時間
根據用戶id等聲明信息創建JWT復制給token
6.屬性名的自動映射
配置文件中的屬性名(如 admin-secret-key
)與 JwtProperties
類的字段名(如 adminSecretKey
)遵循 “寬松綁定”(Relaxed Binding) 規則:
- 配置文件中的屬性名支持多種格式(如
kebab-case
、snake_case
、camelCase
、UPPER_CASE
),最終會映射到類的camelCase
字段。 - 具體映射規則:
- 配置中的
-
(kebab-case,如admin-secret-key
) → 類字段的camelCase
(如adminSecretKey
)。 - 配置中的
_
(snake_case,如admin_secret_key
) → 類字段的camelCase
(如adminSecretKey
)。 - 配置中的全大寫(如
ADMIN_SECRET_KEY
) → 類字段的camelCase
(如adminSecretKey
)。
- 配置中的
7.商品瀏覽功能的邏輯
通過category/list請求返回側邊欄目的套餐項,當點擊一個套餐時通過setmeal/list返回這個套餐下的所有菜品(套餐)
在查詢菜品時點擊一個有口味的菜品,會通過dish/list查詢菜品的口味,然后合并到菜品信息中一起返回給前端