位置: IT常识 - 正文

【Hadoop/Java】基于HDFS的Java Web网络云盘(hadoop java)

编辑:rootadmin
【Hadoop/Java】基于HDFS的Java Web网络云盘 【Hadoop/Java】基于HDFS的Java Web网络云盘

推荐整理分享【Hadoop/Java】基于HDFS的Java Web网络云盘(hadoop java),希望有所帮助,仅作参考,欢迎阅读内容。

文章相关热门搜索词:hadoop运行java程序的命令,hadoop搭建jdk,hadoop javahome,hadoop javahome,hadoop java_home配置,hadoop运行java程序的命令,hadoop java_home is not set,hadoop java_home is not set,内容如对您有帮助,希望把文章链接给更多的朋友!

本人BNUZ大学生萌新,水平不足,还请各位多多指教!

实验目的熟悉HDFS Java API的使用;能使用HDFS Java API编写应用程序实验要求

云盘系统通过互联网为企业和个人提供信息的储存、读取、下载等服务,具有安全稳定、海量存储的特点。根据用户群定位,云盘系统可以划分为公有云盘、社区云盘、私有云盘等。请利用HDFS Java API,编写一个云盘系统,要求实现功能如下:

环境

Ubuntu 20.04LTS + Java (OpenJDK 8) + IDEA Ultimate 2021.3.3 + Hadoop 3.3.2

项目下载

Github仓库:https://github.com/gennwolf/yunpan-hadoop

使用框架以及Web服务器

Maven + SpringBoot 2.6.4 + SpringMVC + Apache Tomcat 9.0.58 前端模板来源:https://colorlib.com (使用了Bootstrap + jQuery)

分布式集群配置

有3个节点,每个节点的主机名、IP以及担任的角色如下表所示:

节点主机名IP角色1Master192.168.170.111NameNode, SecondaryNameNode, DataNode, ResourceManager, NodeManager2Slave1192.168.170.112DataNode, NodeManager3Slave2192.168.170.113DataNode, NodeManager网关子网掩码192.168.170.2255.255.255.0实验步骤

启动Hadoop集群,分别到各个节点使用jps命令查看进程是否与上表匹配: 下图为Master节点的Java进程,和上表对应节点的角色相匹配: 可以在Master上用ssh连接到其他节点查看进程

在HDFS的根目录下创建一个文件userinfo.dat用于保存用户信息,用户信息包含用户名和密码,用逗号分隔,该文件用于云盘的登录/注册等操作,我们往里面添加两个用户spring和summer,密码都为123456,如下图:

每个用户只能访问自己的资源,用以前上数据库系统原理课程的知识来说,就是每一名用户都有自己的文件目录视图,在本次实验中,我的想法是,每一名用户对应一个目录,比如说用户spring对应HDFS中的目录/spring,用户summer对应/summer,用户spring是不能操作用户summer的文件目录的,这样就实现了用户之间的隔离性,确保每位用户访问到的是自己的资源,我们在/spring下创建一个文本文件test.txt,再创建一个目录dd,在dd下也创建一个文本文件test.txt,创建文件可以用touch命令,创建目录可以用mkdir命令,我们递归打印/spring目录下的所有文件查看是否创建成功,到这里就完成了文件的准备工作:

打开IDEA,创建SpringBoot项目,配置好Web相关依赖后,加入Hadoop依赖,依赖的version对应当前系统中的Hadoop版本:

<dependency> <groupId>org.apache.hadoop</groupId> <artifactId>hadoop-client</artifactId> <version>3.3.2</version></dependency>项目的结构如图: 关键的文件及目录说明如下表所示:名称类型目录Controller目录用于存放Controller类FileSystemControllerJava类用于接收前端的请求,从而进行请求处理以及HDFS操作的Controller类PageControllerJava类用于接收前端请求,实现网页跳转的Controller类domain目录用于存放数据类HDFSFileJava类用于描述HDFS文件信息的数据类,含有三个字段,name表示名称,date表示修改日期,type表示类型(文件/目录)YunpanHadoopApplicationJava类用于启动Springboot项目的类resources.static目录用于存放静态资源的目录,本项目的前端的所有静态资源,包括CSS、JS、图片等,都放在此目录下application.properties配置文件SpringBoot配置文件webapp.WEB-INF目录存放JSP页面pom.xml配置文件Maven配置文件………

