H5移动端.md 10 KB

1. 运行前端页面

1. 将页面放入nginx中

将准备好的页面,放入nginx 根目录下

image-2022121210182343545

1.2 配置nginx.conf(无反向代理)

server {
    listen       8989;
    server_name  localhost;

    #charset koi8-r;

    #access_log  logs/host.access.log  main;

    location / {
        root   h5;
        index  index.html index.htm;
    }
}

重要! 访问首页 之后 点击我的 设置 修改 base路径 改为当前网关地址 http://api.gmall.com

1.3 配置nginx.conf(反向代理)

nginx.conf

#配置集群列表 默认负载均衡策略为轮询
upstream gatewayUpstream {
    #server 127.0.0.1:7777 weight=3;
    #server 127.0.0.1:8888 weight=1;
    #server 127.0.0.1:9999 weight=1;
    server 127.0.0.1:80;
    server 127.0.0.1:81;
}

配置监听/api地址

    server {
        listen       8989;
        server_name  localhost;

        #charset koi8-r;

        #access_log  logs/host.access.log  main;

        location / {
            root   h5;
            index  index.html index.htm;
        }
		
		# 监听经过Nginx地址带 /api 全部转发到网关集群
		location /api {
		   proxy_pass http://gatewayUpstream;
		}
}

移动端修改访问地址:改为Nginx

image-20230320101013366

2. 启动项目测试

ServerGatewayApplication :80/

ServiceProductApplication [devtools] :8206/

ServiceListApplication [devtools] :8203/

ServiceItemApplication [devtools] :8202/

2. 商品检索

查看首页,分类,商品检索:

2.1 动态路由

在网关中添加动态路由配置

        - id: service-list
          uri: lb://service-list
          predicates:
            - Path=/*/list/** # 路径匹配

2.2 添加搜索分类接口

service-product模块中ProductApiController

/**
 * 提供给H5移动端查询分类接口
 * @return
 */
@GetMapping("/getBaseCategoryList")
public Result getBaseCategoryListForH5(){
    //  调用服务层方法
    List<JSONObject> list = baseCategoryViewService.getBaseCategoryList();
    return Result.ok(list);
}

2.3 搜索接口

  1. 小程序端检索请求地址

    image-20230319204843472

  2. service-list模块中ListApiController检索商品方法增加映射路径

image-20230319205049638

  1. 分类加载效果如下

image-20230319205200477

  1. 关键字检索,排序效果

image-20230319205247218

3. 购物车模块修改:

service-cart模块中

全选:get:/api/cart/allCheckCart/{isChecked}

CartApiController

/**
 * 提供给移动端 全选/全部取消 购物车数据
 *
 * @param isChecked
 * @param request
 * @return
 */
@GetMapping("/allCheckCart/{isChecked}")
public Result allCheckCart(@PathVariable Integer isChecked, HttpServletRequest request) {
    //  获取用户Id
    String userId = AuthContextHolder.getUserId(request);
    //  判断用户Id 为空
    if (StringUtils.isBlank(userId)) {
        userId = AuthContextHolder.getUserTempId(request);
    }
    //  调用方法
    this.cartService.allCheckCart(userId, isChecked);
    //  默认返回
    return Result.ok();
}

CartService

/**
 * 提供给移动端 全选购物车数据
 *
 * @param isChecked
 * @return
 */
void allCheckCart(String userId, Integer isChecked);

CartServiceImpl

/**
 * 全选 全部取消勾选
 *
 * @param userId
 * @param isChecked
 */
@Override
public void allCheckCart(String userId, Integer isChecked) {
    //1.构建用户购物车hash结构redisKey
    String cartKey = getCartKey(userId.toString());
    BoundHashOperations<String, String, CartInfo> hashOps = redisTemplate.boundHashOps(cartKey);
    //2.查询所有购物车商品列表
    List<CartInfo> cartInfoList = hashOps.values();

    //3.修改选中状态
    if (!CollectionUtils.isEmpty(cartInfoList)) {
        for (CartInfo cartInfo : cartInfoList) {
            cartInfo.setIsChecked(isChecked);
            hashOps.put(cartInfo.getSkuId().toString(), cartInfo);
        }
    }
}

清空: /api/cart/clearCart

CartApiController

/**
 * 清空购物车商品
 * @param request
 * @return
 */
@GetMapping("clearCart")
public Result clearCart(HttpServletRequest request){
    // 如何获取userId
    String userId = AuthContextHolder.getUserId(request);
    if (StringUtils.isBlank(userId)) {
        // 获取临时用户Id
        userId = AuthContextHolder.getUserTempId(request);
    }
    cartService.clearCart(userId);
    return Result.ok();
}

CartService

/**
 * 清空购物车
 * @param userId
 */
void clearCart(String userId);

CartServiceImpl

/**
 * 清空购物车
 * @param userId
 */
@Override
public void clearCart(String userId) {
    //  获取购物车key
    String cartKey = getCartKey(userId);
    //  删除数据
    redisTemplate.delete(cartKey);
}

4. 登录模块

登录模块信息发生变化:

将原来的接收对象UserInfo 改为LoginVo

package com.atguigu.gmall.user.model;

