一步一步搭建Spring/SpringMVC/SpringJPA整合的示例项目

本文详细介绍了如何逐步整合Spring、Spring JPA和Spring MVC,通过创建数据库、构建项目结构,配置相关依赖,实现用户登录及简历的CRUD功能。读者将学习到Spring全家桶的集成应用。
摘要由CSDN通过智能技术生成

文章内容输出来源:拉勾教育Java高薪训练营

目标

项目的主要目标是,将SSS三个主流框架进行整合,并实现简单的用户登录,展示简历的列表、添加、编辑、删除的功能

SSS = Spring + Spring JPA + Spring MVC

整体思路

分为以下三个步骤:
1、整合Spring+Spring JPA
2、整合Spring MVC
3、用户登录示例
4、简历的CRUD功能示例

实现过程

数据库准备

  1. 创建一个MYSQL数据库db_test,创建一张简历表tb_resume
DROP DATABASE IF EXISTS db_test;
CREATE DATABASE db_test DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;

CREATE TABLE `tb_resume`(
 `id` int(10) NOT NULL AUTO_INCREMENT COMMENT '用户ID',
 `name` varchar(200) NOT NULL COMMENT '名称',
 `address` varchar(200)  COMMENT '地址',
 `phone` varchar(200) COMMENT '手机',
  PRIMARY KEY(`id`)
)ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

创建项目

  1. 在IDEA上创建一个空项目,命名为sss_demo
  2. 创建相关包
  • 实体层:com.yyh.sss.entity
  • 数据访问层:com.yyh.sss.dao
  • 业务层:com.yyh.sss.service
  • 控制层:com.yyh.sss.controller
  • 工具类:com.yyh.sss.utils

Spring与Spring JPA的整合

  1. 修改pom.xml,引入依赖
  • 引入单元测试
  • 引入数据库相关:连接池、数据库驱动
  • 引入Spring相关:beans、context、tx、orm等
  • 引入hibernate相关
  • 引入jpa相关
<!--测试相关-->
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
    <scope>test</scope>
</dependency>

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
    <version>5.2.2.RELEASE</version>
    <scope>test</scope>
</dependency>


<!--数据库相关-->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.1.13</version>
</dependency>

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.47</version>
</dependency>


<!--Spring相关-->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-beans</artifactId>
    <version>5.2.2.RELEASE</version>
</dependency>

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.2.2.RELEASE</version>
</dependency>

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-tx</artifactId>
    <version>5.2.2.RELEASE</version>
</dependency>

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aop</artifactId>
    <version>5.2.2.RELEASE</version>
</dependency>

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.5</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>5.2.2.RELEASE</version>
</dependency>

<!--spring对orm的支持-->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-orm</artifactId>
    <version>5.2.2.RELEASE</version>
</dependency>

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-core</artifactId>
    <version>5.2.2.RELEASE</version>
</dependency>

<!--jpa相关-->
<dependency>
    <groupId>org.springframework.data</groupId>
    <artifactId>spring-data-jpa</artifactId>
    <version>2.2.3.RELEASE</version>
</dependency>

<dependency>
    <groupId>org.glassfish.web</groupId>
    <artifactId>javax.el</artifactId>
    <version>2.2.4</version>
    <exclusions>
        <exclusion>
            <groupId>javax.el</groupId>
            <artifactId>javax.el-api</artifactId>
        </exclusion>
    </exclusions>
</dependency>

<dependency>
    <groupId>javax.el</groupId>
    <artifactId>javax.el-api</artifactId>
    <version>2.2.4</version>
</dependency>


<!--hibernate相关-->
<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-core</artifactId>
    <version>5.4.0.Final</version>
</dependency>

<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-entitymanager</artifactId>
    <version>5.4.0.Final</version>
</dependency>

<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>5.4.0.Final</version>
</dependency>
  1. 创建jdbc.properties配置文件
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/db_test
jdbc.username=root
jdbc.password=root
  1. 创建spring-dao.xml配置文件
  • 配置数据源
  • 配置entityManager
  • 配置jpa的dao实现细节jpa:repositories
  • 配置事务transactionManager