下面围绕页面来进行功能讲解,本项目页面数量很少,只有3个页面:

由于操作HDFS,需要频繁创建FileSystem实例,所以我把创建FileSystem实例写成了一个函数,方便以后调用: //实例化Configuration和FileSystem public FileSystem getFileSystem() throws IOException { Configuration conf = new Configuration(); conf.set("fs.defaultFS", "hdfs://192.168.170.111:9000"); return FileSystem.get(conf); }另外本web项目全程session绑定,用户登陆后就设置名为LOGIN_STATUS的session,用户退出登录则删除该session。同时也设置一个名为path的session,用于记录当前用户访问的HDFS目录地址 //当前登录状态检查 public boolean loginStatusCheck(HttpSession session) { return session.getAttribute("LOGIN_STATUS") != null; }index.jsp页面以及register.jsp页面 index.jsp页面全貌: 点击“没有账号?点击此处注册 →”按钮,跳转到注册页面register.jsp,跳转功能用PageController类实现,对应的跳转语句: 前端(前端语句只示例一次):<div class="text-center p-t-136"><a class="txt2" href="<%=request.getContextPath()%>/jumpToRegisterPage">没有账号?点击此处注册<i class="fa fa-long-arrow-right m-l-5" aria-hidden="true"></i></a></div>

后台:

@RequestMapping("/jumpToRegisterPage") public String jumpToRegisterPage() { return "register"; }

跳转到register.jsp页面,页面全貌: 输入用户名,密码以及确认密码,每一项都不能为空,前端做了约束: 两次密码必须输入一致,后台做了约束,否则注册不成功: 执行注册操作,用户名为test,密码为test,后台获取前台的数据,注册操作相关代码:

//注册 @RequestMapping("/register") public String register(HttpServletRequest request, Model model) throws IOException { String username = request.getParameter("username"); String userpasswd = request.getParameter("userpasswd"); String userpasswd_confirm = request.getParameter("userpasswd_confirm"); if(!userpasswd.equals(userpasswd_confirm)) { model.addAttribute("status", "两次密码输入不一致!"); return "register"; } if(userExistCheck(username)) { model.addAttribute("status", "用户已存在!"); return "register"; } insertUserInfoToFile(username, userpasswd); mkdir("/" + username); model.addAttribute("status", "注册成功,请登录!"); return "index"; }

注册的时候要检查该用户是否已经存在,调用userExistCheck方法来检查:

//判断用户是否已经注册 public boolean userExistCheck(String username) throws IOException { FileSystem fs = getFileSystem(); Path srcPath = new Path("/userinfo.dat"); FSDataInputStream in = fs.open(srcPath); BufferedReader reader = new BufferedReader(new InputStreamReader(in)); String line = ""; while((line = reader.readLine()) != null) { String[] userinfo = line.split(","); if(userinfo[0].equals(username)) { fs.close(); return true; } } fs.close(); return false; }【Hadoop/Java】基于HDFS的Java Web网络云盘(hadoop java)

若用户之前没有注册过,则允许该用户注册,注册时把用户信息写入到userinfo.dat中,调用insertUserInfoToFile方法:

//把新注册的用户信息插入到userinfo.dat中 public void insertUserInfoToFile(String username, String userpasswd) throws IOException { FileSystem fs = getFileSystem(); Path srcPath = new Path("/userinfo.dat"); FSDataOutputStream out = fs.append(srcPath); String userinfo = username + "," + userpasswd + "\n"; out.write(userinfo.getBytes(StandardCharsets.UTF_8)); out.close(); fs.close(); }

同时在HDFS中创建该用户的个人目录/test,调用mkdir方法:

//创建目录核心操作 public void mkdir(String path) throws IOException { FileSystem fs = getFileSystem(); Path srcPath = new Path(path); fs.mkdirs(srcPath); fs.close(); }

注册成功后,跳转到登录页面,并且给出提示要求登录: 观察userinfo.dat文件,发现添加了新注册的用户信息: 观察HDFS根目录,发现添加了test用户的个人目录: 下面我们用spring用户登录,输入用户名spring,密码123456,点击登录按钮,把相关表单数据提交到Controller的login方法处理:

