【初体验】使用微信开发工具

0.准备工作

 

【初体验】使用微信开发工具_第1张图片

 【初体验】使用微信开发工具_第2张图片

 小程序 (qq.com)

【初体验】使用微信开发工具_第3张图片

【初体验】使用微信开发工具_第4张图片

【初体验】使用微信开发工具_第5张图片

【初体验】使用微信开发工具_第6张图片

微信开发工具的下载地址: 微信开发者工具(稳定版 Stable Build)下载地址与更新日志 | 微信开放文档

1.了解小程序目录结构

【初体验】使用微信开发工具_第7张图片【初体验】使用微信开发工具_第8张图片

 【初体验】使用微信开发工具_第9张图片

 【初体验】使用微信开发工具_第10张图片

 【初体验】使用微信开发工具_第11张图片

【初体验】使用微信开发工具_第12张图片

2 .设置合法域名

【初体验】使用微信开发工具_第13张图片

3 .微信登录用户信息获取

如果要求登录后,无法显示用户信息

【初体验】使用微信开发工具_第14张图片

 则应该修改一下【调试基础库】

【初体验】使用微信开发工具_第15张图片

 4 .获取用户登录的openid

index/index.wxml

  
    
    授权码:{{code}}
  

index/index.js

Page({
      //微信登录,获取微信用户的授权码:openId【每一次都不一样】
  wxLogin(){
    wx.login({
      success:(res)=>{
        console.log(res.code);
        this.setData({
          code:res.code
        })
      }
    })
  },
})

5 .向后端发送请求

index/index.wxml

  
    
  

index/index.js

  //发送请求
  sendRequest(){
    wx.request({
      url: 'http://localhost:8080/user/shop/status',
      method:'GET',
      success:(res)=>{
        //res返回的是整个JSON对象
        console.log(res.data);
      }
    })
  }

6.微信登录

参考地址:小程序登录 / 小程序登录 (qq.com)

注意:可以使用postman测试登录凭证校验接口

【初体验】使用微信开发工具_第16张图片

需求分析 

 【初体验】使用微信开发工具_第17张图片

 【初体验】使用微信开发工具_第18张图片

 【初体验】使用微信开发工具_第19张图片

代码开发

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

【初体验】使用微信开发工具_第20张图片

 配置为微信用户生成jwt令牌时使用的配置项:

【初体验】使用微信开发工具_第21张图片

 DTO设计

【初体验】使用微信开发工具_第22张图片

 VO设计

【初体验】使用微信开发工具_第23张图片

 根据接口定义创建UserControllerlogin方法:

@RestController
@RequestMapping("/user/user")
@Api(tags = "C端用户相关接口")
@Slf4j
public class UserController {

    @Autowired
    private UserService userService;

    @Autowired
    private JwtProperties jwtProperties;

    @PostMapping("/login")
    @ApiOperation("微信登录")
    public Result login(@RequestBody UserLoginDTO userLoginDTO) {
        //getCode:返回授权码
        log.info("微信用户登录:{}",userLoginDTO.getCode());

        //因为生成JWT令牌需要用户信息,所以要返回用户信息
        User user = userService.wxLogin(userLoginDTO);

        //为微信用户生成jwt令牌
        Map claims = new HashMap<>();
        claims.put(JwtClaimsConstant.USER_ID,user.getId());
        String token = JwtUtil.createJWT(jwtProperties.getUserSecretKey(), jwtProperties.getAdminTtl(),claims);

        //userLogin是要返回给前端的数据
        //这里是对返回给前端的数据进行封装
        //因为这里要getId,所以在userMapper的映射文件中要指定主键值
        UserLoginVO userLoginVO = UserLoginVO.builder()
                .id(user.getId())
                .openid(user.getOpenid())
                .token(token)
                .build();
        return Result.success(userLoginVO);
    }
}

创建UserService接口:

@Service
public interface UserService {

