蒼穹外賣-day06

蒼穹外賣-day06

課程內容

  • HttpClient
  • 微信小程序開發
  • 微信登錄
  • 導入商品瀏覽功能代碼

學習目標

  • 能夠使用HttpClient發送HTTP請求并解析響應結果
  • 了解微信小程序開發過程
  • 掌握微信登錄的流程并實現功能代碼
  • 了解商品瀏覽功能需求

功能實現:微信登錄商品瀏覽

1. HttpClient

1.1 介紹

HttpClient 是Apache Jakarta Common 下的子項目,可以用來提供高效的、最新的、功能豐富的支持 HTTP 協議的客戶端編程工具包,并且它支持 HTTP 協議最新的版本和建議。

HttpClient作用:

  • 發送HTTP請求
  • 接收響應數據

HttpClient應用場景:

當我們在使用掃描支付、查看地圖、獲取驗證碼、查看天氣等功能時

其實,應用程序本身并未實現這些功能,都是在應用程序里訪問提供這些功能的服務,訪問這些服務需要發送HTTP請求,并且接收響應數據,可通過HttpClient來實現。
在這里插入圖片描述

HttpClient的maven坐標:

<dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpclient</artifactId><version>4.5.13</version>
</dependency>

HttpClient的核心API:

  • HttpClient:Http客戶端對象類型,使用該類型對象可發起Http請求。
  • HttpClients:可認為是構建器,可創建HttpClient對象。
  • CloseableHttpClient:實現類,實現了HttpClient接口。
  • HttpGet:Get方式請求類型。
  • HttpPost:Post方式請求類型。

HttpClient發送請求步驟:

  • 創建HttpClient對象
  • 創建Http請求對象
  • 調用HttpClient的execute方法發送請求

1.2 入門案例

對HttpClient編程工具包有了一定了解后,那么,我們使用HttpClient在Java程序當中來構造Http的請求,并且把請求發送出去,接下來,就通過入門案例分別發送GET請求POST請求,具體來學習一下它的使用方法。

1.2.1 GET方式請求

正常來說,首先,應該導入HttpClient相關的坐標,但在項目中,就算不導入,也可以使用相關的API。

因為在項目中已經引入了aliyun-sdk-oss坐標:

<dependency><groupId>com.aliyun.oss</groupId><artifactId>aliyun-sdk-oss</artifactId>
</dependency>

上述依賴的底層已經包含了HttpClient相關依賴。

故選擇導入或者不導入均可。

進入到sky-server模塊,編寫測試代碼,發送GET請求。

實現步驟:

  1. 創建HttpClient對象
  2. 創建請求對象
  3. 發送請求,接受響應結果
  4. 解析結果
  5. 關閉資源
package com.sky.test;import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;@SpringBootTest
public class HttpClientTest {/*** 測試通過httpclient發送GET方式的請求*/@Testpublic void testGET() throws Exception{//創建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();}
}

在訪問http://localhost:8080/user/shop/status請求時,需要提前啟動項目。

測試結果:
在這里插入圖片描述

1.2.2 POST方式請求

在HttpClientTest中添加POST方式請求方法,相比GET請求來說,POST請求若攜帶參數需要封裝請求體對象,并將該對象設置在請求對象中。

實現步驟:

  1. 創建HttpClient對象
  2. 創建請求對象
  3. 發送請求,接收響應結果
  4. 解析響應結果
  5. 關閉資源
	/*** 測試通過httpclient發送POST方式的請求*/@Testpublic void testPOST() throws Exception{// 創建httpclient對象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);HttpEntity entity1 = response.getEntity();String body = EntityUtils.toString(entity1);System.out.println("響應數據為:" + body);//關閉資源response.close();httpClient.close();}

測試結果:

在這里插入圖片描述

2. 微信小程序開發

2.1 介紹

小程序是一種新的開放能力,開發者可以快速地開發一個小程序。可以在微信內被便捷地獲取和傳播,同時具有出色的使用體驗。

**官方網址:**https://mp.weixin.qq.com/cgi-bin/wx?token=&lang=zh_CN

小程序主要運行微信內部,可通過上述網站來整體了解微信小程序的開發。

**首先,**在進行小程序開發時,需要先去注冊一個小程序,在注冊的時候,它實際上又分成了不同的注冊的主體。我們可以以個人的身份來注冊一個小程序,當然,也可以以企業政府、媒體或者其他組織的方式來注冊小程序。那么,不同的主體注冊小程序,最終開放的權限也是不一樣的。比如以個人身份來注冊小程序,是無法開通支付權限的。若要提供支付功能,必須是企業、政府或者其它組織等。所以,不同的主體注冊小程序后,可開發的功能是不一樣的。

**然后,**微信小程序我們提供的一些開發的支持,實際上微信的官方是提供了一系列的工具來幫助開發者快速的接入
并且完成小程序的開發,提供了完善的開發文檔,并且專門提供了一個開發者工具,還提供了相應的設計指南,同時也提供了一些小程序體驗DEMO,可以快速的體驗小程序實現的功能。

**最后,**開發完一個小程序要上線,也給我們提供了詳細地接入流程。

2.2 準備工作

開發微信小程序之前需要做如下準備工作:

  • 注冊小程序
  • 完善小程序信息
  • 下載開發者工具

1). 注冊小程序

注冊地址:https://mp.weixin.qq.com/wxopen/waregister?action=step1

2). 完善小程序信息

