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

深圳宝安住房和建设局网站官网lovestory wordpress

深圳宝安住房和建设局网站官网,lovestory wordpress,网络营销推广的策略,傻瓜式装修设计软件背景#xff1a;由于项目需要#xff0c;需要将apk包加入服务端返回的静态资源文件到apk中#xff0c;形成离线apk包供下载安装。经过调查研究#xff0c;决定使用apktool实现。关于apktool的资料可以参考 https://blog.csdn.net/quantum7/article/details/124060620 htt…背景由于项目需要需要将apk包加入服务端返回的静态资源文件到apk中形成离线apk包供下载安装。经过调查研究决定使用apktool实现。关于apktool的资料可以参考 https://blog.csdn.net/quantum7/article/details/124060620 https://blog.csdn.net/qq_20451879/article/details/117300056 windows版环境 1.JDK环境 2.下载apktool.jar 打包流程 apktool下载地址https://ibotpeaches.github.io/Apktool/ 3.解压apk包 java -jar apktool_2.6.1.jar d app-release.apk 4删除签名文件 签名文件在解压文件后的\original\META-INF目录下 C:\Users***\Downloads\app-release1111\original\META-INF 5.添加要替换的文件到 C:\Users***\Downloads\app-release\assets\assets下 6.生成签名文件 .keystore 签名方式 keytool -genkey -alias test.keystore -keyalg RSA -validity 20000 -keystore test.keystore .jks方式 keytool -genkey -v -keystore test.jks -alias test-keyalg RSA -keysize 2048 -validity 20000 keytool -importkeystore -srckeystore test.jks -destkeystore test.jks -deststoretype pkcs12 7.重新打包 java -jar apktool_2.6.1.jar b app-release 8.使用重新打包后的apk和签名文件打包 .keystore重新签名打包方式 jarsigner -verbose -keystore test.keystore -signedjar app-release-1-0224.apk app-release-1.apk test.keystore .jks重新签名打包方式 jarsigner -verbose -keystore test.jks -signedjar 222.apk test.apk test java环境 构建脚本 bulidApk.bat echo off start cmd /k cd C:\Users\aipingh\Downloads java -jar C:\Users\aipingh\Downloads\apktool.jar b C:\Users\***\Downloads\app-release8 rebuildKeystoreApk.bat echo off start cmd /k cd C:\Users\aipingh\Downloads jarsigner -verbose -keystore tinnove.keystore -storepass 123456 -signedjar C:\Users\***\Downloads\app-release8\dist\app-release.apk C:\Users\aipingh\Downloads\app-release8\dist\app-release8.apk test.keystore 代码 import ch.qos.logback.core.util.FileUtil; import cn.hutool.core.io.FileUtil;import javax.servlet.http.HttpServletResponse; import java.io.*; import java.net.URLEncoder; import java.util.ArrayList; import java.util.List; import java.util.concurrent.TimeUnit;public class ApkUtil {private String outPth;// windows版下载public void downloadWindowsOfflineApk(InfoReqVO reqVO, HttpServletResponse response) {try {// apk解压包路径String apkOriginalPath C:\\Users\\***\\Downloads\\app-release8\\;// 下载离线js文件到目标apk的资源文件路径中String fullPath apkOriginalPath original\\META-INF\\;downloadJsFile(reqVO);//删除签名文件File mkdir FileUtil.mkdir(fullPath);//去掉签名FileUtils.deleteTempFiles(mkdir, fullPath);//重新打包try {String commandStr cmd /c C:\\Users\\***\\Downloads\\buildApk.bat;Runtime.getRuntime().exec(commandStr);} catch (IOException e) {}// 下载签名文件到dist目录中String packagePath dist;File packagePathFile FileUtil.mkdir(apkOriginalPath packagePath);String keystorePath https://***/apk/keystore/tinnove.keystore;ImageInfo appDesignDetailImageInfo new ImageInfo();appDesignDetailImageInfo.setFilename(tinnove.keystore);appDesignDetailImageInfo.setPathUrl(keystorePath);downloadFile(packagePathFile, appDesignDetailImageInfo);// 加签名后打包APKtry {String commandStr cmd /c C:\\Users\\***\\Downloads\\rebuildKeystoreApk.bat;Runtime.getRuntime().exec(commandStr).waitFor(30, TimeUnit.MILLISECONDS);} catch (IOException e) {} catch (InterruptedException e) {e.printStackTrace();}// 重新构建后的apk文件地址String newApkName app-release.apk;String newApkPath apkOriginalPath dist\\ newApkName;// 将apk包返回给前端File file new File(newApkPath);response.setHeader(Content-Disposition, attachment;filename URLEncoder.encode(app-release.apk, UTF-8));//获取文件的输入流InputStream fis new FileInputStream(file);byte[] buffer new byte[1024 * 5];int r;while ((r fis.read(buffer)) ! -1) {response.getOutputStream().write(buffer, 0, r);}// 删除build目录方便下次打包FileUtils.deleteTempFiles(null, apkOriginalPath build);// 删除dist及目录下的apk包FileUtils.deleteTempFiles(null, apkOriginalPath dist);} catch (IOException e) {}}//liunx版下载public void apkShellDownload(InfoReqVO reqVO, HttpServletResponse response) {try {//下载原始apkFile designOfflineFile cn.hutool.core.io.FileUtil.mkdir(outPth);String designOfflineApkPath https://***/apk/offline/app-release.apk;ImageInfo detailImageInfo new ImageInfo();detailImageInfo.setFilename(app-release.apk);detailImageInfo.setPathUrl(designOfflineApkPath);downloadFile(designOfflineFile, detailImageInfo);//下载apktool.jar工具包String apktoolPath https://***/apk/offline/apktool.jar;ImageInfo imageInfo new ImageInfo();imageInfo.setFilename(apktool.jar);imageInfo.setPathUrl(apktoolPath);downloadFile(designOfflineFile, imageInfo);//解压原始apkFileUtils.execSh(cd outPth java -jar outPth apktool.jar d outPth app-release.apk);// apk解压包路径String apkOriginalPath outPth app-release/;// 下载离线js文件到目标apk的资源文件路径中String fullPath apkOriginalPath original/META-INF/;downloadJsFile(reqVO);//删除签名文件 去掉签名cn.hutool.core.io.FileUtil.clean(fullPath);//重新打包FileUtils.execSh(cd outPth java -jar outPth apktool.jar b outPth app-release, 5, TimeUnit.MILLISECONDS);// 下载签名文件到dist目录中String packagePath dist/;File packagePathFile cn.hutool.core.io.FileUtil.mkdir(apkOriginalPath packagePath);String keystorePath https://***/apk/keystore/test.keystore;ImageInfo appDesignDetailImageInfo new ImageInfo();appDesignDetailImageInfo.setFilename(test.keystore);appDesignDetailImageInfo.setPathUrl(keystorePath);downloadFile(packagePathFile, appDesignDetailImageInfo);// 加签名后打包APKFileUtils.execSh(cd outPth jarsigner -verbose -keystore test.keystore -storepass 123456 -signedjar apkOriginalPath packagePath app-release-offline.apk apkOriginalPath packagePath app-release.apk test.keystore, 5, TimeUnit.MILLISECONDS);// ListFile fileList cn.hutool.core.io.FileUtil.loopFiles(outPth);// 重新构建后的apk文件地址String newApkName app-release-offline.apk;String newApkPath apkOriginalPath packagePath;// 将apk包返回给前端File file cn.hutool.core.io.FileUtil.file(newApkPath, newApkName);if (file.exists()) {response.setHeader(Content-Disposition, attachment;filename URLEncoder.encode(app-release.apk, UTF-8));//获取文件的输入流InputStream fis new FileInputStream(file);byte[] buffer new byte[1024 * 5];int r;while ((r fis.read(buffer)) ! -1) {response.getOutputStream().write(buffer, 0, r);}}// 删除build目录方便下次打包cn.hutool.core.io.FileUtil.clean(apkOriginalPath build);// 删除dist及目录下的apk包cn.hutool.core.io.FileUtil.clean(apkOriginalPath dist);} catch (IOException e) {}}private void downloadFile(File target, ImageInfo detailImageInfo) throws IOException {File file org.apache.commons.io.FileUtils.getFile(target, detailImageInfo.getFilename());FileOutputStream outputStream new FileOutputStream(file);//获取文件的网络输入流byte[] bytes cn.hutool.http.HttpUtil.downloadBytes(detailImageInfo.getPathUrl());InputStream fis new ByteArrayInputStream(bytes);byte[] buffer new byte[1024 * 5];int r;while ((r fis.read(buffer)) ! -1) {outputStream.write(buffer, 0, r);}fis.close();outputStream.close();}private void downloadJsFile(InfoReqVO reqVO) {try {//apk包所在的服务器路径String fullPath outPth /app-release/ /assets/app-data/;//本地路径 // String fullPath C:\\Users\\xxx\\Downloads\\app-release\\assets\\app-data; // String fullPath designOfflinePath / reqVO.getDesignId() / reqVO.getCount() /;File target cn.hutool.core.io.FileUtil.mkdir(new File(fullPath)); // File target new File(fullPath preview); // // // 返回图片文件夹ListImageInfo designDetailImages new ArrayList();downloadFiles(designDetailImages, target);// 返回逻辑连线 json文件ListObject designLogicWiring new ArrayList();String logicWiringListJs let logicWiringList cn.hutool.json.JSONUtil.toJsonStr(designLogicWiring);FileUtils.object2JsonFile(fullPath logicWiring.js, logicWiringListJs);// 返回图片url json文件 // ListAppDesignDetailImageInfo designDetailImageUrls getImagesInfo(reqVO); // String previewJs let previewImageUrls JSONUtil.toJsonStr(designDetailImageUrls); // FileUtils.object2JsonFile(fullPath preview.js, previewJs);// 返回分组 json文件ListObject groupList new ArrayList();String groupListJs let groupList cn.hutool.json.JSONUtil.toJsonStr(groupList);FileUtils.object2JsonFile(fullPath group.js, groupListJs);} catch (Exception e) {}}private void downloadFiles(ListImageInfo designDetailImages, File target) {try {//将输出流转换成Zip输出流for (ImageInfo detailImageInfo : designDetailImages) {downloadFile(target, detailImageInfo);}} catch (IOException e) {}}} import cn.hutool.core.util.ObjectUtil; import cn.hutool.json.JSONUtil; import com.google.gson.Gson; import lombok.extern.slf4j.Slf4j; import org.apache.commons.fileupload.FileItem; import org.apache.commons.fileupload.FileItemFactory; import org.apache.commons.fileupload.disk.DiskFileItemFactory; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.http.MediaType; import org.springframework.util.MimeTypeUtils; import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.commons.CommonsMultipartFile;import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.*; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.StringJoiner; import java.util.concurrent.TimeUnit;/*** 文件处理工具类** author*/ Slf4j public class FileUtils {/*** 字符常量斜杠 {code /}*/public static final char SLASH /;/*** 字符常量反斜杠 {code \\}*/public static final char BACKSLASH \\;public static String FILENAME_PATTERN [a-zA-Z0-9_\\-\\|\\.\\u4e00-\\u9fa5];/*** 输出指定文件的byte数组** param filePath 文件路径* param os 输出流* return*/public static void writeBytes(String filePath, OutputStream os) throws IOException {FileInputStream fis null;try {File file new File(filePath);if (!file.exists()) {throw new FileNotFoundException(filePath);}fis new FileInputStream(file);byte[] b new byte[1024];int length;while ((length fis.read(b)) 0) {os.write(b, 0, length);}} catch (IOException e) {throw e;} finally {if (os ! null) {try {os.close();} catch (IOException e1) {e1.printStackTrace();}}if (fis ! null) {try {fis.close();} catch (IOException e1) {e1.printStackTrace();}}}}/*** 删除文件** param filePath 文件* return*/public static boolean deleteFile(String filePath) {boolean flag false;File file new File(filePath);// 路径为文件且不为空则进行删除if (file.isFile() file.exists()) {file.delete();flag true;}return flag;}/*** 文件名称验证** param filename 文件名称* return true 正常 false 非法*/public static boolean isValidFilename(String filename) {return filename.matches(FILENAME_PATTERN);}/*** 检查文件是否可下载** param resource 需要下载的文件* return true 正常 false 非法*/public static boolean checkAllowDownload(String resource) {// 禁止目录上跳级别if (StringUtils.contains(resource, ..)) {return false;}// 检查允许下载的文件规则if (ArrayUtils.contains(MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION, FileTypeUtils.getFileType(resource))) {return true;}// 不在允许下载的文件规则return false;}/*** 下载文件名重新编码** param request 请求对象* param fileName 文件名* return 编码后的文件名*/public static String setFileDownloadHeader(HttpServletRequest request, String fileName) throws UnsupportedEncodingException {final String agent request.getHeader(USER-AGENT);String filename fileName;if (agent.contains(MSIE)) {// IE浏览器filename URLEncoder.encode(filename, utf-8);filename filename.replace(, );} else if (agent.contains(Firefox)) {// 火狐浏览器filename new String(fileName.getBytes(), ISO8859-1);} else if (agent.contains(Chrome)) {// google浏览器filename URLEncoder.encode(filename, utf-8);} else {// 其它浏览器filename URLEncoder.encode(filename, utf-8);}return filename;}/*** 返回文件名** param filePath 文件* return 文件名*/public static String getName(String filePath) {if (null filePath) {return null;}int len filePath.length();if (0 len) {return filePath;}if (isFileSeparator(filePath.charAt(len - 1))) {// 以分隔符结尾的去掉结尾分隔符len--;}int begin 0;char c;for (int i len - 1; i -1; i--) {c filePath.charAt(i);if (isFileSeparator(c)) {// 查找最后一个路径分隔符/或者\begin i 1;break;}}return filePath.substring(begin, len);}/*** 获取文件名不带后缀** param filePath* return*/public static String getFilename(String filePath) {String name getName(filePath);if (null name) {return null;}if (name.contains(.)) {int end name.indexOf(.);return name.substring(0, end);}return name;}/*** 获取文件后缀 如.zip** param filePath* return*/public static String getFilenameSuffix(String filePath) {String name getName(filePath);if (null name) {return null;}if (name.contains(.)) {int end name.indexOf(.);return name.substring(end);}return name;}/*** 是否为Windows或者LinuxUnix文件分隔符br* Windows平台下分隔符为\LinuxUnix为/** param c 字符* return 是否为Windows或者LinuxUnix文件分隔符*/public static boolean isFileSeparator(char c) {return SLASH c || BACKSLASH c;}/*** 下载文件名重新编码** param response 响应对象* param realFileName 真实文件名* return*/public static void setAttachmentResponseHeader(HttpServletResponse response, String realFileName) throws UnsupportedEncodingException {String percentEncodedFileName percentEncode(realFileName);StringBuilder contentDispositionValue new StringBuilder();contentDispositionValue.append(attachment; filename).append(percentEncodedFileName).append(;).append(filename*).append(utf-8).append(percentEncodedFileName);response.setHeader(Content-disposition, contentDispositionValue.toString());response.setHeader(download-filename, percentEncodedFileName);}/*** 百分号编码工具方法** param s 需要百分号编码的字符串* return 百分号编码后的字符串*/public static String percentEncode(String s) throws UnsupportedEncodingException {String encode URLEncoder.encode(s, StandardCharsets.UTF_8.toString());return encode.replaceAll(\\, %20);}/*** 获取路径下所有文件名和文件路径* 以分割** param dirPath 目录路径* return hashMap name和url*/public static HashMapString, String getMapPath(String dirPath) {HashMapString, String pathMap new HashMapString, String();File dirFile new File(dirPath);String[] fileName dirFile.list();StringJoiner joiner new StringJoiner(,);for (String name : fileName) {joiner.add(dirPath name);}pathMap.put(name, String.join(,, fileName));pathMap.put(url, joiner.toString());return pathMap;}public static boolean deleteAllFile(String dir) {File dirFile new File(dir);// 如果dir对应的文件不存在或者不是一个目录则退出if ((!dirFile.exists()) || (!dirFile.isDirectory())) {return false;}boolean flag true;// 删除文件夹中的所有文件包括子文件夹File[] files dirFile.listFiles();for (int i 0; i files.length; i) {// 删除子文件if (files[i].isFile()) {flag deleteFileFlag(files[i].getAbsolutePath());if (!flag) {break;}}// 删除子文件夹else if (files[i].isDirectory()) {flag deleteAllFile(files[i].getAbsolutePath());if (!flag) {break;}}}if (!flag) {return false;}// 删除当前文件夹if (dirFile.delete()) {return true;} else {return false;}}/*** 删除文件返回bool** param fileName* return boolean*/public static boolean deleteFileFlag(String fileName) {File file new File(fileName);// 如果文件路径只有单个文件if (file.exists() file.isFile()) {if (file.delete()) {return true;} else {return false;}} else {return false;}}/*** json文件转json对象** param data 文件流* return json对象*/public static Map readJsonFile(byte[] data) {Gson gson new Gson();String json ;try {Reader reader new InputStreamReader(new ByteArrayInputStream(data), StandardCharsets.UTF_8);int ch 0;StringBuilder buffer new StringBuilder(1024);while ((ch reader.read()) ! -1) {buffer.append((char) ch);}reader.close();json buffer.toString();return gson.fromJson(json, Map.class);} catch (IOException e) {log.error(json文件转json对象失败原因是e{}, e.getMessage());return Collections.emptyMap();}}/*** Object 转换为 json 文件** param finalPath finalPath 是绝对路径 文件名请确保欲生成的文件所在目录已创建好* param content 需要被转换的 content*/public static void object2JsonFile(String finalPath, String content) {try {OutputStreamWriter osw new OutputStreamWriter(new FileOutputStream(finalPath), StandardCharsets.UTF_8);osw.write(content);osw.flush();osw.close();} catch (IOException e) {e.printStackTrace();}}/*** 将java对象转成json文件返回给前端** param object 转换为 json* param fileName json文件名称* param response 结果*/public static void object2JsonFile(Object object, String fileName, HttpServletResponse response) {try {response.setHeader(Content-Disposition, attachment;filename URLEncoder.encode(fileName, UTF-8));//获取文件的网络输入流byte[] bytes JSONUtil.toJsonStr(object).getBytes(StandardCharsets.UTF_8);InputStream fis new ByteArrayInputStream(bytes);byte[] buffer new byte[1024 * 5];int r;while ((r fis.read(buffer)) ! -1) {response.getOutputStream().write(buffer, 0, r);}} catch (IOException e) {e.printStackTrace();}}/*** 获取封装得MultipartFile** param inputStream inputStream* param fileName fileName* return MultipartFile*/private MultipartFile getMultipartFile(InputStream inputStream, String fileName) {FileItem fileItem createFileItem(inputStream, fileName);//CommonsMultipartFile是feign对multipartFile的封装但是要FileItem类对象return new CommonsMultipartFile(fileItem);}/*** FileItem类对象创建** param inputStream inputStream* param fileName fileName* return FileItem*/public FileItem createFileItem(InputStream inputStream, String fileName) {FileItemFactory factory new DiskFileItemFactory(16, null);String textFieldName file;FileItem item factory.createItem(textFieldName, MediaType.MULTIPART_FORM_DATA_VALUE, true, fileName);int bytesRead 0;byte[] buffer new byte[8192];OutputStream os null;//使用输出流输出输入流的字节try {os item.getOutputStream();while ((bytesRead inputStream.read(buffer, 0, 8192)) ! -1) {os.write(buffer, 0, bytesRead);}inputStream.close();} catch (IOException e) {log.error(Stream copy exception, e);throw new IllegalArgumentException(文件上传失败);} finally {if (os ! null) {try {os.close();} catch (IOException e) {log.error(Stream close exception, e);}}if (inputStream ! null) {try {inputStream.close();} catch (IOException e) {log.error(Stream close exception, e);}}}return item;}public static int execSh(String bashCommand) {log.info(开始执行shell命令bashCommand{}, bashCommand);int status 0;try {Runtime runtime Runtime.getRuntime();String[] bash {/bin/bash, -c, bashCommand};Process exec runtime.exec(bash);status exec.waitFor();if (status ! 0) {return 1;}} catch (IOException | InterruptedException e) {log.error(执行shell命令bashCommand{}失败原因是e{}, bashCommand, e.getMessage());}return status;}/*** 执行Shell脚本 0成功 1失败*/public static boolean execSh(String bashCommand, long time, TimeUnit timeUnit) {try {log.info(开始执行shell命令bashCommand{}, bashCommand);Runtime runtime Runtime.getRuntime();String[] bash {/bin/bash, -c, bashCommand};Process exec runtime.exec(bash);return exec.waitFor(time, timeUnit);} catch (IOException | InterruptedException e) {log.error(执行shell命令bashCommand{}失败原因是e{}, bashCommand, e.getMessage());}return false;}public static void deleteTempFiles(File file2, String descDir) {File file1 new File(descDir);//删除zip解压的数据if (ObjectUtil.isNotEmpty(file1) file1.exists()) {log.info(file1{}, file1.getPath());deleteFile(file1);}//删除zip文件//删除zip文件if (ObjectUtil.isNotEmpty(file2) file2.exists()) {log.info(file2{}, file2.getPath());deleteFile(file2);}}public static void deleteFile(File file) {if (file null) {log.info(deleteFile结果filenull);return;}if (file.isFile()) {boolean delete file.delete();log.info(删除结果file{},result{}, file.getPath(), delete);} else if (file.isDirectory()) {for (File sub : file.listFiles()) {deleteFile(sub);}file.delete();}}/*** 根据byte数组生成文件** param bfile 文件数组* param filePath 文件存放路径* param fileName 文件名称*/public static File byte2File(byte[] bfile, String filePath, String fileName) {BufferedOutputStream bos null;FileOutputStream fos null;File file null;try {File dir new File(filePath);if (!dir.exists() !dir.isDirectory()) {//判断文件目录是否存在dir.mkdirs();}file new File(filePath fileName);fos new FileOutputStream(file);bos new BufferedOutputStream(fos);bos.write(bfile);} catch (Exception e) {log.error(byte数组生成文件失败原因是e{}, e.getMessage());} finally {try {if (bos ! null) {bos.close();}if (fos ! null) {fos.close();}} catch (Exception e) {log.error( byte2File error e.getMessage());e.printStackTrace();}}return file;}public static byte[] base64StrToBytes(String base64Str) {byte[] bts org.apache.tomcat.util.codec.binary.Base64.decodeBase64(base64Str);for (int k 0; k bts.length; k) {//调整异常数据if (bts[k] 0) {bts[k] 256;}}return bts;}} import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data;/*** Author:* Description: 校验分享链接入参*/Data ApiModel(入参) public class ImageInfo {ApiModelProperty(name id, value id, required true)private String id;ApiModelProperty(value 资源路径)private String pathUrl;ApiModelProperty(value 文件名称)private String filename;} import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data;/*** 入参** author **** since 2023/02/16*/Data ApiModel(入参) public class InfoReqVO {ApiModelProperty(value id)private Long id;ApiModelProperty(value 版本号)private Integer version; }
http://www.laogonggong.com/news/133936.html

