位置: IT常识 - 正文

SpringBoot+Vue实现简单用户管理平台第一篇(后端接口设计)

编辑:rootadmin
SpringBoot+Vue实现简单用户管理平台第一篇(后端接口设计) 🚀 注重版权,转载请注明原作者和原文链接🥭 作者:Yuan-Programmer🍎 主页:https://blog.csdn.net/weixin_47971206/article/details/121368075?spm=1001.2014.3001.5502🍉 进来的小伙伴点点赞呀

推荐整理分享SpringBoot+Vue实现简单用户管理平台第一篇(后端接口设计),希望有所帮助,仅作参考,欢迎阅读内容。

文章相关热门搜索词:,内容如对您有帮助,希望把文章链接给更多的朋友!

本案例第二篇教程地址:SpringBoot+Vue实现简单用户管理平台第二篇(前端设计,接口对接)

demo地址预览(域名正在审核,将就ip访问):http://43.138.223.178/user-manager

花了几个小时做了一个SpringBoot+Vue的简单用户管理demo项目,适合新手教程,项目已在Gitee上开源,Gitee开源地址:https://gitee.com/yuandewei/Yuan-SpringBoot/tree/master

Gitee上开源的代码跟本次的案例的代码有些区别,本次案例稍微改了一点点,不过不影响Gitee上的项目运行,大致效果如下,功能可以访问demo地址测试哦

前言开发环境

开发工具就不多介绍啦,就IDEA做后端,VSCode做前端,用其他的也都可以

技术

本次后端用到的技术呢: 主要就两个,SpringBoot + MyBatisPlus

前端的技术用到的技术: Vue,结合脚手架以及element ui框架开发前端

表设计

既然是用户管理嘛,肯定有用户表,我们先来设计表结构

这里说明一点,这次案例是新手教程,着重讲解功能的实现,所以用户信息参数方面就没有那么严格的校验,一般像号码这种字段肯定是设置为 char(11) 并且后端要校验的

创建Maven工程

创建一个空的Maven项目,大家应该都会了吧,还不会的小伙伴看之前的其他项目教程哦(我个人习惯创建maven工程,你喜欢直接创建springboot项目也可以,)

我这里创建好了一个 user-manager的maven项目,创建好项目,点击右下角选择自动导入,没有弹出来也没关系

引入依赖

<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.2.1.RELEASE</version> <relativePath/> </parent> <properties> <java.version>1.8</java.version> </properties> <dependencies> <!-- MyBatis-Plus依赖 --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.5.0</version> </dependency> <!-- 数据库驱动 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <!-- Web启动依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- SpringBoot测试依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!-- Lombok --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <!-- 处理JSON的 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.76</version> </dependency> </dependencies>基本配置

创建 com.xiaoyuan.usermanager 目录,新建一个启动类 UserManagerApplication

@SpringBootApplicationpublic class UserManagerApplication { public static void main(String[] args) { SpringApplication.run(UserManagerApplication.class, args); }}

在 resources 资源目录下新建 application.yml 配置文件

图片有误,少了时间格式转换三行代码,看下面

server: # 端口 port: 8081spring: # 数据源配置 datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql:///l_user?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8 username: xiaoyuan password: root # 时间格式转换 jackson: time-zone: GMT+8 date-format: yyyy-MM-dd HH:mm:ssmybatis-plus: # mapper文件映射路径 mapper-locations: classpath*:mapper/*.xml configuration: # 打印SQL语句 log-impl: org.apache.ibatis.logging.stdout.StdOutImpldb层entity实体类

新建 db 包,在 db 包下新建 entity 和 mapper 两个包,在 entity 包下新建一个 User 类

注意一下,图片里 describe 有个注解忘记加上了,以下面代码为准