import com.atguigu.gmall.base.model.BaseEntity;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

@Data
@ApiModel(description = "userInfo")
@TableName("user_info")
public class UserInfo extends BaseEntity {
    private static final long serialVersionUID = 1L;

    @ApiModelProperty(value = "用户名称")
    @TableField("login_name")
    private String loginName;

    @ApiModelProperty(value = "用户昵称")
    @TableField("nick_name")
    private String nickName;

    @ApiModelProperty(value = "用户密码")
    @TableField("passwd")
    private String passwd;

    @ApiModelProperty(value = "用户姓名")
    @TableField("name")
    private String name;

    @ApiModelProperty(value = "手机号")
    @TableField("phone_num")
    private String phoneNum;

    @ApiModelProperty(value = "邮箱")
    @TableField("email")
    private String email;

    @ApiModelProperty(value = "头像")
    @TableField("head_img")
    private String headImg;

    @ApiModelProperty(value = "用户级别")
    @TableField("user_level")
    private String userLevel;

}

service-userPassportController

/**
 * 用户登录接口:提供给PC端小程序端使用
 * @param loginVo
 * @return
 */
@PostMapping("/passport/login")
public Result login(@RequestBody LoginVo loginVo, HttpServletRequest request){
    return userInfoService.login(loginVo, request);
}

UserInfoService

/**
 * 用户登录
 * @param loginUser
 * @param request
 * @return
 */
//Result login(UserInfo loginUser, HttpServletRequest request);
Result login(LoginVo loginVo, HttpServletRequest request);

UserInfoServiceImpl

/**
 * 用户登录
 *
 * @param userInfo loginName可以是账号,邮箱,手机号
 * @param request
 * @return
 */
@Override
public Map<String, Object> login(UserInfo userInfo, HttpServletRequest request) {
    String userEnterPwd = "";
    //1.根据用户提交账号查询用户记录-可以是登录账号,手机号,或者邮箱均可以
    LambdaQueryWrapper<UserInfo> queryWrapper = new LambdaQueryWrapper<>();
    if(StringUtils.isNotBlank(userInfo.getPhone()) && StringUtils.isNotBlank(userInfo.getPassword())){
        //说明手机端登录
        queryWrapper.eq(UserInfo::getPhoneNum, userInfo.getPhone());
        userEnterPwd = DigestUtils.md5DigestAsHex(userInfo.getPassword().getBytes());
    }else{
        queryWrapper.eq(UserInfo::getLoginName, userInfo.getLoginName());
        queryWrapper.or().eq(UserInfo::getEmail, userInfo.getLoginName());
        queryWrapper.or().eq(UserInfo::getPhoneNum, userInfo.getLoginName());
        userEnterPwd = DigestUtils.md5DigestAsHex(userInfo.getPasswd().getBytes());
    }
    UserInfo userDB = this.getOne(queryWrapper);
    if (userDB == null) {
        throw new RuntimeException("账户不存在!");
    }
    //2.验证用户密码是否正确
    //2.1 对用户提交密码进行md5加密得到密文
    //2.2 跟数据库中用户记录的密文进行比较
    if (!userDB.getPasswd().equals(userEnterPwd)) {
        throw new RuntimeException("密码错误!");
    }

    //3.验证通过,生成令牌 将令牌存入Redis中
    //3.1 采用UUID生成令牌 作为存入Redis 的key
    String token = UUID.randomUUID().toString().replaceAll("-", "");
    //3.2 构建存入Redis中用户信息(用户ID,用户登录设备标识(需要客户端提交),用户登录所在城市-避免令牌被盗取,验证措施)
    JSONObject userObj = new JSONObject();
    userObj.put("id", userDB.getId());
    //获取用户IP地址
    try {
        AreaInfo area = BaiDuService.getArea(IpUtil.getIpAddress(request));
        if (area != null) {
            userObj.put("city", area.getCity());
        }
    } catch (Exception e) {
        log.error("[百度API]获取城市异常:{}", e);
    }
    //3.3 将令牌以及用户信息存入Redis
    String key = RedisConst.USER_KEY_PREFIX + token;
    redisTemplate.opsForValue().set(key, userObj, RedisConst.SKUKEY_TIMEOUT, TimeUnit.SECONDS);

    //4.按照接口文档响应登录业务数据
    Map<String, Object> mapResult = new HashMap<>();
    mapResult.put("token", token);
    mapResult.put("nickName", userDB.getNickName());
    return mapResult;
}

4.订单模块

收货地址列表

接口地址:http://api.gmall.com/api/user/userAddress/auth/findUserAddressList

service-user模块 UserApiController

/**
 * 提供给移动端 查询我的收件地址列表
 * @param request
 * @return
 */
@GetMapping("userAddress/auth/findUserAddressList")
public Result findUserAddressList(HttpServletRequest request){
    String userId = AuthContextHolder.getUserId(request);
    return Result.ok(userAddressService.getUserAddressListByUserId(Long.valueOf(userId)));
}

5. 支付系统

生成二维码:要替换掉原来的对象

AlipayTradeWapPayRequest alipayRequest = new AlipayTradeWapPayRequest();

bizContent.put("product_code", "QUICK_WAP_WAY");