登錄小程序后臺:https://mp.weixin.qq.com/

兩種登錄方式選其一即可

完善小程序信息、小程序類目

查看小程序的 AppID

3). 下載開發者工具

資料中已提供,無需下載,熟悉下載步驟即可。

下載地址: https://developers.weixin.qq.com/miniprogram/dev/devtools/stable.html

掃描登錄開發者工具

創建小程序項目

熟悉開發者工具布局

設置不校驗合法域名

**注:**開發階段,小程序發出請求到后端的Tomcat服務器,若不勾選,請求發送失敗。

2.3 入門案例

實際上,小程序的開發本質上屬于前端開發,主要使用JavaScript開發,咱們現在的定位主要還是在后端,所以,對于小程序開發簡單了解即可。

2.3.1 小程序目錄結構

小程序包含一個描述整體程序的 app 和多個描述各自頁面的 page。一個小程序主體部分由三個文件組成,必須放在項目的根目錄,如下:

文件說明:

**app.js:**必須存在,主要存放小程序的邏輯代碼

**app.json:**必須存在,小程序配置文件,主要存放小程序的公共配置

app.wxss: 非必須存在,主要存放小程序公共樣式表,類似于前端的CSS樣式

對小程序主體三個文件了解后,其實一個小程序又有多個頁面。比如說,有商品瀏覽頁面、購物車的頁面、訂單支付的頁面、商品的詳情頁面等等。那這些頁面會放在哪呢?
會存放在pages目錄。

每個小程序頁面主要由四個文件組成:

文件說明:

**js文件:**必須存在,存放頁面業務邏輯代碼,編寫的js代碼。

**wxml文件:**必須存在,存放頁面結構,主要是做頁面布局,頁面效果展示的,類似于HTML頁面。

**json文件:**非必須,存放頁面相關的配置。

**wxss文件:**非必須,存放頁面樣式表,相當于CSS文件。

2.3.2 編寫和編譯小程序

1). 編寫

進入到index.wxml,編寫頁面布局

<!--index.wxml-->
<navigation-bar title="Weixin" back="{{false}}" color="black" background="#FFF"></navigation-bar>
<scroll-view class="scrollarea" scroll-y type="list"><view class="container"><view>{{msg}}</view></view>
<!-- 微信登入按鈕 --><view class="container"><button type="primary" bind:tap="wxlogin">微信登入</button>{{code}}</view><!-- 發送請求 --><view class="container"><button type="primary" bind:tap="sendRequest">發送請求</button>{{result}}</view> 
</scroll-view>

進入到index.js,編寫業務邏輯代碼

// index.js
Page({data:{msg:"Hello wx",code:""},//給登入按鈕綁定登入方法wxlogin:function(){console.log("點擊登入......");//調用wx對象,去發送登入請求wx.login({success: (res) => {console.log(res);this.setData({code:res.code})},})},//給發送請求按鈕綁定函數sendRequest:function(){console.log("發送請求中......");//調用wx對象的request方法,發送請求到指定的服務器wx.request({url: 'http://localhost:8080/user/shop/status',method:'GET',success:(res)=>{console.log(res.data);}})}})

2). 編譯

點擊編譯按鈕

3). 運行效果

點擊微信登錄
在這里插入圖片描述

點擊發送請求

因為請求http://localhost:8080/user/shop/status,先要啟動后臺項目。

在這里插入圖片描述

**注:**設置不校驗合法域名,若不勾選,請求發送失敗。

2.3.3 發布小程序