    /**
     * 微信登录
     * @param userLoginDTO
     * @return
     */
    User wxLogin(UserLoginDTO userLoginDTO);
}

创建UserServiceImpl实现类:

@Service
@Slf4j
public class UserServiceImpl implements UserService {


    //微信服务接口地址
    public static final String WX_LOGIN="https://api.weixin.qq.com/sns/jscode2session";


    @Autowired
    private WeChatProperties weChatProperties;

    @Autowired
    private UserMapper userMapper;

    /**
     * 微信登录
     * @param userLoginDTO
     * @return
     */
    @Override
    public User wxLogin(UserLoginDTO userLoginDTO) {
        //调用微信接口服务,获取微信用户的openid
        String code = userLoginDTO.getCode();
        String openid = getOpenid(code);

        //判断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){
        //调用微信接口服务,获得当前微信用户的openid
        Map map=new HashMap<>();
        map.put("appid",weChatProperties.getAppid());
        map.put("secret",weChatProperties.getSecret());
        map.put("js_code",code);
        map.put("grant_type","authorization_code");
        //使用HttpClient发起GET请求
        //doGet(请求地址,请求参数)
        //返回的是一个JSON对象
        String json = HttpClientUtil.doGet(WX_LOGIN, map);

        JSONObject jsonObject = JSON.parseObject(json);
        String openid = jsonObject.getString("openid");

        return openid;
    }
}

创建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);
}

创建UserMapper.xml映射文件





    
        insert into user(openid,name,phone,sex,id_number,avatar,create_time)
        values
            (#{openid},#{name},#{phone},#{sex},#{idNumber},#{avatar},#{createTime})
    

编写拦截器JwtTokenUserInterceptor,统一拦截用户端发送的请求并进行jwt校验

【初体验】使用微信开发工具_第24张图片

 JwtTokenUserInterceptor 

@Component
@Slf4j
public class JwtTokenUserInterceptor implements HandlerInterceptor {

    @Autowired
    private 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);
            //将用户id存入JWT中
            BaseContext.setCurrentId(userId);
            //3、通过,放行
            return true;
        } catch (Exception ex) {
            //4、不通过,响应401状态码
            response.setStatus(401);
            return false;
        }
    }
}

WebMvcConfiguration配置类中注册拦截器:

【初体验】使用微信开发工具_第25张图片

    @Autowired
    private JwtTokenAdminInterceptor jwtTokenAdminInterceptor;

    @Autowired
    private JwtTokenUserInterceptor jwtTokenUserInterceptor;

    /**
     * 注册自定义拦截器
     *
     * @param registry
     */
    protected void addInterceptors(InterceptorRegistry registry) {
        log.info("开始注册自定义拦截器...");
        registry.addInterceptor(jwtTokenAdminInterceptor)
                .addPathPatterns("/admin/**")
                .excludePathPatterns("/admin/employee/login");

        registry.addInterceptor(jwtTokenUserInterceptor)
                .addPathPatterns("/user/**")
                .excludePathPatterns("/user/user/login")
                .excludePathPatterns("/user/shop/status");
    }

7.用户下单

Day08-05-用户下单_需求分析和设计_接口设计_哔哩哔哩_bilibili

代码开发

根据用户下单接口的参数设计DTO

【初体验】使用微信开发工具_第26张图片

 【初体验】使用微信开发工具_第27张图片

根据用户下单接口的返回结果设计VO 

 【初体验】使用微信开发工具_第28张图片

 【初体验】使用微信开发工具_第29张图片

 创建OrderController并提供用户下单方法

//因为admin管理端也有一个userOrderController,所以这里要区分开
@RestController(value = "userOrderController")
@RequestMapping("/user/order")
@Api(tags = "用户端订单相关接口")
@Slf4j
public class OrderController {

    @Autowired
    private OrderService orderService;