相关文章:

  • 软件培训网站建设怎么查搜索关键词排名
  • 婚恋网站建设项目创业计划书温州小程序制作
  • 长安网站建设详细教程微信网站模板免费下载
  • 龙岗网站建设过程创建网站的基本流程
  • 贵阳网站建设哪家wordpress第三方用户系统
  • 越秀区建设局网站免费商城网站建设
  • 网站页面组成部分两学一做网站源码
  • 一个简易网站怎么做网络营销方式和平台推广
  • 高校教学网站建设企业登录入口官网
  • 网站建设程序员做什么wordpress 微信订阅号
  • 郑州哪家公司给国外做网站上海 建站
  • 福州招聘网站有哪几个建网站免费软件
  • 广州门户网站建设公司南昌seo全网营销
  • 网站开发税率多少钱做盗版网站吗
  • 外贸自建站的推广方式哪个网站可以做微信推送
  • 免费企业信息查询网站从化做网站建设
  • 增城新塘镇 企业网站建设网站建设销售ppt
  • 关于建设网站的报告海南腾雅网络科技有限公司
  • 西部数码网站管理助手v4.0泉州seo排名工具
  • 网站开发毕设参考文献做一个网站的流程是什么
  • 中卫网站推广营销想接网站自己做
  • 网站架构设计师面试技巧简单网页设计主题
  • 一定火网站建设定制互联网广告投放
  • 烟台网站title优化网络企业
  • 免费网站赚钱wordpress页面教程视频教程
  • 大华建设项目管理有限公司网站展厅设计施工
  • 网站模版上传空间后怎么做如何给网站做404页面
  • 完整个人网站开发案例做的网站怎么让百度收录
  • 信息网站建设汇报网站对企业的重要性
  • 建立网站平台网站开发评估与调整