Spring3MVC和JDBC的集成

在以前的教程中我们并没有进行数据库连接操作.
一个没有进行数据库操作的web项目几乎是不存在的.
所以数据库连接也是一个很重要的知识点.

而在本教程中,我们会用SpringMVC+JDBC实现一个简单的数据库访问.
并对Person对象进行简单的CRUD操作.

我们将使用MySql数据库.
相应的也可以用于DB2,oracle,SqlServer,HyperSQL等数据库.
[b]
JDBC是什么?[/b]
[quote]
JDBC(Java Data Base Connectivity,java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口组成。JDBC提供了一种基准,据此可以构建更高级的工具和接口,使数据库开发人员能够编写数据库应用程序,同时,JDBC也是个商标名。
[/quote]

[b]MySql是什么?[/b]

[quote]
MySQL由于性能高、成本低、可靠性好,已经成为最流行的开源数据库,被广泛地应用在Internet上的中小型网站中。随着MySQL的不断成熟,它也逐渐用于更多大规模网站和应用,比如维基百科、Google和Facebook等网站。非常流行的开源软件组合LAMP中的“M”指的就是MySQL。[/quote]

下面是我们的应用程序文件夹结构:

[img]http://dl.iteye.com/upload/attachment/446883/a6c19eb0-b912-3b7d-8646-1937fc3b3e96.png[/img]

然后是pom.xml里添加的jar包:

[img]http://dl.iteye.com/upload/attachment/446885/f5bf661c-5dd6-37bd-9a12-828cb2a4afc0.png[/img]

创建一张MySql表.
注意数据库是 spring3db.



DROP TABLE IF EXISTS `person`;

CREATE TABLE `person` (
`ID` int(11) unsigned NOT NULL AUTO_INCREMENT,
`FIRST_NAME` varchar(255) DEFAULT NULL,
`LAST_NAME` varchar(255) DEFAULT NULL,
`MONEY` double DEFAULT NULL,
PRIMARY KEY (`ID`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;


首先添加Spring MVC所必须的配置.

[b]web.xml[/b]

<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

<servlet>
<servlet-name>spring</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
<servlet-name>spring</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>

<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

</web-app>


在web.xml中我们定义servlet:spring.
按照惯例,我们必须声明一个spring-servle.xml
[b]spring-servle.xml [/b]


<?xml version="1.0" encoding="UTF-8"?>
<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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

<!-- 定义一个视图解析器 -->
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver"
p:prefix="/WEB-INF/jsp/" p:suffix=".jsp" />

</beans>


这个XML配置声明一个视图解析器.在控制器中会根据JSP名映射到/ WEB-INF/jsp中相应的位置.


要进行数据库操作,一定需要一个数据库连接的配置.

[b]jdbc.properties[/b]

# database properties
#spring3db is databaseName.
app.jdbc.driverClassName=com.mysql.jdbc.Driver
app.jdbc.url=jdbc:mysql://localhost/spring3db
app.jdbc.username=root
app.jdbc.password=root


[b]注:以后所有的教程所用到的数据库统一为spring3db[/b]

[b]jdbc-context.xml[/b]


<?xml version="1.0" encoding="UTF-8"?>
<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:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
">
<!-- 定义jdbc配置信息路径 -->
<context:property-placeholder location="/WEB-INF/jdbc.properties" />

<!-- 使用annotation定义事务 -->
<tx:annotation-driven transaction-manager="transactionManager" />

<!-- 数据源配置,使用c3p0数据库连接池 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close"
p:driverClass="${app.jdbc.driverClassName}"
p:jdbcUrl="${app.jdbc.url}"
p:user="${app.jdbc.username}"
p:password="${app.jdbc.password}"
p:acquireIncrement="5"
p:idleConnectionTestPeriod="60"
p:maxPoolSize="100"
p:maxStatements="50"
p:minPoolSize="10" />

<!-- 定义事务管理 -->
<!-- See http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/transaction.html -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
p:dataSource-ref="dataSource" />

</beans>


该文件主要配置了:
1.启用了事务管理
2.声明了一个数据源

我们将使用连接池(Connection pool)对数据库进行管理.
JDBC连接通常是通过一个连接池(Connection pool)管理,而不是直接driver.
连接池包括BoneCP,C3P0的和DBCP.

[b]连接池(Connection pool)是什么东西?[/b]
[quote]
由于创建一个数据库连接比较耗费资源,因此对于一个项目来讲,从使用人数来看,先初始化一部分连接,放在连接池中,有用户过来直接拿来使用.如果全部用完了的话,就新创建连接.当用户从连接池中取出的连接用完以后,自动返回连接池等下个用户来用.
[/quote]

下面是所有开源的Connection Pools
[url=http://java-source.net/open-source/connection-pools]Open Source Database Connection Pools[/url]

网上对于BoneCP,C3P0的和DBCP这3种连接池效率有很多的评测.结果各不相同.
但是Spring和Hibernate官方推荐使用c3p0,(据了解JavaEye也是用的c3p0)肯定有其性能上的优点.
所以我们也使用c3p0

关于c3p0的详细信息可以参考:[url=http://community.jboss.org/wiki/HowToconfiguretheC3P0connectionpool]HowTo configure the C3P0 connection pool[/url]


然后创建一个applicationContext.xml.

[b]applicationContext.xml. [/b]


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">

<!-- 激活spring的注解. -->
<context:annotation-config />

<!-- 扫描注解组件并且自动的注入spring beans中.
例如,他会扫描@Controller 和@Service下的文件.所以确保此base-package设置正确. -->
<context:component-scan base-package="org.liukai.tutorial" />

<!-- 配置注解驱动的Spring MVC Controller 的编程模型.注:次标签只在 Servlet MVC工作! -->
<mvc:annotation-driven />

<!-- 导入jdbc的配置文件 -->
<import resource="jdbc-context.xml" />

</beans>




定义一个Person对象.

[b]Person.java[/b]


package org.liukai.tutorial.domain;

import java.io.Serializable;

public class Person implements Serializable {

private static final long serialVersionUID = -6463052236469808931L;

private Integer id;
private String firstName;
private String lastName;
private Double money;

// setter/getter..

}




由于我们要实现对Person 的CRUD操作.
需要定义一个service来实现对Person进行操作的方法.

[b]PersonService.java[/b]


package org.liukai.tutorial.service;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;
import javax.sql.DataSource;

import org.apache.log4j.Logger;
import org.liukai.tutorial.domain.Person;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.simple.SimpleJdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;


/**
* Service for processing Persons.
* <p>
* 关于Spring JDBC 和 JdbcTemplate
* see http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/jdbc.html
* <p>
* 关于transactions, see http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/transaction.html
*/

@Service("personService")
@Transactional
public class PersonService {

protected static Logger logger = Logger.getLogger("service");

private SimpleJdbcTemplate jdbcTemplate;

@Resource(name="dataSource")
public void setDataSource(DataSource dataSource) {
this.jdbcTemplate = new SimpleJdbcTemplate(dataSource);
}

/**
*检索所有的Person
*/
public List<Person> getAll() {
logger.debug("Retrieving all persons");

String sql = "select id, first_name, last_name, money from person";

// Maps a SQL result to a Java object
RowMapper<Person> mapper = new RowMapper<Person>() {
public Person mapRow(ResultSet rs, int rowNum) throws SQLException {
Person person = new Person();
person.setId(rs.getInt("id"));
person.setFirstName(rs.getString("first_name"));
person.setLastName(rs.getString("last_name"));
person.setMoney(rs.getDouble("money"));
return person;
}
};

return jdbcTemplate.query(sql, mapper);
}

/**
* 新增person
*/
public void add(String firstName, String lastName, Double money) {
logger.debug("Adding new person");

String sql = "insert into person(first_name, last_name, money) values " +
"(:firstName, :lastName, :money)";

Map<String, Object> parameters = new HashMap<String, Object>();
parameters.put("firstName", firstName);
parameters.put("lastName", lastName);
parameters.put("money", money);

// Save
jdbcTemplate.update(sql, parameters);

}

/**
* 删除指定Person
*/
public void delete(Integer id) {
logger.debug("Deleting existing person");

String sql = "delete from person where id = ?";

Object[] parameters = new Object[] {id};

jdbcTemplate.update(sql, parameters);
}

/**
* Edit指定的Person
*/
public void edit(Integer id, String firstName, String lastName, Double money) {
logger.debug("Editing existing person");

String sql = "update person set first_name = :firstName, " +
"last_name = :lastName, money = :money where id = :id";

// Assign values to parameters
Map<String, Object> parameters = new HashMap<String, Object>();
parameters.put("id", id);
parameters.put("firstName", firstName);
parameters.put("lastName", lastName);
parameters.put("money", money);

// Edit
jdbcTemplate.update(sql, parameters);

}

}




我们在PersonService实现了一个简单的CRUD.主要对应了下面几种方法.
getAll
add
delete
edit

注意:我们是通过一个[b]SimpleJdbcTemplate[/b]实例来进行数据库的操作的.

[b]
什么是JdbcTemplate?[/b]

[quote]
JdbcTemplate类是在JDBC核心包的核心类。 它处理的创建和释放资源,它可以帮助您避免如忘记关闭连接常见的错误。 它执行核心的JDBC工作流,如语句创建和执行基本任务,让应用程序代码提供SQL和提取结果。 JdbcTemplate类执行SQL查询,更新语句和存储过程调用,执行过的ResultSets和返回的参数值的提取迭代。 它还捕捉JDBC异常并将它们转换为通用的,更丰富,层次结构异常org.springframework.dao包定义。
[/quote]
来源:[url=http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/jdbc.html]Spring3官方文档[/url]


[b]什么是SimpleJdbcTemplate?[/b]

[quote]SimpleJdbcTemplate类包装的可变参数和自动装箱,如经典的JdbcTemplate,并利用Java 5的语言特性。[/quote]

来源:[url=http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/jdbc.html]Spring3官方文档[/url]

换句通俗点的话就是SimpleJdbcTemplate是JdbcTemplate的加强版.


值得注意的是:
我们的教程中使用的是Spring官方文档中的最佳实践.而实际工作中为了编码的效率和代码的整洁.
我们可以使用SimpleJdbcTemplate自带的其他方法.

比如PersonService中的getAll方法采用的是Spring推荐的最佳实践.

public List<Person> getAll() {
logger.debug("Retrieving all persons");

String sql = "select id, first_name, last_name, money from person";

// Maps a SQL result to a Java object
RowMapper<Person> mapper = new RowMapper<Person>() {
public Person mapRow(ResultSet rs, int rowNum) throws SQLException {
Person person = new Person();
person.setId(rs.getInt("id"));
person.setFirstName(rs.getString("first_name"));
person.setLastName(rs.getString("last_name"));
person.setMoney(rs.getDouble("money"));
return person;
}
};

return jdbcTemplate.query(sql, mapper);
}


我们也可以用BeanPropertyRowMapper来达到检索所有的Person的功能,并且代码更少.


public List<Person> getAll() {
logger.debug("Retrieving all persons");

String sql = "select id, first_name, last_name, money from person";

return jdbcTemplate.query(sql, new BeanPropertyRowMapper<Person>(Person.class));
}


但是要注意BeanPropertyRowMapper的使用条件.返回的对象必须和数据库里的字段相同(可以忽略带"_"和大写的字段).

然后是Controller

[b]MainController.java[/b]


package org.liukai.tutorial.controller;

import java.util.List;

import javax.annotation.Resource;

import org.apache.log4j.Logger;
import org.liukai.tutorial.domain.Person;
import org.liukai.tutorial.service.PersonService;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
@RequestMapping("/main")
public class MainController {

protected static Logger logger = Logger.getLogger("controller");

@Resource(name="personService")
private PersonService personService;

/**
*获得所有的Person并返回到指定JSP页面
*
* @return the name of the JSP page
*/
@RequestMapping(value = "/persons", method = RequestMethod.GET)
public String getPersons(Model model) {

logger.debug("Received request to show all persons");

// 调用personService中的getAll获得所有的Person
List<Person> persons = personService.getAll();

// 把Person装入一个指定的model
model.addAttribute("persons", persons);

// 解析 /WEB-INF/jsp/personspage.jsp
return "personspage";
}

/**
*根据页面传递过来的值新增一Person并跳转到指定页面.
*/
@RequestMapping(value = "/persons/add", method = RequestMethod.GET)
public String add(
@RequestParam(value="firstname", required=true) String firstName,
@RequestParam(value="lastname", required=true) String lastName,
@RequestParam(value="money", required=true) Double money) {

logger.debug("Received request to add new person");

personService.add(firstName, lastName, money);

return "addedpage";
}

/**
* 根据接收的ID删除Person
*/
@RequestMapping(value = "/persons/delete", method = RequestMethod.GET)
public String delete(@RequestParam(value="id", required=true) Integer id,
Model model) {

logger.debug("Received request to delete existing person");

personService.delete(id);

model.addAttribute("id", id);

return "deletedpage";
}

/**
* edit指定的Person
*/
@RequestMapping(value = "/persons/edit", method = RequestMethod.GET)
public String edit(
@RequestParam(value="id", required=true) Integer id,
@RequestParam(value="firstname", required=true) String firstName,
@RequestParam(value="lastname", required=true) String lastName,
@RequestParam(value="money", required=true) Double money,
Model model){

logger.debug("Received request to edit existing person");

personService.edit(id, firstName, lastName, money);

model.addAttribute("id", id);

return "editedpage";
}

}



该Controller包含了4个映射.


[quote]/persons
/persons/add?firstname=''&lastname=''&money=''
/persons/delete?id=''
/persons/edit?id=''&firstname=''&lastname=''&money=''[/quote]

每个映射调用一个PersonService.当调用成功后则会跳转到指定的JSP页面

[b]addedpage.jsp[/b]

[img]http://dl.iteye.com/upload/attachment/446948/59b05b6c-2d78-3559-b418-060894994d88.png[/img]



<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page import="java.util.Date" %>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>

<h1>Persons</h1>

<p>你于
<%= new java.util.Date() %>
新增一个Person
</p>
</body>
</html>


[b]editedpage.jsp[/b]


[img]http://dl.iteye.com/upload/attachment/446950/78fdc38d-009e-3fe8-853c-49439c3fda17.png[/img]

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page import="java.util.Date" %>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>

<h1>Persons</h1>

<p>你于
<%= new java.util.Date() %>
根据${id }修改了一个Person
</p>
</body>
</html>



[b]deletedpage.jsp[/b]

[img]http://dl.iteye.com/upload/attachment/446955/7421c1fa-4223-3503-9189-b5f30e053b24.png[/img]


<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page import="java.util.Date" %>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>

<h1>Persons</h1>

<p>你于
<%= new java.util.Date() %>
根据${id }删除了一个Person
</p>

</body>
</html>



[b]personspage.jsp[/b]


[img]http://dl.iteye.com/upload/attachment/446961/2b8dbb6b-87be-3429-b5f1-3d5742d38bed.png[/img]


<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>

<h1>Persons</h1>

<table>
<tr>
<td width="50">Id</td>
<td width="150">First Name</td>
<td width="150">Last Name</td>
<td width="50">Money</td>
</tr>
<c:forEach items="${persons}" var="person">
<tr>
<td><c:out value="${person.id}" /></td>
<td><c:out value="${person.firstName}" /></td>
<td><c:out value="${person.lastName}" /></td>
<td><c:out value="${person.money}" /></td>
</tr>
</c:forEach>
</table>

</body>
</html>



我们的应用程序已经完成了

进入主页输入:[url]http://localhost:8080/spring-jdbc/main/persons[/url]

新增一Person:[url]http://localhost:8080/spring-jdbc/main/persons/add?firstname=John&lastname=Smith&money=1000[/url]

删除一Person:[url]http://localhost:8080/spring-jdbc/main/persons/delete?id=1[/url]

修改一Person:[url]http://localhost:8080/spring-jdbc/main//persons/edit?id=1&firstname=Johnny&lastname=Smith&money=2000[/url]

[size=x-large]
[b]总结[/b][/size]
这样我们完成了预定的目标:成功的连接了数据库并通过使用SpringMVC和JDBC实现了一个简单的CRUD操作;
我们了解了什么是JdbcTemplate以及如何使用SimpleJdbcTemplate对数据库进行操作.
而spring3MVC自带的SimpleJdbcTemplate能够很好的封装JDBC.数据库操作方便.
和Hibernate的HQL不同.因为是直接用原生态的sql进行查询.所以能够对sql语句进行拼接.
十分的灵活.这点是HQL所不能比拟的.


BTW:附件为本次教程源码.你可以下载后直接在tomcat或其他web服务器启动.也可以自行添加
maven插件启动.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring是一个开源的Java框架,用于构建企业级应用程序。它提供了一种轻量级的方式来开发应用程序,并可以集成不同的模块来满足各种需求。Spring MVCSpring框架的一部分,它是用于构建Web应用程序的模块。Spring Boot是基于Spring框架的一个扩展,旨在简化新Spring应用程序的初始搭建和开发过程。 区别在于: 1. Spring是一个全面的框架,提供了许多功能模块和组件,如Spring JDBCSpring MVCSpring Security等。而Spring MVCSpring框架的一部分,专门用于构建Web应用程序。 2. Spring Boot是建立在Spring框架之上的,它通过自动配置和约定大于配置的原则,极大地简化了Spring应用程序的开发过程。它提供了默认配置和依赖管理,使得开发人员可以更快地启动和运行应用程序。 3. Spring Boot还提供了一些额外的功能,如嵌入式Web服务器、自动化配置、健康检查和监控等。它的目标是提供一个更简单、更快速的方式来构建Spring应用程序。 综上所述,Spring是一个全面的Java框架,Spring MVCSpring框架的一部分,专注于构建Web应用程序,而Spring Boot是基于Spring框架的扩展,旨在简化Spring应用程序的开发过程。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [一看就懂的SpringSpringMVCSpringBoot!](https://blog.csdn.net/m0_45270667/article/details/108692537)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [SpringSpringMVCSpringBoot](https://blog.csdn.net/weixin_44079636/article/details/119854411)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值