Vue+Axios+SSM框架实现增删改查与文件上传
链接:https://pan.baidu.com/s/163wHTpcdLdOfCUSg1PqMgg?pwd=4fb1提取码:4fb1--来自百度网盘超级会员V3的分享。
总结
随手搭建一个Vue+SSM框架,实现增删改查和上传、预览图片的功能,这里把用到的技术点和工具罗列一下:
前端:
1. 使用VUE作为基础框架。
2. 使用elementUI的一些组件,搭建表格、弹框、表单等。
3. 使用form-generator,在线搭建属于自己的form表单,可以下载自定义的from表单代码,网址:https://mrhj.gitee.io/form-generator/#/
4. 使用axios,将前端数据封装,异步传输给后端。
5. 使用vue实现三级联动、省市区三级信息查询、回显功能。
6. 使用element的组件实现分页查询、文件上传的功能。
后端:
1. 使用ssm框架,搭建分页查询、增删改接口。
2. 定义上传接口,将文件上传至远程服务器。
3. 使用mybatis的逆向工程,生成mybatis的mapper文件、bean实体、mapper接口。
访问以下地址下载源码:
链接:https://pan.baidu.com/s/163wHTpcdLdOfCUSg1PqMgg?pwd=4fb1
提取码:4fb1
--来自百度网盘超级会员V3的分享
准备工作
创建数据库表
数据库DDL语句如下:
CREATE TABLE
gameuser
(
usrId INT NOT NULL AUTO_INCREMENT,
usrLoginNm VARCHAR(183),
usrLoginPwd VARCHAR(183),
usrNm VARCHAR(183),
usrCardNum VARCHAR(18),
usrAddr VARCHAR(183),
usrBirDate DATE,
usrHobby VARCHAR(183),
usrDetail VARCHAR(183),
usrFileUrl VARCHAR(183),
PRIMARY KEY (usrId)
)
ENGINE=InnoDB DEFAULT CHARSET=utf8 DEFAULT COLLATE=utf8_general_ci;
搭建前端开发环境
1. 首先,我们需要访问地址:https://mrhj.gitee.io/form-generator/#/
利用此网站定义我们的form表单,生成完毕后将vue文件下载到本地,后面我们会导入到项目中。
2. 在本地搭建vue项目,使用黑窗口命令:vue create vueproject 创建前端Vue项目:
3. 在项目的创建目录下运行命令:npm i element-ui -S 安装elementUI
4. 项目中需要与后端接口通信,需要使用的技术为axios,执行 npm install axios 命令安装axios:
5. 使用Hbuilder打开前端项目,在package.json文件的rules中添加以下内容,去掉esline校验:
"vue/no-unused-components": "off",
"no-mixed-spaces-and-tabs": 0
6. 解决跨域问题,修改前端配置 vue.config.js 增加跨域配置项,跨域的解决方案有很多,这里选择使用前端代理实现跨域问题,配置以下内容:
devServer: {//配置代理 解决跨域问题
proxy: {
'/api': {
// 此处填写项目的访问地址
target: 'http://localhost:8082/Ajaxd01',
// 允许跨域
changeOrigin: true,
ws: true,
pathRewrite: {
'^/api': ''
}
}
}
}
7. 因为需要用到elementUI,此处在main.js中导入elementUI相关的信息,此处小编为了省事儿,就直接全部引入了,大家根据自己情况选择按需引入还是全部引入(具体引用方式可参考官网):
//引入elementUI相关的组件
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.use(ElementUI);//use之后生效
8. 在main.js引入axios的相关包并use。
//引入axios
import axios from 'axios'
//配置请求的根路径
axios.defaults.baseURL = '/api/'
// 原型上挂载axios, 所有组件都可以通过this.$http来请求
Vue.prototype.$http = axios
Vue.use(axios)
9. 最终mai.js中的配置如下:
10. 我们来运行一下项目试试看,输入命令:npm run serve 项目可以正常运行即可
11. 至此,可以访问前端项目,前端项目准备工作结束,可以进行VUE项目的开发了。
搭建后端开发环境
1. 后端采用传统的SSM框架实现文件的上传下载、三级联动、以及普通的增删改查,这里我们会利用Mybatis的逆向工程为我们提供支持,以简化我们的开发效率。
2. 首先,我们先来创建一个普通SSM的Maven项目,按照图示步骤创建:
3. 创建maven web 项目,补充缺失目录,java、resources、test目录。
4. 更新web.xml中的约束:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
</web-app>
5. 创建各个层的包:controller、bean、service、impl、mappe
6. 导入maven相关的依赖:
<!--Spring核心包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.5</version>
</dependency>
<!--spring切面 包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.3.5</version>
</dependency>
<!--aop联盟包-->
<dependency>
<groupId>aopalliance</groupId>
<artifactId>aopalliance</artifactId>
<version>1.0</version>
</dependency>
<!--德鲁伊连接池-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>
<!--mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.22</version>
</dependency>
<!--springJDBC包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.5</version>
</dependency>
<!--spring事务控制包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.3.5</version>
</dependency>
<!--orm映射依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>5.3.5</version>
</dependency>
<!--apache commons日志包-->
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
<!--log4j日志包-->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>2.14.0</version>
<scope>test</scope>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
<scope>provided</scope>
</dependency>
<!--springtest 支持包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.3.5</version>
</dependency>
<!--junit5单元测试包-->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.7.0</version>
<scope>test</scope>
</dependency>
<!--springMVC支持包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.3.5</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.5</version>
</dependency>
<!--jsp-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
<!--servlet-->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.3</version>
<scope>provided</scope>
</dependency>
<!--JSON依赖-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.1</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.1</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.9.1</version>
</dependency>
<!--mybaties的核心jar包-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.3</version>
</dependency>
<!--spring和mybatis的整合包-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.3</version>
</dependency>
<!--日志包-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.6.1</version>
</dependency>
<!--代码生成工具-->
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>1.3.2</version>
</dependency>
<!--junit-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
7. 准备配置文件springmvc.xml、log4j2.xml、jdbc.properties、applicationContext.xml、web.xml、generatorConfig.xml。
generatorConfig.xml:生成mybatis相关的mapper接口和xml、实体类:
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE generatorConfiguration PUBLIC
"-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<classPathEntry
location="D:\maven\repository\mysql\mysql-connector-java\8.0.22\mysql-connector-java-8.0.22.jar"/>
<context id="testTables" targetRuntime="MyBatis3">
<commentGenerator>
<!-- 是否去除自动生成的注释 true:是 : false:否 -->
<property name="suppressAllComments" value="true"/>
</commentGenerator>
<!--数据库连接的信息:驱动类、连接地址、用户名、密码 -->
<!--<jdbcConnection driverClass="${jdbc.driver}"--> <!--connectionURL="${jdbc.url}"--> <!--userId="${jdbc.username}"--> <!--password="${jdbc.password}">--> <!--</jdbcConnection>-->
<jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
connectionURL="jdbc:mysql://127.0.0.1:3306/test?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true"
userId="root" password="******">
</jdbcConnection>
<!-- 默认false,把JDBC DECIMAL 和 NUMERIC 类型解析为 Integer,为 true时把JDBC DECIMAL 和 NUMERIC 类型解析为java.math.BigDecimal -->
<javaTypeResolver>
<property name="forceBigDecimals" value="false"/>
</javaTypeResolver>
<!-- targetProject:生成PO类的位置 -->
<javaModelGenerator targetPackage="com.ssm.bean"
targetProject="F:\myTestProject\mySsmProject\src\main\java">
<!-- enableSubPackages:是否让schema作为包的后缀 -->
<property name="enableSubPackages" value="false"/>
<!-- 从数据库返回的值被清理前后的空格 -->
<property name="trimStrings" value="true"/>
</javaModelGenerator>
<!-- targetProject:mapper映射文件生成的位置 -->
<sqlMapGenerator targetPackage="com.ssm.mapper"
targetProject="F:\myTestProject\mySsmProject\src\main\resources">
<!-- enableSubPackages:是否让schema作为包的后缀 -->
<property name="enableSubPackages" value="false"/>
</sqlMapGenerator>
<!-- targetPackage:mapper接口生成的位置 -->
<javaClientGenerator type="XMLMAPPER" targetPackage="com.ssm.mapper"
targetProject="F:\myTestProject\mySsmProject\src\main\java">
<!-- enableSubPackages:是否让schema作为包的后缀 -->
<property name="enableSubPackages" value="false"/>
</javaClientGenerator>
<!-- 指定数据库表 -->
<table tableName="gameuser" domainObjectName="Gameuser"
enableCountByExample="false"
enableUpdateByExample="false"
enableDeleteByExample="false"
enableSelectByExample="false"
selectByExampleQueryId="false">
</table>
<!-- 有些表的字段需要指定java类型
<table tableName="area" domainObjectName="Area"
enableCountByExample="false"
enableUpdateByExample="false"
enableDeleteByExample="false"
enableSelectByExample="false"
selectByExampleQueryId="false">
</table>
-->
</context>
</generatorConfiguration>
springmvc.xml:springMvc的核心配置文件 :
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util
http://www.sprineframework.ore/schema/util/spring-util.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- 扫描comtroller包的路径 -->
<context:component-scan base-package="com.ssm"></context:component-scan>
<!--开启默认配置器 配置三大组件-->
<mvc:annotation-driven></mvc:annotation-driven>
<!--配置视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/jsp/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
<!--配置静态资源放行-->
<mvc:default-servlet-handler/>
</beans>
log4j2.xml: spring 使用此配置文件打印日志:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="INFO">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{YYYY-MM-dd HH:mm:ss} [%t] %-5p %c{1}:%L - %msg%n"/>
</Console>
</Appenders>
<Loggers>
<Root level="info">
<AppenderRef ref="Console"/>
</Root>
</Loggers>
</Configuration>
jdbc.properties:数据库连接信息配置
## key=value
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/test?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
username=root
password=12346
applicationContext.xml: spring的核心配置文件
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util
http://www.sprineframework.ore/schema/util/spring-util.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!--加载配置文件properties-->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!--包扫描 扫描service层-->
<context:component-scan base-package="com.ssm.service"/>
<!--配置数据源 德鲁伊数据库连接池 读取properties配置文件中的信息-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<!--读取properties配置文件中的信息-->
<property name="driverClassName" value="${driver}"></property>
<property name="url" value="${url}"></property>
<property name="username" value="${username}"></property>
<property name="password" value="${password}"></property>
</bean>
<!--将sqlsessionfactory对象交由spring创建和管理-->
<bean id="factory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!--配置数据源-->
<property name="dataSource" ref="dataSource"></property>
<!--配置实体类扫描包路径-->
<property name="typeAliasesPackage" value="com.lc.ssm.bean"></property>
</bean>
<!--将mapper交由spring创建和管理 生成mapper对象放入容器-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!--注入sqlsessionfactory-->
<property name="sqlSessionFactoryBeanName" value="factory"></property>
<!--扫描所有的mapper接口和映射文件-->
<property name="basePackage" value="com.lc.ssm.mapper"></property>
</bean>
<!--配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--开启事务注解-->
<tx:annotation-driven transaction-manager="transactionManager"/>
</beans>
Web.xml:配置基础信息:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!--配置dispacherServlet-->
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!--配置SpringMVC的编码过滤器 解决post请求乱码-->
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!--配置spring核心容器 配置spring 核心配置文件的位置 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<!--监听servletContext对象 在创建servletContext对象时创建spring容器放入其中-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
</web-app>
配置log4j.properties,生成mapper时需要使用此打印日志:
#定义全局日志级别调试阶段推荐debug
log4j.rootLogger=debug,stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.err
log4j.appender.stdout.layout=org.apache.log4j.SimpleLayout
log4j.appender.logfile=org.apache.log4j.FileAppender
log4j.appender.logfile.File=d:/msb.log
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
log4j.appender.logfile.layout.ConversionPattern=%d(yyyy-MM-dd HH:mm:ss)%1 %F %p %m%n
在test目录下新增测试类,运行时用于生成mybatis相关的代码,代码如下:
package com.ssm.test;
import org.mybatis.generator.api.MyBatisGenerator;
import org.mybatis.generator.config.Configuration;
import org.mybatis.generator.config.xml.ConfigurationParser;
import org.mybatis.generator.internal.DefaultShellCallback;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
/**
* @{NAME}
* @Description TODO
* @Author luocong
* @Date
* @Version 1.0
**/
public class GeneratorCode {
public void generator() throws Exception {
List<String> warnings = new ArrayList<String>();
boolean overwrite = true;
File configFile = new File("F:\\ideagit\\springall\\mybatisTest01\\target\\classes\\generatorConfig.xml");
ConfigurationParser cp = new ConfigurationParser(warnings);
Configuration config = cp.parseConfiguration(configFile);
DefaultShellCallback callback = new DefaultShellCallback(overwrite);
MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config,
callback,warnings);
myBatisGenerator.generate(null);
}
public static void main(String[] args) {
GeneratorCode generatorSqlmap = new GeneratorCode();
try {
generatorSqlmap.generator();
} catch (Exception e) {
e.printStackTrace();
}
}
}
执行mian类,生成mapperxml和mapper接口以及mapper实体类。
至此,ssm开发环境搭建完毕。
开发前端项目代码
App.vue:
<template>
<div id="app">
<!-- <img alt="Vue logo" src="./assets/logo.png"> -->
<!-- <HelloWorld msg="Welcome to Your Vue.js App"/> -->
<tableInfo/>
</div>
</template>
<script>
// import HelloWorld from './components/HelloWorld.vue'
import tableInfo from './components/tableInfo.vue'
export default {
name: 'App',
components: {
// HelloWorld
tableInfo
}
}
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
tableInfoVue:
<template>
<div>
<div>
<el-form ref="elForm" :model="formQueryData" :rules="rules" size="small" label-width="100px"
label-position="left">
<el-form-item label="用户姓名" prop="query_usrNm">
<el-input v-model="formQueryData.query_usrNm" placeholder="请输入用户姓名" :maxlength="20" show-word-limit
clearable prefix-icon='el-icon-s-custom' :style="{width: '100%'}"></el-input>
</el-form-item>
<el-form-item label="用户名称" prop="query_usrLoginNm">
<el-input v-model="formQueryData.query_usrLoginNm" placeholder="请输入用户名称" :maxlength="20"
show-word-limit clearable prefix-icon='el-icon-user' :style="{width: '100%'}"></el-input>
</el-form-item>
<el-form-item label="身份证号" prop="query_usrCardNum">
<el-input v-model="formQueryData.query_usrCardNum" placeholder="请输入身份证号" :maxlength="18"
show-word-limit clearable prefix-icon='el-icon-postcard' :style="{width: '100%'}"></el-input>
</el-form-item>
<el-form-item label="用户地址" prop="query_usrPro">
<el-select v-model="formQueryData.query_usrPro" placeholder="请选择用户地址" clearable
:style="{width: '100%'}">
</el-select>
</el-form-item>
<el-form-item label="生日" prop="query_usrBirDate">
<el-date-picker v-model="formQueryData.query_usrBirDate" format="yyyy-MM-dd" value-format="yyyy-MM-dd"
:style="{width: '100%'}" placeholder="请选择生日" clearable></el-date-picker>
</el-form-item>
<el-form-item label="爱好" prop="query_usrHobby">
<el-checkbox-group v-model="formQueryData.query_usrHobby" :min="1" size="medium">
<el-checkbox-button v-for="(item, index) in query_usrHobbyOptions" :key="index" :label="item.value"
:disabled="item.disabled" border>{{item.label}}</el-checkbox-button>
</el-checkbox-group>
</el-form-item>
<el-form-item label="用户简介" prop="query_usrDetail">
<el-input v-model="formQueryData.query_usrDetail" type="textarea" placeholder="请输入用户简介"
:maxlength="50" show-word-limit :autosize="{minRows: 4, maxRows: 4}" :style="{width: '100%'}">
</el-input>
</el-form-item>
<el-form-item size="large">
<el-button type="primary" @click="submitForm">提交</el-button>
<el-button @click="resetForm">重置</el-button>
</el-form-item>
</el-form>
</div>
<el-button style="margin-left: 20px;" @click="addUser()">新增</el-button>
<el-table
:data="tableData"
border
style="width: 100%">
<el-table-column
prop="usrFileUrl"
label="头像"
width="200">
<template v-slot:default="scope">
<el-image :src="scope.row.usrFileUrl"/>
<el-link :href="scope.row.usrFileUrl">查看详情</el-link>
</template>
</el-table-column>
<el-table-column
prop="usrNm"
label="用户姓名"
width="200">
</el-table-column>
<el-table-column
prop="usrCardNum"
label="身份证号"
width="200">
</el-table-column>
<el-table-column
prop="usrAddr"
label="通信地址"
width="200">
</el-table-column>
<el-table-column
prop="usrBirDate"
label="出生日期"
width="200">
</el-table-column>
<el-table-column
prop="usrHobby"
label="爱好"
width="200">
</el-table-column>
<el-table-column
prop="usrDetail"
label="个人简介"
width="300">
</el-table-column>
<el-table-column
fixed="right"
label="操作"
width="200">
<template slot-scope="scope">
<template>
<el-popconfirm title="这是一段内容确定删除吗?" @confirm="handleClick(scope.row)" >
<el-button slot="reference">删除</el-button>
</el-popconfirm>
</template>
<el-button style="margin-left: 20px;" @click="upuser(scope.row)">修改</el-button>
</template>
</el-table-column>
</el-table>
<div class="block">
<span class="demonstration"></span>
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="currentPage"
:page-sizes="pageSizes"
:page-size="PageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="totalCount">
</el-pagination>
</div>
<div>
<el-dialog title="用户信息新增" :visible.sync="addialogFormVisible" >
<el-form ref="elForm" :model="formAddData.usrFileUrl" :rules="rules" size="medium" label-width="100px">
<el-form-item label="点击上传" prop="usrImg" required>
<el-upload
class="avatar-uploader"
action="http://localhost:8080/api/uploadFile"
:show-file-list="false"
:on-success="handleAvatarSuccess"
:before-upload="beforeAvatarUpload">
<img v-if="imageUrl" :src="imageUrl" class="avatar">
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
</el-upload>
</el-form-item>
<el-form-item label="用户名称" prop="usrLoginNm">
<el-input v-model="formAddData.usrLoginNm" placeholder="请输入用户名称" :maxlength="20" show-word-limit
clearable prefix-icon='el-icon-user' :style="{width: '100%'}"></el-input>
</el-form-item>
<el-form-item label="用户密码" prop="usrLoginPwd">
<el-input v-model="formAddData.usrLoginPwd" placeholder="请输入用户密码" :maxlength="12" show-word-limit
clearable prefix-icon='el-icon-star-on' show-password :style="{width: '100%'}"></el-input>
</el-form-item>
<el-form-item label="确认密码" prop="usrLoginPwd1">
<el-input v-model="formAddData.usrLoginPwd1" placeholder="请再次确认密码" :maxlength="12" show-word-limit
clearable prefix-icon='el-icon-star-on' show-password :style="{width: '100%'}"></el-input>
</el-form-item>
<el-form-item label="用户姓名" prop="usrNm">
<el-input v-model="formAddData.usrNm" placeholder="请输入用户姓名" :maxlength="20" show-word-limit clearable
prefix-icon='el-icon-s-custom' :style="{width: '100%'}"></el-input>
</el-form-item>
<el-form-item label="身份证号" prop="usrCardNum">
<el-input v-model="formAddData.usrCardNum" placeholder="请输入身份证号" :maxlength="18" show-word-limit
clearable prefix-icon='el-icon-postcard' :style="{width: '100%'}"></el-input>
</el-form-item>
<el-form-item label="所属省份" prop="usrPro">
<el-select v-model="formAddData.usrPro" placeholder="请选择所属省份" clearable :style="{width: '100%'}" @change="changeAddCitySelect($event)">
<el-option
v-for="(item,index) in usrAddProList"
:key="index"
:label="item.areaname"
:value="item.areaid">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="所属市" prop="usrCity">
<el-select v-model="formAddData.usrCity" placeholder="请选择所属市" filterable clearable
:style="{width: '100%'}" @change="changeAddFaddrSelect($event)" >
<el-option
v-for="(item,index) in usrAddCityList"
:key="index"
:label="item.areaname"
:value="item.areaid">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="所属县/区" prop="usrFaddr">
<el-select v-model="formAddData.usrFaddr" placeholder="请选择所属县/区" filterable clearable
:style="{width: '100%'}">
<el-option
v-for="(item,index) in usrAddFaddrList"
:key="index"
:label="item.areaname"
:value="item.areaid">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="生日" prop="usrBirDate">
<el-date-picker v-model="formAddData.usrBirDate" format="yyyy-MM-dd" value-format="yyyy-MM-dd"
:style="{width: '100%'}" placeholder="请选择生日" clearable></el-date-picker>
</el-form-item>
<el-form-item label="爱好" prop="usrHobby">
<el-checkbox-group v-model="formAddData.usrHobby" :min="1" size="medium">
<el-checkbox-button v-for="(item, index) in usrHobbyOptions" :key="index" :label="item.value"
:disabled="item.disabled" border>{{item.label}}</el-checkbox-button>
</el-checkbox-group>
</el-form-item>
<el-form-item label="用户简介" prop="usrDetail">
<el-input v-model="formAddData.usrDetail" type="textarea" placeholder="请输入用户简介" :maxlength="50"
show-word-limit :autosize="{minRows: 4, maxRows: 4}" :style="{width: '100%'}"></el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="addialogFormVisible = false">取 消</el-button>
<el-button type="primary" @click="addSubmit">确 定</el-button>
</div>
</el-dialog>
</div>
<div>
<el-dialog title="用户信息修改" :visible.sync="updialogFormVisible" >
<el-form ref="elForm" :model="formData.usrFileUrl" :rules="rules" size="medium" label-width="100px">
<el-form-item label="点击上传" prop="usrImg" required>
<el-upload
class="avatar-uploader"
action="http://localhost:8080/api/uploadFile"
:show-file-list="false"
:on-success="handleAvatarSuccess"
:before-upload="beforeAvatarUpload">
<img v-if="imageUrl" :src="imageUrl" class="avatar">
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
</el-upload>
</el-form-item>
<el-form-item label="用户名称" prop="usrLoginNm">
<el-input v-model="formData.usrLoginNm" placeholder="请输入用户名称" :maxlength="20" show-word-limit
clearable prefix-icon='el-icon-user' :style="{width: '100%'}"></el-input>
</el-form-item>
<el-form-item label="用户密码" prop="usrLoginPwd">
<el-input v-model="formData.usrLoginPwd" placeholder="请输入用户密码" :maxlength="12" show-word-limit
clearable prefix-icon='el-icon-star-on' show-password :style="{width: '100%'}"></el-input>
</el-form-item>
<el-form-item label="确认密码" prop="usrLoginPwd1">
<el-input v-model="formData.usrLoginPwd1" placeholder="请再次确认密码" :maxlength="12" show-word-limit
clearable prefix-icon='el-icon-star-on' show-password :style="{width: '100%'}"></el-input>
</el-form-item>
<el-form-item label="用户姓名" prop="usrNm">
<el-input v-model="formData.usrNm" placeholder="请输入用户姓名" :maxlength="20" show-word-limit clearable
prefix-icon='el-icon-s-custom' :style="{width: '100%'}"></el-input>
</el-form-item>
<el-form-item label="身份证号" prop="usrCardNum">
<el-input v-model="formData.usrCardNum" placeholder="请输入身份证号" :maxlength="18" show-word-limit
clearable prefix-icon='el-icon-postcard' :style="{width: '100%'}"></el-input>
</el-form-item>
<el-form-item label="所属省份" prop="usrPro">
<el-select v-model="formData.usrPro" placeholder="请选择所属省份" clearable :style="{width: '100%'}" @change="changeCitySelect($event)">
<el-option
v-for="(item,index) in usrProList"
:key="index"
:label="item.areaname"
:value="item.areaid">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="所属市" prop="usrCity">
<el-select v-model="formData.usrCity" placeholder="请选择所属市" filterable clearable
:style="{width: '100%'}" @change="changeFaddrSelect($event)" >
<el-option
v-for="(item,index) in usrCityList"
:key="index"
:label="item.areaname"
:value="item.areaid">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="所属县/区" prop="usrFaddr">
<el-select v-model="formData.usrFaddr" placeholder="请选择所属县/区" filterable clearable
:style="{width: '100%'}">
<el-option
v-for="(item,index) in usrFaddrList"
:key="index"
:label="item.areaname"
:value="item.areaid">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="生日" prop="usrBirDate">
<el-date-picker v-model="formData.usrBirDate" format="yyyy-MM-dd" value-format="yyyy-MM-dd"
:style="{width: '100%'}" placeholder="请选择生日" clearable></el-date-picker>
</el-form-item>
<el-form-item label="爱好" prop="usrHobby">
<el-checkbox-group v-model="formData.usrHobby" :min="1" size="medium">
<el-checkbox-button v-for="(item, index) in usrHobbyOptions" :key="index" :label="item.value"
:disabled="item.disabled" border>{{item.label}}</el-checkbox-button>
</el-checkbox-group>
</el-form-item>
<el-form-item label="用户简介" prop="usrDetail">
<el-input v-model="formData.usrDetail" type="textarea" placeholder="请输入用户简介" :maxlength="50"
show-word-limit :autosize="{minRows: 4, maxRows: 4}" :style="{width: '100%'}"></el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="updialogFormVisible = false">取 消</el-button>
<el-button type="primary" @click="uponSubmit">确 定</el-button>
</div>
</el-dialog>
</div>
</div>
</template>
<script>
export default {
name:'tableInfo',
inheritAttrs: false,
components:{
},
data() {
return {
addialogFormVisible:false,
imageUrl: '',
usrAddProList:[],
usrAddCityList:[],
usrAddFaddrList:[],
usrProList:[],
usrCityList:[],
usrFaddrList:[],
tableData: [{
usrId:'',
usrLoginNm:'',
usrLoginPwd:'',
usrNm:'',
usrCardNum:'',
usrAddr:'',
usrBirDate:null,
usrHobby:[],
usrDetail:'',
usrFileUrl:''
}],
fits: [''],//图片展示的属性
// 默认显示第几页
currentPage:1,
// 总条数,根据接口获取数据长度(注意:这里不能为空)
totalCount:1,
// 个数选择器(可修改)
pageSizes:[10,20,30,40,50,100],
// 默认每页显示的条数(可修改)
PageSize:10,
updialogFormVisible:false,
formQueryData: {
query_usrNm: '',
query_usrLoginNm: "",
query_usrCardNum: '',
query_usrPro: '',
query_usrBirDate: null,
query_usrHobby: [],
query_usrDetail: ''
},
formData: {
usrImg: null,
usrLoginNm: "",
usrLoginPwd: undefined,
usrLoginPwd1: undefined,
usrNm: undefined,
usrCardNum: undefined,
usrPro: undefined,
usrCity: undefined,
usrFaddr: undefined,
usrBirDate: null,
usrHobby: [],
usrDetail: undefined,
},
formAddData: {
usrImg: null,
usrLoginNm: "",
usrLoginPwd: undefined,
usrLoginPwd1: undefined,
usrNm: undefined,
usrCardNum: undefined,
usrPro: undefined,
usrCity: undefined,
usrFaddr: undefined,
usrBirDate: null,
usrHobby: [],
usrDetail: undefined,
},
//表单校验
rules: {
query_usrNm: [],
query_usrLoginNm: [{
pattern: /^[a-zA-Z0-9_-]{4,16}$/,
message: '用户名必须由字母、数字、下划线或减号组成!',
trigger: 'blur'
}],
query_usrCardNum: [{
pattern: /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/,
message: '请输入正确格式的身份证号码!',
trigger: 'blur'
}],
query_usrPro: [],
query_usrBirDate: [],
query_usrHobby: [],
query_usrDetail: [],
},
query_usrHobbyOptions: [{
"label": "唱歌",
"value": 1
}, {
"label": "游泳",
"value": 2
}, {
"label": "看书",
"value": 3
}, {
"label": "打游戏",
"value": 4
}, {
"label": "party",
"value": 5
}],
usrLoginNm: [{
required: true,
message: '请输入用户名称',
trigger: 'blur'
}, {
pattern: /^[a-zA-Z0-9_-]{4,16}$/,
message: '用户名必须由字母、数字、下划线或减号组成!',
trigger: 'blur'
}],
usrLoginPwd: [{
required: true,
message: '请输入用户密码',
trigger: 'blur'
}, {
pattern: /^.*(?=.{6,})(?=.*\d)(?=.*[A-Z])(?=.*[a-z])(?=.*[!@#$%^&*? ]).*$/,
message: '密码长度必须满足6位且由大写字母、小写字母、数字、和特殊字符组成!',
trigger: 'blur'
}],
usrLoginPwd1: [{
required: true,
message: '请再次确认密码',
trigger: 'blur'
}, {
pattern: /^.*(?=.{6,})(?=.*\d)(?=.*[A-Z])(?=.*[a-z])(?=.*[!@#$%^&*? ]).*$/,
message: '密码长度必须满足6位且由大写字母、小写字母、数字、和特殊字符组成!',
trigger: 'blur'
}],
usrNm: [{
required: true,
message: '请输入用户姓名',
trigger: 'blur'
}],
usrCardNum: [{
required: true,
message: '请输入身份证号',
trigger: 'blur'
}, {
pattern: /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/,
message: '请输入正确格式的身份证号码!',
trigger: 'blur'
}],
usrPro: [{
required: true,
message: '请选择所属省份',
trigger: 'change'
}],
usrCity: [{
required: true,
message: '请选择所属市',
trigger: 'change'
}],
usrFaddr: [{
required: true,
message: '请选择所属县/区',
trigger: 'change'
}],
usrBirDate: [{
required: true,
message: '请选择生日',
trigger: 'change'
}],
usrHobby: [],
usrDetail: [{
required: true,
message: '请输入用户简介',
trigger: 'blur'
}],
usrImgAction: 'http://localhost:8080/api/uploadFile',
usrImgfileList: [],
usrHobbyOptions: [{
"label": "唱歌",
"value": 1
}, {
"label": "游泳",
"value": 2
}, {
"label": "看书",
"value": 3
}, {
"label": "打游戏",
"value": 4
}, {
"label": "party",
"value": 5
}]
}
},
methods:{
addSubmit(){
var fileurl=''
if(this.formAddData.usrFileUrl==undefined){
fileurl=''
}else{
fileurl=this.formAddData.usrFileUrl
}
//获取formAddData的数据 修改用户信息
this.$http.get('/addGameUserInfo', {params:{
usrLoginNm:this.formAddData.usrLoginNm,
usrLoginPwd:this.formAddData.usrLoginPwd,
usrNm:this.formAddData.usrNm,
usrCardNum:this.formAddData.usrCardNum,
usrAddr:this.formAddData.usrPro+"-"+this.formAddData.usrCity+"-"+this.formAddData.usrFaddr,
usrBirDate:this.formAddData.usrBirDate,
usrHobby:this.formAddData.usrHobby.join(","),
usrDetail:this.formAddData.usrDetail,
usrFileUrl:fileurl
}}).then((response) =>{
if(response.data.msg=='success'){
this.addialogFormVisible=false;
this.getTableList()
}
}).catch((error) =>{
alert("error"+error)
});
},
addUser(){
this.addialogFormVisible=true;
//调用接口获取省份信息
this.getAddProList(0,0)
},
changeFaddrSelect(event){
this.usrFaddrList=[]
this.formData.usrFaddr=''
console.log("选择县区",event)
//调用查询市信息的接口查询市信息 为县区列表赋值
this.$http.get('/getAreaInfo', {params:{
parentid:event
}}).then((response) =>{
this.usrFaddrList=response.data
}).catch((error) => {
console.log(error.getMessage);
});
},
changeCitySelect(event){
this.usrCityList=[]
this.formData.usrCity=''
this.formData.usrFaddr=''
console.log("选择市1",event)
//调用查询市信息的接口查询市信息 为市列表赋值
this.$http.get('/getAreaInfo', {params:{
parentid:event
}}).then((response) =>{
this.usrCityList=response.data
}).catch((error) => {
console.log(error.getMessage);
});
},
getProList(parentid,listInfo){//获取省份信息
this.$http.get('/getAreaInfo', {params:{
parentid:parentid
}}).then((response) =>{
console.log(response.data.areaList)
if(listInfo==0){//0-查询省信息
this.usrProList=response.data
}else if(listInfo==1){//1-查询市信息
this.usrCityList=response.data
}else{//2-查询县/区信息
this.usrFaddrList=response.data
}
}).catch((error) => {
console.log(error.getMessage);
});
},
changeAddFaddrSelect(event){
this.usrAddFaddrList=[]
this.formAddData.usrFaddr=''
console.log("选择县区",event)
//调用查询市信息的接口查询市信息 为县区列表赋值
this.$http.get('/getAreaInfo', {params:{
parentid:event
}}).then((response) =>{
this.usrAddFaddrList=response.data
}).catch((error) => {
console.log(error.getMessage);
});
},
changeAddCitySelect(event){
this.usrAddCityList=[]
this.formAddData.usrCity=''
this.formAddData.usrFaddr=''
console.log("选择市1",event)
//调用查询市信息的接口查询市信息 为市列表赋值
this.$http.get('/getAreaInfo', {params:{
parentid:event
}}).then((response) =>{
this.usrAddCityList=response.data
}).catch((error) => {
console.log(error.getMessage);
});
},
getAddProList(parentid,listInfo){//获取省份信息
this.$http.get('/getAreaInfo', {params:{
parentid:parentid
}}).then((response) =>{
console.log(response.data.areaList)
if(listInfo==0){//0-查询省信息
this.usrAddProList=response.data
}else if(listInfo==1){//1-查询市信息
this.usrAddCityList=response.data
}else{//2-查询县/区信息
this.usrAddFaddrList=response.data
}
}).catch((error) => {
console.log(error.getMessage);
});
},
handleClick(row) {//传入选中这一行的数据,可以进行操作
this.$http.get('/delGameUserInfoById', {params:{
usrId:row.usrId
}}).then((response) =>{
if(response.data.msg=='success'){
this.getTableList()
}
}).catch((error) => {
console.log(error.getMessage);
});
},
getTableList(){
console.log("this.formQueryData: "+this.formQueryData.query_usrHobby.join(","))
this.$http.get('/getAllGameUserList', {params:{
currentPage:this.currentPage,
pageSize:this.PageSize,
recordCount:this.totalCount,
usrLoginNm:this.formQueryData.query_usrLoginNm,
usrNm:this.formQueryData.query_usrNm,
usrCardNum:this.formQueryData.query_usrCardNum,
usrAddr:this.formQueryData.query_usrPro,
usrBirDate:this.formQueryData.query_usrBirDate,
usrHobby:this.formQueryData.query_usrHobby.join(","),
usrDetail:this.formQueryData.query_usrDetail
}}).then((response) =>{
this.totalCount=response.data.totalCount
this.currentPage=response.data.currentPage
this.PageSize=response.data.pageSize
this.tableData=response.data.recordList
}).catch((error) =>{
alert("error"+error)
});
},
// 分页
// 每页显示的条数
handleSizeChange(val) {
// 改变每页显示的条数
this.PageSize=val
// 注意:在改变每页显示的条数时,要将页码显示到第一页
this.currentPage=1
//改变条数时触发查询
this.getTableList()
},
// 显示第几页
handleCurrentChange(val) {
// 改变默认的页数
this.currentPage=val
//改变页数是触发查询
this.getTableList()
},
submitForm() {
this.$refs['elForm'].validate(valid => {
if (!valid) return
// TODO 提交表单触发查询
this.getTableList()
})
},
resetForm() {
this.$refs['elForm'].resetFields()
},
onOpen() {},
onClose() {
this.$refs['elForm'].resetFields()
},
close() {
this.$emit('update:visible', false)
},
handelConfirm() {
this.$refs['elForm'].validate(valid => {
if (!valid) return
this.close()
})
},
handleAvatarSuccess(res, file) {
this.imageUrl = URL.createObjectURL(file.raw);
this.formData.usrFileUrl=res.fileUrl
this.formAddData.usrFileUrl=res.fileUrl
console.log("imageUrl: "+this.imageUrl);
},
beforeAvatarUpload(file) {
const isJPG = file.type === 'image/jpeg';
const isLt2M = file.size / 1024 / 1024 < 2;
if (!isJPG) {
this.$message.error('上传头像图片只能是 JPG 格式!');
}
if (!isLt2M) {
this.$message.error('上传头像图片大小不能超过 2MB!');
}
return isJPG && isLt2M;
},
upuser(row){
this.updialogFormVisible = true
//使用map将字符串数组转化为数字数组 用于checkBox回显数据
var arr=row.usrHobbys.split(',')
arr=arr.map(Number)
console.log("arr "+arr)
//将用户信息回显在form表单上
const userinfo={
usrId:row.usrId,
usrLoginNm:row.usrLoginNm,
usrLoginPwd:row.usrLoginPwd,
usrLoginPwd1:row.usrLoginPwd,
usrNm:row.usrNm,
usrCardNum:row.usrCardNum,
usrPro:row.usrAddr.split("-")[0],
usrCity:row.usrAddr.split("-")[1],
usrFaddr:row.usrAddr.split("-")[2],
usrBirDate:row.usrBirDate,
usrHobby:arr,
usrDetail:row.usrDetail
}
this.formData=userinfo
//调用接口获取省份信息
this.getProList(0,0)
},
uponSubmit(){
var fileurl=''
if(this.formData.usrFileUrl==undefined||this.formData.usrFileUrl==''){
fileurl=''
}else{
fileurl=this.formData.usrFileUrl
}
//获取formData的数据 修改用户信息
this.$http.get('/updateGameUserInfo', {params:{
usrId:this.formData.usrId,
usrLoginNm:this.formData.usrLoginNm,
usrLoginPwd:this.formData.usrLoginPwd,
usrNm:this.formData.usrNm,
usrCardNum:this.formData.usrCardNum,
usrAddr:this.formData.usrPro+"-"+this.formData.usrCity+"-"+this.formData.usrFaddr,
usrBirDate:this.formData.usrBirDate,
usrHobby:this.formData.usrHobby.join(","),
usrDetail:this.formData.usrDetail,
usrFileUrl:fileurl
}}).then((response) =>{
if(response.data.msg=='success'){
this.updialogFormVisible=false;
this.getTableList()
}
}).catch((error) =>{
alert("error"+error)
});
},
handleChange (value) {
console.log(value)
}
},
mounted(){
this.getTableList()
}
}
</script>
<style>
.el-upload__tip {
line-height: 1.2;
}
.avatar-uploader .el-upload {
border: 1px dashed #d9d9d9;
border-radius: 6px;
cursor: pointer;
position: relative;
overflow: hidden;
}
.avatar-uploader .el-upload:hover {
border-color: #409EFF;
}
.avatar-uploader-icon {
font-size: 28px;
color: #8c939d;
width: 178px;
height: 178px;
line-height: 178px;
text-align: center;
}
.avatar {
width: 178px;
height: 178px;
display: block;
}
</style>
开发后端项目代码
后端项目目录结构如下:
源码下载地址:
链接:https://pan.baidu.com/s/163wHTpcdLdOfCUSg1PqMgg?pwd=4fb1
提取码:4fb1
--来自百度网盘超级会员V3的分享
更多推荐
所有评论(0)