//登录 @RequestMapping("/login") public String login(HttpServletRequest request, HttpSession session, Model model) throws IOException { String username = request.getParameter("username"); String userpasswd = request.getParameter("userpasswd"); if(!loginCheck(username, userpasswd)) { model.addAttribute("status", "用户名或密码错误!"); return "index"; } session.setAttribute("LOGIN_STATUS", username); session.setAttribute("path", "/" + username); model.addAttribute("currentpath", "/" + username); model.addAttribute("filelist", getFileList("/" + username)); return "myfiles"; }

登录时后台会检查用户名和密码是否正确,调用loginCheck方法:

//检查用户名和密码是否正确 public boolean loginCheck(String username, String userpasswd) throws IOException { FileSystem fs = getFileSystem(); Path srcPath = new Path("/userinfo.dat"); FSDataInputStream in = fs.open(srcPath); BufferedReader reader = new BufferedReader(new InputStreamReader(in)); String line = ""; while((line = reader.readLine()) != null) { String[] userinfo = line.split(","); if(userinfo[0].equals(username) && userinfo[1].equals(userpasswd)) { fs.close(); return true; } } fs.close(); return false; }

若登录不成功,则刷新登陆页面,并给出文字提示: 若登陆成功,则设置session,LOGIN_STATUS的值为当前用户的用户名,path设置为用户的个人目录,然后跳转到个人网盘页面myfiles.jsp 9. myfiles.jsp页面: 个人网盘页面,页面全貌: 该页面有上传文件按钮,表单左上角显示当前所在路径,表单第一行提供返回上级目录功能,然后就是文件列表,若为目录,则在类型列显示目录,若为文件,则在类型列显示文件,另外显示文件或目录的创建时间,最右边一列提供删除文件或目录的功能,左下角提供创建目录/退出登录以及注销账户的功能 当登录成功后,跳转到个人网盘页面,在页面打印用户个人目录下的文件,我们用的是spring用户,所以我们打印HDFS中/spring路径下的所有文件和目录,以及相关的信息,由于文件创建时间在HDFS中用的是时间戳表示,所以我们要先转换为我们方便看的时间,格式为年-月-日 时:分:秒,每一个文件或者目录相关信息我都放在HDFSFile数据类里面:

import lombok.Data;@Datapublic class HDFSFile { private String name; private String date; private String type;}

通过遍历得到文件和目录列表,用List类型封装HDFSFile数据,然后我们要保证目录始终在文件列表的前面,所以我排了个序,得到最终的文件列表,该方法名为getFileList方法:

//获取特定路径的所有文件 public List<HDFSFile> getFileList(String path) throws IOException { FileSystem fs = getFileSystem(); SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); List<HDFSFile> fileList = new ArrayList<>(); FileStatus[] fileStatuses = fs.listStatus(new Path(path)); for(FileStatus fileStatus: fileStatuses) { HDFSFile file = new HDFSFile(); file.setName(fileStatus.getPath().getName()); file.setDate(format.format(fileStatus.getModificationTime())); if(fileStatus.isDirectory()) file.setType("目录"); else file.setType("文件"); fileList.add(file); } //排序,目录放前面,文件放后面 Collator collator = Collator.getInstance(Locale.CHINA); fileList.sort((f1, f2) -> (collator.compare(f1.getType(), f2.getType()))); return fileList; }

当点击文件列表中的目录的时候,改变session,把path的值变成当前目录,然后刷新页面,显示你选的目录中的文件,若点击文件列表中的文件,则下载该文件,处理文件和目录请求用Controller的fileHandle方法:

//处理文件和目录请求,如果是目录,则跳转到对应目录中去,如果是文件,则下载文件 @RequestMapping("/fileHandle") public String fileHandle(HttpSession session, HttpServletRequest request, Model model, HttpServletResponse response) throws IOException { if(!loginStatusCheck(session)) { model.addAttribute("status", "此操作需要你登录!"); return "index"; } String filename = request.getParameter("filename"); String filetype = request.getParameter("type"); if(filetype.equals("目录")) { session.setAttribute("path", session.getAttribute("path").toString() + "/" + filename); model.addAttribute("currentpath", session.getAttribute("path").toString()); model.addAttribute("filelist", getFileList(session.getAttribute("path").toString())); return "myfiles"; } FileSystem fs = getFileSystem(); FSDataInputStream in = fs.open(new Path(session.getAttribute("path").toString() + "/" + filename)); response.setHeader("Content-disposition", "attachment; filename=" + URLEncoder.encode(filename, "UTF-8")); BufferedInputStream bufferedInputStream = new BufferedInputStream(in); BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(response.getOutputStream()); byte[] buff = new byte[2048]; int bytesRead; while((bytesRead = bufferedInputStream.read(buff, 0, buff.length)) != -1) bufferedOutputStream.write(buff, 0, bytesRead); bufferedInputStream.close(); bufferedOutputStream.close(); fs.close(); return null; }