    /**
     * 用户下单
     *
     * @param ordersSubmitDTO
     * @return
     */
    @PostMapping("/submit")
    @ApiOperation("c端用户下单")
    public Result submit(@RequestBody OrdersSubmitDTO ordersSubmitDTO) {
        log.info("用户下单:{}",ordersSubmitDTO);
        OrderSubmitVO orderSubmitVO = orderService.submitOrder(ordersSubmitDTO);
        return Result.success(orderSubmitVO);
    }
}

创建OrderService接口,并声明用户下单方法

public interface OrderService {

    /**
     * 用户下单
     * @param ordersSubmitDTO
     * @return
     */
    OrderSubmitVO submitOrder(OrdersSubmitDTO ordersSubmitDTO);
}

创建OrderServiceImpl实现OrderService接口

@Service
public class OrderServiceImpl implements OrderService {


    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private OrderDetailMapper orderDetailMapper;

    @Autowired
    private AddressBookMapper addressBookMapper;

    @Autowired
    private ShoppingCartMapper shoppingCartMapper;

    @Autowired
    private WeChatPayUtil weChatPayUtil;

    @Autowired
    private UserMapper userMapper;

    /**
     * 用户下单
     * @param ordersSubmitDTO
     * @return
     */
    @Transactional//开启事务
    @Override
    public OrderSubmitVO submitOrder(OrdersSubmitDTO ordersSubmitDTO) {

        //1. 出来各种业务异常(地址为空,购物车数据为空)
        AddressBook addressBook = addressBookMapper.getById(ordersSubmitDTO.getAddressBookId());
        if(addressBook==null){
            //抛出业务异常
            throw new AddressBookBusinessException(MessageConstant.ADDRESS_BOOK_IS_NULL);
        }

        //查询当前用户的购物车数据
        Long userId = BaseContext.getCurrentId();
        //因为shoppingCartMapper的list要求传入是ShoppingCart对象,所以我们要先转换为该对象
        ShoppingCart shoppingCart = new ShoppingCart();
        shoppingCart.setUserId(userId);
        List shoppingCartList = shoppingCartMapper.list(shoppingCart);

        if(shoppingCartList==null || shoppingCartList.size()==0){
            //抛出业务异常
            throw new ShoppingCartBusinessException(MessageConstant.SHOPPING_CART_IS_NULL);
        }

        //2.向订单表插入1条数据
        Orders orders = new Orders();
        //属性拷贝,将已经传入的数据拷贝到另外一个进行查询
        BeanUtils.copyProperties(ordersSubmitDTO, orders);
        orders.setOrderTime(LocalDateTime.now());
        orders.setPayStatus(Orders.UN_PAID);//未支付
        orders.setStatus(Orders.PENDING_PAYMENT);//待付款
        orders.setNumber(String.valueOf(System.currentTimeMillis()));//使用时间戳形成订单号
        orders.setPhone(addressBook.getPhone());
        orders.setConsignee(addressBook.getConsignee());
        orders.setUserId(userId);

        orderMapper.insert(orders);

        //生成一个List集合存放数据
        ArrayList orderDetailList = new ArrayList<>();
        //3.向订单明细表插入n条数据【需要获取当前的订单id】,故上面的insert中要返回主键值
        for(ShoppingCart cart:shoppingCartList){
            OrderDetail orderDetail = new OrderDetail();//订单明细
            BeanUtils.copyProperties(cart, orderDetail);
            orderDetail.setOrderId(orders.getId());//设置当前订单详细关联的订单id
            orderDetailList.add(orderDetail);
        }
        orderDetailMapper.insertBatch(orderDetailList);
        //4.清空当前用户的购物车数据
        shoppingCartMapper.deleteById(userId);
        //5.封装VO返回结果

        OrderSubmitVO orderSubmitVO = OrderSubmitVO.builder()
                .id(orders.getId())
                .orderTime(orders.getOrderTime())
                .orderNumber(orders.getNumber())
                .orderAmount(orders.getAmount())
                .build();
        return orderSubmitVO;
    }

} 
  

