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查询菜品的口味,然后合并到菜品信息中一起返回给前端