小程序的代碼都已經開發完畢,要將小程序發布上線,讓所有的用戶都能使用到這個小程序。

點擊上傳按鈕:

指定版本號:

上傳成功:

把代碼上傳到微信服務器就表示小程序已經發布了嗎?
**其實并不是。**當前小程序版本只是一個開發版本。

進到微信公眾平臺,打開版本管理頁面。

需提交審核,變成審核版本,審核通過后,進行發布,變成線上版本。

一旦成為線上版本,這就說明小程序就已經發布上線了,微信用戶就可以在微信里面去搜索和使用這個小程序了。

3. 微信登錄

3.1 導入小程序代碼

開發微信小程序,本質上是屬于前端的開發,我們的重點其實還是后端代碼開發。所以,小程序的代碼已經提供好了,直接導入到微信開發者工具當中,直接來使用就可以了。

1). 找到資料

2). 導入代碼

AppID:使用自己的AppID

3). 查看項目結構

主體的文件:app.js app.json app.wxss
項目的頁面比較多,主要存放在pages目錄。

4). 修改配置

因為小程序要請求后端服務,需要修改為自己后端服務的ip地址和端口號(默認不需要修改)

common–>vendor.js–>搜索(ctrl+f)–>baseUri

3.2 微信登錄流程【重點】

微信登錄:https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/login.html

流程圖:

步驟分析:

  1. 小程序端,調用wx.login()獲取code,就是授權碼。
  2. 小程序端,調用wx.request()發送請求并攜帶code,請求開發者服務器(自己編寫的后端服務)。
  3. 開發者服務端,通過HttpClient向微信接口服務發送請求,并攜帶appId+appsecret+code三個參數。
  4. 開發者服務端,接收微信接口服務返回的數據,session_key+opendId等。opendId是微信用戶的唯一標識。
  5. 開發者服務端,自定義登錄態,生成令牌(token)和openid等數據返回給小程序端,方便后緒請求身份校驗。
  6. 小程序端,收到自定義登錄態,存儲storage。
  7. 小程序端,后緒通過wx.request()發起業務請求時,攜帶token。
  8. 開發者服務端,收到請求后,通過攜帶的token,解析當前登錄用戶的id。
  9. 開發者服務端,身份校驗通過后,繼續相關的業務邏輯處理,最終返回業務數據。

接下來,我們使用Postman進行測試。

說明:

  1. 調用 wx.login() 獲取 臨時登錄憑證code ,并回傳到開發者服務器。
  2. 調用 auth.code2Session 接口,換取 用戶唯一標識 OpenID 、 用戶在微信開放平臺帳號下的唯一標識UnionID(若當前小程序已綁定到微信開放平臺帳號) 和 會話密鑰 session_key

之后開發者服務器可以根據用戶標識來生成自定義登錄態,用于后續業務邏輯中前后端交互時識別用戶身份。

實現步驟:

1). 獲取授權碼

點擊確定按鈕,獲取授權碼,每個授權碼只能使用一次,每次測試,需重新獲取。

2). 明確請求接口

請求方式、請求路徑、請求參數
在這里插入圖片描述

3). 發送請求

獲取session_key和openid

若出現code been used錯誤提示,說明授權碼已被使用過,請重新獲取

3.3 需求分析和設計

3.3.1 產品原型

用戶進入到小程序的時候,微信授權登錄之后才能點餐。需要獲取當前微信用戶的相關信息,比如昵稱、頭像等,這樣才能夠進入到小程序進行下單操作。是基于微信登錄來實現小程序的登錄功能,沒有采用傳統賬戶密碼登錄的方式。若第一次使用小程序來點餐,就是一個新用戶,需要把這個新的用戶保存到數據庫當中完成自動注冊。

登錄功能原型圖:

業務規則:

  • 基于微信登錄實現小程序的登錄功能
  • 如果是新用戶需要自動完成注冊
3.3.2 接口設計

通過微信登錄的流程,如果要完成微信登錄的話,最終就要獲得微信用戶的openid。在小程序端獲取授權碼后,向后端服務發送請求,并攜帶授權碼,這樣后端服務在收到授權碼后,就可以去請求微信接口服務。最終,后端向小程序返回openid和token等數據。

基于上述的登錄流程,就可以設計出該接口的請求參數返回數據

**說明:**請求路徑/user/user/login,第一個user代表用戶端,第二個user代表用戶模塊。

3.3.3 表設計

當用戶第一次使用小程序時,會完成自動注冊,把用戶信息存儲到user表中。