若为下载,需要触发浏览器事件,所以要改变header,让浏览器执行下载操作: 若为目录跳转,则用新路径重新运行getFileList方法,刷新页面: 因为涉及HDFS核心操作,所以若检测到LOGIN_STATUS session不存在,则跳转到登陆页面要求用户登录,后面的核心操作也同样设定了安全约束: 点击返回上层目录,则更新session,改变path,去掉path的最后一个/右边内容以及最后一个/,然后重新调用getFileList方法,刷新页面,请求交给Controller的back方法处理:

//返回上一级目录 @RequestMapping("/back") public String back(HttpSession session, HttpServletRequest request, Model model) throws IOException { if(!loginStatusCheck(session)) { model.addAttribute("status", "此操作需要你登录!"); return "index"; } String currentpath = session.getAttribute("path").toString(); String[] pathsplit = currentpath.split("/"); if(pathsplit.length == 2) { model.addAttribute("warning", "alert(\"当前已经是根目录!\");"); model.addAttribute("currentpath", session.getAttribute("path").toString()); model.addAttribute("filelist", getFileList(session.getAttribute("path").toString())); return "myfiles"; } StringBuilder sb = new StringBuilder(); for(int i = 1; i < pathsplit.length - 1; i++) sb.append("/").append(pathsplit[i]); session.setAttribute("path", sb.toString()); model.addAttribute("currentpath", session.getAttribute("path").toString()); model.addAttribute("filelist", getFileList(session.getAttribute("path").toString())); return "myfiles"; }

若当前已经是用户个人目录的最上层,若还点返回上层目录,则弹出警告,并刷新页面: 点击test.txt最右边的删除按钮,则删除文件,若点击的是目录的删除,则会顺带删除该目录下面的所有文件,删除文件或目录的请求交给Controller的deleteFile方法处理,然后核心操作交给delete方法处理:

//删除文件或目录 @RequestMapping("/deleteFile") public String deleteFile(HttpSession session, HttpServletRequest request, Model model) throws IOException { if(!loginStatusCheck(session)) { model.addAttribute("status", "此操作需要你登录!"); return "index"; } String filename = request.getParameter("filename"); delete(session.getAttribute("path").toString() + "/" + filename); model.addAttribute("warning", "alert(\"删除成功!\");"); model.addAttribute("currentpath", session.getAttribute("path").toString()); model.addAttribute("filelist", getFileList(session.getAttribute("path").toString())); return "myfiles"; } //删除文件或目录核心操作 public void delete(String path) throws IOException { FileSystem fs = getFileSystem(); Path srcPath = new Path(path); fs.delete(srcPath, true); fs.close(); }

删除成功后弹出提示框,然后刷新页面: 点击创建目录按钮,则弹出提示框: 输入新目录的名称,输入不能为空,否则会弹出警示: 若输入目录正确,则创建目录,刷新页面,创建目录请求交给Controller的makeDirectory方法处理:

//创建目录 @RequestMapping("/makeDirectory") public String makeDirectory(HttpSession session, HttpServletRequest request, Model model) throws IOException { String dirname = request.getParameter("dirname"); if(fileExist(session.getAttribute("path").toString() + "/" + dirname)) model.addAttribute("warning", "alert(\"该目录已存在,请重新输入目录名!\");"); else { mkdir(session.getAttribute("path").toString() + "/" + dirname); model.addAttribute("warning", "alert(\"创建成功!\");"); } model.addAttribute("currentpath", session.getAttribute("path").toString()); model.addAttribute("filelist", getFileList(session.getAttribute("path").toString())); return "myfiles"; }

创建成功后弹出提示: 页面刷新后可以看到刚刚创建的目录: 若要创建的目录已经存在,则弹出警告,刷新页面: 检测目录或文件是否存在,用fileExist方法处理:

//判断文件或目录是否存在 public boolean fileExist(String path) throws IOException { FileSystem fs = getFileSystem(); boolean isExist = fs.exists(new Path(path)); fs.close(); return isExist; }

