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

天河岗顶棠下上社网站建设备份核验单时网站域名

天河岗顶棠下上社网站建设,备份核验单时网站域名,郴州网约车平台有哪些,asp无刷新网站模板分析若依的文件上传处理逻辑 注#xff1a;已经从若依框架完成拆分#xff0c;此处单独分析一下人家精彩的封装#xff0c;也来理解一下怎么做一个通用的上传接口#xff01;如有分析的#xff0c;理解的不透彻的地方#xff0c;大家多多包含#xff0c;欢迎批评指正已经从若依框架完成拆分此处单独分析一下人家精彩的封装也来理解一下怎么做一个通用的上传接口如有分析的理解的不透彻的地方大家多多包含欢迎批评指正但是请不要恶语相向 控制层代码剖析 PostMapping(/upload)public AjaxResult uploadFile(MultipartFile file){try {// 上传文件路径String filePath RuoYiConfig.getUploadPath();// 上传并返回新文件名称String fileName FileUploadUtils.upload(filePath, file);String url serverConfig.getUrl() fileName;AjaxResult ajax AjaxResult.success();ajax.put(url, url);ajax.put(fileName, fileName);ajax.put(newFileName, FileUtils.getName(fileName));ajax.put(originalFilename, file.getOriginalFilename());return ajax;} catch (Exception e) {return AjaxResult.error(e.getMessage());}}PostMapping(/upload)这是一个用于处理HTTP POST请求的注解它将请求映射到/upload路径。在这里它用于处理文件上传请求。 public AjaxResult uploadFile(MultipartFile file)这是处理文件上传的方法。它接收一个MultipartFile对象这是Spring提供的用于处理文件上传的类。 String filePath RuoYiConfig.getUploadPath();获取文件上传路径通过RuoYiConfig.getUploadPath()方法获取是从配置文件中读取的上传路径。 server:port: 8888 # 项目相关配置 ruoyi:# 文件路径 示例 Windows配置D:/ruoyi/uploadPathLinux配置 /home/ruoyi/uploadPathprofile: ./ String fileName FileUploadUtils.upload(filePath, file);调用FileUploadUtils.upload方法实现文件上传该方法包含文件存储逻辑根据传入的文件路径和MultipartFile对象返回新的文件名。下一标题我们将会着重对于这个方法进行解析。 String url serverConfig.getUrl() fileName;构造文件的访问URL是通过拼接服务器的URL和上传后的文件名得到的。 AjaxResult ajax AjaxResult.success();创建一个成功的AjaxResult对象用于封装返回给客户端的数据。 ajax.put(url, url);将文件的访问URL放入AjaxResult中以便客户端获取上传后的文件的访问地址。 ajax.put(fileName, fileName);将上传后的文件名放入AjaxResult中。 ajax.put(newFileName, FileUtils.getName(fileName));将上传后的文件名去除路径的部分只保留文件名放入AjaxResult中。 ajax.put(originalFilename, file.getOriginalFilename());将原始文件名放入AjaxResult中。 return ajax;返回封装了文件相关信息的AjaxResult对象向客户端提供文件上传成功的响应。 } catch (Exception e) { return AjaxResult.error(e.getMessage());}捕获可能的异常如果发生异常返回一个包含异常信息的错误AjaxResult对象向客户端提供文件上传失败的响应。 upload文件上传方法 点击方法跳进去之后我们可以看到如下代码 package com.it_wanghui_cn.file.utils;import java.io.File; import java.io.IOException; import java.nio.file.Paths; import java.util.Objects;import com.it_wanghui_cn.file.config.RuoYiConfig; import com.it_wanghui_cn.file.constant.Constants; import com.it_wanghui_cn.file.exception.FileNameLengthLimitExceededException; import com.it_wanghui_cn.file.exception.FileSizeLimitExceededException; import com.it_wanghui_cn.file.exception.InvalidExtensionException; import com.it_wanghui_cn.file.utils.uuid.Seq; import org.apache.commons.io.FilenameUtils; import org.springframework.web.multipart.MultipartFile;/*** 文件上传工具类** author ruoyi*/ public class FileUploadUtils {/*** 默认大小 50M*/public static final long DEFAULT_MAX_SIZE 50 * 1024 * 1024;/*** 默认大小 50M*/public static final long DEFAULT_APP_MAX_SIZE 200 * 1024 * 1024;/*** 默认的文件名最大长度 100*/public static final int DEFAULT_FILE_NAME_LENGTH 100;/*** 默认上传的地址*/private static String defaultBaseDir RuoYiConfig.getProfile();public static void setDefaultBaseDir(String defaultBaseDir){FileUploadUtils.defaultBaseDir defaultBaseDir;}public static String getDefaultBaseDir(){return defaultBaseDir;}/*** 以默认配置进行文件上传** param file 上传的文件* return 文件名称* throws Exception*/public static final String upload(MultipartFile file) throws IOException{try{return upload(getDefaultBaseDir(), file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION);}catch (Exception e){throw new IOException(e.getMessage(), e);}}/*** 根据文件路径上传** param baseDir 相对应用的基目录* param file 上传的文件* return 文件名称* throws IOException*/public static final String upload(String baseDir, MultipartFile file) throws IOException{try{return upload(baseDir, file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION);}catch (Exception e){throw new IOException(e.getMessage(), e);}}/*** 文件上传** param baseDir 相对应用的基目录* param file 上传的文件* param allowedExtension 上传文件类型* return 返回上传成功的文件名* throws FileSizeLimitExceededException 如果超出最大大小* throws FileNameLengthLimitExceededException 文件名太长* throws IOException 比如读写文件出错时* throws InvalidExtensionException 文件校验异常*/public static final String upload(String baseDir, MultipartFile file, String[] allowedExtension)throws FileSizeLimitExceededException, IOException, FileNameLengthLimitExceededException,InvalidExtensionException{int fileNamelength Objects.requireNonNull(file.getOriginalFilename()).length();if (fileNamelength FileUploadUtils.DEFAULT_FILE_NAME_LENGTH){throw new FileNameLengthLimitExceededException(FileUploadUtils.DEFAULT_FILE_NAME_LENGTH);}assertAllowed(file, allowedExtension);String fileName extractFilename(file);String absPath getAbsoluteFile(baseDir, fileName).getAbsolutePath();file.transferTo(Paths.get(absPath));return getPathFileName(baseDir, fileName);}/*** 编码文件名*/public static final String extractFilename(MultipartFile file){return StringUtils.format({}/{}_{}.{}, DateUtils.datePath(),FilenameUtils.getBaseName(file.getOriginalFilename()), Seq.getId(Seq.uploadSeqType), getExtension(file));}public static final File getAbsoluteFile(String uploadDir, String fileName) throws IOException{File desc new File(uploadDir File.separator fileName);if (!desc.exists()){if (!desc.getParentFile().exists()){desc.getParentFile().mkdirs();}}return desc;}public static final String getPathFileName(String uploadDir, String fileName) throws IOException{int dirLastIndex RuoYiConfig.getProfile().length() 1;String currentDir StringUtils.substring(uploadDir, dirLastIndex);return Constants.RESOURCE_PREFIX / currentDir / fileName;}/*** 文件大小校验** param file 上传的文件* return* throws FileSizeLimitExceededException 如果超出最大大小* throws InvalidExtensionException*/public static final void assertAllowed(MultipartFile file, String[] allowedExtension)throws FileSizeLimitExceededException, InvalidExtensionException{long size file.getSize();String fileSuffix;if (null ! file.getOriginalFilename() file.getOriginalFilename().contains(.)) {fileSuffix file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf(.)1);}else {fileSuffix null;}if (apk.equals(fileSuffix) || ipa.equals(fileSuffix)) {if (size DEFAULT_APP_MAX_SIZE){throw new FileSizeLimitExceededException(DEFAULT_APP_MAX_SIZE / 1024 / 1024);}}else {if (size DEFAULT_MAX_SIZE){throw new FileSizeLimitExceededException(DEFAULT_MAX_SIZE / 1024 / 1024);}}String fileName file.getOriginalFilename();String extension getExtension(file);if (allowedExtension ! null !isAllowedExtension(extension, allowedExtension)){if (allowedExtension MimeTypeUtils.IMAGE_EXTENSION){throw new InvalidExtensionException.InvalidImageExtensionException(allowedExtension, extension,fileName);}else if (allowedExtension MimeTypeUtils.FLASH_EXTENSION){throw new InvalidExtensionException.InvalidFlashExtensionException(allowedExtension, extension,fileName);}else if (allowedExtension MimeTypeUtils.MEDIA_EXTENSION){throw new InvalidExtensionException.InvalidMediaExtensionException(allowedExtension, extension,fileName);}else if (allowedExtension MimeTypeUtils.VIDEO_EXTENSION){throw new InvalidExtensionException.InvalidVideoExtensionException(allowedExtension, extension,fileName);}else{throw new InvalidExtensionException(allowedExtension, extension, fileName);}}}/*** 判断MIME类型是否是允许的MIME类型** param extension* param allowedExtension* return*/public static final boolean isAllowedExtension(String extension, String[] allowedExtension){for (String str : allowedExtension){if (str.equalsIgnoreCase(extension)){return true;}}return false;}/*** 获取文件名的后缀** param file 表单文件* return 后缀名*/public static final String getExtension(MultipartFile file){String extension FilenameUtils.getExtension(file.getOriginalFilename());if (StringUtils.isEmpty(extension)){extension MimeTypeUtils.getExtension(Objects.requireNonNull(file.getContentType()));}return extension;} } 这是一个文件上传工具类主要用于处理文件上传的相关逻辑。 常量定义 DEFAULT_MAX_SIZE默认文件大小限制为50MB。DEFAULT_APP_MAX_SIZE默认App文件大小限制为200MB。DEFAULT_FILE_NAME_LENGTH默认文件名最大长度为100字符。defaultBaseDir默认的文件上传基目录初始化时可能从RuoYiConfig中获取。 上传文件方法 upload(MultipartFile file)使用默认配置上传文件调用upload(String baseDir, MultipartFile file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION)。 upload(String baseDir, MultipartFile file)根据给定的基目录上传文件调用upload(String baseDir, MultipartFile file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION)。 upload(String baseDir, MultipartFile file, String[] allowedExtension)文件上传的核心方法包含文件大小、文件名长度和文件扩展名的校验逻辑。 public static final String upload(String baseDir, MultipartFile file, String[] allowedExtension)throws FileSizeLimitExceededException, IOException, FileNameLengthLimitExceededException,InvalidExtensionException{int fileNamelength Objects.requireNonNull(file.getOriginalFilename()).length();if (fileNamelength FileUploadUtils.DEFAULT_FILE_NAME_LENGTH){throw new FileNameLengthLimitExceededException(FileUploadUtils.DEFAULT_FILE_NAME_LENGTH);}assertAllowed(file, allowedExtension);String fileName extractFilename(file);String absPath getAbsoluteFile(baseDir, fileName).getAbsolutePath();file.transferTo(Paths.get(absPath));return getPathFileName(baseDir, fileName);}由于这段代码是文件上传的核心方法我们对其进行细分析 文件名长度检查 int fileNamelength Objects.requireNonNull(file.getOriginalFilename()).length(); if (fileNamelength FileUploadUtils.DEFAULT_FILE_NAME_LENGTH) {throw new FileNameLengthLimitExceededException(FileUploadUtils.DEFAULT_FILE_NAME_LENGTH); }获取上传文件的原始文件名并检查其长度是否超过了设定的最大文件名长度DEFAULT_FILE_NAME_LENGTH。如果超过了限制抛出FileNameLengthLimitExceededException异常。 文件扩展名和大小校验 assertAllowed(file, allowedExtension);调用assertAllowed方法对文件的扩展名和大小进行校验。 如果不符合要求会抛出FileSizeLimitExceededException、InvalidExtensionException等异常。 public static final void assertAllowed(MultipartFile file, String[] allowedExtension)throws FileSizeLimitExceededException, InvalidExtensionException{long size file.getSize();String fileSuffix;if (null ! file.getOriginalFilename() file.getOriginalFilename().contains(.)) {fileSuffix file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf(.)1);}else {fileSuffix null;}if (apk.equals(fileSuffix) || ipa.equals(fileSuffix)) {if (size DEFAULT_APP_MAX_SIZE){throw new FileSizeLimitExceededException(DEFAULT_APP_MAX_SIZE / 1024 / 1024);}}else {if (size DEFAULT_MAX_SIZE){throw new FileSizeLimitExceededException(DEFAULT_MAX_SIZE / 1024 / 1024);}}String fileName file.getOriginalFilename();String extension getExtension(file);if (allowedExtension ! null !isAllowedExtension(extension, allowedExtension)){if (allowedExtension MimeTypeUtils.IMAGE_EXTENSION){throw new InvalidExtensionException.InvalidImageExtensionException(allowedExtension, extension,fileName);}else if (allowedExtension MimeTypeUtils.FLASH_EXTENSION){throw new InvalidExtensionException.InvalidFlashExtensionException(allowedExtension, extension,fileName);}else if (allowedExtension MimeTypeUtils.MEDIA_EXTENSION){throw new InvalidExtensionException.InvalidMediaExtensionException(allowedExtension, extension,fileName);}else if (allowedExtension MimeTypeUtils.VIDEO_EXTENSION){throw new InvalidExtensionException.InvalidVideoExtensionException(allowedExtension, extension,fileName);}else{throw new InvalidExtensionException(allowedExtension, extension, fileName);}}}这是文件上传工具类中的文件校验方法 assertAllowed以下是对其进行细分析 获取文件大小和扩展名 long size file.getSize(); String fileSuffix; if (null ! file.getOriginalFilename() file.getOriginalFilename().contains(.)) {fileSuffix file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf(.)1); } else {fileSuffix null; }获取上传文件的大小和原始文件名中的扩展名。 文件大小校验 if (apk.equals(fileSuffix) || ipa.equals(fileSuffix)) {if (size DEFAULT_APP_MAX_SIZE) {throw new FileSizeLimitExceededException(DEFAULT_APP_MAX_SIZE / 1024 / 1024);} } else {if (size DEFAULT_MAX_SIZE) {throw new FileSizeLimitExceededException(DEFAULT_MAX_SIZE / 1024 / 1024);} }根据文件扩展名fileSuffix判断文件类型如果是apk或ipa文件检查文件大小是否超过默认限制DEFAULT_APP_MAX_SIZE否则检查是否超过常规文件大小限制DEFAULT_MAX_SIZE。如果超过了大小限制抛出 FileSizeLimitExceededException 异常。 文件扩展名校验 String fileName file.getOriginalFilename(); String extension getExtension(file); if (allowedExtension ! null !isAllowedExtension(extension, allowedExtension)) {// ... }获取上传文件的原始文件名和文件扩展名。如果 allowedExtension 不为空且文件扩展名不在允许的扩展名列表中进入后续的异常判断逻辑。 根据文件类型抛出不同的异常 if (allowedExtension MimeTypeUtils.IMAGE_EXTENSION) {throw new InvalidExtensionException.InvalidImageExtensionException(allowedExtension, extension, fileName); } else if (allowedExtension MimeTypeUtils.FLASH_EXTENSION) {throw new InvalidExtensionException.InvalidFlashExtensionException(allowedExtension, extension, fileName); } else if (allowedExtension MimeTypeUtils.MEDIA_EXTENSION) {throw new InvalidExtensionException.InvalidMediaExtensionException(allowedExtension, extension, fileName); } else if (allowedExtension MimeTypeUtils.VIDEO_EXTENSION) {throw new InvalidExtensionException.InvalidVideoExtensionException(allowedExtension, extension, fileName); } else {throw new InvalidExtensionException(allowedExtension, extension, fileName); }根据不同的文件类型抛出对应的异常。例如如果文件类型是图片抛出 InvalidImageExtensionException 异常。 所以综上所述呢assertAllowed 方法主要用于对文件的大小和扩展名进行校验确保文件满足预定义的条件否则抛出相应的异常。 生成文件名和绝对路径 String fileName extractFilename(file); String absPath getAbsoluteFile(baseDir, fileName).getAbsolutePath();调用extractFilename方法根据上传文件生成编码后的文件名。调用getAbsoluteFile方法获取文件的绝对路径。 文件写入磁盘 file.transferTo(Paths.get(absPath));使用transferTo方法将文件写入磁盘具体路径由absPath决定。 返回文件相对路径 return getPathFileName(baseDir, fileName);调用getPathFileName方法生成相对于上传基目录的文件路径。 所以综上所述呢这段代码通过一系列步骤完成了文件上传的核心逻辑包括文件名长度、扩展名、大小的校验生成文件名将文件写入磁盘并返回相对路径。异常的处理确保了在上传过程中出现问题时能够向上层抛出相应的异常。 文件名处理 extractFilename(MultipartFile file)根据上传文件生成编码后的文件名包括日期路径、文件基名、Seq以及文件扩展名。 public static final String extractFilename(MultipartFile file) {return StringUtils.format({}/{}_{}.{}, DateUtils.datePath(),FilenameUtils.getBaseName(file.getOriginalFilename()), Seq.getId(Seq.uploadSeqType), getExtension(file)); }构造文件名 StringUtils.format({}/{}_{}.{}, DateUtils.datePath(),FilenameUtils.getBaseName(file.getOriginalFilename()), Seq.getId(Seq.uploadSeqType), getExtension(file));使用字符串格式化工具可能是自定义的StringUtils.format方法构建文件名。这个文件名包括以下几个部分 {}/日期路径可能是根据上传日期生成的目录结构。{}_原始文件名去除扩展名后的部分。{}通过某种方式获取的上传序列号或ID。.文件名的分隔符。getExtension(file)获取文件的扩展名。 返回构造的文件名 return StringUtils.format(...);返回构造好的文件名。 所以综上所述呢extractFilename 方法主要用于根据上传文件的信息构建一个新的文件名其中包括日期路径、原始文件名的基本部分、上传序列号或ID以及文件扩展名。这个文件名通常用于确定上传文件在服务器上的存储位置。 文件路径操作 getAbsoluteFile(String uploadDir, String fileName)获取文件的绝对路径并确保其父目录存在。 public static final File getAbsoluteFile(String uploadDir, String fileName) throws IOException{File desc new File(uploadDir File.separator fileName);if (!desc.exists()){if (!desc.getParentFile().exists()){desc.getParentFile().mkdirs();}}return desc;} 这就是文件上传工具类中的 getAbsoluteFile 方法以下是对其进行细分析 构造文件对象 File desc new File(uploadDir File.separator fileName);创建一个 File 对象表示上传目录 (uploadDir) 下的特定文件 (fileName)。 检查文件是否存在 if (!desc.exists()) {// ... }判断文件是否已经存在。如果文件不存在执行后续的逻辑。 创建文件父目录 if (!desc.getParentFile().exists()) {desc.getParentFile().mkdirs(); }如果文件的父目录不存在调用 mkdirs() 方法创建父目录。这样可以确保文件存储路径的所有父目录都存在。 返回文件对象 return desc;返回表示上传文件的 File 对象。 getAbsoluteFile 方法主要用于获取表示上传文件的 File 对象并确保文件所在的目录结构是存在的。如果文件所在的目录不存在会先创建这些目录。这样可以保证文件写入磁盘时其所在的目录结构是正确的。 getPathFileName(String uploadDir, String fileName)根据上传目录和文件名构造相对路径通常用于构造访问URL。 public static final String getPathFileName(String uploadDir, String fileName) throws IOException{int dirLastIndex RuoYiConfig.getProfile().length() 1;String currentDir StringUtils.substring(uploadDir, dirLastIndex);return Constants.RESOURCE_PREFIX / currentDir / fileName;}文件大小和扩展名校验 assertAllowed(MultipartFile file, String[] allowedExtension)对上传的文件进行大小和扩展名的校验根据文件扩展名调用isAllowedExtension方法判断是否允许上传。isAllowedExtension(String extension, String[] allowedExtension)判断文件扩展名是否在允许的扩展名列表中。 其他方法 getExtension(MultipartFile file)获取文件的扩展名优先使用原始文件名的扩展名如果为空则使用文件的MIME类型来获取扩展名。 总体而言该工具类提供了一系列方法用于方便地进行文件上传并包含了一些常见的文件校验逻辑。 transferTo方法再深入 default void transferTo(Path dest) throws IOException, IllegalStateException {FileCopyUtils.copy(this.getInputStream(), Files.newOutputStream(dest));}Files.newOutputStream(dest) 是 Java NIONew I/O库提供的一种方式用于创建一个输出流OutputStream以写入文件。这方法返回一个输出流你可以使用它来写入字节到指定的文件。 具体来说Files.newOutputStream(dest) 的参数 dest 是一个 Path 对象表示文件路径。下面是一些关键的点 创建输出流 Path dest ...; // 指定文件路径 OutputStream outputStream Files.newOutputStream(dest);使用 Files.newOutputStream(dest) 创建一个输出流。 写入数据 byte[] data ...; // 准备写入的数据 outputStream.write(data);利用得到的输出流可以使用 write 方法将数据写入文件。 关闭流 outputStream.close();在数据写入完成后确保调用 close 方法关闭输出流以释放相关资源。 这个方法的主要优点是简洁且易用不需要手动创建文件或处理一些底层的操作。它是 Java NIO 中用于文件写入的一部分提供了更灵活和高性能的 I/O 操作。 看来还是千呼万唤始出来犹抱琵琶半遮面我们再进一层 public static int copy(InputStream in, OutputStream out) throws IOException {Assert.notNull(in, No InputStream specified);Assert.notNull(out, No OutputStream specified);int var2;try {var2 StreamUtils.copy(in, out);} finally {close(in);close(out);}return var2;}这是一个用于将输入流InputStream的内容复制到输出流OutputStream的辅助方法。以下是对这个方法进行细分析 参数校验 Assert.notNull(in, No InputStream specified); Assert.notNull(out, No OutputStream specified);使用 Spring Framework 的 Assert 工具类确保输入流和输出流都不为 null。如果为 null抛出 IllegalArgumentException 异常。 流复制 try {var2 StreamUtils.copy(in, out); } finally {close(in);close(out); }在 try 块中使用 StreamUtils.copy 方法将输入流的内容复制到输出流。StreamUtils.copy 方法是 Spring Framework 提供的用于复制流的实用方法。在 finally 块中调用 close 方法关闭输入流和输出流。这确保在复制完成或发生异常时都会关闭这两个流避免资源泄漏。 返回复制的字节数 return var2;返回复制的字节数。StreamUtils.copy 方法通常返回复制的字节数这里将其作为方法的返回值。 综合而言这个方法是一个简化的输入流到输出流的复制操作确保在完成复制或发生异常时关闭输入流和输出流。这种实现方式通常用于避免手动处理流关闭操作提高代码的简洁性和可读性。 总结 以上就是我们对于若依文件上传接口的一个分析可能还是比较浅显由于我也是一个初学者对于这套优秀的框架掌握尚欠欢迎大家进行批评指正 项目源码 https://gitee.com/wanghui1201/FileOperateUtils 可以直接拿去当做轮子用大家做毕设啥的可以直接用简单好用就不用大家自己拆离了
http://www.yutouwan.com/news/59419/