字段名數據類型說明備注
idbigint主鍵自增
openidvarchar(45)微信用戶的唯一標識
namevarchar(32)用戶姓名
phonevarchar(11)手機號
sexvarchar(2)性別
id_numbervarchar(18)身份證號
avatarvarchar(500)微信用戶頭像路徑
create_timedatetime注冊時間

**說明:**手機號字段比較特殊,個人身份注冊的小程序沒有權限獲取到微信用戶的手機號。如果是以企業的資質
注冊的小程序就能夠拿到微信用戶的手機號。

3.4 代碼開發

3.4.1 定義相關配置

配置微信登錄所需配置項:

application-dev.yml

sky:wechat:appid: wxffb3637a228223b8secret: 84311df9199ecacdf4f12d27b6b9522d

application.yml

sky:wechat:appid: ${sky.wechat.appid}secret: ${sky.wechat.secret}

配置為微信用戶生成jwt令牌時使用的配置項:

application.yml

sky:jwt:# 設置jwt簽名加密時使用的秘鑰admin-secret-key: itcast# 設置jwt過期時間admin-ttl: 7200000# 設置前端傳遞過來的令牌名稱admin-token-name: tokenuser-secret-key: itheimauser-ttl: 7200000user-token-name: authentication
3.4.2 DTO設計

根據傳入參數設計DTO類:

在sky-pojo模塊,UserLoginDTO.java已定義

package com.sky.dto;import lombok.Data;import java.io.Serializable;/*** C端用戶登錄*/
@Data
public class UserLoginDTO implements Serializable {private String code;}
3.4.3 VO設計

根據返回數據設計VO類:

在sky-pojo模塊,UserLoginVO.java已定義

package com.sky.vo;import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;import java.io.Serializable;@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class UserLoginVO implements Serializable {private Long id;private String openid;private String token;}
3.4.4 Controller層

根據接口定義創建UserController的login方法:

