当前位置: 首页 > wzjs >正文

好用的网站建设英语培训

好用的网站建设,英语培训,咸宁有做网站的吗,阿里云服务器怎么用功能23:从后端获取路由/菜单数据 功能22:用户管理 功能21:使用axios发送请求 功能20:使用分页插件 功能19:集成MyBatis-Plus 功能18:创建后端工程 功能17:菜单管理 功能16:角色管理…

功能23:从后端获取路由/菜单数据

功能22:用户管理
功能21:使用axios发送请求
功能20:使用分页插件
功能19:集成MyBatis-Plus
功能18:创建后端工程
功能17:菜单管理
功能16:角色管理
功能15:用户管理
功能14:使用本地SVG图标库
功能13:侧边栏加入Logo
功能12:折叠/展开侧边栏
功能11:实现面包屑功能
功能10:添加首页菜单项
功能9:退出登录功能
功能8:页面权限控制
功能7:路由全局前置守卫
功能6:动态添加路由记录
功能5:侧边栏菜单动态显示
功能4:首页使用Layout布局
功能3:点击登录按钮实现页面跳转
功能2:静态登录界面
功能1:创建前端项目

前言

drop table if exists sys_menu;
create table sys_menu (menu_id           bigint(20)      not null auto_increment    comment '菜单ID',menu_name         varchar(50)     not null                   comment '菜单名称',parent_id         bigint(20)      default 0                  comment '父菜单ID',order_num         int(4)          default 0                  comment '显示顺序',path              varchar(200)    default ''                 comment '路由地址',component         varchar(255)    default null               comment '组件路径',query             varchar(255)    default null               comment '路由参数',route_name        varchar(50)     default ''                 comment '路由名称',is_frame          int(1)          default 1                  comment '是否为外链(0是 1否)',is_cache          int(1)          default 0                  comment '是否缓存(0缓存 1不缓存)',menu_type         char(1)         default ''                 comment '菜单类型(M目录 C菜单 F按钮)',visible           char(1)         default 0                  comment '菜单状态(0显示 1隐藏)',status            char(1)         default 0                  comment '菜单状态(0正常 1停用)',perms             varchar(100)    default null               comment '权限标识',icon              varchar(100)    default '#'                comment '菜单图标',create_by         varchar(64)     default ''                 comment '创建者',create_time       datetime                                   comment '创建时间',update_by         varchar(64)     default ''                 comment '更新者',update_time       datetime                                   comment '更新时间',remark            varchar(500)    default ''                 comment '备注',primary key (menu_id)
) engine=innodb auto_increment=2000 comment = '菜单权限表';

一.操作步骤(后端)

1.SysLoginController

src/main/java/com/ruoyi/web/controller/system/SysLoginController.java
监听接口/getRouters

@RestController
public class SysLoginController {@Autowiredprivate ISysMenuService menuService;/*** 获取路由信息** @return 路由信息*/@GetMapping("getRouters")public AjaxResult getRouters() {return AjaxResult.success(menuService.buildMenus(1L));}
}

2.Service接口和实现

src/main/java/com/ruoyi/system/service/ISysMenuService.java

public interface ISysMenuService extends IService<SysMenu> {List<RouterVo> buildMenus(Long userId);
}

src/main/java/com/ruoyi/system/service/impl/SysMenuServiceImpl.java
复杂的逻辑将数据库表中的数据进行转换后返回(具体逻辑到后续菜单管理功能也实现后再统一梳理)