创建OrderMapper接口和对应的xml映射文件:

【初体验】使用微信开发工具_第30张图片

 创建OrderDetailMapper接口和对应的xml映射文件

 【初体验】使用微信开发工具_第31张图片

 【初体验】使用微信开发工具_第32张图片

 8.订单支付

微信支付介绍

参考产品中心 - 微信支付商户平台

【初体验】使用微信开发工具_第33张图片

 JSAPI下单商户系统调用该接口在微信支付服务后台生成预支付交易单

【初体验】使用微信开发工具_第34张图片

 【初体验】使用微信开发工具_第35张图片

 【初体验】使用微信开发工具_第36张图片

 微信小程序调起支付通过JSAPI下单接口获取到发起支付的必要参数prepay_id,然后使用微信支付提供的小程序方法调起小程序支付

【初体验】使用微信开发工具_第37张图片

 【初体验】使用微信开发工具_第38张图片

 微信小程序支付时序图

【初体验】使用微信开发工具_第39张图片

获取临时域名:支付成功后微信服务通过该域名回调我们的程序

【初体验】使用微信开发工具_第40张图片

 代码导入

微信支付相关配置:

 【初体验】使用微信开发工具_第41张图片

【初体验】使用微信开发工具_第42张图片

 重点代码

【初体验】使用微信开发工具_第43张图片

 

【初体验】使用微信开发工具_第44张图片

 OrderController

    /**
     * 订单支付
     *
     * @param ordersPaymentDTO
     * @return
     */
    @PutMapping("/payment")
    @ApiOperation("订单支付")
    public Result payment(@RequestBody OrdersPaymentDTO ordersPaymentDTO) throws Exception {
        log.info("订单支付:{}", ordersPaymentDTO);
        OrderPaymentVO orderPaymentVO = orderService.payment(ordersPaymentDTO);
        log.info("生成预支付交易单:{}", orderPaymentVO);

        //业务出来,修改订单状态,来单提醒
        //因为无法调用微信支付接口,所以模拟一下
        orderService.paySuccess(ordersPaymentDTO.getOrderNumber());
        return Result.success(orderPaymentVO);
    }

OrderService

    /**
     * 订单支付
     * @param ordersPaymentDTO
     * @return
     */
    OrderPaymentVO payment(OrdersPaymentDTO ordersPaymentDTO) throws Exception;

    /**
     * 支付成功,修改订单状态
     * @param outTradeNo
     */
    void paySuccess(String outTradeNo);

 OrderServiceImpl

    /**
     * 订单支付
     *
     * @param ordersPaymentDTO
     * @return
     */
    public OrderPaymentVO payment(OrdersPaymentDTO ordersPaymentDTO) throws Exception {
        // 当前登录用户id
        Long userId = BaseContext.getCurrentId();
        User user = userMapper.getById(userId);

        //调用微信支付接口,生成预支付交易单
//        JSONObject jsonObject = weChatPayUtil.pay(
//                ordersPaymentDTO.getOrderNumber(), //商户订单号
//                new BigDecimal(0.01), //支付金额,单位 元
//                "苍穹外卖订单", //商品描述
//                user.getOpenid() //微信用户的openid
//        );
        //因为无法调用微信支付接口,所以模拟一下
        JSONObject jsonObject = new JSONObject();

        if (jsonObject.getString("code") != null && jsonObject.getString("code").equals("ORDERPAID")) {
            throw new OrderBusinessException("该订单已支付");
        }

        OrderPaymentVO vo = jsonObject.toJavaObject(OrderPaymentVO.class);
        vo.setPackageStr(jsonObject.getString("package"));

        return vo;
    }

    /**
     * 支付成功,修改订单状态
     *
     * @param outTradeNo
     */
    public void paySuccess(String outTradeNo) {

        // 根据订单号查询订单
        Orders ordersDB = orderMapper.getByNumber(outTradeNo);

        // 根据订单id更新订单的状态、支付方式、支付状态、结账时间
        Orders orders = Orders.builder()
                .id(ordersDB.getId())
                .status(Orders.TO_BE_CONFIRMED)
                .payStatus(Orders.PAID)
                .checkoutTime(LocalDateTime.now())
                .build();

        orderMapper.update(orders);
    }