选择文件,然后点击上传,若没有选择文件直接点击上传,前台做了相关约束,不允许提交请求: 点击选择文件按钮,弹出文件选择框,选中文件,点击打开,则网页显示文件的名称: 点击上传,由于上传需要时间,在上传过程中,不可进行浏览器的刷新等其他操作,很可能会造成文件上传失败,所以在等待上传的时间里,页面会显示警示文字: 文件上传成功后,弹出提示框提示用户: 然后页面刷新,文件已经在文件列表中: 用命令行查看/spring目录,文件已经上传到HDFS中: 若上传的文件已经在HDFS中了,如果重复上传,则不允许执行上传操作,并弹出警告,刷新页面: 上传文件操作请求交给Controller的upload方法处理,这里用了commons-io以及commons-fileupload插件,需要在Maven POM文件中导入相关依赖:

<dependency><groupId>commons-fileupload</groupId><artifactId>commons-fileupload</artifactId><version>1.4</version></dependency><dependency><groupId>commons-io</groupId><artifactId>commons-io</artifactId><version>2.11.0</version></dependency> //文件上传 @RequestMapping("/upload") public String upload(HttpSession session, HttpServletRequest request, Model model) throws FileUploadException, IOException { FileSystem fs = getFileSystem(); boolean isExist = false; DiskFileItemFactory factory = new DiskFileItemFactory(); ServletFileUpload upload = new ServletFileUpload(factory); upload.setHeaderEncoding("UTF-8"); List<FileItem> list = upload.parseRequest(request); for(FileItem item: list) { if(!item.isFormField()) { String filename = item.getName(); if(filename == null || filename.trim().equals("")) continue; isExist = fileExist(session.getAttribute("path").toString() + "/" + filename); if(isExist) continue; fs = getFileSystem(); InputStream in = item.getInputStream(); FSDataOutputStream out = fs.create(new Path(session.getAttribute("path").toString() + "/" + filename)); byte[] buff = new byte[2048]; int bytesRead = 0; while((bytesRead = in.read(buff)) > 0) out.write(buff, 0, bytesRead); in.close(); out.close(); item.delete(); } } model.addAttribute("currentpath", session.getAttribute("path").toString()); model.addAttribute("filelist", getFileList(session.getAttribute("path").toString())); if(isExist) model.addAttribute("warning", "alert(\"网盘有同名文件,建议更改文件名!\");"); else model.addAttribute("warning", "alert(\"文件上传成功!\");"); fs.close(); return "myfiles"; }

判断文件是否存在使用上面提到的fileExist方法处理 点击退出登录按钮,则清空LOGIN_STATUS session,然后返回登陆页面,要求客户登录: 对应的退出登录请求交给Controller的logout方法处理:

//退出登录 @RequestMapping("/logout") public String logout(HttpSession session) { session.removeAttribute("path"); session.removeAttribute("LOGIN_STATUS"); return "index"; }

用户点击注销账户按钮,则弹出选择框让用户再次确认是否注销账户: 当用户点击确认后,则开始执行注销用户任务,注销成功后,弹出提示框提示用户: 注销用户请求交给Controller的deleteUser方法处理:

//注销账户 @RequestMapping("/deleteUser") public String deleteUser(HttpSession session, Model model) throws IOException { String username = session.getAttribute("path").toString().split("/")[1]; delete("/" + username); removeUserFromFile(username); model.addAttribute("warning", "alert(\"注销成功!\");"); session.removeAttribute("path"); session.removeAttribute("LOGIN_STATUS"); return "index"; }

首先调用上面提到的delete方法,删除该用户的个人目录/spring,然后修改userinfo.dat,删除该用户的账号密码信息,修改userinfo.dat使用removeUserFromFile方法:

//从userinfo.dat中移除用户 public void removeUserFromFile(String username) throws IOException { FileSystem fs = getFileSystem(); Path srcPath = new Path("/userinfo.dat"); FSDataInputStream in = fs.open(srcPath); BufferedReader reader = new BufferedReader(new InputStreamReader(in)); StringBuilder sb = new StringBuilder(); String line = ""; while((line = reader.readLine()) != null) { String[] userinfo = line.split(","); if(userinfo[0].equals(username)) continue; sb.append(line).append("\n"); } in.close(); FSDataOutputStream out = fs.create(srcPath, true); out.write(sb.toString().getBytes(StandardCharsets.UTF_8)); out.close(); fs.close(); }