相关文章:

  • 海珠电子商务网站建设wordpress做社交网站
  • 网站有服务器怎么备案中信建设有限责任公司电话打不通
  • 水墨风格网站源码腾讯云服务器控制台
  • 哪些网站做家政推广php 免费装修网站
  • 南昌做微信网站遵义水网站建设
  • 装饰公司用哪个招聘网站网站地图怎么制作
  • 个人如何建网站企业邮箱费用
  • 济南网站建设运营wordpress模板汉化教程视频
  • 一个人做网站 知乎建设网app下载安装
  • 网站建设的公司工作室论坛网站策划
  • 网站建设做的好的公司阿里云主机安装wordpress
  • 什么样的网站需要服务器网页版 微信
  • 西安网站设计百度网盘如何获得2t免费空间
  • 微企帮做网站个人网页设计总结
  • 简单小网站dw怎么做自我展示网站
  • 博客建站系统天津网站优化哪家快
  • 根据网站集约化建设要求深圳建设网站哪家最好
  • 长宁网站建设wordpress分类目录在
  • 衡水建设网站公司提供服务好的网站建设
  • 美食网站建设服务策划书seo中文全称是什么
  • 网站项目案例app是什么意思通俗讲
  • 微网站建设公司首选公司wordpress热门吗
  • 宁阳网站建设价格南昌网站开发培训班
  • 如皋企业网站建设杭州市拱墅区建设局网站
  • 利用ps做兼职的网站小网站模板下载地址
  • 个性化的个人网站做网站推广的销售电话开场白
  • 怎么给自己制作一个网站做公司官网需要哪些技术
  • 网页游戏的网站登尼特网站建设服务
  • 网站的标志可以修改吗个性定制网站有哪些
  • 汇米网站建设网页首页动态设计