H5移动端.md 9.8 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:7777;
}

配置监听/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 loginVo
 * @param request
 * @return
 */
@Override
public Result login(LoginVo loginVo, HttpServletRequest request) {
    //SELECT id,login_name,phone_num FROM user_info  where passwd = '96e79218965eb72c92a549dd5a330112' and (phone_num='11111' or email = 'atguigu.com' or login_name = 'atguigu')
    //1.根据用户认证信息 账号(手机号,邮箱,用户名称)跟密码 查询用户记录-判断用户是否存在
    //1.1 对用户提交密码进行加密
    String userPwd = DigestUtils.md5DigestAsHex(loginVo.getPassword().getBytes());
    LambdaQueryWrapper<UserInfo> queryWrapper = new LambdaQueryWrapper<>();
    queryWrapper.eq(UserInfo::getPasswd, userPwd);
    queryWrapper.and(wrapper -> {
        wrapper.or().eq(UserInfo::getPhoneNum, loginVo.getPhone())
                .or().eq(UserInfo::getEmail, loginVo.getEmail())
                .or().eq(UserInfo::getLoginName, loginVo.getLoginName());
    });
    UserInfo userInfo = this.getOne(queryWrapper);
    if (userInfo == null) {
        return Result.fail().message("用户名或者密码错误!");
    }
    //2.用户存在-生成用户令牌 将令牌信息存入Redis
    //2.1 生成存入Redis用户令牌 uuid
    String uuId = UUID.randomUUID().toString().replaceAll("-", "");
    String userKey = "user:login:" + uuId;

    //2.2 生成存入Redis用户信息 用户ID 用户登录IP/城市
    //2.2.1 得到的登录用户IP
    String ipAddress = IpUtil.getIpAddress(request);

    //2.2.2 根据IP获取用户所在城市 TODO 调用百度API

    HashMap<String, String> userRedis = new HashMap<>();
    userRedis.put("userId", userInfo.getId().toString());
    userRedis.put("ip", ipAddress);
    userRedis.put("city", "北京市");

    redisTemplate.opsForValue().set(userKey, userRedis, RedisConst.USERKEY_TIMEOUT, TimeUnit.SECONDS);

    //3.按照前端要求响应登录结果 token nickName
    HashMap<String, String> loginResult = new HashMap<>();
    loginResult.put("token", uuId);
    loginResult.put("nickName", userInfo.getNickName());
    return Result.ok(loginResult);
}

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");