@Service
public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu>implements ISysMenuService {@Overridepublic List<RouterVo> buildMenus(Long userId) {List<SysMenu> menus = list();List<SysMenu> menuTree = getChildPerms(menus, 0);return menu2Router(menuTree);}private List<RouterVo> menu2Router(List<SysMenu> menus) {List<RouterVo> routers = new LinkedList<>();for (SysMenu menu : menus) {RouterVo router = buildBaseRouter(menu);handleChildrenRoutes(menu, router);routers.add(router);}return routers;}/*** 根据父ID获取所有子菜单(递归构建树形结构)** @param list     菜单列表(平铺结构)* @param parentId 目标父菜单ID(需与菜单ID类型一致,此处假设为long)* @return 树形结构子菜单列表*/private List<SysMenu> getChildPerms(List<SysMenu> list, long parentId) {// 1. 预构建父节点到子节点的映射(提升查找效率)Map<Long, List<SysMenu>> parentIdToChildrenMap = list.stream().collect(Collectors.groupingBy(SysMenu::getParentId));// 2. 直接获取父节点的子节点列表,并递归构建树List<SysMenu> returnList = new ArrayList<>();for (SysMenu menu : list) {if (menu.getParentId() == parentId) {buildTree(parentIdToChildrenMap, menu);returnList.add(menu);}}return returnList;}/*** 递归构建菜单树形结构(基于预生成的映射)** @param parentMap   父节点到子节点的映射* @param currentNode 当前处理节点*/private void buildTree(Map<Long, List<SysMenu>> parentMap, SysMenu currentNode) {List<SysMenu> childList = parentMap.getOrDefault(currentNode.getMenuId(), new ArrayList<>());currentNode.setChildren(childList);for (SysMenu child : childList) {buildTree(parentMap, child); // 递归处理子节点}}/*** 构建基础路由信息*/private RouterVo buildBaseRouter(SysMenu menu) {RouterVo router = new RouterVo();router.setHidden("1".equals(menu.getVisible()));router.setName(getRouteName(menu));router.setPath(getRouterPath(menu));router.setComponent(getComponent(menu));router.setQuery(menu.getQuery());router.setMeta(buildMetaData(menu));return router;}/*** 处理子路由的特殊情况*/private void handleChildrenRoutes(SysMenu menu, RouterVo router) {List<SysMenu> childMenus = menu.getChildren();// 处理目录类型if (isDirectoryWithChildren(menu, childMenus)) {router.setAlwaysShow(true);router.setRedirect("noRedirect");router.setChildren(menu2Router(childMenus));return;}// 处理根菜单if (isRootMenu(menu)) {handleRootMenu(menu, router);return;}// 处理根菜单的内部链接if (isRootInnerLink(menu)) {handleRootInnerLink(menu, router);}}/*** 构建元数据信息*/private MetaVo buildMetaData(SysMenu menu) {return new MetaVo(menu.getMenuName(),menu.getIcon(),"1".equals(menu.getIsCache()),menu.getPath());}/*** 处理菜单框架的特殊情况*/private void handleRootMenu(SysMenu menu, RouterVo router) {router.setMeta(null);RouterVo child = buildBaseRouter(menu);child.setPath(menu.getPath()); // 覆盖路径child.setComponent(menu.getComponent());child.setName(getRouteName(menu.getRouteName(), menu.getPath()));router.setChildren(Collections.singletonList(child));}/*** 处理内部链接的特殊情况*/private void handleRootInnerLink(SysMenu menu, RouterVo router) {router.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon()));router.setPath("/");RouterVo child = new RouterVo();child.setPath(innerLinkReplaceEach(menu.getPath()));child.setComponent(UserConstants.INNER_LINK);child.setName(getRouteName(menu.getRouteName(), child.getPath()));child.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), menu.getPath()));router.setChildren(Collections.singletonList(child));}/* 以下为辅助方法 *//*** 判断是否为目录类型且包含子菜单*/private boolean isDirectoryWithChildren(SysMenu menu, List<SysMenu> childMenus) {return CollectionUtils.isNotEmpty(childMenus)&& UserConstants.TYPE_DIR.equals(menu.getMenuType());}/*** 判断是否为根菜单*/private boolean isRootMenu(SysMenu menu) {return isRoot(menu)&& UserConstants.TYPE_MENU.equals(menu.getMenuType())&& UserConstants.NO_FRAME.equals(menu.getIsFrame());}/*** 判断是否为根内部链接*/private boolean isRootInnerLink(SysMenu menu) {return isRoot(menu) && isInnerLink(menu);}/*** 判断是否内部展示的地址*/private boolean isInnerLink(SysMenu menu) {return UserConstants.NO_FRAME.equals(menu.getIsFrame())&& StringUtils.ishttp(menu.getPath());}/*** 判断是否为根菜单(parentId为0)*/private boolean isRoot(SysMenu menu) {return menu.getParentId() != null && menu.getParentId().intValue() == 0;}/*** 获取路由名称(优先使用配置的路由名)*/private String getRouteName(SysMenu menu) {return isRootMenu(menu)? StringUtils.EMPTY: getRouteName(menu.getRouteName(), menu.getPath());}/*** 生成最终路由名称(首字母大写)*/private String getRouteName(String routeName, String path) {return StringUtils.capitalize(StringUtils.defaultIfEmpty(routeName, path));}/*** 获取路由路径(处理特殊路径情况)*/private String getRouterPath(SysMenu menu) {if (isNonRootInnerLink(menu)) {return innerLinkReplaceEach(menu.getPath());}if (isRootDirectoryFrame(menu)) {return "/" + menu.getPath();}return isRootMenu(menu) ? "/" : menu.getPath();}/*** 判断非根菜单的内部链接*/private boolean isNonRootInnerLink(SysMenu menu) {return !isRoot(menu) && isInnerLink(menu);}/*** 判断是否为根目录框架*/private boolean isRootDirectoryFrame(SysMenu menu) {return isRoot(menu)&& UserConstants.TYPE_DIR.equals(menu.getMenuType())&& UserConstants.NO_FRAME.equals(menu.getIsFrame());}/*** 获取组件路径(智能处理不同情况)*/private String getComponent(SysMenu menu) {if (StringUtils.isNotEmpty(menu.getComponent()) && !isRootMenu(menu)) {return menu.getComponent();}if (isInnerLinkComponent(menu)) {return UserConstants.INNER_LINK;}if (isParentView(menu)) {return UserConstants.PARENT_VIEW;}return UserConstants.LAYOUT;}private boolean isInnerLinkComponent(SysMenu menu) {return StringUtils.isEmpty(menu.getComponent())&& menu.getParentId().intValue() != 0&& isInnerLink(menu);}/*** 判断是否需要父视图组件*/private boolean isParentView(SysMenu menu) {return !isRoot(menu) && UserConstants.TYPE_DIR.equals(menu.getMenuType());}/*** 处理内部链接路径格式转换(使用正则表达式优化)*/private String innerLinkReplaceEach(String path) {return path.replaceAll("^(http|https|www)([.:])+", "").replaceAll("[.:]", "/");}
}

3.Mapper

src/main/java/com/ruoyi/system/mapper/SysMenuMapper.java

public interface SysMenuMapper extends BaseMapper<SysMenu> {
}

4.实体类SysMenu

src/main/java/com/ruoyi/common/core/domain/entity/SysMenu.java

@TableName("sys_menu")
public class SysMenu {/*** 菜单ID*/@TableId(type = IdType.AUTO)  // 主键自增private Long menuId;/*** 菜单名称*/private String menuName;/*** 父菜单名称*/@TableField(exist = false)private String parentName;/*** 父菜单ID*/private Long parentId;/*** 显示顺序*/private Integer orderNum;/*** 路由地址*/private String path;/*** 组件路径*/private String component;/*** 路由参数*/private String query;/*** 路由名称,默认和路由地址相同的驼峰格式(注意:因为vue3版本的router会删除名称相同路由,为避免名字的冲突,特殊情况可以自定义)*/private String routeName;/*** 是否为外链(0是 1否)*/private String isFrame;/*** 是否缓存(0缓存 1不缓存)*/private String isCache;/*** 类型(M目录 C菜单 F按钮)*/private String menuType;/*** 显示状态(0显示 1隐藏)*/private String visible;/*** 菜单状态(0正常 1停用)*/private String status;/*** 权限字符串*/private String perms;/*** 菜单图标*/private String icon;/*** 创建者*/private String createBy;/*** 创建时间*/private Date createTime;/*** 更新者*/private String updateBy;/*** 更新时间*/private Date updateTime;/*** 备注*/private String remark;/*** 子菜单*/@TableField(exist = false)private List<SysMenu> children = new ArrayList<>();public List<SysMenu> getChildren() {return children;}public void setChildren(List<SysMenu> children) {this.children = children;}public Long getMenuId() {return menuId;}public void setMenuId(Long menuId) {this.menuId = menuId;}public String getMenuName() {return menuName;}public void setMenuName(String menuName) {this.menuName = menuName;}public String getParentName() {return parentName;}public void setParentName(String parentName) {this.parentName = parentName;}public Long getParentId() {return parentId;}public void setParentId(Long parentId) {this.parentId = parentId;}public Integer getOrderNum() {return orderNum;}public void setOrderNum(Integer orderNum) {this.orderNum = orderNum;}public String getPath() {return path;}public void setPath(String path) {this.path = path;}public String getComponent() {return component;}public void setComponent(String component) {this.component = component;}public String getQuery() {return query;}public void setQuery(String query) {this.query = query;}public String getRouteName() {return routeName;}public void setRouteName(String routeName) {this.routeName = routeName;}public String getIsFrame() {return isFrame;}public void setIsFrame(String isFrame) {this.isFrame = isFrame;}public String getIsCache() {return isCache;}public void setIsCache(String isCache) {this.isCache = isCache;}public String getMenuType() {return menuType;}public void setMenuType(String menuType) {this.menuType = menuType;}public String getVisible() {return visible;}public void setVisible(String visible) {this.visible = visible;}public String getStatus() {return status;}public void setStatus(String status) {this.status = status;}public String getPerms() {return perms;}public void setPerms(String perms) {this.perms = perms;}public String getIcon() {return icon;}public void setIcon(String icon) {this.icon = icon;}public String getCreateBy() {return createBy;}public void setCreateBy(String createBy) {this.createBy = createBy;}public Date getCreateTime() {return createTime;}public void setCreateTime(Date createTime) {this.createTime = createTime;}public String getUpdateBy() {return updateBy;}public void setUpdateBy(String updateBy) {this.updateBy = updateBy;}public Date getUpdateTime() {return updateTime;}public void setUpdateTime(Date updateTime) {this.updateTime = updateTime;}public String getRemark() {return remark;}public void setRemark(String remark) {this.remark = remark;}
}

5.工具类StringUtils

src/main/java/com/ruoyi/common/utils/StringUtils.java

public class StringUtils extends org.apache.commons.lang3.StringUtils {/*** 空字符串*/private static final String NULLSTR = "";/*** * 判断一个字符串是否为空串** @param str String* @return true:为空 false:非空*/public static boolean isEmpty(String str) {return isNull(str) || NULLSTR.equals(str.trim());}/*** * 判断一个字符串是否为非空串** @param str String* @return true:非空串 false:空串*/public static boolean isNotEmpty(String str) {return !isEmpty(str);}/*** * 判断一个对象是否为空** @param object Object* @return true:为空 false:非空*/public static boolean isNull(Object object) {return object == null;}/*** 是否为http(s)://开头** @param link 链接* @return 结果*/public static boolean ishttp(String link) {return StringUtils.startsWithAny(link, Constants.HTTP, Constants.HTTPS);}
}

6.VO

src/main/java/com/ruoyi/system/domain/vo/RouterVo.java

public class RouterVo {/*** 路由名字*/private String name;/*** 路由地址*/private String path;/*** 是否隐藏路由,当设置 true 的时候该路由不会再侧边栏出现*/private boolean hidden;/*** 重定向地址,当设置 noRedirect 的时候该路由在面包屑导航中不可被点击*/private String redirect;/*** 组件地址*/private String component;/*** 路由参数:如 {"id": 1, "name": "ry"}*/private String query;/*** 当你一个路由下面的 children 声明的路由大于1个时,自动会变成嵌套的模式--如组件页面*/private Boolean alwaysShow;/*** 其他元素*/private MetaVo meta;/*** 子路由*/private List<RouterVo> children;public String getName() {return name;}public void setName(String name) {this.name = name;}public String getPath() {return path;}public void setPath(String path) {this.path = path;}public boolean getHidden() {return hidden;}public void setHidden(boolean hidden) {this.hidden = hidden;}public String getRedirect() {return redirect;}public void setRedirect(String redirect) {this.redirect = redirect;}public String getComponent() {return component;}public void setComponent(String component) {this.component = component;}public String getQuery() {return query;}public void setQuery(String query) {this.query = query;}public Boolean getAlwaysShow() {return alwaysShow;}public void setAlwaysShow(Boolean alwaysShow) {this.alwaysShow = alwaysShow;}public MetaVo getMeta() {return meta;}public void setMeta(MetaVo meta) {this.meta = meta;}public List<RouterVo> getChildren() {return children;}public void setChildren(List<RouterVo> children) {this.children = children;}
}

src/main/java/com/ruoyi/system/domain/vo/MetaVo.java

public class MetaVo {/*** 设置该路由在侧边栏和面包屑中展示的名字*/private String title;/*** 设置该路由的图标,对应路径src/assets/icons/svg*/private String icon;/*** 设置为true,则不会被 <keep-alive>缓存*/private boolean noCache;/*** 内链地址(http(s)://开头)*/private String link;public MetaVo() {}public MetaVo(String title, String icon) {this.title = title;this.icon = icon;}public MetaVo(String title, String icon, boolean noCache) {this.title = title;this.icon = icon;this.noCache = noCache;}public MetaVo(String title, String icon, String link) {this.title = title;this.icon = icon;this.link = link;}public MetaVo(String title, String icon, boolean noCache, String link) {this.title = title;this.icon = icon;this.noCache = noCache;if (StringUtils.ishttp(link)) {this.link = link;}}public boolean isNoCache() {return noCache;}public void setNoCache(boolean noCache) {this.noCache = noCache;}public String getTitle() {return title;}public void setTitle(String title) {this.title = title;}public String getIcon() {return icon;}public void setIcon(String icon) {this.icon = icon;}public String getLink() {return link;}public void setLink(String link) {this.link = link;}
}

7.pom

引入工具依赖

        <!--常用工具类 --><dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId></dependency>

8.配置文件

src/main/resources/application.yml

spring:jackson:default-property-inclusion: NON_EMPTY

9.常量类

src/main/java/com/ruoyi/common/constant/Constants.java

public class Constants {/*** http请求*/public static final String HTTP = "http://";/*** https请求*/public static final String HTTPS = "https://";
}

src/main/java/com/ruoyi/common/constant/UserConstants.java

public class UserConstants {public static final String YES_FRAME = "0";public static final String NO_FRAME = "1";/*** 菜单类型(目录)*/public static final String TYPE_DIR = "M";/*** 菜单类型(菜单)*/public static final String TYPE_MENU = "C";/*** 菜单类型(按钮)*/public static final String TYPE_BUTTON = "F";/*** Layout组件标识*/public final static String LAYOUT = "Layout";/*** ParentView组件标识*/public final static String PARENT_VIEW = "ParentView";/*** InnerLink组件标识*/public final static String INNER_LINK = "InnerLink";
}

操作步骤(前端)

10.API

src\api\login.js

import request from '@/utils/request'// 获取路由
export const getRouters = () => {return request({url: '/getRouters',method: 'get'})
}

11.前置守卫

src\permission.js

import router from './router'
import { getToken } from '@/utils/auth'
import usePermissionStore from '@/stores/permission'const whiteList = ['/login']
const whiteListDict = whiteList.reduce((acc, cur) => {acc[cur] = true;return acc;
}, {});router.beforeEach(async (to, from, next) => {if (getToken()) {if (whiteListDict[to.path]) {next({ path: '/' })} else {if (router.getRoutes().length <= 3) {try {const newRouteRecord = await usePermissionStore().generateRoutes()newRouteRecord.forEach(route => {router.addRoute(route) // 动态添加可访问路由表})next({ ...to, replace: true })} catch (error) {console.error(error)}} else {next()}}} else {// 没有tokenif (whiteListDict[to.path]) {// 在免登录白名单,直接进入next()} else {next(`/login?redirect=${to.fullPath}`) // 否则全部重定向到登录页}}
})

12.permissionStore

src\stores\permission.js
调用新增的API接口,并处理返回结果。

import { ref } from 'vue'
import { defineStore } from 'pinia'
import Layout from '@/layout/index.vue'
import { constantRoutes } from '@/router'
import { getRouters } from '@/api/login'
import { isHttp } from '@/utils/ruoyi'// 匹配views里面所有的.vue文件
const modules = import.meta.glob('@/views/**/*.vue')const usePermissionStore = defineStore('permission', () => {const arrayForMenu = ref([])const arrayForRouter = ref([])// 异步操作const generateRoutes = async () => {const res = await getRouters()const menuData = JSON.parse(JSON.stringify(res.data))const routeData = JSON.parse(JSON.stringify(res.data))arrayForMenu.value = constantRoutes.concat(menuData)const routeDataFilter = filterAsyncRouter(routeData)arrayForRouter.value = routeDataFilterreturn routeDataFilter}return {arrayForMenu,arrayForRouter,generateRoutes}
})/*** 异步路由过滤器 - 核心路由配置处理器* 功能: * 1. 递归处理路由配置树,动态加载Vue组件* 2. 特殊处理Layout组件和ParentView结构* 3. 规范化路由配置结构* * @param {Array} asyncRouterArr - 原始异步路由配置数组* @returns {Array} 处理后的标准化路由配置数组* * 处理逻辑:* 1. 遍历路由配置,处理子路由配置* 2. 动态加载组件(转换字符串路径为真实组件)* 3. 递归处理嵌套子路由* 4. 清理空children和redirect属性*/
const filterAsyncRouter = (asyncRouterArr) => {return asyncRouterArr.filter(routeMap => {if (isHttp(routeMap.path)) {return false;}// 处理子路由if (routeMap.children) {routeMap.children = filterChildrenForRouter(routeMap.children);}if (routeMap.component) {// Layout 组件特殊处理if (routeMap.component === 'Layout') {routeMap.component = Layout} else {routeMap.component = loadView(routeMap.component)}}// 递归处理子路由if (routeMap.children?.length) {filterAsyncRouter(routeMap.children);} else {delete routeMap.children;delete routeMap.redirect;}return true;});
}/*** 子路由结构转换器 - 路由层级扁平化处理器* 功能:* 1. 处理ParentView类型的路由结构* 2. 合并嵌套子路由路径* 3. 将多级路由转换为扁平结构* * @param {Array} childrenArr - 原子路由配置数组* @returns {Array} 转换后的扁平化子路由数组* * 处理逻辑:* 1. 当遇到ParentView组件时,将其子路由提升到当前层级* 2. 合并父级路径到子路由path* 3. 保留普通路由配置*/
const filterChildrenForRouter = (childrenArr) => {let children = [];childrenArr.forEach(el => {if (el.children?.length && el.component === 'ParentView') {children.push(...el.children.map(c => ({...c,path: `${el.path}/${c.path}`})));return;}children.push(el);});return children;
}/*** 动态组件加载器 - 模块解析器* 功能:* 根据组件路径字符串动态加载Vue组件* * @param {string} view - 组件路径字符串(例: "system/user/index")* @returns {Component} Vue组件* * 处理逻辑:* 1. 遍历预编译的模块集合(modules)* 2. 匹配views目录下的对应组件文件* 3. 返回组件异步加载函数*/
const loadView = (view) => {let res;for (const path in modules) {const dir = path.split('views/')[1].split('.vue')[0];if (dir === view) {res = () => modules[path]();}}return res;
}export default usePermissionStore

13.工具类

src\utils\ruoyi.js

/*** 判断url是否是http或https * @param {string} url* @returns {Boolean}*/
export function isHttp(url) {return typeof url === 'string' && url.startsWith('http');
}

二.功能验证

运行项目,浏览器访问http://localhost:5173/index
在这里插入图片描述
侧边栏显示正常。

http://www.dtcms.com/wzjs/61371.html

相关文章:

  • 买CAD设计图做的网站产品推广软件有哪些
  • 网站建设的过程包括几个阶段seo免费教程
  • 通过邮箱查注册网站百度公司招聘官网最新招聘
  • 淘宝优惠网站如何做seo搜索引擎实战详解
  • 武汉网站建设收费做网站关键词优化的公司
  • wordpress标题添加新字广东seo推广哪里好
  • 公司网站建设制作丹东网站seo
  • 网站建设合同书 简易关键词优化怎么写
  • 枣庄公司做网站seo是什么技术
  • 太原网站建设制作企业员工培训内容及计划
  • 模板网站和定制网站后缀的区别关键词批量调词 软件
  • 做学术研究的网站厦门人才网手机版
  • 做竞价的网站需要做外部链接吗seo网站免费优化软件
  • dede5.7内核qq个性门户网站源码百度分析
  • 介绍做网站的标题营销网络图
  • 做此广告的网站谷歌浏览器下载安装(手机安卓版)
  • 网站开发从哪里学起孝感seo
  • 做网站的怎么挣钱、科学新概念外链平台
  • 客服网站备案长沙网站关键词排名公司
  • 做网站的语言叫什么保定网站推广公司
  • 网站怎么做动效百度搜索引擎平台
  • 往网站上做新东西需要什么老铁外链
  • 常德制作网站seo推广学院
  • asp网站导航怎么做seo优化sem推广
  • 用网站ip做代理网站搜索优化排名
  • 各大网站域名seo营销名词解释
  • 深圳企业网站建设服务百度打开
  • 做拼货商城网站app开发软件
  • 淘宝联盟怎么做自已的网站程序员培训班要多少钱
  • 西宁网站建设高端北京seo服务行者