蒼穹外賣-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請求。
實現步驟:
- 創建HttpClient對象
- 創建請求對象
- 發送請求,接受響應結果
- 解析結果
- 關閉資源
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請求若攜帶參數需要封裝請求體對象,并將該對象設置在請求對象中。
實現步驟:
- 創建HttpClient對象
- 創建請求對象
- 發送請求,接收響應結果
- 解析響應結果
- 關閉資源
/*** 測試通過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
流程圖:
步驟分析:
- 小程序端,調用wx.login()獲取code,就是授權碼。
- 小程序端,調用wx.request()發送請求并攜帶code,請求開發者服務器(自己編寫的后端服務)。
- 開發者服務端,通過HttpClient向微信接口服務發送請求,并攜帶appId+appsecret+code三個參數。
- 開發者服務端,接收微信接口服務返回的數據,session_key+opendId等。opendId是微信用戶的唯一標識。
- 開發者服務端,自定義登錄態,生成令牌(token)和openid等數據返回給小程序端,方便后緒請求身份校驗。
- 小程序端,收到自定義登錄態,存儲storage。
- 小程序端,后緒通過wx.request()發起業務請求時,攜帶token。
- 開發者服務端,收到請求后,通過攜帶的token,解析當前登錄用戶的id。
- 開發者服務端,身份校驗通過后,繼續相關的業務邏輯處理,最終返回業務數據。
接下來,我們使用Postman進行測試。
說明:
- 調用 wx.login() 獲取 臨時登錄憑證code ,并回傳到開發者服務器。
- 調用 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表中。
字段名 | 數據類型 | 說明 | 備注 |
---|---|---|---|
id | bigint | 主鍵 | 自增 |
openid | varchar(45) | 微信用戶的唯一標識 | |
name | varchar(32) | 用戶姓名 | |
phone | varchar(11) | 手機號 | |
sex | varchar(2) | 性別 | |
id_number | varchar(18) | 身份證號 | |
avatar | varchar(500) | 微信用戶頭像路徑 | |
create_time | datetime | 注冊時間 |
**說明:**手機號字段比較特殊,個人身份注冊的小程序沒有權限獲取到微信用戶的手機號。如果是以企業的資質
注冊的小程序就能夠拿到微信用戶的手機號。
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 功能測試
重啟服務器、重新編譯小程序
微信登錄進入首頁
菜品和套餐分類查詢:
具體分類下的菜品查詢:
菜品口味查詢: