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

dedecms 音乐网站模板自己怎么建设收费电影网站

dedecms 音乐网站模板,自己怎么建设收费电影网站,网站建设工作函,好看的商标logo设计文章目录 1 环境搭建及简介2 项目介绍2.1 应用2.2 业务说明2.3 技术栈2.4 收获2.5 大纲 3 Nacos准备3.1 安装Nacos 4 初始工程搭建4.1 环境准备4.1.1 导入项目4.1.2 设置本地仓库4.1.3 设置项目编码格式 4.2 全局异常4.2.1 自动装配 4.3 工程主体结构 5 登录功能开发5.1 需求分… 文章目录 1 环境搭建及简介2 项目介绍2.1 应用2.2 业务说明2.3 技术栈2.4 收获2.5 大纲 3 Nacos准备3.1 安装Nacos 4 初始工程搭建4.1 环境准备4.1.1 导入项目4.1.2 设置本地仓库4.1.3 设置项目编码格式 4.2 全局异常4.2.1 自动装配 4.3 工程主体结构 5 登录功能开发5.1 需求分析5.1.1 表结构分析5.1.2 实体类ApUser的导入5.1.3 表结构中salt的解释5.1.3.1 注册过程5.1.3.2 登录过程 6 用户端微服务的搭建6.1 service模块的依赖说明6.2 创建用户微服务模块6.2.1 创建引导类6.2.2 创建controller.v1、service、mapper、config6.2.3 创建resources的配置文件6.2.3.1 bootstrap.yml6.2.3.2 logback.xml 6.3 整体用户端框架 7 登录接口实现7.1 app登录-接口定义7.1.1 DTO的LoginDto类7.1.2 Controller层ApUserLoginController类7.1.3 Mapper层ApUserMapper接口7.1.4 Service层ApUserService接口7.1.5 实现ApUserService接口7.1.6 完善业务层接口 7.2 登录思路分析7.2.1 业务层登录实现7.2.2 Controller注入7.2.3 测试 8 App端网关8.1 导入依赖8.2 微服务创建网关8.2.1 AppGateway8.2.2 创建配置文件bootstrap.yml8.2.3 在Nacos中创建配置中心 9 认证过滤器9.1 全局过滤器9.2 测试 10 app前端项目集成10.1 Nginx反向代理和静态资源配置 1 环境搭建及简介 2 项目介绍 2.1 应用 2.2 业务说明 2.3 技术栈 前端 后端 2.4 收获 2.5 大纲 3 Nacos准备 3.1 安装Nacos 1)拉取镜像 docker pull nacos/nacos-server:1.2.02)创建容器 docker run --env MODEstandalone --name nacos --restartalways -d -p 8848:8848 nacos/nacos-server:1.2.03)查看日志 docker logs -f nacos4)访问当前Nacos http://192.168.204.129:8848/nacos 4 初始工程搭建 4.1 环境准备 4.1.1 导入项目 解压heima-leadnews.zip并且导入idea设置jdk为1.8 4.1.2 设置本地仓库 respository_new.zip解压到本地仓库文件夹 打开idea-settings设置本地仓库 修改为 4.1.3 设置项目编码格式 4.2 全局异常 heima-leadnews-common模块下的com.heima.common.exception包下自定义异常类CustomException如果我们手动抛出异常就需要抛出CustomException类 public class CustomException extends RuntimeException {private AppHttpCodeEnum appHttpCodeEnum;public CustomException(AppHttpCodeEnum appHttpCodeEnum){this.appHttpCodeEnum appHttpCodeEnum;}public AppHttpCodeEnum getAppHttpCodeEnum() {return appHttpCodeEnum;} }另外一个类ExceptionCatch类全局异常拦截类 注解ControllerAdviceControllerAdvice本质上是一个Component因此也会被当成组件扫描一视同仁扫扫扫。 这个类是为那些声明了ExceptionHandler、InitBinder 或 ModelAttribute注解修饰的方法的类而提供的专业化的Component , 以供多个 Controller类所共享。 ControllerAdvice //控制器增强类 Slf4j public class ExceptionCatch {/*** 处理不可控异常* param e* return*/ExceptionHandler(Exception.class)ResponseBodypublic ResponseResult exception(Exception e){e.printStackTrace();log.error(catch exception:{},e.getMessage());return ResponseResult.errorResult(AppHttpCodeEnum.SERVER_ERROR);}/*** 处理可控异常 自定义异常* param e* return*/ExceptionHandler(CustomException.class)ResponseBodypublic ResponseResult exception(CustomException e){log.error(catch exception:{},e);return ResponseResult.errorResult(e.getAppHttpCodeEnum());} }在heima-leadnews-model模块下的com.heima.model包下的common包下的enums包下有个枚举类AppHttpCodeEnum用来存放对异常的说明 public enum AppHttpCodeEnum {// 成功段0SUCCESS(200,操作成功),// 登录段1~50NEED_LOGIN(1,需要登录后操作),LOGIN_PASSWORD_ERROR(2,密码错误),// TOKEN50~100TOKEN_INVALID(50,无效的TOKEN),TOKEN_EXPIRE(51,TOKEN已过期),TOKEN_REQUIRE(52,TOKEN是必须的),// SIGN验签 100~120SIGN_INVALID(100,无效的SIGN),SIG_TIMEOUT(101,SIGN已过期),// 参数错误 500~1000PARAM_REQUIRE(500,缺少参数),PARAM_INVALID(501,无效参数),PARAM_IMAGE_FORMAT_ERROR(502,图片格式有误),SERVER_ERROR(503,服务器内部错误),// 数据错误 1000~2000DATA_EXIST(1000,数据已经存在),AP_USER_DATA_NOT_EXIST(1001,ApUser数据不存在),DATA_NOT_EXIST(1002,数据不存在),// 数据错误 3000~3500NO_OPERATOR_AUTH(3000,无权限操作),NEED_ADMIND(3001,需要管理员权限);int code;String errorMessage;AppHttpCodeEnum(int code, String errorMessage){this.code code;this.errorMessage errorMessage;}public int getCode() {return code;}public String getErrorMessage() {return errorMessage;} }4.2.1 自动装配 resource下META-INF有spring.factories只有有微服务引用了heima-leadnews-common服务器初始化spring容器的时候就会找到spring.factories把spring.factories中需要自动配置的文件加载到当前微服务的容器中也就能用全局处理器了。 4.3 工程主体结构 5 登录功能开发 5.1 需求分析 5.1.1 表结构分析 打开本地sql工具引入sql脚本创建leadnews_user有四张表 5.1.2 实体类ApUser的导入 在heima-leadnews-model模块下创建com.heima.model.user.pojos包下创建实体类ApUser TableName(ap_user)表的映射 TableId(value id, type IdType.AUTO)主键的映射 TableField(name)其他字段的映射 Data TableName(ap_user) public class ApUser implements Serializable {private static final long serialVersionUID 1L;/*** 主键*/TableId(value id, type IdType.AUTO)private Integer id;/*** 密码、通信等加密盐*/TableField(salt)private String salt;/*** 用户名*/TableField(name)private String name;/*** 密码,md5加密*/TableField(password)private String password;/*** 手机号*/TableField(phone)private String phone;/*** 头像*/TableField(image)private String image;/*** 0 男1 女2 未知*/TableField(sex)private Boolean sex;/*** 0 未1 是*/TableField(is_certification)private Boolean certification;/*** 是否身份认证*/TableField(is_identity_authentication)private Boolean identityAuthentication;/*** 0正常1锁定*/TableField(status)private Boolean status;/*** 0 普通用户1 自媒体人2 大V*/TableField(flag)private Short flag;/*** 注册时间*/TableField(created_time)private Date createdTime;}5.1.3 表结构中salt的解释 salt密码、通信等加密盐 5.1.3.1 注册过程 5.1.3.2 登录过程 6 用户端微服务的搭建 heima-leadnews-service模块是管理其他所有微服务模块 6.1 service模块的依赖说明 6.2 创建用户微服务模块 在heima-leadnews-service下创建模块 6.2.1 创建引导类 然后创建一个包com.heima.user再创建一个引导类UserApplication SpringBootApplication 启动类注解 EnableDiscoveryClient 集成当前的注册中心加入注册中心 MapperScan(com.heima.user.mapper) 继承MybatisPlus扫描Mapper接口没有就在com.heima.user下创建mapper包 SpringBootApplication EnableDiscoveryClient MapperScan(com.heima.user.mapper) public class UserApplication {public static void main(String[] args) {SpringApplication.run(UserApplication.class, args);} }6.2.2 创建controller.v1、service、mapper、config controller.v1是不同版本的controller 6.2.3 创建resources的配置文件 6.2.3.1 bootstrap.yml 若application.yml 和bootstrap.yml在同一目录下bootstrap.yml 先加载 application.yml后加载application.yml会覆盖 创建bootstrap.yml server:port: 51801 spring:application:name: leadnews-usercloud:nacos:discovery:server-addr: 192.168.204.129:8848config:server-addr: 192.168.204.129:8848file-extension: yml这里面暂时只有Nacos的配置关于数据库的等等都需要在Nacos的配置中心进行配置 spring:datasource:driver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql://localhost:3306/leadnews_user?useUnicodetruecharacterEncodingUTF-8serverTimezoneUTCuseSSLfalseusername: rootpassword: 123sjbsjb # 设置Mapper接口所对应的XML文件位置如果你在Mapper接口中有自定义方法需要进行该配置 mybatis-plus:mapper-locations: classpath*:mapper/*.xml# 设置别名包扫描路径通过该属性可以给包中的类注册别名type-aliases-package: com.heima.model.user.pojos 发布查看 6.2.3.2 logback.xml 创建日志文件logback.xml ?xml version1.0 encodingUTF-8?configuration!--定义日志文件的存储地址,使用绝对路径--property nameLOG_HOME valueD:\Code\JavaCode\HeimaToutiao\logs/!-- Console 输出设置 --appender nameCONSOLE classch.qos.logback.core.ConsoleAppenderencoder!--格式化输出%d表示日期%thread表示线程名%-5level级别从左显示5个字符宽度%msg日志消息%n是换行符--pattern%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n/patterncharsetutf8/charset/encoder/appender!-- 按照每天生成日志文件 --appender nameFILE classch.qos.logback.core.rolling.RollingFileAppenderrollingPolicy classch.qos.logback.core.rolling.TimeBasedRollingPolicy!--日志文件输出的文件名--fileNamePattern${LOG_HOME}/leadnews.%d{yyyy-MM-dd}.log/fileNamePattern/rollingPolicyencoderpattern%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n/pattern/encoder/appender!-- 异步输出 --appender nameASYNC classch.qos.logback.classic.AsyncAppender!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 --discardingThreshold0/discardingThreshold!-- 更改默认的队列的深度,该值会影响性能.默认值为256 --queueSize512/queueSize!-- 添加附加的appender,最多只能添加一个 --appender-ref refFILE//appenderlogger nameorg.apache.ibatis.cache.decorators.LoggingCache levelDEBUG additivityfalseappender-ref refCONSOLE//loggerlogger nameorg.springframework.boot leveldebug/root levelinfo!--appender-ref refASYNC/--appender-ref refFILE/appender-ref refCONSOLE//root /configuration6.3 整体用户端框架 7 登录接口实现 7.1 app登录-接口定义 7.1.1 DTO的LoginDto类 heima-leadnews-model模块下的com.heima.model.user.pojos.dtos包下创建LoginDto类 Data public class LoginDto {private String phone;private String password; }7.1.2 Controller层ApUserLoginController类 再在heima-leadnews-service模块下的com.heima.user.controller.v1下创建ApUserLoginController类 POST请求采用RequestBody RestController RequestMapping(/api/v1/login) public class ApUserLoginController {PostMapping(/login_auth)public ResponseResult login(RequestBody(requiredfalse) LoginDto dto) {return null;} }7.1.3 Mapper层ApUserMapper接口 使用mybatisplus 在com.heima.user.mapper创建ApUserMapper接口 Mapper public interface ApUsermapper extends BaseMapperApUser {}7.1.4 Service层ApUserService接口 public interface ApUserService extends IServiceApUser{ }7.1.5 实现ApUserService接口 Service Transactional Slf4j public class ApUserServiceImpl extends ServiceImplApUsermapper, ApUser implements ApUserService { }Service标注业务层实现 Transactional标注事务 7.1.6 完善业务层接口 public interface ApUserService extends IServiceApUser{/*** 登录功能* param dto* return*/public ResponseResult login(LoginDto dto); }实现方法 Service Transactional Slf4j public class ApUserServiceImpl extends ServiceImplApUsermapper, ApUser implements ApUserService {Overridepublic ResponseResult login(LoginDto dto) {return null;} }7.2 登录思路分析 7.2.1 业务层登录实现 在ApUserServiceImpl类中实现思路 Service Transactional Slf4j public class ApUserServiceImpl extends ServiceImplApUsermapper, ApUser implements ApUserService {Overridepublic ResponseResult login(LoginDto dto) {//1.正常登录 用户名、密码if(StringUtils.isNotBlank(dto.getPhone()) StringUtils.isNotBlank(dto.getPassword())) {//1.1 查询用户信息根据手机号查询用户信息ApUser dbUser getOne(Wrappers.ApUserlambdaQuery().eq(ApUser::getPhone, dto.getPhone()));if(dbUser null) {return ResponseResult.errorResult(AppHttpCodeEnum.AP_USER_DATA_NOT_EXIST, 用户不存在);}//1.2 比对密码String salt dbUser.getSalt();String password dto.getPassword();String pwd DigestUtils.md5DigestAsHex((password salt).getBytes());if(!pwd.equals(dbUser.getPassword())) {return ResponseResult.errorResult(AppHttpCodeEnum.LOGIN_PASSWORD_ERROR, 密码错误);}//1.3 没问题的话返回数据生成jwtString token AppJwtUtil.getToken(dbUser.getId().longValue());MapString,Object mapnew HashMap();map.put(token,token);//清空敏感信息前端只要id,手机号,昵称ApUser userVOnew ApUser();userVO.setId(dbUser.getId());userVO.setPhone(dbUser.getPhone());userVO.setName(dbUser.getName());map.put(user,userVO);return ResponseResult.okResult(map);}else{//2.游客登录MapString,Object mapnew HashMap();map.put(token,AppJwtUtil.getToken(0L));return ResponseResult.okResult(map);}} }加密采用DigestUtils.md5DigestAsHex传入字节流 生成JWT令牌是使用heima-leadnews-utils模块下的com.heima.utils.common包下的AppJWTUtil public class AppJwtUtil {// TOKEN的有效期一天Sprivate static final int TOKEN_TIME_OUT 3_600;// 加密KEYprivate static final String TOKEN_ENCRY_KEY MDk4ZjZiY2Q0NjIxZDM3M2NhZGU0ZTgzMjYyN2I0ZjY;// 最小刷新间隔(S)private static final int REFRESH_TIME 300;// 生产IDpublic static String getToken(Long id){MapString, Object claimMaps new HashMap();claimMaps.put(id,id);long currentTime System.currentTimeMillis();return Jwts.builder().setId(UUID.randomUUID().toString()).setIssuedAt(new Date(currentTime)) //签发时间.setSubject(system) //说明.setIssuer(heima) //签发者信息.setAudience(app) //接收用户.compressWith(CompressionCodecs.GZIP) //数据压缩方式.signWith(SignatureAlgorithm.HS512, generalKey()) //加密方式.setExpiration(new Date(currentTime TOKEN_TIME_OUT * 1000)) //过期时间戳.addClaims(claimMaps) //cla信息.compact();}/*** 获取token中的claims信息** param token* return*/private static JwsClaims getJws(String token) {return Jwts.parser().setSigningKey(generalKey()).parseClaimsJws(token);}/*** 获取payload body信息** param token* return*/public static Claims getClaimsBody(String token) {try {return getJws(token).getBody();}catch (ExpiredJwtException e){return null;}}/*** 获取hearder body信息** param token* return*/public static JwsHeader getHeaderBody(String token) {return getJws(token).getHeader();}/*** 是否过期** param claims* return -1有效0有效1过期2过期*/public static int verifyToken(Claims claims) {if(claimsnull){return 1;}try {claims.getExpiration().before(new Date());// 需要自动刷新TOKENif((claims.getExpiration().getTime()-System.currentTimeMillis())REFRESH_TIME*1000){return -1;}else {return 0;}} catch (ExpiredJwtException ex) {return 1;}catch (Exception e){return 2;}}/*** 由字符串生成加密key** return*/public static SecretKey generalKey() {byte[] encodedKey Base64.getEncoder().encode(TOKEN_ENCRY_KEY.getBytes());SecretKey key new SecretKeySpec(encodedKey, 0, encodedKey.length, AES);return key;}public static void main(String[] args) {/* Map map new HashMap();map.put(id,11);*/System.out.println(AppJwtUtil.getToken(1102L));JwsClaims jws AppJwtUtil.getJws(eyJhbGciOiJIUzUxMiIsInppcCI6IkdaSVAifQ.H4sIAAAAAAAAADWLQQqEMAwA_5KzhURNt_qb1KZYQSi0wi6Lf9942NsMw3zh6AVW2DYmDGl2WabkZgreCaM6VXzhFBfJMcMARTqsxIG9Z888QLui3e3Tup5Pb81013KKmVzJTGo11nf9n8v4nMUaEY73DzTabjmDAAAA.4SuqQ42IGqCgBai6qd4RaVpVxTlZIWC826QA9kLvt9d-yVUw82gU47HDaSfOzgAcloZedYNNpUcd18Ne8vvjQA);Claims claims jws.getBody();System.out.println(claims.get(id));}}7.2.2 Controller注入 RestController RequestMapping(/api/v1/login) public class ApUserLoginController {Autowiredprivate ApUserService apUserService;PostMapping(/login_auth)public ResponseResult login(RequestBody LoginDto dto) {return apUserService.login(dto);} }7.2.3 测试 启动redis报错 修改bootstrap.yml文件添加redis地址 redis:host: 127.0.0.1port: 6379database: 0启动Nacos的服务管理中有leadnews-user 访问http://localhost:51801/api/v1/login/login_auth 8 App端网关 8.1 导入依赖 在heima-leadnews-gateway导入以下依赖 dependenciesdependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-starter-gateway/artifactId/dependencydependencygroupIdcom.alibaba.cloud/groupIdartifactIdspring-cloud-starter-alibaba-nacos-discovery/artifactId/dependencydependencygroupIdcom.alibaba.cloud/groupIdartifactIdspring-cloud-starter-alibaba-nacos-config/artifactId/dependencydependencygroupIdio.jsonwebtoken/groupIdartifactIdjjwt/artifactId/dependency /dependencies8.2 微服务创建网关 8.2.1 AppGateway 针对各个微服务创建相应的网关 创建引导类com.heima.app.gateway.AppGatewayApplication SpringBootApplication EnableDiscoveryClient public class AppGatewayApplication {public static void main(String[] args) {SpringApplication.run(AppGatewayApplication.class, args);} }8.2.2 创建配置文件bootstrap.yml server:port: 51601 spring:application:name: leadnews-app-gatewaycloud:nacos:discovery:server-addr: 192.168.204.129:8848config:server-addr: 192.168.204.129:8848file-extension: yml8.2.3 在Nacos中创建配置中心 spring:cloud:gateway:globalcors:add-to-simple-url-handler-mapping: truecorsConfigurations:[/**]:allowedHeaders: *allowedOrigins: *allowedMethods:- GET- POST- DELETE- PUT- OPTIONroutes:# 平台管理- id: useruri: lb://leadnews-userpredicates:- Path/user/**filters:- StripPrefix 1id: user: 这是此路由的唯一标识符。uri: lb://leadnews-user: 当请求匹配到该路由时它会被路由到leadnews-user服务的实例。URI的前缀lb://表示路由到负载均衡器。predicates: 定义了路由的匹配规则。在这种情况下请求路径必须以/user/开头才会匹配到此路由。filters: 定义了路由的过滤器。在这里使用了StripPrefix过滤器该过滤器会将请求的路径中的一层前缀移除。具体来说这里是将路径中的第一层/user移除以便在转发请求到leadnews-user服务时去除不必要的前缀。 访问http://localhost:51601/user/api/v1/login/login_auth 9 认证过滤器 9.1 全局过滤器 要实现这个功能要实现一个全局的过滤器 在heima-leadnews-gateway模块下创建com.heima.app.gateway.filter.AuthorizeFilter类用作全局过滤器 Component Slf4j public class AuthorizeFilter implements Ordered, GlobalFilter {Overridepublic MonoVoid filter(ServerWebExchange exchange, GatewayFilterChain chain) {//1.获取Request对象和Response对象ServerHttpRequest request exchange.getRequest();ServerHttpResponse response exchange.getResponse();//2.判断当前请求是否为登录请求如果是直接放行if (request.getURI().getPath().contains(/login)) {//放行return chain.filter(exchange);}//3.获取当前请求的token信息String token request.getHeaders().getFirst(token);//4.判断token是否存在if(StringUtils.isBlank(token)) {response.setStatusCode(HttpStatus.UNAUTHORIZED);return response.setComplete();}//5.判断token是否有效//5.1 解析tokentry{Claims body AppJwtUtil.getClaimsBody(token);//5.2 判断token是否有效int result AppJwtUtil.verifyToken(body);if(result 1||result 2) {//5.3 token过期response.setStatusCode(HttpStatus.UNAUTHORIZED);return response.setComplete();}}catch (Exception e) {e.printStackTrace();//5.4 token无效response.setStatusCode(HttpStatus.UNAUTHORIZED);return response.setComplete();}//6.放行return chain.filter(exchange);}/*** 过滤器的执行顺序返回值越小执行优先级越高* return*/Overridepublic int getOrder() {return 0;} }把AppJwtUtil放入gateway的工具包中 9.2 测试 包含/login直接放行 10 app前端项目集成 10.1 Nginx反向代理和静态资源配置 访问http://localhost:80 将静态资源和nginx都放在工作目录下 在nginx的conf目录下创建文件夹leadnews.conf新建文件heimi-leadnews-app.conf nginx端口8801然后转发到gateway端口51601gateway添加user路径后通过Nacos路由到leadnews-user也就是端口51801完成访问 静态资源存放在D:/Code/JavaCode/HeimaToutiao/app-web/展示其目录下的index.html upstream heima-app-gateway{server localhost:51601; }server {listen 8801;location / {root D:/Code/JavaCode/HeimaToutiao/app-web/;index index.html;}location ~/app/(.*) {proxy_pass http://heima-app-gateway/$1;proxy_set_header HOST $host; # 不改变源请求头的值proxy_pass_request_body on; #开启获取请求体proxy_pass_request_headers on; #开启获取请求头proxy_set_header X-Real-IP $remote_addr; # 记录真实发出请求的客户端IPproxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; #记录代理信息} }在nginx.conf中引入 #user nobody; worker_processes 1;events {worker_connections 1024; } http {include mime.types;default_type application/octet-stream;sendfile on;keepalive_timeout 65;# 引入自定义配置文件include leadnews.conf/*.conf; }访问http://localhost:8801 访问成功
http://www.zqtcl.cn/news/435944/