OrderMapper

    /**
     * 修改订单信息
     * @param orders
     */
    void update(Orders orders);

OrderMapper

    
        update orders
        
            
                cancel_reason=#{cancelReason},
            
            
                rejection_reason=#{rejectionReason},
            
            
                cancel_time=#{cancelTime},
            
            
                pay_status=#{payStatus},
            
            
                pay_method=#{payMethod},
            
            
                checkout_time=#{checkoutTime},
            
            
                status = #{status},
            
            
                delivery_time = #{deliveryTime}
            
        
        where id = #{id}
    

PayNotifyController【固定】

/**
 * 支付回调相关接口
 */
@RestController
@RequestMapping("/notify")
@Slf4j
public class PayNotifyController {
    @Autowired
    private OrderService orderService;
    @Autowired
    private WeChatProperties weChatProperties;

    /**
     * 支付成功回调
     *
     * @param request
     */
    @RequestMapping("/paySuccess")
    public void paySuccessNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {
        //读取数据
        String body = readData(request);
        log.info("支付成功回调:{}", body);

        //数据解密
        String plainText = decryptData(body);
        log.info("解密后的文本:{}", plainText);

        JSONObject jsonObject = JSON.parseObject(plainText);
        String outTradeNo = jsonObject.getString("out_trade_no");//商户平台订单号
        String transactionId = jsonObject.getString("transaction_id");//微信支付交易号

        log.info("商户平台订单号:{}", outTradeNo);
        log.info("微信支付交易号:{}", transactionId);

        //业务处理,修改订单状态、来单提醒
        orderService.paySuccess(outTradeNo);

        //给微信响应
        responseToWeixin(response);
    }

    /**
     * 读取数据
     *
     * @param request
     * @return
     * @throws Exception
     */
    private String readData(HttpServletRequest request) throws Exception {
        BufferedReader reader = request.getReader();
        StringBuilder result = new StringBuilder();
        String line = null;
        while ((line = reader.readLine()) != null) {
            if (result.length() > 0) {
                result.append("\n");
            }
            result.append(line);
        }
        return result.toString();
    }

    /**
     * 数据解密
     *
     * @param body
     * @return
     * @throws Exception
     */
    private String decryptData(String body) throws Exception {
        JSONObject resultObject = JSON.parseObject(body);
        JSONObject resource = resultObject.getJSONObject("resource");
        String ciphertext = resource.getString("ciphertext");
        String nonce = resource.getString("nonce");
        String associatedData = resource.getString("associated_data");

        AesUtil aesUtil = new AesUtil(weChatProperties.getApiV3Key().getBytes(StandardCharsets.UTF_8));
        //密文解密
        String plainText = aesUtil.decryptToString(associatedData.getBytes(StandardCharsets.UTF_8),
                nonce.getBytes(StandardCharsets.UTF_8),
                ciphertext);

        return plainText;
    }

    /**
     * 给微信响应
     * @param response
     */
    private void responseToWeixin(HttpServletResponse response) throws Exception{
        response.setStatus(200);
        HashMap map = new HashMap<>();
        map.put("code", "SUCCESS");
        map.put("message", "SUCCESS");
        response.setHeader("Content-type", ContentType.APPLICATION_JSON.toString());
        response.getOutputStream().write(JSONUtils.toJSONString(map).getBytes(StandardCharsets.UTF_8));
        response.flushBuffer();
    }
}

你可能感兴趣的:(java,开发语言)