SSM框架17 SpringMVC、JSON数据、jackson、fastjson、整合SSM框架、ajax技术、拦截器、文件上传和下载

一、JSON数据

JSON(JavaScript Object Notation, JS 对象标记) 是一种轻量级的数据交换格式,目前使用特别广泛。

  • 采用完全独立于编程语言的文本格式来存储和表示数据。
  • 简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。
  • 易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率。
  • 在 JavaScript 语言中,一切都是对象。因此,任何JavaScript 支持的类型都可以通过 JSON来表示,例如字符串、数字、对象、数组等。

看看他的要求和语法格式:

  • 对象表示为键值对,数据由逗号分隔
  • 花括号保存对象
  • 方括号保存数组
  • 采用kew-value形式保存数据,键/值对组合中的键名写在前面并用双引号 “” 包裹,使用冒号 : 分隔,然后紧接着值:

JSON和javascript对象可以相互转换

//json转javascript
var obj = JSON.parse('{"a": "Hello", "b": "World"}'); 

//javascript转json
var json = JSON.stringify({a: 'Hello', b: 'World'});

二、json工具之jackson

首先导包

<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.13.3</version>
</dependency>

<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.83</version>
</dependency>


@Controller
public class JsonController {
    @RequestMapping("/json1")
    @ResponseBody//不走视图直接返回一个字符串
    public JSON json1(ModelAndView mv){
        ApplicationContext context = new ClassPathXmlApplicationContext("springmvc.xml");
        User user = context.getBean("user", User.class);
        return (JSON) JSON.toJSON(user);

    }
}

    @RequestMapping(value = "/json1",produces = "application/json;charset=utf-8")
    @ResponseBody//不走视图直接返回一个字符串
    public User json1(ModelAndView mv){
        ApplicationContext context = new ClassPathXmlApplicationContext("springmvc.xml");
        User user = context.getBean("user", User.class);
        return user;

    }
@Controller
public class JsonController {
    @RequestMapping(value = "/json1",produces = "application/json;charset=utf-8")
    @ResponseBody//不走视图直接返回一个字符串
    public String json1(ModelAndView mv) throws JsonProcessingException {
        ObjectMapper objectMapper = new ObjectMapper();
        ApplicationContext context = new ClassPathXmlApplicationContext("springmvc.xml");
        User user = context.getBean("user", User.class);
        return objectMapper.writeValueAsString(user);

    }
}

解决json乱码问题 在springmvc.xml

<!--配置json乱码问题解决-->
    <mvc:annotation-driven>
        <mvc:message-converters register-defaults="true">
            <bean class="org.springframework.http.converter.StringHttpMessageConverter">
                <constructor-arg value="UTF-8"/>
            </bean>
            <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
                <property name="objectMapper">
                    <bean class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean">
                        <property name="failOnEmptyBeans" value="false"/>
                    </bean>
                </property>
            </bean>
        </mvc:message-converters>
    </mvc:annotation-driven>

在类上直接使用 @RestController ,使得里面所有的方法都只会返回 json 字符串,不用再每一个都添加@ResponseBody !我们在前后端分离开发中,一般都使用 @RestController 。

@RestController
public class UserController {
    //produces:指定响应体返回类型和编码
    @RequestMapping(value = "/json1")
    public String json1() throws JsonProcessingException {
        //创建一个jackson的对象映射器,用来解析数据
        ObjectMapper mapper = new ObjectMapper();
        //创建一个对象
        User user = new User("秦疆1号", 3, "男");
        //将我们的对象解析成为json格式
        String str = mapper.writeValueAsString(user);
        //由于@ResponseBody注解,这里会将str转成json格式返回;十分方便
        return str;
    }
}
package until;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;

import java.text.SimpleDateFormat;

public class JsonUntil {
    public static String getJson(Object object,String dataFormat) throws JsonProcessingException {
        ObjectMapper mapper=new ObjectMapper();

        mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS,false);

        SimpleDateFormat sdf=new SimpleDateFormat(dataFormat);

        mapper.setDateFormat(sdf);

        return mapper.writeValueAsString(object);
    }
}

三、json工具之fastjson

package controller;

import com.alibaba.fastjson.JSON;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import pojo.User;

import java.sql.Array;
import java.util.ArrayList;

@Controller
public class FastJsonController {

    @RequestMapping("/fj1")
    @ResponseBody
    public String FastJson(){
        ArrayList<User> list = new ArrayList<>();
        list.add(new User(1,"l1","123"));
        list.add(new User(2,"l2","123"));
        list.add(new User(2,"l3","123"));
        String s = JSON.toJSONString(list);
        return s;
    }
}

四、整合SSM框架

use mybatis;
create table `bookshop`(
    `book_id`    int(20)     not null auto_increment,
    `book_name`  varchar(50) not null,
    `book_count` int(50) not null,
    `detail`     varchar(50) not null,
    primary key(`book_id`)
)ENGINE=INNODB DEFAULT CHARSET=utf8;

INSERT  INTO `bookshop`(`book_id`,`book_name`,`book_count`,`detail`)VALUES
(1,'Java',1,'从入门到放弃'),
(2,'MySQL',10,'从删库到跑路'),
(3,'Linux',5,'从进门到进牢');

aplicationContext.xml

<?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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/beans/spring-context.xsd">
    <import resource="spring-dao.xml"/>
    <import resource="spring-service.xml"/>
    <import resource="spring-mvc.xml"/>

</beans>

db.properties

jdbc.username=root
jdbc.password=123456
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC

mybatis.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <settings>
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>
    <typeAliases>
        <package name="pojo"/>
    </typeAliases>
    <mappers>
        <mapper resource="mapper/BookMapper.xml"/>
    </mappers>

</configuration>

spring-dao.xml

<?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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">
    <!--    1、关联数据库配置文件-->
    <context:property-placeholder location="classpath:db.properties"/>
    <!--    2、连接池
            dbcp:半自动化,不能自动连接
            c3p0:自动化操作 自动化加载配置文件,自动设置到对象
    -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="${jdbc.driver}"/>
        <property name="jdbcUrl" value="${jdbc.url}"/>
        <property name="user" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
        
        <property name="maxPoolSize" value="30"/>
        <property name="minPoolSize" value="10"/>
        <property name="autoCommitOnClose" value="false"/>
        <property name="checkoutTimeout" value="10000"/>
        <property name="acquireRetryAttempts" value="2"/>
    </bean>

    <!--    3SqlSessionFactory-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <!--        绑定mybatis配置文件-->
        <property name="configLocation" value="classpath:mybatis.xml"/>
    </bean>
    <!--    配置dao接口扫描包 动态实现Dao接口注入到Spring容器-->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
        <property name="basePackage" value="dao"/>
    </bean>

</beans>

spring-service.xml

<?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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

<!--    1、扫描service下的包-->
    <context:component-scan base-package="service"/>
<!--    2、将我们的所有业务类,注入到spring 可以通过配置实现-->
    <bean id="BookServiceImpl" class="service.BookServiceImpl">
        <property name="bookMapper" ref="bookMapper"/>
    </bean>
<!--    3、声明事务配置-->
    <bean id="transactionManger" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>
<!--    4AOP支持-->

</beans>

spring-mvc.xml

<?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:mvc="http://www.springframework.org/schema/mvc"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/mvc
            http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
            http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
            http://www.springframework.org/schema/context
                  http://www.springframework.org/schema/context/spring-context-4.0.xsd">
    <!--    自动扫描包 让指定包下注解生效 IOC容器统一管理-->
    <context:component-scan base-package="controller"/>
    <!--SpringMVC不处理静态资源 .css .js .html .mp3 .mp4-->
    <mvc:default-servlet-handler/>
    <!--支持注解驱动
        @RequestMapping注解完成映射关系
        用annotation-driven完成了DefaultAnnotationHandlerMappingAnnotationMethodHanlderAdapter的配置
        -->
    <mvc:annotation-driven/>

    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <property name="suffix" value=".jsp"/>
    </bean>



</beans>


BookMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="dao.BookMapper">
    <insert id="addBook" parameterType="Book">
        insert into bookshop values (#{BookId},#{BookName},#{BookCount},#{detail});
    </insert>

    <delete id="deleteBook" parameterType="int">
        delete from bookshop where book_id=#{bookid};
    </delete>

    <update id="updateBook" parameterType="Book">
        update bookshop set book_name=#{BookName},book_count=#{BookCount},detail=#{detail}
        where book_id=#{BookId};
    </update>

    <select id="SelectOneBook" parameterType="int" resultType="Book">
        select * from bookshop where book_id=#{BookId};
    </select>

    <select id="SelectBooks" resultType="Book">
        select * from bookshop
    </select>

</mapper>
package controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import pojo.Book;
import service.BookService;

import java.util.List;

@Controller
public class BookController {
    @Autowired
    @Qualifier("BookServiceImpl")
    private BookService bookService;

    @RequestMapping("/allbook")
    public ModelAndView allbook(ModelAndView mv){
        List<Book> list=bookService.SelectBooks();
        mv.addObject("list",list);
        mv.setViewName("allbook");
        return mv;
    }
}

五、ajax技术

ajax是异步的js,无需加载页面便可以更新局部页面
jQuery Ajax本质就是 XMLHttpRequest,对他进行了封装,方便调用

jQuery.ajax(...)
       部分参数:
              url:请求地址
             type:请求方式,GETPOST1.9.0之后用method)
          headers:请求头
             data:要发送的数据
      contentType:即将发送信息至服务器的内容编码类型(默认: "application/x-www-form-urlencoded; charset=UTF-8")
            async:是否异步
          timeout:设置请求超时时间(毫秒)
       beforeSend:发送请求前执行的函数(全局)
         complete:完成之后执行的回调函数(全局)
          success:成功之后执行的回调函数(全局)
            error:失败之后执行的回调函数(全局)
          accepts:通过请求头发送给服务器,告诉服务器当前客户端课接受的数据类型
         dataType:将服务器端返回的数据转换成指定类型
            "xml": 将服务器端返回的内容转换成xml格式
           "text": 将服务器端返回的内容转换成普通文本格式
           "html": 将服务器端返回的内容转换成普通文本格式,在插入DOM中时,如果包含JavaScript标签,则会尝试去执行。
         "script": 尝试将返回值当作JavaScript去执行,然后再将服务器端返回的内容转换成普通文本格式
           "json": 将服务器端返回的内容转换成相应的JavaScript对象
          "jsonp": JSONP 格式使用 JSONP 形式调用函数时,如 "myurl?callback=?" jQuery 将自动替换 ? 为正确的函数名,以执行回调函数
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<script src="/jquery-1.9.1.min.js">
</script>

<body>

<div>
    <p>请输入:</p>
    <p>
        <input type="text" id="username"/>
        <input type="button" value="提交" onclick="go()">
    </p>
</div>


</body>
<script>
    function go(){
        $.ajax({
                url:"/t3",
                type:'POST',
                data:{"name":$("#username").val()},
                success:function (data){
                    alert(data+1);
                }
            }
        );
    }
</script>
</html>
package controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Controller
public class AjaxController {

    @PostMapping("/t1")
    public void test1(String name, HttpServletResponse response) throws IOException {
        if (name.equals("admin")){
            response.getWriter().print("ok");
        }else {
            response.getWriter().print("no");
        }
    }

    @RequestMapping("/t")
    public String test2() throws IOException {
        return "test";
    }

    @PostMapping("/t3")
    @ResponseBody
    public String test3(String name,HttpServletResponse response) throws IOException {
        System.out.println(name);
        if (name.equals("admin")){
            return "ok";
        }else {
            return "no";
        }
    }
}

六、拦截器

过滤器和拦截器的区别是,拦截器是AOP思想的具体应用

过滤器:javaweb的一部分 在 url-pattern中配置/*之后,可以对所有要访问的资源拦截

拦截器:springmvc有自己的拦截器,拦截器只会拦截访问的控制器方法,如果访问的是jso、html、css、image、js是不会进行拦截的

自定义拦截器

package interceptor;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class MyInterceptor implements HandlerInterceptor {
//  return true 执行下一个拦截器 放行
//  return false 不执行下一个拦截器 放行
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("处理前");
        return true;
    }

    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("处理后");
    }

    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("清理");
    }
}

注册拦截器

<?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:mvc="http://www.springframework.org/schema/mvc"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/mvc
            http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
            http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
            http://www.springframework.org/schema/context
                  http://www.springframework.org/schema/context/spring-context-4.0.xsd">
    <!--    自动扫描包 让指定包下注解生效 IOC容器统一管理-->
    <context:component-scan base-package="controller"/>
    <!--SpringMVC不处理静态资源 .css .js .html .mp3 .mp4-->
    <mvc:default-servlet-handler/>
    <!--支持注解驱动
        @RequestMapping注解完成映射关系
        用annotation-driven完成了DefaultAnnotationHandlerMappingAnnotationMethodHanlderAdapter的配置
        -->
    <mvc:annotation-driven/>

    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/pages/"/>
        <property name="suffix" value=".html"/>
    </bean>

    <mvc:interceptors>
        <mvc:interceptor>
<!--            包括这个请求下面的所有请求-->
            <mvc:mapping path="/**"/>
            <bean class="interceptor.MyInterceptor"/>
        </mvc:interceptor>
    </mvc:interceptors>


</beans>

七、文件下载

​前端表单要求:为了能上传文件,必须将表单的method设置为POST,并将enctype设置为multipart/form-data。只有在这样的情况下,浏览器才会把用户选择的文件以二进制数据发送给服务器。

表单中的 enctype 属性:

  • application/x-www=form-urlencoded:默认方式,只处理表单域中的 value
    属性值,采用这种编码方式的表单会将表单域中的值处理成 URL 编码方式。
  • multipart/form-data:这种编码方式会以二进制流的方式来处理表单数据,这种编码方式会把文件域指定文件的内容也封装到请求参数中,不会对字符编码。
  • text/plain:除了把空格转换为 “+” 号外,其他字符都不做编码处理,这种方式适用直接通过表单发送邮件

SpringMVC中

  • Servlet3.0规范已经提供方法来处理文件上传,但这种上传需要在Servlet中完成
  • Spring MVC提供了更简单的封装
  • Spring MVC为文件上传提供了直接的支持,这种支持是用即插即用的MultipartResolver实现的。
  • Spring MVC使用Apache Commons FileUpload技术实现了一个MultipartResolver实现类:CommonsMultipartResolver。因此,SpringMVC的文件上传还需要依赖Apache Commons FileUpload的组件。

依赖

<!--文件上传-->
        <dependency>
            <groupId>commons-fileupload</groupId>
            <artifactId>commons-fileupload</artifactId>
            <version>1.3.3</version>
        </dependency>
        <!--servlet-api导入高版本的-->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.1</version>
        </dependency>

文件上传配置

   <!--文件上传配置-->
    <bean id="multipartResolver"  class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <!-- 请求的编码格式,必须和jSP的pageEncoding属性一致,以便正确读取表单的内容,默认为ISO-8859-1 -->
        <property name="defaultEncoding" value="utf-8"/>
        <!-- 上传文件大小上限,单位为字节(10485760=10M) -->
        <property name="maxUploadSize" value="10485760"/>
        <property name="maxInMemorySize" value="40960"/>
    </bean>
package controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.commons.CommonsMultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.*;

@Controller
public class FileController {

    @RequestMapping("/upload")
    public String upload(@RequestParam("file")CommonsMultipartFile file, HttpServletRequest request) throws IOException {
        String uploadfilename = file.getOriginalFilename();
        if (uploadfilename.equals("")){
            return "redirect:/index.jsp";
        }
        System.out.println("文件名:"+uploadfilename);

        String realPath = request.getServletContext().getRealPath("/upload");
        File newfile = new File(realPath);

        if (!newfile.exists()){
            newfile.mkdir();
        }

        System.out.println("上传文件保存地址"+newfile);

        InputStream is = file.getInputStream();
        FileOutputStream os = new FileOutputStream(new File(newfile, uploadfilename));

        int len=0;
        byte[] buffer = new byte[1024];
        while ((len=is.read(buffer))!=-1){
            os.write(buffer,0,len);
            os.flush();
        }
        os.close();
        is.close();
        return "redirect:/index.jsp";
    }
//  直接用transferTo方法保存
    @RequestMapping("/upload2")
    public String  fileUpload2(@RequestParam("file") CommonsMultipartFile file, HttpServletRequest request) throws IOException {
        //上传路径保存设置
        String path = request.getServletContext().getRealPath("/upload");
        File realPath = new File(path);
        if (!realPath.exists()){
            realPath.mkdir();
        }
        //上传文件地址
        System.out.println("上传文件保存地址:"+realPath);
        //通过CommonsMultipartFile的方法直接写文件(注意这个时候)
        file.transferTo(new File(realPath +"/"+ file.getOriginalFilename()));
        return "redirect:/index.jsp";
    }

}

八、文件下载

    @RequestMapping("/down")
    public String down(HttpServletRequest request, HttpServletResponse response) throws IOException {
        String path = request.getServletContext().getRealPath("/upload");
        String filename="file1.jpg";

        response.reset();
        response.setContentType("multipart/form-data");
        response.setCharacterEncoding("UTF-8");

        response.setHeader("Content-Disposition",
                "attachment;fileName="+ URLEncoder.encode(filename, "UTF-8"));

        File file = new File(path, filename);


        InputStream input=new FileInputStream(file);

        OutputStream out = response.getOutputStream();

        byte[] buff =new byte[1024];
        int index=0;
        while((index= input.read(buff))!= -1){
            out.write(buff, 0, index);
            out.flush();
        }
        out.close();
        input.close();

        return "redirect:/index.jsp";
    }
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值