<beans>
    <context:property-placeholder location="classpath:jdbc.properties"/>
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${jdbc.driver}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>

    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <!--配置数据源-->
        <property name="dataSource" ref="dataSource"/>
        <!--配置包扫描-->
        <property name="packagesToScan" value="com.yyh.sss.entity"/>
        <!--指定jpa的具体实现hibernate-->
        <property name="persistenceProvider">
            <bean class="org.hibernate.jpa.HibernatePersistenceProvider"></bean>
        </property>
        <!--jpa方言配置-->
        <property name="jpaDialect">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect"></bean>
        </property>
        <!--配置具体provider,hibearnte框架的执行细节-->
        <property name="jpaVendorAdapter" >
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
                <!--配置数据表是否自动创建-->
                <property name="generateDdl" value="false"/>
                <!--指定数据库的类型 -->
                <property name="database" value="MYSQL"/>
                <!--配置数据库的方言-->
                <property name="databasePlatform" value="org.hibernate.dialect.MySQLDialect"/>
                <!--是否显示sql-->
                <property name="showSql" value="true"/>
            </bean>
        </property>
    </bean>

    <!--配置jpa的dao层-->
    <jpa:repositories base-package="com.yyh.sss.dao" entity-manager-factory-ref="entityManagerFactory"
                      transaction-manager-ref="transactionManager"/>
    <!--事务管理器配置-->
    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory"/>
    </bean>
</beans>
  1. 创建spring-service.xml
  • 配置业务接口的扫描
  • 开启事务注解
<beans>
    <context:component-scan base-package="com.yyh.sss.service"/>
    <!--开启事务注解-->
    <tx:annotation-driven/>
</beans>
  1. 创建entity类
@Id
@Entity
@Table(name = "tb_resume")
public class ResumeEntity {
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private Long id;
    @Column(name = "name")
    private String name;
    @Column(name = "address")
    private String address;
    @Column(name = "phone")
    private String phone;
    //ignore setter/getter
}    
  1. 编写dao接口
public interface ResumeDao extends JpaRepository<ResumeEntity, Long>, JpaSpecificationExecutor<ResumeEntity> {
}
  1. 创建service接口,添加增、删、改、查方法
public interface ResumeService {
    void add(ResumeEntity resume);
    void update(ResumeEntity resume);
    List<ResumeEntity> list();
    void remove(Long id);
}
  1. 创建service接口的实现类
@Service
public class ResumeServiceImpl implements ResumeService {
    @Autowired
    private ResumeDao resumeDao;

    public void add(ResumeEntity resume) {
        resumeDao.save(resume);
    }

    public void update(ResumeEntity resume) {
        resumeDao.save(resume);
    }

    public List<ResumeEntity> list() {
        return resumeDao.findAll();
    }

    public void remove(Long id) {
        Optional<ResumeEntity> resume = resumeDao.findById(id);
        if(!resume.isPresent()) {
            return;
        }
        resumeDao.deleteById(id);
    }
}
  1. 创建单元测试进行测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"classpath:spring-dao.xml",
        "classpath:spring-service.xml"})
public class ResumeServiceTest {
    @Autowired
    private ResumeService resumeService;
    @Test
    public void testAdd() {
        ResumeEntity entity = new ResumeEntity();
        entity.setName("李小清");
        entity.setAddress("福建省厦门市集美区软件园");
        entity.setPhone("18095847334");
        resumeService.add(entity);
    }

    @Test
    public void testUpdate() {
        ResumeEntity entity = new ResumeEntity();
        entity.setId(1L);
        entity.setName("李小青");
        entity.setAddress("福建省厦门市集美区软件园三期");
        entity.setPhone("18095847354");
        resumeService.add(entity);
    }

    @Test
    public void testList() {
        List<ResumeEntity> list = resumeService.list();
        if(null != list) {
            for (ResumeEntity row : list) {
                System.out.println(row.toString());
            }   
        }
    }

    @Test
    public void testRemove() {
        resumeService.remove(1L);
    }
}
  1. 以上就整合完成了Spring+Spring JPA。跑下单元测试,验证下效果