相关文章:

  • 山东通信局报备网站东营城镇建设规划网站
  • 建设银行如何招聘网站网站开发转包协议
  • 主流网站建设服务器有哪些电商平台
  • 网站与数据库的联系wordpress改为中文
  • 如何不让百度收录网站wix和wordpress比较
  • php开源网站 网上商城网站建设公司做销售好不好
  • 网站开发学哪种语言网站加水印
  • 帮人家做网站维护女性手机网站模板
  • 给一个企业做网站苏州网站备案查询
  • 域名备案期间怎么做网站广告投放行业
  • wordpress站内搜索统计网站突然不收录了
  • 网站源码小千个人网做网页设计一个月能挣多少
  • 贵州省建设厅公示网站广州seo网站推广费用
  • 旅游网站建设前期分析公众号制作多少钱
  • 延庆长沙网站建设怎样下载门户网站
  • flash 网站建设建设带数据搜索的网站
  • 设计网站网站名称云主机 小型网站
  • 网站建设方案书 模版公司制作网站收费标准
  • 福州企业网站html模板网站模板下载
  • 湛江自做网站城乡住建局官网
  • 广东网站建设找自己做网站还有出路吗
  • wordpress后台管理地址更改班级优化大师怎么用
  • 电脑网站开发学习产品怎么做市场推广
  • 上海市网站建设公叿目前流行的app网站开发模式
  • 企业手机网站建设效果wordpress栏目链接地址
  • 产品经理做网站网络公司名字免费起名大全
  • 做得比较好的公司网站kol营销
  • 百度指数分析平台长春seo优化企业网络跃升
  • 如何免费做网站域名wordpress 赚钱
  • 苏州市住房建设局网站首页温州网站设计公司