package com.sky.controller.user;import com.sky.constant.JwtClaimsConstant;
import com.sky.dto.UserLoginDTO;
import com.sky.entity.User;
import com.sky.properties.JwtProperties;
import com.sky.result.Result;
import com.sky.service.UserService;
import com.sky.utils.JwtUtil;
import com.sky.vo.UserLoginVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.HashMap;
import java.util.Map;@RestController
@RequestMapping("/user/user")
@Slf4j
@Api(tags = "C端用戶相關接口")
public class UserController {@Autowiredprivate UserService userService;@Autowiredprivate JwtProperties jwtProperties;/*** 微信登錄* @param dto* @return*/@PostMapping("/login")@ApiOperation("微信登入")public Result login(@RequestBody UserLoginDTO dto){log.info("員工登錄信息:{}", dto);//1.掉用Service進行登錄,拿到微信掃碼返回的臨時登錄憑證codeUser user =userService.login(dto);//2.如果登入成功,生成jwt令牌Map<String, Object> claims = new HashMap<>();claims.put(JwtClaimsConstant.USER_ID, user.getId());String token = JwtUtil.createJWT(jwtProperties.getUserSecretKey(),jwtProperties.getUserTtl(),claims);//3.構造UserLoginVO對象,返回ResultUserLoginVO userLoginVO = UserLoginVO.builder().id(user.getId()).openid(user.getOpenid()).token(token).build();return Result.success(userLoginVO);}
}

其中,JwtClaimsConstant.USER_ID常量已定義。

3.4.5 Service層接口

創建UserService接口:

package com.sky.service;import com.sky.dto.UserLoginDTO;
import com.sky.entity.User;public interface UserService {/*** 微信登錄* @param dto* @return*/User login(UserLoginDTO dto);
}
3.4.6 Service層實現類

**創建UserServiceImpl實現類:**實現獲取微信用戶的openid和微信登錄功能

package com.sky.service.impl;import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.sky.constant.MessageConstant;
import com.sky.dto.UserLoginDTO;
import com.sky.entity.User;
import com.sky.exception.LoginFailedException;
import com.sky.mapper.UserMapper;
import com.sky.properties.WeChatProperties;
import com.sky.service.UserService;
import com.sky.utils.HttpClientUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.client.HttpClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;@Slf4j
@Service
public class UserServiceImpl implements UserService {@Autowiredprivate WeChatProperties weChatProperties;@Autowiredprivate UserMapper userMapper;@Overridepublic User login(UserLoginDTO dto) {//1.通過HttpClient,構造登入憑證校驗請求//構造請求參數Map<String, String> paramMap = new HashMap<>();paramMap.put("appid", weChatProperties.getAppid());paramMap.put("secret", weChatProperties.getSecret());paramMap.put("js_code", dto.getCode());paramMap.put("grant_type", "authorization_code");//調用HttpClientUtil工具類,發送請求String res = HttpClientUtil.doGet("https://api.weixin.qq.com/sns/jscode2session", paramMap);log.info("res={}",res);//2.解析響應結果,獲取openidJSONObject jsonObject = JSON.parseObject(res);String openid = (String) jsonObject.get("openid");if(openid== null){throw new LoginFailedException(MessageConstant.USER_NOT_LOGIN);}//3.判斷用戶是否為新用戶,根據openid查詢user表User user = userMapper.selectByOpenid(openid);//4.如果是新用戶,初始化用戶數據到user表if (user==null){user = new User();user.setOpenid(openid);user.setCreateTime(LocalDateTime.now());user.setName(openid.substring(0,5));userMapper.insert(user);}//5.否則,直接返回user對象數據return user;}
}
3.4.7 Mapper層

創建UserMapper接口:

package com.sky.mapper;import com.sky.entity.User;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Options;
import org.apache.ibatis.annotations.Select;
@Mapper
public interface UserMapper {@Select("select * from user where openid = #{openid}")User selectByOpenid(String openid);@Options(useGeneratedKeys = true, keyProperty = "id")
@Insert("insert into user (openid,name,create_time) values (#{openid}, #{name},#{createTime})")void insert(User user);
}
3.4.8 編寫攔截器

**編寫攔截器JwtTokenUserInterceptor:**統一攔截用戶端發送的請求并進行jwt校驗

package com.sky.interceptor;import com.sky.constant.JwtClaimsConstant;
import com.sky.context.BaseContext;
import com.sky.properties.JwtProperties;
import com.sky.utils.JwtUtil;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;/*** 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;}}
}

在WebMvcConfiguration配置類中注冊攔截器:

	@Autowiredprivate JwtTokenUserInterceptor jwtTokenUserInterceptor;/*** 注冊自定義攔截器* @param registry*/protected void addInterceptors(InterceptorRegistry registry) {log.info("開始注冊自定義攔截器...");//.........registry.addInterceptor(jwtTokenUserInterceptor).addPathPatterns("/user/**").excludePathPatterns("/user/user/login").excludePathPatterns("/user/shop/status");}

3.5 功能測試

重新編譯小程序,進行登錄,獲取到openid和token數據

查看后臺日志

查看數據庫user表,第一次登錄,會自動注冊

/>

4. 導入商品瀏覽功能代碼

4.1 需求分析和設計

4.1.1 產品原型

用戶登錄成功后跳轉到系統首頁,在首頁需要根據分類來展示菜品和套餐。如果菜品設置了口味信息,需要展示
按鈕,否則顯示
按鈕。

4.1.2 接口設計

根據上述原型圖先粗粒度設計接口,共包含4個接口。

接口設計:

  • 查詢分類
  • 根據分類id查詢菜品
  • 根據分類id查詢套餐
  • 根據套餐id查詢包含的菜品

接下來細粒度分析每個接口,明確每個接口的請求方式、請求路徑、傳入參數和返回值。

1). 查詢分類

2). 根據分類id查詢菜品

3). 根據分類id查詢套餐

4). 根據套餐id查詢包含的菜品

4.2 代碼導入

導入資料中的商品瀏覽功能代碼即可

可按照mapper–>service–>controller依次導入,這樣代碼不會顯示相應的報錯。

進入到sky-server模塊中

4.2.1 Mapper層

在SetmealMapper.java中添加list和getDishItemBySetmealId兩個方法

	/*** 動態條件查詢套餐* @param setmeal* @return*/List<Setmeal> list(Setmeal setmeal);/*** 根據套餐id查詢菜品選項* @param setmealId* @return*/@Select("select sd.name, sd.copies, d.image, d.description " +"from setmeal_dish sd left join dish d on sd.dish_id = d.id " +"where sd.setmeal_id = #{setmealId}")List<DishItemVO> getDishItemBySetmealId(Long setmealId);

創建SetmealMapper.xml文件

<?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.SetmealMapper"><select id="list" parameterType="Setmeal" resultType="Setmeal">select * from setmeal<where><if test="name != null">and name like concat('%',#{name},'%')</if><if test="categoryId != null">and category_id = #{categoryId}</if><if test="status != null">and status = #{status}</if></where></select>
</mapper>
4.2.2 Service層