查看HDFS根目录,发现spring用户的个人目录已经被移除: 查看userinfo.dat文件,发现spring用户的个人信息已经被删除: 然后清空session,返回登陆页面,完成注销账户的所有操作

至此本云盘的所有功能以及代码都说明完毕!

存在的一些问题

后端的话,我觉得优化空间还是很大的,代码的逻辑上应该是可以优化的

关于前端的话,我属于前端小白来着,非常不会写前端 我觉得文件上传可以写一个进度条,然后一些交互通讯其实可以用AJAX来处理

本文链接地址:https://www.jiuchutong.com/zhishi/299528.html 转载请保留说明!

上一篇:Vue前后端交互(vuenode前后端交互的方式)

下一篇:【Vue】实现当前页面刷新的四种方法(vue获取当前行)

  • 学位证网络公证无需本人到场(学位证公证处公证一次多少钱)

    学位证网络公证无需本人到场(学位证公证处公证一次多少钱)

  • vivox70pro+怎么更换主题(vivox70pro怎么更改桌面图标样式)

    vivox70pro+怎么更换主题(vivox70pro怎么更改桌面图标样式)

  • 微信横屏模式是怎么打开(微信横屏模式是什么意思)

    微信横屏模式是怎么打开(微信横屏模式是什么意思)

  • 电源总闸推不上去(电源总闸推不上去是什么原因)

    电源总闸推不上去(电源总闸推不上去是什么原因)

  • 怎么在图片中加标注(怎么在图片中加文字)

    怎么在图片中加标注(怎么在图片中加文字)

  • 为什么qq留言会莫名其妙消失(为什么给别人qq留言留上一会儿,就消失了)

    为什么qq留言会莫名其妙消失(为什么给别人qq留言留上一会儿,就消失了)

  • 拼多多订阅是什么意思(拼多多里的订阅是什么)

    拼多多订阅是什么意思(拼多多里的订阅是什么)

  • 抖音壁纸怎么保存相册(抖音壁纸怎么保持)

    抖音壁纸怎么保存相册(抖音壁纸怎么保持)

  • qq加群失败什么意思(qq加群不成功)

    qq加群失败什么意思(qq加群不成功)

  • 淘宝商家可以删除买家的评论吗(淘宝商家可以删除客户的评论吗)

    淘宝商家可以删除买家的评论吗(淘宝商家可以删除客户的评论吗)

  • 苹果6导航能定位但不走(苹果6导航定位不准)

    苹果6导航能定位但不走(苹果6导航定位不准)

  • 淘气值怎么显示不出来(淘宝淘气值在哪)

    淘气值怎么显示不出来(淘宝淘气值在哪)

  • 摄像头2.8mm4mm6mm有什么区别(摄像头2.8mm4mm6mm8mm有什么区别)

    摄像头2.8mm4mm6mm有什么区别(摄像头2.8mm4mm6mm8mm有什么区别)

  • 苹果智能电池壳能一直戴吗(苹果智能电池壳怎么用)

    苹果智能电池壳能一直戴吗(苹果智能电池壳怎么用)

  • 快手粉丝团前面的数字是什么意思(快手粉丝团左边的是什么)

    快手粉丝团前面的数字是什么意思(快手粉丝团左边的是什么)

  • 手机是5g的,手机卡也必须是5g的吗(手机是5g的手机卡也是5g的为什么上不了g5)

    手机是5g的,手机卡也必须是5g的吗(手机是5g的手机卡也是5g的为什么上不了g5)

  • 小米手表能用微信吗(小米手表能用微信打语音通话吗)

    小米手表能用微信吗(小米手表能用微信打语音通话吗)

  • 华为手机左上角有个hd是什么意思(华为手机左上角出现一个HD怎么取消)

    华为手机左上角有个hd是什么意思(华为手机左上角出现一个HD怎么取消)

  • 青少年模式怎么开启(青少年模式怎么强制解除)

    青少年模式怎么开启(青少年模式怎么强制解除)

  • word2003脚注在哪(word中脚注在哪里设置)

    word2003脚注在哪(word中脚注在哪里设置)

  • ps怎么水平翻转图层(ps怎么水平翻转图像)

    ps怎么水平翻转图层(ps怎么水平翻转图像)

  • 动态评分怎么提高(动态评分能改吗)

    动态评分怎么提高(动态评分能改吗)

  • 华为荣耀9x指纹在哪(华为荣耀9x指纹设置不见了)

    华为荣耀9x指纹在哪(华为荣耀9x指纹设置不见了)

  • 键盘的乘在哪(键盘键位乘号在哪)

    键盘的乘在哪(键盘键位乘号在哪)

  • 天翼网关识别码怎么查(天翼网关识别码是什么)

    天翼网关识别码怎么查(天翼网关识别码是什么)

  • 文件附件格式怎么弄(文件附件格式怎么排版)

    文件附件格式怎么弄(文件附件格式怎么排版)

  • iphonexr无法隔空投送(苹果xr无法隔空投送)

    iphonexr无法隔空投送(苹果xr无法隔空投送)

  • 电脑换电源后无法开机(电脑换电源后无法进入系统)

    电脑换电源后无法开机(电脑换电源后无法进入系统)

  • 前端get/post等请求后,一直处于pending状态,解决办法(前端get请求传多个参数)

    前端get/post等请求后,一直处于pending状态,解决办法(前端get请求传多个参数)

  • 从0到1搭建Vue项目(webpack版)(vue从0创建一个项目)

    从0到1搭建Vue项目(webpack版)(vue从0创建一个项目)

  • 车船税可以免掉吗
  • 企业取得被投资单位的长期股权可以享有
  • 开红字发票需要收回原发票吗
  • 医院能否开具增值税专用发票
  • 公司付给中间人居间费用如何纳税
  • 供热管道属于什么经营范围内
  • 个人所得税app是什么意思
  • 企业资产折旧抵扣所得税
  • 税控发票包括哪些
  • 物业公司收物业费如何入账
  • 前程无忧靠什么赚钱
  • 预交增值税附加税费减免吗
  • 跨行业能开发票吗
  • 合同印花税进哪个科目
  • 个人所得税申报是什么意思?
  • 逾期增值税扣税凭证抵扣问题
  • 车船使用税是否必须交
  • 发票收款人和开票人
  • 马克龙成就
  • 拍卖中,必须规定一切税费由买受人承担吗?
  • 金税盘新领的发票怎么分发出去
  • 火车票抵扣进项税额怎么申报
  • 收入冲正
  • 员工差旅补贴是否需要发票
  • 劳动保护用品应由什么开支
  • 存货跌价准备转销
  • 印花税可以计入在建工程吗
  • 物流公司支付运费怎么做账
  • 小企业原材料包括
  • PHP:apache_setenv()的用法_Apache函数
  • 应收账款挂账多年
  • 硬盘跳线设置
  • vue设置时间格式
  • 阳光照耀下的人
  • 进项税额准予抵扣的有哪些
  • 房产税和土地使用税什么时候申报
  • 达特穆尔动物园
  • 固定资产清理的金额怎么算
  • 公益性怎么解释
  • 租用办公室装修费用会计分录
  • 工资如何记账
  • python怎么用
  • 残保金是什么单位收的
  • 出口退税转内销的损失
  • 其他收益在利润表中的位置
  • 采购原材料未入库
  • 管理费用如何填列
  • 水泥销售会计分录怎么做
  • 资产减值损失科目借方增加还是减少
  • 预提费用在汇算清缴时调整,会计分录怎么做
  • 速动比率例子
  • 少数股东权益如何保障
  • 个体户记账报税
  • 坏账准备具有什么功能
  • 企业安全生产费用可由企业用于购置
  • 管理费用是负数影响利润表吗
  • 预收账款怎么做账
  • Ubuntu14.4下Sublime Text 3无法输入中文解决方法
  • solaris如何关闭usb接口
  • windows精简版精简了哪些
  • win7系统对拷的方法
  • 苹果电脑mac系统键盘无法找到
  • windows7怎么说
  • 使用和启动故障的区别
  • win8如何关闭杀毒软件
  • Linux系统怎么用FTP传文件
  • android jdk下载
  • 如何正确使用标准电池和检流计
  • jquery滚动到底部
  • python搜索引擎网络爬虫
  • python生成随机
  • python3.6语法
  • node.js调用c
  • 详解javascript事件冒泡
  • python计算π值
  • Android音乐播放器评论功能怎么实现
  • android studio中r文件在哪
  • 税控发票开票软件(金税盘版)事件代码768功能代码5?
  • 江西省国税局全称
  • 柴油增值税发票
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

    网站地图: 企业信息 工商信息 财税知识 网络常识 编程技术

    友情链接: 武汉网站建设