整合Spring MVC

  1. 在pom.xml中添加相关依赖
  • Spring MVC
  • jsp和servlet相关
  • jstl表达式
 <!--SpringMVC-->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.2.2.RELEASE</version>
</dependency>

<!--jsp-api&servlet-api-->
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>jsp-api</artifactId>
    <version>2.0</version>
    <scope>provided</scope>
</dependency>
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>3.1.0</version>
    <scope>provided</scope>
</dependency>
<!--页面使用jstl表达式-->
<dependency>
    <groupId>jstl</groupId>
    <artifactId>jstl</artifactId>
    <version>1.2</version>
</dependency>
<dependency>
    <groupId>taglibs</groupId>
    <artifactId>standard</artifactId>
    <version>1.1.2</version>
</dependency>
  1. 添加mvc的配置文件spring-web.xml
  • 配置controller的扫描包
  • 开启mvc相关Bean注册的配置
  • 配置视图解析器
<beans>
    <context:component-scan base-package="com.yyh.sss.controller"/>
    <mvc:annotation-driven/>

    <!--配置springmvc的视图解析器-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <property name="suffix" value=".jsp"/>
    </bean>
</beans>
  1. src/main目录下创建webapp目录,接着在webapp目录下创建WEB-INF目录,在WEB-INF中创建jsp目录
  2. WEB-INF目录下创建web.xml文件,用于配置spring的监听器和mvc的DisptcherServlet
<!DOCTYPE web-app PUBLIC
        "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
        "http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
    <display-name>Archetype Created Web Application</display-name>

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath*:spring-*.xml</param-value>
    </context-param>
    <!--spring框架启动-->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <!--springmvc启动-->
    <servlet>
        <servlet-name>springmvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath*:spring-web.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>
  1. jsp目录下创建login.jsp页面,页面中添加上用户登录的form表单
<%@ page language="java" pageEncoding="UTF-8" %>
<%
    String path = request.getContextPath();
    String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE html>
<html>
    <body>
        <h2>用户登录</h2>
        <form>
            <div>
                <b>用户名:</b><input type="text" placeholder="请输入用户名"/>
            </div>
            <div>
                <b>密码:</b><input type="password" placeholder="请输入用户密码"/>
            </div>
            <div>
                <input type="button" value="登录"/>
            </div>
        </form>
    </body>
</html>
  1. webapp目录下创建index.jsp默认页面,在此页面中设置跳转到登录页面
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <!--马上重定向到home-->
    <meta http-equiv="Refresh" content="0;url=login" />
</head>
<body>
</body>
</html>
  1. 创建LoginController,添加上登录页面的handler方法
@Controller
public class LoginController {
    @GetMapping("/login")
    public String loginPage() {
        return "login";
    }
}
  1. 在pom.xml中添加tomcat的插件(或者直接在IDEA配置外部的tomcat进行访问)
<plugin>
    <groupId>org.apache.tomcat.maven</groupId>
    <artifactId>tomcat7-maven-plugin</artifactId>
    <version>2.2</version>
    <configuration>
        <port>8080</port>
        <path>/</path>
    </configuration>
</plugin>
  1. 在IDEA的Maven Projects中对应项目的Plugins中启动tomcat【tomcat7/tomcat7:run】
  2. 启动完毕后,在浏览器访问http://localhost:8080,如果跳转到了登录页面,则表示整合成功

实现用户登录功能

  1. 用户名和密码直接硬编码,当输入用户名为admin,密码为admin时,则登录成功,否则失败
  2. 统一各个请求方法的返回数据,添加Res
public class Res {
    //是否成功
    private Boolean success;
    //返回的数据
    private Object data;

    //成功请求
    public static Res ok(Object data) {
        Res res = new Res();
        res.success = true;
        res.data = data;
        return res;
    }

    //失败请求
    public static Res fail(Object data) {
        Res res = new Res();
        res.success = false;
        res.data = data;
        return res;
    }
    //ignore getter/setter
}
  1. LoginController中添加login方法。同时添加了一个LoginVO表示登录的传入参数实体
  • 当登录成功,则在session中记录下登录用户的名称