創建SetmealService.java

package com.sky.service;import com.sky.dto.SetmealDTO;
import com.sky.dto.SetmealPageQueryDTO;
import com.sky.entity.Setmeal;
import com.sky.result.PageResult;
import com.sky.vo.DishItemVO;
import com.sky.vo.SetmealVO;
import java.util.List;public interface SetmealService {/*** 條件查詢* @param setmeal* @return*/List<Setmeal> list(Setmeal setmeal);/*** 根據id查詢菜品選項* @param id* @return*/List<DishItemVO> getDishItemById(Long id);}

創建SetmealServiceImpl.java

package com.sky.service.impl;import com.sky.entity.Setmeal;
import com.sky.mapper.DishMapper;
import com.sky.mapper.SetmealDishMapper;
import com.sky.mapper.SetmealMapper;
import com.sky.service.SetmealService;
import com.sky.vo.DishItemVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.util.List;/*** 套餐業務實現*/
@Service
@Slf4j
public class SetmealServiceImpl implements SetmealService {@Autowiredprivate SetmealMapper setmealMapper;@Autowiredprivate SetmealDishMapper setmealDishMapper;@Autowiredprivate DishMapper dishMapper;/*** 條件查詢* @param setmeal* @return*/public List<Setmeal> list(Setmeal setmeal) {List<Setmeal> list = setmealMapper.list(setmeal);return list;}/*** 根據id查詢菜品選項* @param id* @return*/public List<DishItemVO> getDishItemById(Long id) {return setmealMapper.getDishItemBySetmealId(id);}
}

在DishService.java中添加listWithFlavor方法定義

	/*** 條件查詢菜品和口味* @param dish* @return*/List<DishVO> listWithFlavor(Dish dish);