@Datapublic class User { // 主键ID @TableId(value = "id", type = IdType.AUTO) private Integer id; // 用户名 private String username; // 昵称 private String nickname; // 密码 private String password; // 号码 private String phone; // 性别 private Character sex; // 描述 @TableField(value = "`describe`") // describe属于数据库关键字,加上``区分 private String describe; // 创建时间 @TableField(fill = FieldFill.INSERT) // insert操作时自动注入时间 private Date gmtCreate;}mapper数据访问层

在 mapper 包下新建一个 UserMapper,继承MyBatisPlus的 BaseMapper 类,作为DAO层操作数据

MyBaitsPlus配置

这里创建的两个包都与db包同级目录

config配置类

创建一个config包,新建一个MyBatisPlusConfig 类

@Configurationpublic class MyBatisPlusConfig { /* 分页插件 */ @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); // 开启 interceptor.addInnerInterceptor(new PaginationInnerInterceptor()); return interceptor; }}handler处理

新建一个 handler 包,包下新建一个 MyMetaObjectHandler 类,实现 MetaObjectHandler 类,改类有两个方法,一个insert…在向数据库插入数据的时候,会自动插入我们设置的值

@Componentpublic class MyMetaObjectHandler implements MetaObjectHandler { /** * 新增数据执行 * * insert插入数据到数据库操作时执行 */ @Override public void insertFill(MetaObject metaObject) { // 配置初始创建时间 this.setFieldValByName("gmtCreate", new Date(), metaObject); } /** * 修改数据执行 * * update修改数据库数据操作时执行 */ @Override public void updateFill(MetaObject metaObject) { }}

这里的 this.setFi… 第一个参数对应的是User实体类的名字,不是表中的字段名,第二个参数的默认值

Vo对象

新建一个 vo 包,用于和前端交互数据的类

统一结果返回类

vo 包下新建一个 R 类,作为我们统一返回给前端数据的类,

@Datapublic class R { private Boolean success; private Integer code; private String message; private Map<String, Object> data = new HashMap<>(); // 把构造方法私有化 private R() {} // 成功静态方法 public static R ok() { R r = new R(); r.setSuccess(true); r.setCode(200); r.setMessage("成功"); return r; } // 失败静态方法 public static R error() { R r = new R(); r.setSuccess(false); r.setCode(201); r.setMessage("失败"); return r; } public R success(Boolean success){ this.setSuccess(success); return this; } public R message(String message){ this.setMessage(message); return this; } public R code(Integer code){ this.setCode(code); return this; } public R data(String key, Object value){ this.data.put(key, value); return this; }}

vo 包下新建 QueryParam 类

@Datapublic class QueryParam { // 用户名 private String username; // 昵称 private String nickname; // 号码 private String phone; // 性别 private String sex; // 创建时间 private String time;}

这里讲一下吧,这个类是用来干嘛的呢?我们在效果展示的时候,是不是在上面看到有5个筛选条件,这5个筛选条件参数刚好对应类中的5个属性,我们统一封装起来

service业务层SpringBoot+Vue实现简单用户管理平台第一篇(后端接口设计)

新建一个 service 包,包下新建一个 UserService 接口类,继承MyBatisPlus的 IService 类 service 包下新建 impl 包,新建一个 UserServiceImpl 实现类,继承MyBatisPlus的 ServiceImpl 类,实现我们自己的 UserService 类 我们先在 UserService 接口类定义五个方法,接下来我们一一实现这五个功能

public interface UserService extends IService<User> { /** * 添加用户 * @param user * @return */ R insertUser(User user); /** * 删除单个用户 * @param id 用户编号 * @return */ R deleteUser(Integer id); /** * 删除多个用户 * @param ids 用户编号集合 * @return */ R deleteUserMore(List<Integer> ids); /** * 编辑用户 * @param user * @return */ R modifyUser(User user); /** * 分页查询用户列表 * @param index 当前页 * @param size 每页显示数量 * @param queryParam 筛选条件对象 * @return */ R findUserList(Integer index, Integer size, QueryParam queryParam);/** * 查询单个用户详细信息 * @param id 用户编号 * @return */ R getUserInfoById(Integer id);}添加用户

UserServiceImpl 实现类里实现添加用户方法,这里只做了简单的非空判断,其他参数的非法性校验可以自己额外完善

@Overridepublic R insertUser(User user) {if (user == null) return R.error().message("参数错误"); // 用户名String username = user.getUsername();// 构建条件对象, 查询是否已经存在用户名QueryWrapper<User> wrapper = new QueryWrapper<>();wrapper.select("id");wrapper.eq("username", username);wrapper.last("limit 1");// 查询判断, 如果查询出来有数据, 则不为nullif (this.baseMapper.selectOne(wrapper) != null) R.error().message("该用户名已存在");// 执行插入数据操作return this.baseMapper.insert(user) == 0 ? R.error().message("添加用户失败") : R.ok();}删除用户

删除用户就比较简单啦,肯定有人会问,前端做了非空校验,后端怎么还要做参数校验校验呢?

其实前后端都做是最好的,有绕过前端发送请求的,就比如我们自己测试接口时用的postman, apifox,后端多做一层校验,避免直接操作数据库,我这里也是比较简单的做了校验

@Overridepublic R deleteUser(Integer id) {if (id == null || id <= 0) return R.error().message("参数错误");return this.baseMapper.deleteById(id) == 0 ? R.error().message("删除失败") : R.ok();}一键删除多个用户

删除多个用户也没难度,将多个用户的编号放到一个集合中,一次删除多个

@Overridepublic R deleteUserMore(List<Integer> ids) {if (ids.size() == 0) return R.error().message("参数错误");return this.baseMapper.deleteBatchIds(ids) != ids.size() ? R.error().message("删除失败") : R.ok();}编辑用户

这个也没什么难度,做个简单校验,然后根据ID更新用户信息(参数其他合法性校验可以自己额外做哦)

@Override public R modifyUser(User user) { if (user == null || user.getId() == null || user.getId() <= 0) return R.error().message("参数错误"); return this.baseMapper.updateById(user) == 0 ? R.error().message("编辑用户失败") : R.ok(); }获取单个用户信息

先实现这个吧,这个也很简单,直接通过用户编号查询用户的信息返回即可

@Overridepublic R getUserInfoById(Integer id) {if (id == null || id <= 0) return R.error().message("参数错误");return R.ok().data("userInfo", this.baseMapper.selectById(id));}查询用户列表

先创建编写SQL语句的文件,在 resources 下新建 mapper 包,包下新建 UserMapper.xml 文件 代码中的SQL语句不能包含注释,所以我在图片给出了每行的注释,代码中删掉了,对应看着

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"><!-- namespace路径根据自己而定 --><mapper namespace="com.xiaoyuan.usermanager.db.mapper.UserMapper"> <!-- 查询用户列表(带多条件) --> <select id="findUserList" resultType="com.xiaoyuan.usermanager.db.entity.User"> select * from user <where> 1 = 1 <if test="queryParam != null"> <if test="queryParam.username != null and queryParam.username != ''"> and username = #{queryParam.username} </if> <if test="queryParam.nickname != null and queryParam.nickname != ''"> and nickname like CONCAT(#{queryParam.nickname}, '%') </if> <if test="queryParam.phone != null and queryParam.phone != ''"> and phone = #{queryParam.phone} </if> <if test="queryParam.sex != null and queryParam.sex != ''"> and sex = #{queryParam.sex} </if> <if test="queryParam.time != null and queryParam.time != ''"> and DATE_FORMAT(gmt_create,'%Y-%m-%d') = #{queryParam.time} </if> </if> </where> </select></mapper>

我们大致来分析一下上面的SQL语句,首先 select * from user这里没毛病吧,咋们是管理用户,所有信息都得要上,* 查询所有

后面 where 里有个 1 = 1 作用是恒等式,为了防止没有做筛选条件时,queryParam 条件对象为 null 导致 where 里面没东西,执行SQL语句的时候就会出现 where 后面没加东西,就会抛出异常

CONCAT 函数的作用是拼接,当然你直接用下面这样也行,推荐还是使用CONCAT,以后会遇到的,还有就是 % 只写右边就可以了,避免全表扫描,采用单模糊查询

and nickname like #{queryParam.nickname} '%'

DATE_FORMAT 函数作用是对时间进行格式化,2022-05-06 11:17:36 转换为 2022-05-06

SQL语句写好了,更新一下我们的 UserMapper 类,映射到 UserMapper.xml 文件的SQL语句,函数名就是 < select id=“xxxx”> 这里id的值

@Repositorypublic interface UserMapper extends BaseMapper<User> { /** * 查询用户列表 * @param page 分页对象 * @param queryParam 筛选条件 * @return */ IPage<User> findUserList(Page<User> page, QueryParam queryParam);}

最后就是在 UserServiceImpl 实现查询用户列表的方法

@Overridepublic R findUserList(Integer index, Integer size, QueryParam queryParam) {if (index == null || size == null || index <= 0 || size <= 0) {return R.error().message("参数错误");}else if (size > 10) {return R.error().message("一次最多10条数据");}// 构建分页对象Page<User> page = new Page<>(index, size);// 查询IPage<User> iPage = this.baseMapper.findUserList(page, queryParam);// 回传两个数据, 一个 userList --> 用户数据列表, 一个 total -> 总页数return R.ok().data("userList", iPage.getRecords()).data("total", iPage.getTotal());}controller控制层

这里是最后一步了,处理接口,我们采用 RESTful 的风格,相同的路径处理不用的操作

@RestController@RequestMapping("/user")@CrossOriginpublic class UserController { @Autowired private UserService userService; // 添加用户 @PostMapping("") public R insertUser(@RequestBody User user) { return userService.insertUser(user); } // 删除单个用户 @DeleteMapping("{id}") public R deleteUser(@PathVariable(value = "id") Integer id) { return userService.deleteUser(id); } // 删除多个用户 @DeleteMapping("") public R deleteUserMore(@RequestBody List<Integer> ids) { return userService.deleteUserMore(ids); } // 编辑用户 @PutMapping("") public R modifyUser(@RequestBody User user) { return userService.modifyUser(user); } // 查询用户列表 @PostMapping("{index}/{size}") public R findUserList(@PathVariable(value = "index") Integer index, @PathVariable(value = "size") Integer size, @RequestBody(required = false) QueryParam queryParam) { return userService.findUserList(index, size, queryParam); } // 根据用户编号查询用户信息 @PostMapping("{id}") public R getUserInfo(@PathVariable(value = "id") Integer id) { return userService.getUserInfoById(id); }}接口测试

最后,在启动类加上两个注解,一个 MapperScan 扫描我们的 mapper 类,一个 ComponentScan 扫描我们的组件

@SpringBootApplication@MapperScan(basePackages = {"com.xiaoyuan.usermanager.db.mapper"})@ComponentScan({"com.xiaoyuan"})public class UserManagerApplication { public static void main(String[] args) { SpringApplication.run(UserManagerApplication.class, args); }}

OK,到这里功能已经全部做好了,我们测试一下接口,运行启动类,我这里只展示部分接口的测试接口,全部接口我已经测试过,都没有问题了

大家可以自己去测试每个接口,我用的时 ApiFox 工具,非常好用,还能一键导出接口文档,可以显示接口耗时,分组分项目分接口分环境,非常的方便

添加用户,成功插入数据 当然,你可以在代码里面用测试,新建一个 SpringBoot 的测试类,测试业务层也可以的,如下 其他的就不一一放出来了,大伙自己去试试吧~

扩展(拦截器,权限拦截)

像管理这种一般都会有权限的,总不可能每个人都能访问自己的接口来增删改查用户吧?如何做到不给其他人访问自己的接口,判断别人是否有权限访问呢?

下面我们简单来设计一下,理解大概过程

首先,usermanager 主目录下创建两个包,一个 interceptor 拦截器,一个 WebMVCConfig MVC的配置类

interceptor 包下新建一个 PermissionInterceptor 类,实现 HandlerInterceptor 类

拦截器有三个阶段,preHandle -> postHandle -> afterCompletion,依次按顺序执行,只有前一个return返回true,才会执行下一个阶段方法,简单介绍三个阶段

preHandle:controller执行目标方法之前执行,一般用于权限验证等操作postHandle:controller执行完目标方法返回(如调用service业务层的方法),在前端数据渲染之前执行,一般用于更改视图数据afterCompletion:整个接口访问执行完毕,前端数据渲染完成,执行此方法,一般用于资源释放等操作

很明显,我们这个权限验证拦截就是在 preHandle 阶段去全性

这个 code 呢就是我们自己定义的权限码,我这里只是随便敲了长长的一段,反正自己知道就好,你可以做加密处理,这里我简单模拟一下

@Componentpublic class PermissionInterceptor implements HandlerInterceptor { private static final String code = "dwagfhwhgiawpfwabifpjwaidjwaidwiafihwigfhwaigwhaipgwaihiwahifhwdefef"; @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// 放行OPTIONS请求 if (HttpMethod.OPTIONS.matches(request.getMethod())) { return true; } // 获取请求头里面的 Authentication 属性值 String authentication = request.getHeader("Authentication"); // 两者相等 -> 通过放行, 两者不相等 -> 不通过不放行 if (code.equals(authentication)) { // 放行 return true; }else { // 不放行, 回传没有权限 response.setContentType("text/html;charset=utf-8"); response.getWriter().println(JSON.toJSONString(R.error().message("没有操作权限"))); return false; } }}

config 包下新建一个 WebMVCConfig 类,实现 WebMvcConfigurer 类,设置拦截器

@Configurationpublic class WebMVCConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new PermissionInterceptor()) // 添加拦截器 .addPathPatterns("/user/**"); // 选择拦截路径,拦截/user下的所有请求 }}

好的,我们接下来看看效果,当然,就不适合在代码用SpringBoot测试类啦,因为校验请求头

我们采用接口测试工具,老样子,我使用的是ApiFox,你可以使用postman等其他工具

首先我们继续运行一下之前写好的请求路径(没加Authentication 权限码),可以看到,我们访问的是查询用户列表接口,显示没有权限 接下来我们在 header 请求头加上我们的 Authentication 的权限码,同样的路径,测试一下 是不是就成功访问到了 我们随便改错一个字母,也成功显示没有权限,除非你的权限码被别人知道了,或者被破解了(设置的复杂一点再加密基本不可能被破),不然你的接口别人访问不了

🌹 结束语

好了,整篇的教程呢到这也就结束,整篇教程即为原创一字一字手敲,也花了心思想怎么写怎么设计才能更好的直观简洁展示给大家,让大家能看懂

最后,关于教程还有什么不懂的可以评论区留言,我一定会回复的,或者有什么更好的建议和想法也可以在评论区留言,看到好的我会一一采纳,感谢大家的支持

再一次附上Gitee开源地址:https://gitee.com/yuandewei/Yuan-SpringBoot/tree/master 不用大伙翻上去复制了

都看到这里啦,点点赞呀 😋感谢阅读 😘
本文链接地址:https://www.jiuchutong.com/zhishi/298761.html 转载请保留说明!

上一篇:〖大前端 - 基础入门三大核心之JS篇㉓〗- JavaScript 的「数组」(大前端入门指南)

下一篇:基于微信小程序的电影订票系统设计与实现(代码+数据库+论文)(基于微信小程序制作)

  • iPad开机(ipad开机一直显示白苹果)

    iPad开机(ipad开机一直显示白苹果)

  • 拼多多退款率高会影响店铺吗(拼多多退款率高吗)

    拼多多退款率高会影响店铺吗(拼多多退款率高吗)

  • 三星手机提示volte不可用(三星手机提示有水不能充电)

    三星手机提示volte不可用(三星手机提示有水不能充电)

  • Word目录的行距怎么调(word目录的行距怎么改)

    Word目录的行距怎么调(word目录的行距怎么改)

  • 魅族m681q什么型号(魅族m681是什么型号)

    魅族m681q什么型号(魅族m681是什么型号)

  • 钉钉麦克风权限在哪设置(钉钉麦克风权限关了,视频会议还能听见声音吗)

    钉钉麦克风权限在哪设置(钉钉麦克风权限关了,视频会议还能听见声音吗)

  • 折屏手机都有啥牌子(折屏手机都有啥功能)

    折屏手机都有啥牌子(折屏手机都有啥功能)

  • 5g网络需要换手机吗(5g是不是需要更换手机)

    5g网络需要换手机吗(5g是不是需要更换手机)

  • 怎么把手机闹钟设置成自己喜欢的音乐(怎么把手机闹钟时间显示到桌面)

    怎么把手机闹钟设置成自己喜欢的音乐(怎么把手机闹钟时间显示到桌面)

  • 电脑开机windows未能启动是怎么回事(电脑开机windows无法启动)

    电脑开机windows未能启动是怎么回事(电脑开机windows无法启动)

  • 在抖音上怎么发视频作品(在抖音上怎么发作品有收益)

    在抖音上怎么发视频作品(在抖音上怎么发作品有收益)

  • 什么叫分布式服务攻击(什么是分布式服务)

    什么叫分布式服务攻击(什么是分布式服务)

  • 信息有个叹号怎么回事(信息有个叹号怎么弄掉)

    信息有个叹号怎么回事(信息有个叹号怎么弄掉)

  • 发出去的短信能撤销吗(发出去的短信能删除记录吗)

    发出去的短信能撤销吗(发出去的短信能删除记录吗)

  • 麦克风启用不成功(麦克风启用不成功怎么设置)

    麦克风启用不成功(麦克风启用不成功怎么设置)

  • 无线面板ap怎么设置(无线面板ap怎么安装调试)

    无线面板ap怎么设置(无线面板ap怎么安装调试)

  • 抖音号怎么注销手机号(抖音号怎么注销不了)

    抖音号怎么注销手机号(抖音号怎么注销不了)

  • 苹果手机在哪里可以测量距离(苹果手机在哪里看激活时间)

    苹果手机在哪里可以测量距离(苹果手机在哪里看激活时间)

  • 虎牙直播如何投屏(虎牙直播如何投电脑)

    虎牙直播如何投屏(虎牙直播如何投电脑)

  • 电脑硬盘内存怎么扩大(电脑硬盘内存怎么合并)

    电脑硬盘内存怎么扩大(电脑硬盘内存怎么合并)

  • win11重置系统保留个人文件的方法步骤(win11重置系统保留我的文件)

    win11重置系统保留个人文件的方法步骤(win11重置系统保留我的文件)

  • React入门笔记(react 入门)

    React入门笔记(react 入门)

  • WEB核心【案例:文件下载,案例:点击切换验证码,几种获取properties资源方式】第十二章(web核心的三个标准)

    WEB核心【案例:文件下载,案例:点击切换验证码,几种获取properties资源方式】第十二章(web核心的三个标准)

  • python如何使用字典实现switch(python怎么写文字)

    python如何使用字典实现switch(python怎么写文字)

  • 按适用税率计税销售额和按简易办法计税销售额
  • 简易征收预缴税率怎么算
  • 咨询服务业涉及税费
  • 私车公用协议可以入账吗?
  • 购进餐饮服务的会计分录
  • 提供教育服务免征增值税文件
  • 公司为员工租房费用的会计分录
  • 收到车辆保险返还会计分录
  • 发票缴税怎么交的
  • 劳务公司购买材料怎么做账
  • 房地产企业土地增值税
  • 合作保证金可以退吗
  • 个人去税务局开居间费发票
  • 加油票可以抵扣几个点的增值税
  • 旅行社代订机票怎么做账
  • 小规模开专票不超过45万要交税吗
  • 对公账户提取备用金可以每天提现嘛
  • 分红未及时扣缴税款要缴滞纳金吗?
  • 进口商品的关税计入入账价值吗
  • 企业分立账务处理办法
  • 对赌协议的账务处理流程
  • 样品送出,不收款怎么做账?
  • 法人治理包括哪些方面
  • 零售业收入
  • 为离职员工代缴社保 如何规避法律责任
  • 预收款退回怎么写分录
  • windows11 怎么更新
  • php操作mysql数据库
  • win10启用网络发现保存后又变成了关闭
  • erl.exe是什么进程
  • linux attached
  • 对公帐户定期存款利率
  • 政府补助退回的账务处理
  • PHP:stream_get_filters()的用法_Stream函数
  • ccmexec.exe是什么程序
  • php socket_select
  • 存货包括其他业务成本吗
  • 小型微利企业税收优惠2023
  • thinkphp伪静态nginx
  • 企业所得税可以结转以后年度扣除的费用
  • 租出固定资产的处理步骤
  • 一篇文章让你了解什么
  • 残疾人就业保障金怎么申报
  • python 字典中的字典
  • phpcms插件
  • wndgui降级
  • 机关单位差旅费
  • 金蝶专业版利润表怎么生成
  • 小规模企业没有进项票能开发票吗
  • 接受捐赠如何进项
  • ERROR CODE: 1175 YOU ARE USING SAFE UPDATE MODE AN
  • 固定资产加速折旧计算方法
  • 企业合并的账务处理
  • 开具定额发票应如何做账?
  • 增值税抵扣了,主要成本怎么算
  • 公司借个人款利息产生个人所得税公司可以承担吗
  • 跨年进项发票怎样账务处理
  • 主营业务成本包括工资吗
  • 白条入账的新会计政策
  • 库存商品差额调整会计目录
  • 收据注明实际到账时间
  • 销售预付卡的账务处理
  • 固定资产一次性加速折旧
  • 弥补亏损的会计处理
  • 简易计税项目可以抵扣进项税吗?
  • 公益捐赠仪式流程
  • SQL语句查询数据库账号和权限
  • 获取客户端所有cookie对象的方法
  • win10怎么给Windows Defender添加排除项?
  • windows已保护你的电脑,阻止你的应用
  • 如何使用搜狗拼音输入法
  • mac截屏后的图片在哪里
  • win8 所有程序
  • LiteSpeed添加虚拟主机+支持htaccess图文教程
  • linux 映射 fn键
  • 在windows下搭建snort和base
  • 遮罩层 css
  • Javascript & DHTML 实例编程(教程)DOM基础和基本API
  • 新手入门常用代词有哪些
  • 如何理解python语言
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

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

    友情链接: 武汉网站建设