@PostMapping("/login")
@ResponseBody
public Res login(HttpServletRequest request, @RequestBody LoginVO loginVO) {
    if(null == loginVO.getName() || loginVO.getName().trim().length() == 0) {
        return Res.fail("用户名不能为空");
    }

    if(null == loginVO.getPassword() || loginVO.getPassword().trim().length() == 0) {
        return Res.fail("密码不能为空");
    }

    if(!loginVO.getName().equals("admin") || !loginVO.getPassword().equals("admin")) {
        return Res.fail("用户名或密码错误");
    }

    request.getSession().setAttribute("loginUser", "admin");
    return Res.ok("登录成功");
}

public class LoginVO {
    //用户名
    private String name;
    //密码
    private String password;
    //ignore getter/setter
}
  1. 添加登录拦截器LoginInterceptor
  • 在请求处理前进行判断session中是否有相关记录,如果没有则跳转到登录页面
public class LoginInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        Object loginUser = request.getSession().getAttribute("loginUser");

        if(null != loginUser) {
            return true;
        }

        response.sendRedirect("/login");
        return false;
    }
}
  • spring-web.xml中配置上拦截器,排除掉login的路由
<!--配置拦截器-->
<mvc:interceptors>
    <mvc:interceptor>
        <mvc:mapping path="/**"/>
        <mvc:exclude-mapping path="/login"/>
        <bean class="com.yyh.sss.utils.LoginInterceptor"/>
    </mvc:interceptor>
</mvc:interceptors>
  1. 修改LoginControllerloginPage方法
  • 增加上以下判断,如果用户已经登录了则直接跳转到简历列表
Object loginUser = request.getSession().getAttribute("loginUser");

if(null != loginUser) {
    return "redirect:resumes/list";
}
  1. 修改login.jsp,实现登录的交互
<html>
    <body>
        <h2>用户登录</h2>
        <div>
            <div>
                <b>用户名:</b><input id="name" type="text" placeholder="请输入用户名"/>
            </div>
            <div>
                <b>密码:</b><input id="password" type="password" placeholder="请输入用户密码"/>
            </div>

            <div>
                <input id="btnLogin" type="button" value="登录"/>
            </div>
        </div>
    </body>

<script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
<script type="text/javascript">
    $('#btnLogin').on('click', function() {
       var name =  $('#name').val().trim();
       var password =  $('#password').val().trim();

       if(name.length == 0) {
           alert('请输入用户名');
           return;
       }

       if(password.length == 0) {
           alert('请输入密码');
           return;
       }

       var params = {
           'name': name,
           'password': password
       };

        $.ajax({
            type: 'post',
            url: 'login',
            data: JSON.stringify(params),
            contentType: 'application/json;charset=utf-8',
            dataType: 'json',
            success: function(result) {
                if(result.success) {
                    window.location.href = 'resumes/list';

                }else {
                    alert(result.data);
                }
            }
        });

    });
</script>
</html>

简历的CRUD功能实现

  1. 添加ResumeController的简历Controller类
  2. 添加resume_list.jsp页面
  3. ResumeController中添加listPage跳转页面、save保存、remove删除方法
@Controller
@RequestMapping("resumes")
public class ResumeController {
    @Autowired
    private ResumeService resumeService;

    @GetMapping("/list")
    public String list(Model model) {
        List<ResumeEntity> list = resumeService.list();
        model.addAttribute("resumes", list);

        return "resume_list";
    }

    @PostMapping("/save")
    @ResponseBody
    public Res save(@RequestBody ResumeEntity resume) {
        if(null != resume.getId()) {
            resumeService.update(resume);

        }else {
            resumeService.add(resume);
        }


        return Res.ok("保存成功");
    }

    @DeleteMapping("/{id}/remove")
    @ResponseBody
    public Res remove(@PathVariable Long id) {
        resumeService.remove(id);
        return Res.ok("删除成功");
    }
}
  1. resume_list.jsp页面中对简历数据进行迭代,使用table进行展示数据,对每行数据添加一栏编辑、删除操作,并在列表上方添加上新增简历按钮
<%@ page language="java" pageEncoding="UTF-8" %>
<%@page isELIgnored="false" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<%
    String path = request.getContextPath();
    String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE html>