在DishServiceImpl.java中實現listWithFlavor方法

	/*** 條件查詢菜品和口味* @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;}
4.2.3 Controller層

創建DishController.java

package com.sky.controller.user;import com.sky.constant.StatusConstant;
import com.sky.entity.Dish;
import com.sky.result.Result;
import com.sky.service.DishService;
import com.sky.vo.DishVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;@RestController("userDishController")
@RequestMapping("/user/dish")
@Slf4j
@Api(tags = "C端-菜品瀏覽接口")
public class DishController {@Autowiredprivate DishService dishService;/*** 根據分類id查詢菜品** @param categoryId* @return*/@GetMapping("/list")@ApiOperation("根據分類id查詢菜品")public Result<List<DishVO>> list(Long categoryId) {Dish dish = new Dish();dish.setCategoryId(categoryId);dish.setStatus(StatusConstant.ENABLE);//查詢起售中的菜品List<DishVO> list = dishService.listWithFlavor(dish);return Result.success(list);}}

創建CategoryController.java

package com.sky.controller.user;import com.sky.entity.Category;
import com.sky.result.Result;
import com.sky.service.CategoryService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;@RestController("userCategoryController")
@RequestMapping("/user/category")
@Api(tags = "C端-分類接口")
public class CategoryController {@Autowiredprivate CategoryService categoryService;/*** 查詢分類* @param type* @return*/@GetMapping("/list")@ApiOperation("查詢分類")public Result<List<Category>> list(Integer type) {List<Category> list = categoryService.list(type);return Result.success(list);}
}

創建SetmealController.java

package com.sky.controller.user;import com.sky.constant.StatusConstant;
import com.sky.entity.Setmeal;
import com.sky.result.Result;
import com.sky.service.SetmealService;
import com.sky.vo.DishItemVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;@RestController("userSetmealController")
@RequestMapping("/user/setmeal")
@Api(tags = "C端-套餐瀏覽接口")
public class SetmealController {@Autowiredprivate SetmealService setmealService;/*** 條件查詢** @param categoryId* @return*/@GetMapping("/list")@ApiOperation("根據分類id查詢套餐")public Result<List<Setmeal>> list(Long categoryId) {Setmeal setmeal = new Setmeal();setmeal.setCategoryId(categoryId);setmeal.setStatus(StatusConstant.ENABLE);List<Setmeal> list = setmealService.list(setmeal);return Result.success(list);}/*** 根據套餐id查詢包含的菜品列表** @param id* @return*/@GetMapping("/dish/{id}")@ApiOperation("根據套餐id查詢包含的菜品列表")public Result<List<DishItemVO>> dishList(@PathVariable("id") Long id) {List<DishItemVO> list = setmealService.getDishItemById(id);return Result.success(list);}
}

4.3 功能測試

重啟服務器、重新編譯小程序

微信登錄進入首頁

菜品和套餐分類查詢:

具體分類下的菜品查詢:

菜品口味查詢:

4.4 代碼提交

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/88595.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/88595.shtml
英文地址,請注明出處:http://en.pswp.cn/web/88595.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

安卓定制功能

未解決的定制功能 1.創建自定義分區 2.通過服務啟動應用進程 3.應用白名單 4.網絡白名單 5.應用鎖 6.默認launcher 7.多主頁動態切換 8.禁止狀態欄下拉/鎖屏頁面禁止下拉狀態欄&#xff08;兩種一起&#xff09; 9.導航欄動態打開關閉 10.固件默認是手勢還是導航欄 11.狀態欄動…

【項目】GraphRAG基于知識圖譜的檢索增強技術-實戰入門

GraphRAG—基于知識圖譜的檢索增強技術&#xff08;一&#xff09;GraphRAG入門介紹&#xff08;二&#xff09;GraphRAG基本原理回顧&#xff08;三&#xff09;GraphRAG運行流程3.1 索引&#xff08;Indexing&#xff09;過程3.2 查詢&#xff08;Query&#xff09;過程3.3 P…

Zookeeper添加SASL安全認證 修復方案

#作者&#xff1a;任少近 文章目錄1修復背景2 修復方案說明3 配置流程3.1停止zookeeper服務3.2Zookeeper添加SASL參數3.3配置jaas密碼文件3.4 添加啟動參數3.5啟動zookeeper服務3.6訪問測試4 Kafka連接zookeeper服務端配置4.1未配置身份認證4.2停止kafka服務4.3配置身份認證4.4…

AI進化論07:第二次AI寒冬——AI“改頭換面”,從“AI”變成“機器學習”

書接上回&#xff0c;上回咱們聊了神經網絡在第一次寒冬中的“蟄伏”與“萌動”。但別高興太早&#xff0c;AI很快就迎來了它的第二次“寒冬”&#xff08;大概從20世紀80年代末到90年代中期&#xff09;。這次寒冬啊&#xff0c;比第一次還“冷”&#xff0c;還“漫長”。AI這…

基于開源AI智能名片鏈動2+1模式與S2B2C商城小程序的渠道選擇策略研究

摘要&#xff1a;在數字化商業環境下&#xff0c;品牌與產品的渠道選擇對其市場推廣和運營成功至關重要。本文聚焦于如何依據自身品牌和產品特性&#xff0c;結合開源AI智能名片鏈動21模式與S2B2C商城小程序&#xff0c;運用科學的渠道選擇方法&#xff0c;慎重挑選1 - 2個適宜…

開源 C# .net mvc 開發(八)IIS Express輕量化Web服務器的配置和使用

文章的目的為了記錄.net mvc學習的經歷。本職為嵌入式軟件開發&#xff0c;公司安排開發文件系統&#xff0c;臨時進行學習開發&#xff0c;系統上線3年未出沒有大問題。開發流程和要點有些記憶模糊&#xff0c;趕緊記錄&#xff0c;防止忘記。 相關鏈接: 開源 C# .net mvc 開…

PostgreSQL安裝及簡單應用

下載地址&#xff1a;EDB: Open-Source, Enterprise Postgres Database Management 安裝 注意&#xff1a;端口號默認是5432 配置dbeaver應用&#xff0c;創建數據庫和表 -- 創建模式&#xff08;如果不存在&#xff09; CREATE SCHEMA IF NOT EXISTS bbbase;-- 創建序列&…

wedo智能車庫-----第31節(免費分享圖紙)

夸克網盤&#xff1a;https://pan.quark.cn/s/10302f7bbae0 高清圖紙源文件&#xff0c;需要的請自取

【springboot】IDEA創建SpringBoot簡單工程(有插件)

需求 使用SpringBoot開發一個web應用&#xff0c;瀏覽器發起請求/hello后&#xff0c;給瀏覽器返回字符串 hello world~ 步驟 1.創建Maven工程 2.導入spring-boot-stater-web起步依賴 3.編寫controller 4.提供啟動類 pom.xml文件了解 啟動類 新建包 創建類 package com.zw…

python正則表達式re(Regular Expression)

目錄 正則表達式&#xff1a; match()函數&#xff1a; search()函數&#xff1a; findall()函數&#xff1a; 正則表達式的參數&#xff1a; 表示字符范圍的參數&#xff1a; 表示字符出現的次數的參數&#xff1a; 表示同一類字符的參數&#xff1a; 貪婪和非貪婪模式…

事件驅動設計:Spring監聽器如何像咖啡師一樣優雅處理高并發

架構哲學&#xff1a;當咖啡店面對洶涌客流時&#xff0c;真正的優雅不是更快的動作&#xff0c;而是科學的協作機制。Spring事件驅動正是通過發布-訂閱模式&#xff0c;讓系統像頂級咖啡師般從容應對突發流量。一、從咖啡店看監聽器本質&#xff1a;3大核心組件拆解 場景還原&…

C++ const 關鍵字解析

const 是 C 中用于定義常量或指定不可變性的關鍵字&#xff0c;它在不同上下文中有不同的含義和用法。下面是對 const 的全面解析&#xff1a;1. 基本用法定義常量const int MAX_SIZE 100; const double PI 3.14159;這些值在程序運行期間不能被修改必須在定義時初始化與指針結…

[es自動化更新] Updatecli編排配置.yaml | dockerfilePath值文件.yml

鏈接&#xff1a;https://github.com/elastic/elasticsearch/tree/main/build-conventions elasticsearch自動化更新 本專欄使用updatecli實現自動化版本更新與依賴管理。 其配置通過編排文件&#xff08;updatecli-compose.yaml&#xff09;實現&#xff0c;該文件羅列了稱…

新手向:使用Python將多種圖像格式統一轉換為JPG

本文將詳細解析一個專業的Python腳本&#xff0c;它能夠將指定文件夾中的所有非JPG格式圖像批量轉換為JPG格式。這個腳本雖然代碼量不大&#xff0c;但包含了文件操作、圖像處理、異常處理等多個重要編程概念&#xff0c;非常適合初學者系統學習。環境準備在開始之前&#xff0…

深入剖析C++ RPC框架原理:有棧協程與分布式系統設計

深入剖析C RPC框架原理&#xff1a;有棧協程與分布式系統設計 &#x1f6e0;? 第一部分&#xff1a;RPC框架核心原理與技術架構 &#x1f310; 1.1 RPC在分布式系統中的核心地位 遠程過程調用&#xff08;RPC&#xff09;是現代分布式系統的基石&#xff0c;它實現了&#xf…

基于springboot+Vue的二手物品交易的設計與實現

基于springbootVue的二手物品交易的設計與實現 作者&#xff1a; Mr順 | 某大廠全棧開發工程師 | CSDN新星計劃導師 | Java領域優質創作者 技術棧&#xff1a; SpringBoot, JavaWeb, 數據庫等。精通Java、微信小程序開發。 項目亮點&#xff1a; 完整可運行&#xff1a; 提供…

騰訊云輕量服務器創建快照免費API接口教程

接口簡介 該API用于騰訊云輕量服務器系統盤快照創建&#xff0c;無需關機即可自動刪除舊快照并創建新快照。特點包括&#xff1a; 不占用騰訊云快照配額支持自動備份策略適用于定時備份任務僅支持系統盤快照&#xff08;云硬盤需調用專用接口&#xff09; ?請求地址? https…

C++中的智能指針(1):unique_ptr

一、背景普通指針是指向某塊內存區域地址的變量。如果一個指針指向的是一塊動態分配的內存區域&#xff0c;那么即使這個指針變量離開了所在的作用域&#xff0c;這塊內存區域也不會被自動銷毀。動態分配的內存不進行釋放則會導致內存泄漏。如果一個指針指向的是一塊已經被釋放…

HTTPS安全機制:從加密到證書全解析

目錄 1.HTTPS是什么 2.加密是什么 3.HTTPS的加密過程 3.1對稱加密 3.2非對稱加密 4.引入證書 4.1"中間人"攻擊 4.2 引入證書機制 4.3 理解數據簽名 4.4 非對稱加密 對稱加密 證書認證 5.常見問題 5.1 Fiddler等抓包工具&#xff0c;為啥能解析HTTPS的數據…

2024年深度學習技術主要發展分析

摘要&#xff1a;深度學習作為人工智能領域的戰略級技術&#xff0c;在2024年持續取得突破性進展&#xff0c;持續重構現代戰爭規則&#xff0c;成為大國軍事智能化競爭的核心角力點。對2024年深度學習技術熱門領域的主要發展進行了綜合評述。研究了深度學習技術的發展現狀&…