当前位置: 首页> 教育> 大学 > [苍穹外卖]-06微信登录详解

[苍穹外卖]-06微信登录详解

时间:2025/9/5 0:01:05来源:https://blog.csdn.net/CSDN20221005/article/details/142043739 浏览次数:0次

HttpClient

介绍

HttpClient是Apache Jakarta Common下的子项目, 可以用来提供高效的, 最新的,功能丰富的支持HTTP协议的客户端编程工具包, 并且支持Http协议最新的版本和建议

核心API

HttpClient: 请求对象

HttpClients: 请求对象构造器

CloseableHttpClient: 请求对象实现类

HttpGet: 发送get请求

HttpPost: 发送post请求

请求步骤

创建HttpClient对象

创建Http请求对象

代用HttpCliect的execute方法发生请求

入门案例

引入依赖: 阿里云OSS依赖已经默认引入HttpClient依赖

发送get请求

@SpringBootTest //创建测试类
public class HttpClientTest {/*** 测试通过httpclient发送get请求*/@Test // 创建测试方法public void testGET() throws IOException {// 创建httpclient对象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);HttpEntity entity = response.getEntity();String body = EntityUtils.toString(entity);System.out.println("服务端返回的数据为:" + body);// 关闭资源response.close();httpClient.close();}}

发送post请求

@SpringBootTest //创建测试类
public class HttpClientTest {/*** 测试通过httpclient发送post请求*/@Test // 创建测试方法public void testPOST() throws IOException {// 创建httpclient对象CloseableHttpClient httpClient = HttpClients.createDefault();// 创建请求对象HttpPost httpPost = new HttpPost("http://localhost:8080/admin/employee/login");// 创建请求参数 (fastjson提供的方法)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);HttpEntity entity1 = response.getEntity();String body = EntityUtils.toString(entity1);System.out.println("响应的数据为" + body);// 关闭资源response.close();httpClient.close();}}

使用工具类. 封装HttpClient的操作

/*** Http工具类*/
public class HttpClientUtil {static final  int TIMEOUT_MSEC = 5 * 1000;/*** 发送GET方式请求* @param url* @param paramMap* @return*/public static String doGet(String url,Map<String,String> paramMap){// 创建Httpclient对象CloseableHttpClient httpClient = HttpClients.createDefault();String result = "";CloseableHttpResponse response = null;try{URIBuilder builder = new URIBuilder(url);if(paramMap != null){for (String key : paramMap.keySet()) {builder.addParameter(key,paramMap.get(key));}}URI uri = builder.build();//创建GET请求HttpGet httpGet = new HttpGet(uri);//发送请求response = httpClient.execute(httpGet);//判断响应状态if(response.getStatusLine().getStatusCode() == 200){result = EntityUtils.toString(response.getEntity(),"UTF-8");}}catch (Exception e){e.printStackTrace();}finally {try {response.close();httpClient.close();} catch (IOException e) {e.printStackTrace();}}return result;}/*** 发送POST方式请求* @param url* @param paramMap* @return* @throws IOException*/public static String doPost(String url, Map<String, String> paramMap) throws IOException {// 创建Httpclient对象CloseableHttpClient httpClient = HttpClients.createDefault();CloseableHttpResponse response = null;String resultString = "";try {// 创建Http Post请求HttpPost httpPost = new HttpPost(url);// 创建参数列表if (paramMap != null) {List<NameValuePair> paramList = new ArrayList();for (Map.Entry<String, String> param : paramMap.entrySet()) {paramList.add(new BasicNameValuePair(param.getKey(), param.getValue()));}// 模拟表单UrlEncodedFormEntity entity = new UrlEncodedFormEntity(paramList);httpPost.setEntity(entity);}httpPost.setConfig(builderRequestConfig());// 执行http请求response = httpClient.execute(httpPost);resultString = EntityUtils.toString(response.getEntity(), "UTF-8");} catch (Exception e) {throw e;} finally {try {response.close();} catch (IOException e) {e.printStackTrace();}}return resultString;}/*** 发送POST方式请求* @param url* @param paramMap* @return* @throws IOException*/public static String doPost4Json(String url, Map<String, String> paramMap) throws IOException {// 创建Httpclient对象CloseableHttpClient httpClient = HttpClients.createDefault();CloseableHttpResponse response = null;String resultString = "";try {// 创建Http Post请求HttpPost httpPost = new HttpPost(url);if (paramMap != null) {//构造json格式数据JSONObject jsonObject = new JSONObject();for (Map.Entry<String, String> param : paramMap.entrySet()) {jsonObject.put(param.getKey(),param.getValue());}StringEntity entity = new StringEntity(jsonObject.toString(),"utf-8");//设置请求编码entity.setContentEncoding("utf-8");//设置数据类型entity.setContentType("application/json");httpPost.setEntity(entity);}httpPost.setConfig(builderRequestConfig());// 执行http请求response = httpClient.execute(httpPost);resultString = EntityUtils.toString(response.getEntity(), "UTF-8");} catch (Exception e) {throw e;} finally {try {response.close();} catch (IOException e) {e.printStackTrace();}}return resultString;}private static RequestConfig builderRequestConfig() {return RequestConfig.custom().setConnectTimeout(TIMEOUT_MSEC).setConnectionRequestTimeout(TIMEOUT_MSEC).setSocketTimeout(TIMEOUT_MSEC).build();}}

小程序开发

介绍

小程序是一种新的开放能力, 可以在微信内被便捷的获取和传播, 同时具有出色的使用体验

官网: https://mp.weixin.qq.com/cgi-bin/

说明: 个人身份无法开通微信支付功能

接入流程:

  1. 注册: 在微信公众平台注册小程序, 完成注册后可以同步进行信息完善和开发
  2. 信息完善: 填写小程序基本信息, 包括名称, 头像, 介绍及服务范围等
  3. 开发小程序: 完成小程序开发者绑定, 开发信息配置后, 开发者可以下载开发者工具, 参考开发文档进行开发
  4. 提交审核和发布: 完成小程序开发后, 提交代码至微信团队审核, 审核通过后即可发布

准备

注册小程序: 小程序

完善小程序信息, 获取AppID和小程序秘钥

  • AppID: wxb161c259ad057fe9
  • AppSecret(秘钥): 6695e2fc4c13a6cdd4dc87c3c3baa988

下载开发者工具, 使用开发者工具创建小程序工程

入门

目录结构: 小程序由描述整体程序的app文件和描述页面的page文件组成

  1. 小程序的主体部分由三个文件组成,
  2. 必须放在项目的根目录:
  • app.js: 小程序逻辑
  • app.json: 小程序公共配置
  • app.wxs: 小程序公共样式

小程序的页面由四个文件组成程

  1. js: 页面逻辑
  2. wxml: 页面结构
  3. json: 页面配置
  4. wxss: 页面样式表

基础语法: 了解微信小程序的基础语法

page({// 定义数据data: {mag:  'hello word',code: ''},//  获取用户信息getUserInfo() {wx.geyUserProfile({desc: '获取用户信息',success: (res) => {console.log(res.userInfo)}})},//  微信登录: 获取微信用户的授权码wxLogin() {wx.login({success: (res) => {//赋值this.setData({code: res.code})} })},// 发请请求sendRequest() {url: 'http://localhost:8080/user/shop/status',method: 'GET',success: (res)=>{console.log(res.data)  }}
})
<view>// 插值表达式:  <view>{{ msg }}</view>// 图片标签: <image style="width 100px; height: 100px;" sec="{{ url }}"></image>// 绑定事件:<button bindtap="getUserInfo"  type="primary">获取用户信息</button>
</view>

发布小程序: 点击上传按钮, 输入版本号, 提交代码到微信开发者管理后台, 在微信后台提交测试版本

上线小程序: 我们发布的小程序是开发版本 用于测试, 测试完成后, 需要提交审核, 审核通过后才能发布上线

微信登录

准备工作

导入前端代码: 使用微信开发者工具打开 mp-weixin 工程

  • 注意检查common/vendor.js文件中的baseUrl是否与后端服务一致

了解微信登录流程

登录流程:

  • wx.login()获取code
  • wx.request()把code传给后端服务器
  • 后端服务器把appid, 小程序秘钥, code授权码传给微信服务器
  • 微信服务器返回用户信息,其中最重要的是opedid
  • 后端服务器把用户信息储存起来,并生成token令牌,响应给前端
  • 前端根据登录状态进行业务操作
  1. 官网小程序登录 | 微信开放文档
  2. 测试: 可以使用微信开发者工具获取登录授权码, 使用测试工具校验微信接口

分析和设计

查看原型, 确定需求: 基于微信登录实现小程序的登录功能, 如果是新用户需要自动完成注册

接口设计

数据表设计: user表, 用户存储用户信息