<html>
    <style type="text/css">
        table{border-collapse: collapse;text-align: center;}
        table td, table th{border: 1px solid #cad9ea;color: #666;height: 30px;}
        table thead th{background-color: #CCE8EB;width: 100px;}
        table tr:nth-child(odd){background: #fff;}
        table tr:nth-child(even) {background: #F5FAFA;}
    </style>
    <body>
        <h2>简历列表</h2>
        <div><input id="btnAdd" type="button" value="新增简历"/></div>
        <hr/>
        <div id="resumeForm" style="display: none;">
            <input id="id" type="hidden" value=""/>
            <p><b>用户名称:</b><input id="name" type="text" placeholder="请输入名称" width="300px"/></p>
            <p><b>用户地址:</b><input id="address" type="text" placeholder="请输入地址" width="300px"/></p>
            <p><b>用户手机:</b><input id="phone" type="text" placeholder="请输入手机" width="300px"/></p>
            <p><input id="btnSave" type="button" value="保存"/>&nbsp; <input id="btnCancel" type="button" value="取消"/></p>
            <hr/>
        </div>


        <div>
            <table>
                <thead>
                <tr>
                    <td>用户ID</td>
                    <td>用户名称</td>
                    <td>用户地址</td>
                    <td>用户手机</td>
                    <td>操作</td>
                </tr>
                </thead>
                <tbody>
                <c:forEach var="row" items="${resumes}">
                    <tr>
                       <td>${row.id}</td>
                       <td>${row.name}</td>
                       <td>${row.address}</td>
                       <td>${row.phone}</td>
                        <td>
                            <a class="btnEdit" href="javascript:void(0);">编辑</a>&nbsp;&nbsp;
                            <a class="btnDelete" href="javascript:void(0);" data-id="${row.id}">删除</a>
                        </td>
                    </tr>

                </c:forEach>
                </tbody>
            </table>
        </div>
    </body>
</html>
  1. resume_list.jsp页面中添加上js的交互操作,实现简历表单的展示/隐藏、保存以及删除操作的ajax请求
<script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
<script type="text/javascript">
    $('#btnAdd').on('click', function () {
        $('#resumeForm').css('display', "block");

    });

    $('#btnCancel').on('click', function () {
        $('#resumeForm').css('display', "none");
    });

    $('#btnSave').on('click', function() {
        var name =  $('#name').val().trim();
        var phone =  $('#phone').val().trim();
        var address =  $('#address').val().trim();
        var id =  $('#id').val().trim();

        if(name.length == 0) {
            alert('请输入名称');
            return;
        }

        if(address.length == 0) {
            alert('请输入地址');
            return;
        }

        if(phone.length == 0) {
            alert('请输入手机');
            return;
        }

        var params = {
            'name': name,
            'address': address,
            'phone': phone,
            'id': id
        };

        $.ajax({
            type: 'post',
            url: '/resumes/save',
            data: JSON.stringify(params),
            contentType: 'application/json;charset=utf-8',
            dataType: 'json',
            success: function(result) {
                if(result.success) {
                    window.location.reload();

                }else {
                    alert(result.data);
                }
            }

        });

    });

    $('.btnEdit').on('click', function() {
       var $tds =  $(this).parents("tr").find('td');

       console.log($tds);
       $('#id').val($tds.eq(0).text());
       $('#name').val($tds.eq(1).text());
       $('#address').val($tds.eq(2).text());
       $('#phone').val($tds.eq(3).text());
       $('#resumeForm').css('display', "block");
    });

    $('.btnDelete').on('click', function() {
        var id =  $(this).data('id');
        if(id > 0) {
            if(confirm('是否确认删除?')) {
                $.ajax({
                    type: 'delete',
                    url: '/resumes/'+id+'/remove',
                    data: {},
                    success: function(result) {
                        if(result.success) {
                            window.location.reload();

                        }else {
                            alert(result.data);
                        }
                    }

                })
            }
        }
    });

</script>

6.演示的效果

  • 登录页面
    用户登录

  • 简历列表
    简历列表

项目代码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值