SpringMVC框架入门(二)---注解式开发

目录

第二章、SpringMVC注解式开发

2.1 @RequestMappring定义请求规则

2.1.1 指定模块名称

2.1.2 对请求提交方式的定义

2.2 处理器方法的参数

2.2.1 逐个参数接收

2.2.2 利用过滤器解决中文乱码问题

2.2.3 校正请求参数名@RequestParam

2.2.4 对象参数接收

2.3 处理器方法的返回值

2.3.1 返回ModelAndView

2.3.2 返回String

2.3.3 返回void

2.3.4 返回对象Object---原理解释

2.3.5 返回自定义对象

2.3.6 返回List对象

2.3.7 返回String对象


第二章、SpringMVC注解式开发

2.1 @RequestMappring定义请求规则

2.1.1 指定模块名称

   @RequestMappring注解在类上,可以给类中的方法加一个公共的前缀,叫做模块名称

   修改Controller对象:

@Controller
/**
 * @RequestMapping:
 *     value:所有请求地址的公共部分,叫做模块名称
 *     位置:放在类的上面
 */
@RequestMapping("/test")
public class MyController {
    
    @RequestMapping(value = "/some.do")
    public ModelAndView doSome(HttpServletRequest request){
        ModelAndView mv = new ModelAndView();

        mv.addObject("msg","欢迎使用springmvc做web开发" + request.getParameter("name"));
        mv.addObject("fun","执行的是doSome方法");

        mv.setViewName("show");

        //返回mv
        return mv;
    }

    
    @RequestMapping(value = "/other.do")
    public ModelAndView doOther(){
        ModelAndView mv = new ModelAndView();
        mv.addObject("msg","欢迎使用springmvc做web开发");
        mv.addObject("fun","执行的是doFirst方法");
        mv.setViewName("other");
        return mv;
    }
}

   修改index.jsp文件:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <p>第一个springmvc项目</p>
    <p><a href="test/some.do">发起some.do的get请求</a></p><br/>
    <p><a href="test/other.do">发起first.do的get请求</a></p><br/>
</body>
</html>

2.1.2 对请求提交方式的定义

   指定请求方式method属性

   修改Controller对象:

@Controller
@RequestMapping("/test")
public class MyController {

    /**
     * @RequestMapping: 请求映射
     *       属性:method,表示请求的方式。它的值是RequestMethod类的枚举值
     *            例如表示get请求方式,RequestMethod.GET
     *                  post请求方式,RequestMethod.POST
     *
     * 如果请求方式错误,会发生405错误
     */
    //指定some.do使用get请求方式
    @RequestMapping(value = "/some.do",method = RequestMethod.GET)
    public ModelAndView doSome(HttpServletRequest request){
        ModelAndView mv = new ModelAndView();

        mv.addObject("msg","欢迎使用springmvc做web开发" + request.getParameter("name"));
        mv.addObject("fun","执行的是doSome方法");

        mv.setViewName("show");

        //返回mv
        return mv;
    }

    //指定other.do使用post请求方式
    @RequestMapping(value = "/other.do",method = RequestMethod.POST)
    public ModelAndView doOther(){
        ModelAndView mv = new ModelAndView();
        mv.addObject("msg","欢迎使用springmvc做web开发");
        mv.addObject("fun","执行的是doFirst方法");
        mv.setViewName("other");
        return mv;
    }

    //不指定请求方式,没有限制
    @RequestMapping(value = "/first.do")
    public ModelAndView doFirst(){
        ModelAndView mv = new ModelAndView();
        mv.addObject("msg","欢迎使用springmvc做web开发");
        mv.addObject("fun","执行的是doFirst方法");
        mv.setViewName("first");
        return mv;
    }
}

    修改index.jsp文件:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <p>第一个springmvc项目</p>
    <p><a href="test/some.do">发起some.do的get请求</a></p><br/>

    <form action="test/other.do" method="post">
        <input type="submit" value="post请求other.do"/>
    </form>
    <br/>
    <p><a href="test/first.do">发起first.do的get请求</a></p><br/>

    <form action="test/first.do" method="post">
        <input type="submit" value="post请求first.do"/>
    </form>
</body>
</html>

2.2 处理器方法的参数

   处理器方法可以包含以下四类参数,这些参数会在系统调用时由系统自动赋值,即开发人员可以在方法内直接使用。

        ①HttpServletRequest

        ②HttpServletResponse

        ③HttpSession

        ④请求中所携带的请求参数:逐个接收;对象接收

2.2.1 逐个参数接收

   要求:处理器(控制器)方法的形参名和请求中参数名必须一致。同名的请求参数赋给同名的形参。名字对应即可,和形参位置无关

   index.jsp文件:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <p>提交参数给Controller</p>
    <form action="receiveproperty.do" method="post">
        姓名:<input type="text" name="name"/><br/>
        年龄:<input type="text" name="age"/><br/>
        <input type="submit" value="提交参数"/><br/>
    </form>
</body>
</html>

   Controller对象:

public class MyController {
    /**
     * 逐个接收请求参数:
     *    要求:处理器(控制器)方法的形参名和请求中参数名必须一致
     *         同名的请求参数赋值给同名的形参
     * 框架接收请求参数
     *    1.使用request对象接收请求参数
     *      String strName = request.getParameter("name");
     *      String strAge = request.getParameter("age");
     *    2.springmvc框架通过DispatcherServlet调用MyController的doSome()方法
     *      调用方法时,按名称对应,把接收的参数赋值给形参
     *      doSome(strName,Integer.valueOf(strAge))//此处如果age定义成了int类型,如果不填写,age为"",无法转换,因此改成Integer类型,当不填写时,会赋值null
     *      框架会提供类型转换的功能,能把String转为int,long,float,double等类型。
     *
     * 400状态码:是客户端错误,表示提交请求参数过程中,发生了问题。
     */
    @RequestMapping(value = "/receiveproperty.do")
    public ModelAndView doSome(String name,Integer age){
        System.out.println("doSome,name="+ name + ",age=" + age);
        //可以在方法中直接使用name,age
        ModelAndView mv = new ModelAndView();

        mv.addObject("myname",name);
        mv.addObject("myage",age);
        //show是试图文件的逻辑名称(文件名称)
        mv.setViewName("show");

        //返回mv
        return mv;
    }
}

2.2.2 利用过滤器解决中文乱码问题

   当使用get请求方式时,提交中文不存在乱码问题;当使用post请求方式时,如果提交参数值是中文,接收后显示在页面上会产生中文乱码问题,此时需要使用过滤器处理乱码的问题。

   过滤器可以自定义,也可以使用框架中提供的过滤器CharacterEncodingFilter

   在web.xml文件中注册声明过滤器。

    <!--注册声明过滤器,解决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>
        <!--强制请求对象(HttpServletRequest)使用encoding编码的值-->
        <init-param>
            <param-name>forceRequestEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
        <!--强制响应对象(HttpServletResponse)使用encoding编码的值-->
        <init-param>
            <param-name>forceResponseEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>characterEncodingFilter</filter-name>
        <!--
            /*:表示强制所有的请求先通过过滤器处理。
        -->
        <url-pattern>/*</url-pattern>
    </filter-mapping>

2.2.3 校正请求参数名@RequestParam

   指若请求URL携带的参数名称与处理方法中指定的参数名不相同时,则需要在处理方法参数钱,添加一个注解@RequestParam("请求参数名"),指定请求URL所携带参数的名称。该注解是对处理器方法参数进行修饰的,value属性指定请求参数的名称。

   index.jsp文件:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <p>请求参数名和处理器方法的形参名不一样</p>
    <form action="receiveparam.do" method="post">
        姓名:<input type="text" name="rname"/><br/>
        年龄:<input type="text" name="rage"/><br/>
        <input type="submit" value="提交参数"/><br/>
</body>
</html>

   Controller对象:

@Controller
public class MyController {
    /**
     * 请求中参数名和处理器方法的形参名不一样
     * @RequestParam: 逐个接收请求参数中,解决请求中参数名形参名不一样的问题
     *           属性: 1.value  请求中的参数名
     *                 2.required 是一个boolean,默认是true
     *                   true:表示请求中必须包含此参数
     *                   false:表示请求中可以没有此参数
     *           位置:在处理器方法的形参定义的前面
     */
    @RequestMapping(value = "/receiveparam.do")
    public ModelAndView receiveParam(@RequestParam(value = "rname",required = false) String name,
                                     @RequestParam(value = "rage",required = false) Integer age){
        System.out.println("doSome,name="+ name + ",age=" + age);
        //可以在方法中直接使用name,age
        ModelAndView mv = new ModelAndView();

        mv.addObject("myname",name);
        mv.addObject("myage",age);
        //show是试图文件的逻辑名称(文件名称)
        mv.setViewName("show");

        //返回mv
        return mv;
    }
}

2.2.4 对象参数接收

   将处理器方法的参数定义为一个对象,只要保证请求参数名与这个对象的属性同名即可。

   实体类:

//保存请求参数值的一个普通类
public class Student {
    //属性名和请求中参数名要一样
    private String name;
    private Integer age;
}
public class School {
    private String name;
}

   index.jsp文件:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <p>使用java对象接收请求参数</p>
    <form action="receiveobject.do" method="post">
        姓名:<input type="text" name="name"/><br/>
        年龄:<input type="text" name="age"/><br/>
        <input type="submit" value="提交参数"/><br/>
    </form>
</body>
</html>

   Controller对象:

@Controller
public class MyController {
    /**
     * 处理器方法形参是java对象,这个对象的属性名和请求中参数名是一样的。
     * 框架会创建形参的java对象,给属性赋值。请求中的参数是name,框架会调用setName()
     * 如果两个不同的类有一样名字的属性,会共同赋值。
     */
    @RequestMapping(value = "/receiveobject.do")
    public ModelAndView receiveObject(Student myStudent, School mySchool){
        //可以在方法中直接使用name,age
        ModelAndView mv = new ModelAndView();

        mv.addObject("myname",mySchool.getName());
        mv.addObject("myage",myStudent.getAge());
        mv.addObject("mystudent",myStudent);
        mv.addObject("myschool",mySchool);
        //show是试图文件的逻辑名称(文件名称)
        mv.setViewName("show");

        //返回mv
        return mv;
    }
}

2.3 处理器方法的返回值

2.3.1 返回ModelAndView

   若处理器方法处理完后,需要跳转到其它资源,且又要在跳转的资源间传递数据,此时处理器方法返回ModelAndView比较好。当然,若要返回ModelAndView,则处理器方法中需要定义 ModelAndView对象。

   在使用时,若该处理器方法只是进行跳转而不传递数据,或只是传递数据而并不向任何资源跳转(如对页面的Ajax异步响应),此时若返回ModelAndView,则将总是有一部分多余:要么Model多余,要么View多余,即此时返回ModelAndView将不合适。

2.3.2 返回String

   处理器方法返回的字符串可以指定逻辑视图名,通过视图解析器解析可以将其转换为物理视图地址。

   index.jsp文件:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <p>处理器方法返回String表示视图名称</p>
    <form action="returnString-view.do" method="post">
        姓名:<input type="text" name="name"/><br/>
        年龄:<input type="text" name="age"/><br/>
        <input type="submit" value="提交参数"/><br/>
    </form>
    <br/>

    <p>处理器方法返回String表示视图完整路径</p>
    <form action="returnString-view2.do" method="post">
        姓名:<input type="text" name="name"/><br/>
        年龄:<input type="text" name="age"/><br/>
        <input type="submit" value="提交参数"/><br/>
    </form>
    <br/>
</body>
</html>

   Controller对象:

@Controller
public class MyController {
    /**
     * 处理器方法返回String---表示逻辑视图名称,需要配置视图解析器
     */
    @RequestMapping(value = "/returnString-view.do")
    public String doReturnView(HttpServletRequest request,String name,Integer age){
        System.out.println("doReturnView,name = " + name + ",age = " + age);
        //可以自己手工添加数据到request作用域
        request.setAttribute("myname",name);
        request.setAttribute("myage",age);
        //show:逻辑视图名称,项目中配置了视图解析器
        //框架对试图执行forward转发操作
        return "show";
    }

    /**
     * 处理器方法返回String---表示完整视图路径,此时不能配置视图解析器
     */
    @RequestMapping(value = "/returnString-view2.do")
    public String doReturnView2(HttpServletRequest request,String name,Integer age){
        System.out.println("doReturnView2,name = " + name + ",age = " + age);
        //可以自己手工添加数据到request作用域
        request.setAttribute("myname",name);
        request.setAttribute("myage",age);
        //完整视图路径,项目中不能配置视图解析器
        //框架对试图执行forward转发操作
        return "/WEB-INF/view/show.jsp";
    }
}

2.3.3 返回void

   若处理器对请求处理后,无需跳转到其他任何资源,此时可以让处理器方法返回void。

   对于处理器方法返回void的应用场景,ajax响应。ajax请求服务端返回的就是数据,和视图无关。

        1.在maven中加入jackson依赖。

<!--Jackson依赖-->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-core</artifactId>
    <version>2.9.0</version>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.9.0</version>
</dependency>

        2.引入jQuery库。

        3.index.jsp文件:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
    <script type="text/javascript" src="js/jquery-3.4.1.js"></script>
    <script type="text/javascript">
        $(function () {
            $("button").click(function () {
                $.ajax({
                    url:"returnVoid-ajax.do",
                    data:{
                        name:"zhangsan",
                        age:20
                    },
                    type:"post",
                    dataType:"json",//我需要的是json格式的数据
                    success:function (resp) {
                        //resp从服务器端返回的是json格式的字符串{"name":"zhangsan","age":20}
                        //jquery会把字符串转为json对象,赋值给resp形参。
                        alert(resp.name + "   " + resp.age);
                    }
                })
            })
        })
    </script>
</head>
<body>
    <button id="btn">发起ajax请求</button>
</body>
</html>

        4.Controller对象:

@Controller
public class MyController {
    /**
     * 处理器方法返回void,响应ajax请求
     * 手工实现ajax,json数据:代码有重复的 1.java对象转为json;2.通过HttpServletResponse输出json数据
     */
    @RequestMapping(value = "/returnVoid-ajax.do")
    public void doReturnVoidAjax(HttpServletResponse response, String name, Integer age) throws IOException {
        System.out.println("doReturnVoidAjax,name = " + name + ",age = " + age);
        //处理ajax,使用json做数据的格式
        //假设现在service调用完成了,使用Student表示处理结果
        Student student = new Student();
        student.setName(name);
        student.setAge(age);

        String json="";
        //把结果的对象转为json格式的数据
        if(student != null){
            ObjectMapper om = new ObjectMapper();
            json = om.writeValueAsString(student);
            System.out.println(json);
        }

        //输出数据,响应ajax的请求
        response.setContentType("application/json;charset=utf-8");//告诉浏览器是一个json格式的数据
        PrintWriter pw = response.getWriter();
        pw.println(json);
        pw.flush();
        pw.close();
    }
}

2.3.4 返回对象Object---原理解释

   处理器方法也可以返回Object对象。这个Object可以是Integer,String,自定义对象,Map,List等。但返回的对象不是作为逻辑视图出现的,而是作为直接在页面显示的数据出现的。

   返回对象,需要使用@ResponseBody注解,将转换后的JSON数据放入到响应体中。

   1.在maven中加入jackson依赖。

<!--Jackson依赖-->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-core</artifactId>
    <version>2.9.0</version>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.9.0</version>
</dependency>

   2.声明注解驱动。将Object数据转化为JSON数据,需要由消息转换器HttpMessageConverter完成。而转换器的开启,需要由<mvc:annotation-driven/>来完成。在springmvc配置文件中声明注解驱动,会自动创建HttpMessageConveter接口的8个实现类对象

        注解驱动的功能:完成java对象到json、xml、text、二进制等数据格式的转换

        HttpMessageConveter接口:消息转换器。功能是定义了java转为json、xml等数据格式的方

      法,这个接口有很多的实现类,这些实现类完成了java对象到json、java对象到xml、java对象

      到二进制数据的转换。

        canWrite和write方法是控制器类把结果输出到浏览器时使用的。

        canWrite:作用是检查处理器方法的返回值,能不能转为var2表示的数据格式。 

                MediaType:表示数据格式的,如json、xml等等。

        write:把处理器方法的返回值对象,调用jackson中的ObjectMapper转为json字符串。

                json = om.writeValueAsString(student);

        八个实现类:

        代码实现:

<!--注解驱动-->
<mvc:annotation-driven />

   3.在处理器方法的上面加入@ResponseBody注解。通过HttpServletResponse输出数据,响应ajax请求的。这个注解完成的功能就是手动完成部分中的:

response.getWriter();
pw.println(json);

pw.flush();

pw.close();

2.3.5 返回自定义对象

   index.jsp文件:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
    <script type="text/javascript" src="js/jquery-3.4.1.js"></script>
    <script type="text/javascript">
        $(function () {
            $("button").click(function () {
                $.ajax({
                    url:"returnStudentJson.do",
                    data:{
                        name:"zhangsan",
                        age:20
                    },
                    type:"post",
                    dataType:"json",//我需要的是json格式的数据
                    success:function (resp) {
                        //resp从服务器端返回的是json格式的字符串{"name":"zhangsan","age":20}
                        //jquery会把字符串转为json对象,赋值给resp形参。
                        alert(resp.name + "   " + resp.age);
                    }
                })
            })
        })
    </script>
</head>
<body>
    <button id="btn">发起ajax请求</button>
</body>
</html>

   Controller对象:

@Controller
public class MyController {
    /**
     * 处理器方法返回一个Student,通过框架转为json,响应ajax请求
     * @ResponseBody:
     *      作用:把处理器方法返回的对象转为json后,通过HttpServletResponse输出给浏览器。
     *      位置:方法的定义上面,和其他注解没有顺序的关系。
     * 返回对象框架的处理流程:
     *     1.框架会把返回Student类型,调用框架中的ArrayList<HttpMessageConverter>中每个类的canWrite()方法,
     *       检查那个HttpMessageConverter接口的实现类能处理Student类型的数据---MappingJackson2HttpMessageConverter
     *
     *     2.框架会调用实现类的write(),即MappingJackson2HttpMessageConverter的write()方法
     *       把"xxy"的student对象转为json格式,调用jackson的ObjectMapper实现转为json
     *       默认contextType:application/json;charset=utf-8
     *
     *     3.框架会调用@ResponseBody把2的结果数据输出到浏览器,ajax请求处理完成
     */
    @RequestMapping(value = "/returnStudentJson.do")
    @ResponseBody
    public Student soStudentJsonObject(String name,Integer age){
        //调用service,获取请求结果数据,Student对象表示结果数据
        Student student = new Student();
        student.setName("xxy");
        student.setAge(24);
        return student;//会被框架转为json
    }
}

2.3.6 返回List对象

   index.jsp文件:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
    <script type="text/javascript" src="js/jquery-3.4.1.js"></script>
    <script type="text/javascript">
        $(function () {
            $("button").click(function () {
                $.ajax({
                    url:"returnStudentJsonArray.do",
                    data:{
                        name:"zhangsan",
                        age:20
                    },
                    type:"post",
                    dataType:"json",//我需要的是json格式的数据
                    success:function (resp) {
                        //resp从服务器端返回的是json格式的字符串{"name":"zhangsan","age":20}
                        //jquery会把字符串转为json对象,赋值给resp形参。
                        $.each(resp,function (i,n) {
                            alert(n.name + "     " + n.age)
                        })
                    }
                })
            })
        })
    </script>
</head>
<body>
    <button id="btn">发起ajax请求</button>
</body>
</html>

   Controller对象:

@Controller
public class MyController {
    /**
     * 处理方法返回List<Student>
     *     返回对象框架的处理流程:
     *       1.框架会把返回ListStudent<>类型,调用框架中的ArrayList<HttpMessageConverter>中每个类的canWrite()方法,
     *         检查那个HttpMessageConverter接口的实现类能处理Student类型的数据---MappingJackson2HttpMessageConverter
     *
     *       2.框架会调用实现类的write(),即MappingJackson2HttpMessageConverter的write()方法
     *         把多个student对象转为json格式,调用jackson的ObjectMapper实现转为json array
     *         默认contextType:application/json;charset=utf-8
     *
     *       3.框架会调用@ResponseBody把2的结果数据输出到浏览器,ajax请求处理完成
     */
    @RequestMapping(value = "/returnStudentJsonArray.do")
    @ResponseBody
    public List<Student> soStudentJsonObjectArray(String name, Integer age){
        List<Student> list = new ArrayList<>();
        //调用service,获取请求结果数据,Student对象表示结果数据
        Student student1 = new Student();
        student1.setName("xxy");
        student1.setAge(24);
        list.add(student1);

        Student student2 = new Student();
        student2.setName("张三");
        student2.setAge(20);
        list.add(student2);

        return list;
    }
}

2.3.7 返回String对象

   index.jsp文件:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
    <script type="text/javascript" src="js/jquery-3.4.1.js"></script>
    <script type="text/javascript">
        $(function () {
            $("button").click(function () {
                $.ajax({
                    url:"returnStringData.do",
                    type:"post",
                    dataType:"text",
                    success:function (resp) {
                        alert("返回的是文本数据:" + resp)
                    }
                })
            })
        })
    </script>
</head>
<body>
    <button id="btn">发起ajax请求</button>
</body>
</html>

   Controller对象:

@Controller
public class MyController {
    /**
     * 处理器方法返回的是String,这里String表示数据的,不是之前讲的视图。
     * 区分返回值String是数据,还是视图,看有没有@ResponseBody注解
     * 如果有@ResponseBody注解,返回String就是数据,反之就是视图。
     *
     * 默认使用"text/plain;charset=ISO-8859-1"作为contentType,导致中文有乱码
     * 解决方案:给RequestMapping增加一个属性produces,使用这个属性指定新的contentType
     *
     * 返回String对象框架的处理流程:
     *     1.框架会把返回String类型,调用框架中的ArrayList<HttpMessageConverter>中每个类的canWrite()方法,
     *       检查那个HttpMessageConverter接口的实现类能处理String类型的数据---StringHttpMessageConverter
     *
     *     2.框架会调用实现类的write(),即MappingJackson2HttpMessageConverter的write()方法
     *       把字符串按照指定的编码处理text/plain;charset=ISO-8859-1
     *       这里过滤器的设置是无效的,因为ajax请求不会经过过滤器。
     *
     *     3.框架会调用@ResponseBody把2的结果数据输出到浏览器,ajax请求处理完成
     */
    @RequestMapping(value = "/returnStringData.do",produces = "text/plain;charset=utf-8")
    @ResponseBody
    public String doStringData(){
        return "hello springmvc 返回对象,表示数据";
    }
}

PS:根据动力节点课程整理,如有侵权,联系删除。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值