  1. 个人身份的开发者无法获取微信用户的手机号

代码开发

配置微信登录所需的配置项

sky:jwt:# 设置jwt签名加密时使用的秘钥(客户端)user-secret-key: itheima# 设置jwt过期时间(客户端)user-ttl: 7200000# 设置前端传递过来的令牌名称(客户端)user-token-name: authenticationwechat:appid: ${sky.wechat.appid}secret: ${sky.wechat.secret}
sky:wechat:appid: wxb161c259ad057fe9secret: 6695e2fc4c13a6cdd4dc87c3c3baa988

配置属性类: 把配置文件中的配置信息封装在配置类的属性中, 供程序调用

// 配置属性封装类, 用于封装配置文件中的数据
// 通过注入该类, 就可以方便的在程序中使用配置类中的数据
@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;}
@Component
@ConfigurationProperties(prefix = "sky.wechat")
@Data
public class WeChatProperties {private String appid; //小程序的appidprivate String secret; //小程序的秘钥}

准备DTO: 把前端请求参数封装在DTO对象中

/*** C端用户登录*/
@Data
public class UserLoginDTO implements Serializable {private String code;}

准备VO: 把后端返回给前端的数据封装在VO对象中

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class UserLoginVO implements Serializable {private Long id;private String openid;private String token;}

Controller: 新建UserController

@RestController
@RequestMapping("/user/user")
@Api(tags = "用户相关接口")
@Slf4j
public class UserController {@Autowiredprivate UserService userService;@Autowiredprivate JwtProperties jwtProperties;@PostMapping("/login")@ApiOperation("微信登录")public Result<UserLoginVO> login(@RequestBody UserLoginDTO userLoginDTO) {log.info("微信用户登录: {}", userLoginDTO);// 微信登录User user = userService.wxLogin(userLoginDTO);// 为微信用户生成JWT令牌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()).openid(user.getOpenid()).token(token).build();return Result.success(userLoginVO);}
}

Service: 新建UserService接口和UserServiceImpl实现类

public interface UserService {/*** 微信登录* @param userLoginDTO* @return*/User wxLogin(UserLoginDTO userLoginDTO);
}
@Service
@Slf4j
public class UserServiceImpl implements UserService {// 微信服务接口地址public static final String WX_LOGIN = "https://api.weixin.qq.com/sns/jscode2session";@Autowiredprivate WeChatProperties weChatProperties;@Autowiredprivate UserMapper userMapper;/*** 微信登录** @param userLoginDTO* @return*/public User wxLogin(UserLoginDTO userLoginDTO) {// 获取openidString openid = getOpenid(userLoginDTO.getCode());// 判断openid是否为空, 如果空表示登录失败, 抛出异常if (openid == null) {throw new LoginFailedException(MessageConstant.LOGIN_FAILED);}// 判断当前用户是否为新用户User user = userMapper.getByOpenid(openid);// 新用户要实现自动注册if (user == null) {user = User.builder().openid(openid).createTime(LocalDateTime.now()).build();userMapper.insert(user);}// 返回这个用户对象return user;}/*** 调用微信接口服务, 获取微信用户的openid* @param code* @return*/private String getOpenid(String code) {// 调用微信接口服务, 获得放前微信用户的openidHashMap<String, String> map = new HashMap<>();map.put("appid", weChatProperties.getAppid());map.put("secret", weChatProperties.getSecret());map.put("js_code", code);map.put("grant_type", "authorization_code");String json = HttpClientUtil.doGet(WX_LOGIN, map);JSONObject jsonObject = JSON.parseObject(json);String openid = jsonObject.getString("openid");return openid;}
}

Mapper: 新建UserMapper

@Mapper
public interface UserMapper {/*** 根据openid查询用户* @param openid* @return*/@Select("select * from user where openid = #{openid}")User getByOpenid(String openid);/*** 新增用户* @param user*/void insert(User user);
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.sky.mapper.UserMapper"><insert id="insert" useGeneratedKeys="true" keyProperty="id">insert into user (openid, name, phone, sex, id_number, avatar, create_time)values (#{openid}, #{name}, #{phone}, #{sex}, #{idNumber}, #{avatar}, #{createTime})</insert></mapper>

JWT校验

定义拦截器

/*** jwt令牌校验的拦截器*/
@Component
@Slf4j
public class JwtTokenUserInterceptor implements HandlerInterceptor {@Autowiredprivate JwtProperties jwtProperties;/*** 校验jwt     ** @param request* @param response* @param handler* @return* @throws Exception*/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;}}
}

注册拦截器

/*** 配置类,注册web层相关组件*/
@Configuration
@Slf4j
public class WebMvcConfiguration extends WebMvcConfigurationSupport {private JwtTokenUserInterceptor jwtTokenUserInterceptor;/*** 注册自定义拦截器** @param registry*/protected void addInterceptors(InterceptorRegistry registry) {log.info("开始注册自定义拦截器...");registry.addInterceptor(jwtTokenUserInterceptor).addPathPatterns("/user/**").excludePathPatterns("/user/user/login").excludePathPatterns("/user/shop/status");}}

商品浏览

需求分析

查看产品原型

接口设计

查询分类接口

根据分类id查询菜品

根据分类id查询套餐

根据套餐id查询包含的菜品

功能实现

代码导入: day06-微信登录-商品浏览/资料/代码导入

前后端联调功能测试

关键字:[苍穹外卖]-06微信登录详解

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

责任编辑: