赞
踩
帮助我们用户(客户端)去更轻松的实现功能,不需要关心门面背后的细节,当调用你接口的客户端觉得麻烦的时候,是不是就可以抽象成一个门面了?
后端
将controller层的业务代码抽象到manager/SearchFacade中
前端
IndexPage代码改造为加载单类数据
<template> <div class="index-page"> <a-input-search v-model:value="searchText" placeholder="input search text" enter-button @search="onSearch" /> <MyDivider/> <a-tabs v-model:activeKey="activeKey" @change="onTabChange"> <a-tab-pane key="post" tab="文章" > <PostList :post-list="postList"/></a-tab-pane> <a-tab-pane key="picture" tab="图片" force-render><PictureList :picture-list="pictureList"/></a-tab-pane> <a-tab-pane key="user" tab="用户"> <UserList :user-list="userList"/></a-tab-pane> </a-tabs> </div> </template> <script setup lang="ts"> import {ref, watchEffect} from 'vue'; import PostList from '@/components/PostList.vue'; import PictureList from '@/components/PictureList.vue'; import UserList from '@/components/UserList.vue'; import MyDivider from '@/components/MyDivider.vue'; import { useLink, useRoute, useRouter } from 'vue-router'; import myAxios from '@/plugins/myAxios'; import { message } from 'ant-design-vue'; //创建路由实例 const router = useRouter(); //获取路由所有信息 const route = useRoute(); const activeKey = route.params.category; const initSearchParams = { type: activeKey, text:"", pageSize: 10, pageNum: 1, }; const searchText = ref(route.query.text || ""); //把initSearchParams变为响应式对象 const searchParams = ref(initSearchParams); const postList = ref([]); const userList = ref([]); const pictureList = ref([]); //旧 :加载数据 const loadDataOld = (params: any) => { const pictureQuery = { ...params, searchText: params.text, }; myAxios.post("/picture/search/page/vo",pictureQuery).then((res: any) => { pictureList.value = res.records; }); const postQuery = { ...params, searchText: params.text, }; myAxios.post("/post/list/page/vo", postQuery).then((res: any) => { postList.value = res.records; }); const userQuery = { ...params, userName: params.text, } myAxios.post("/user/list/page/vo", userQuery).then((res: any) => { userList.value = res.records; }); }; //新 :加载聚合数据 const loadAllData = (params: any) => { const query = { ...params, searchText: params.text, }; myAxios.post("/search/all",query).then((res: any) => { userList.value = res.userList; pictureList.value = res.pictureList; postList.value = res.postList; }); }; //更新 :加载单类数据 const loadData = (params: any) => { const {type} = params; if(!type){ message.error("类别为空"); return; } const query = { ...params, searchText: params.text, }; myAxios.post("/search/all",query).then((res: any) => { if(type === "post"){ postList.value = res.postList; }else if(type === "user"){ userList.value = res.userList; }else if(type === "picture"){ pictureList.value = res.pictureList; } }); }; //监视路由变化 watchEffect(() =>{ searchParams.value = { ...initSearchParams, text: route.query.text, type: route.params.category, } as any; loadData(searchParams.value); }); //用户每次搜索 loadData(initSearchParams); const onSearch = (value: string) =>{ //把搜索框里面的内容压到路由中 router.push({ query:{ ...searchParams.value, text: value, }, }); loadData(searchParams.value); }; //每次导航栏切换 const onTabChange = (key: string) => { router.push({ path: `/${key}`, query: searchParams.value, }); }; </script>
package com.yupi.springbootinit.dataSource;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.apache.poi.ss.formula.functions.T;
/**
* 数据源接口
* (新接入的数据源必须实现)
*/
public interface DataSource<T> {
Page<T> doSearch(String searchText, long pageNum, long pageSize);
}
package com.yupi.springbootinit.dataSource; import cn.hutool.json.JSONUtil; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.yupi.springbootinit.common.ErrorCode; import com.yupi.springbootinit.exception.BusinessException; import com.yupi.springbootinit.model.entity.Picture; import com.yupi.springbootinit.service.PictureService; import lombok.extern.slf4j.Slf4j; import org.apache.poi.ss.formula.functions.T; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; import org.jsoup.select.Elements; import org.springframework.stereotype.Service; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Map; /** * 帖子服务实现 * * * */ @Service @Slf4j public class PictureDataSource implements DataSource<Picture> { @Override public Page<Picture> doSearch(String searchText, long pageNum, long pageSize) { long current = (pageNum - 1) * pageSize; String url = String.format("https://cn.bing.com/images/search?q=%s&first=%s",searchText,current); Document doc = null; try { doc = Jsoup.connect(url).get(); } catch (IOException e) { throw new BusinessException(ErrorCode.PARAMS_ERROR, "数据抓取失败"); } Elements elements = doc.select(".iuscp.isv"); //数组,每个元素是每一张图片 List<Picture> pictures = new ArrayList<>(); for (Element element : elements) { //取图片地址murl String m = element.select(".iusc").attr("m"); Map<String, Object> map = JSONUtil.toBean(m, Map.class); String murl = (String) map.get("murl"); //取标题 String title = element.select(".inflnk").attr("aria-label"); Picture picture = new Picture(); picture.setTitle(title); picture.setUrl(murl); pictures.add(picture); if (pictures.size() >= pageSize) break; } Page<Picture> picturePage = new Page<>(pageNum,pageSize); picturePage.setRecords(pictures); return picturePage; } }
package com.yupi.springbootinit.dataSource; import cn.hutool.core.collection.CollUtil; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.yupi.springbootinit.common.ErrorCode; import com.yupi.springbootinit.constant.CommonConstant; import com.yupi.springbootinit.exception.BusinessException; import com.yupi.springbootinit.exception.ThrowUtils; import com.yupi.springbootinit.mapper.PostFavourMapper; import com.yupi.springbootinit.mapper.PostMapper; import com.yupi.springbootinit.mapper.PostThumbMapper; import com.yupi.springbootinit.model.dto.post.PostEsDTO; import com.yupi.springbootinit.model.dto.post.PostQueryRequest; import com.yupi.springbootinit.model.entity.Post; import com.yupi.springbootinit.model.entity.PostFavour; import com.yupi.springbootinit.model.entity.PostThumb; import com.yupi.springbootinit.model.entity.User; import com.yupi.springbootinit.model.vo.PostVO; import com.yupi.springbootinit.model.vo.UserVO; import com.yupi.springbootinit.service.PostService; import com.yupi.springbootinit.service.UserService; import com.yupi.springbootinit.utils.SqlUtils; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; import org.elasticsearch.index.query.BoolQueryBuilder; import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.search.sort.SortBuilder; import org.elasticsearch.search.sort.SortBuilders; import org.elasticsearch.search.sort.SortOrder; import org.springframework.data.domain.PageRequest; import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate; import org.springframework.data.elasticsearch.core.SearchHit; import org.springframework.data.elasticsearch.core.SearchHits; import org.springframework.data.elasticsearch.core.query.NativeSearchQuery; import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder; import org.springframework.stereotype.Service; import org.springframework.web.context.request.RequestAttributes; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import java.util.*; import java.util.stream.Collectors; /** * 帖子服务实现 */ @Service @Slf4j public class PostDataSource extends ServiceImpl<PostMapper, Post> implements DataSource<PostVO> { @Resource private PostService postService; @Override public Page<PostVO> doSearch(String searchText, long pageNum, long pageSize) { PostQueryRequest postQueryRequest = new PostQueryRequest(); postQueryRequest.setSearchText(searchText); postQueryRequest.setCurrent(pageNum); postQueryRequest.setPageSize(pageSize); HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest(); Page<PostVO> postVOPage = postService.listPostVOByPage(postQueryRequest, request); return postVOPage; } }
package com.yupi.springbootinit.dataSource; import cn.hutool.core.collection.CollUtil; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.yupi.springbootinit.common.ErrorCode; import com.yupi.springbootinit.constant.CommonConstant; import com.yupi.springbootinit.exception.BusinessException; import com.yupi.springbootinit.mapper.UserMapper; import com.yupi.springbootinit.model.dto.user.UserQueryRequest; import com.yupi.springbootinit.model.entity.User; import com.yupi.springbootinit.model.enums.UserRoleEnum; import com.yupi.springbootinit.model.vo.LoginUserVO; import com.yupi.springbootinit.model.vo.UserVO; import com.yupi.springbootinit.service.UserService; import com.yupi.springbootinit.utils.SqlUtils; import lombok.extern.slf4j.Slf4j; import me.chanjar.weixin.common.bean.WxOAuth2UserInfo; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.BeanUtils; import org.springframework.stereotype.Service; import org.springframework.util.DigestUtils; import javax.annotation.RegEx; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; import static com.yupi.springbootinit.constant.UserConstant.USER_LOGIN_STATE; /** * 用户服务实现 * * * */ @Service @Slf4j public class UserDataSource extends ServiceImpl<UserMapper, User> implements DataSource { @Resource private UserService userService; @Override public Page doSearch(String searchText, long pageNum, long pageSize) { UserQueryRequest userQueryRequest = new UserQueryRequest(); userQueryRequest.setUserName(searchText); Page<User> userPage = this.page(new Page<>(pageNum, pageSize), userService.getQueryWrapper(userQueryRequest)); Page<UserVO> userVOPage = new Page<>(pageNum, pageSize, userPage.getTotal()); List<UserVO> userVO = userService.getUserVO(userPage.getRecords()); userVOPage.setRecords(userVO); return userVOPage; } }
@Component @Slf4j public class SearchFacade { @Resource private PictureDataSource pictureDataSource; @Resource private UserDataSource userDataSource; @Resource private PostDataSource postDataSource; public SearchVO searchAll(@RequestBody SearchRequest searchRequest, HttpServletRequest request) { String type = searchRequest.getType(); ThrowUtils.throwIf(StringUtils.isBlank(type), ErrorCode.PARAMS_ERROR); SearchTypeEnum searchTypeEnum = SearchTypeEnum.getEnumByValue(type); String searchText = searchRequest.getSearchText(); long current = searchRequest.getCurrent(); long pageSize = searchRequest.getPageSize(); if(searchTypeEnum == null){ CompletableFuture<Page<UserVO>> userTask = CompletableFuture.supplyAsync(() ->{ UserQueryRequest userQueryRequest = new UserQueryRequest(); userQueryRequest.setUserName(searchText); Page<UserVO> userVOPage = userDataSource.doSearch(searchText,current,pageSize); return userVOPage; }); CompletableFuture<Page<PostVO>> postTask = CompletableFuture.supplyAsync(()->{ PostQueryRequest postQueryRequest = new PostQueryRequest(); postQueryRequest.setSearchText(searchText); Page<PostVO> postVOPage = postDataSource.doSearch(searchText,current,pageSize); return postVOPage; }); CompletableFuture<Page<Picture>> pictureTask = CompletableFuture.supplyAsync(()->{ Page<Picture> picturePage = pictureDataSource.doSearch(searchText, 1, 10); return picturePage; }); //聚合 CompletableFuture.allOf(userTask,postTask,pictureTask).join(); try { Page<UserVO> userVOPage = userTask.get(); Page<PostVO> postVOPage = postTask.get(); Page<Picture> picturePage = pictureTask.get(); SearchVO searchVO = new SearchVO(); searchVO.setUserList(userVOPage.getRecords()); searchVO.setPictureList(picturePage.getRecords()); searchVO.setPostList(postVOPage.getRecords()); return searchVO; }catch (Exception e){ log.error("查询异常",e); throw new BusinessException(ErrorCode.SYSTEM_ERROR,"查询异常"); } }else{ Map<String, DataSource> typeDataSourceMap = new HashMap(){{ put(SearchTypeEnum.POST.getValue(),postDataSource); put(SearchTypeEnum.USER.getValue(),userDataSource); put(SearchTypeEnum.PICTURE.getValue(),pictureDataSource); }}; SearchVO searchVO = new SearchVO(); DataSource dataSource = typeDataSourceMap.get(type); Page page = dataSource.doSearch(searchText, current, pageSize); searchVO.setDataList(page.getRecords()); return searchVO; } } }
(本质也是单例)
提前用一个map或者其他类型存储好后面需要调用的对象。
作用:代码量大幅度减少,可维护可扩展
@Component public class DataSourceRegistry { @Resource private PictureDataSource pictureDataSource; @Resource private UserDataSource userDataSource; @Resource private PostDataSource postDataSource; private Map<String, DataSource> typeDataSourceMap; /** * @PostConstruct标识的方法会在Spring容器完成依赖注入后立即执行。 * 没有这个初始化方法的话,依赖注入以后还没有执行typeDataSourceMap的赋值操作,就调用了getDataSourceByType方法,肯定是返回空的 */ @PostConstruct public void init() { typeDataSourceMap = new HashMap() { { put(SearchTypeEnum.POST.getValue(), postDataSource); put(SearchTypeEnum.USER.getValue(), userDataSource); put(SearchTypeEnum.PICTURE.getValue(), pictureDataSource); } }; } public DataSource getDataSourceByType(String type) { if(typeDataSourceMap == null){ return null; } return typeDataSourceMap.get(type); } }
@Component @Slf4j public class SearchFacade { @Resource private PictureDataSource pictureDataSource; @Resource private UserDataSource userDataSource; @Resource private PostDataSource postDataSource; @Resource private DataSourceRegistry dataSourceRegistry; public SearchVO searchAll(@RequestBody SearchRequest searchRequest, HttpServletRequest request) { String type = searchRequest.getType(); ThrowUtils.throwIf(StringUtils.isBlank(type), ErrorCode.PARAMS_ERROR); SearchTypeEnum searchTypeEnum = SearchTypeEnum.getEnumByValue(type); String searchText = searchRequest.getSearchText(); long current = searchRequest.getCurrent(); long pageSize = searchRequest.getPageSize(); if(searchTypeEnum == null){ CompletableFuture<Page<UserVO>> userTask = CompletableFuture.supplyAsync(() ->{ UserQueryRequest userQueryRequest = new UserQueryRequest(); userQueryRequest.setUserName(searchText); Page<UserVO> userVOPage = userDataSource.doSearch(searchText,current,pageSize); return userVOPage; }); CompletableFuture<Page<PostVO>> postTask = CompletableFuture.supplyAsync(()->{ PostQueryRequest postQueryRequest = new PostQueryRequest(); postQueryRequest.setSearchText(searchText); Page<PostVO> postVOPage = postDataSource.doSearch(searchText,current,pageSize); return postVOPage; }); CompletableFuture<Page<Picture>> pictureTask = CompletableFuture.supplyAsync(()->{ Page<Picture> picturePage = pictureDataSource.doSearch(searchText, 1, 10); return picturePage; }); //聚合 CompletableFuture.allOf(userTask,postTask,pictureTask).join(); try { Page<UserVO> userVOPage = userTask.get(); Page<PostVO> postVOPage = postTask.get(); Page<Picture> picturePage = pictureTask.get(); SearchVO searchVO = new SearchVO(); searchVO.setUserList(userVOPage.getRecords()); searchVO.setPictureList(picturePage.getRecords()); searchVO.setPostList(postVOPage.getRecords()); return searchVO; }catch (Exception e){ log.error("查询异常",e); throw new BusinessException(ErrorCode.SYSTEM_ERROR,"查询异常"); } }else{ SearchVO searchVO = new SearchVO(); DataSource dataSource = dataSourceRegistry.getDataSourceByType(type); Page page = dataSource.doSearch(searchText, current, pageSize); searchVO.setDataList(page.getRecords()); return searchVO; } } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。