SpringMVC学习记录

SpringMVC

基于MVC开发模式的框架,用来优化控制器,是Spring的一员,也具备IOC和AOP
MVC是一种开发模式,它是模型视图控制器的简称,所有web应用都是基于MVC开发
M:模型层,包含实体类,业务逻辑层,数据访问层
V:视图层,html,JavaScript,vue
C:控制器,用来接收客户端的请求,并返回响应到客户端的组件,Servlet就是组件

分析web请求

  DispatcherServlet要在web.xml文件中注册才可用
    web请求执行流程  xxx.jsp<------>DispatcherServlet<------>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:springmvc.xml</param-value>
            </init-param>
        </servlet>
        <!--设置简短访问名后缀-->
        <servlet-mapping>
            <servlet-name>springmvc</servlet-name>
            <url-pattern>*.action</url-pattern>
    </servlet-mapping>

@RequestMapping注解用来映射服务器访问的路径

加在方法上,是为此方法注册一个可访问的名称(路径) /路径.action
加在类上,相当于是包名(虚拟路径) /虚拟路径/路径.action

   @Controller//交给Spring创建对象
    public class DemoAction {
        /*
        * action中所有的功能实现都是由方法来完成
        * action方法的规范
        * 1.访问权限public
        * 2.方法的返回值任意
        * 3.方法名称任意
        * 4.方法可以无参
        * 5.要用@RequestMapping注解来声明一个访问的路径名称
        * */
        @RequestMapping("/demo")
        public String demo(){
            System.out.println("服务器被访问");
            return "main";//可以直接转到/admin/main.jsp页面上
        }
    }

   此注解可以区分get请求和post请求
    @Controller
    public class ReqAction {
        @RequestMapping(value = "/req",method = RequestMethod.GET)
        public String req(){
            System.out.println("get请求处理");
            return "main";
        }
        @RequestMapping(value = "/req",method = RequestMethod.POST)
        public String req1(){
            System.out.println("post请求处理");
            return "main";
        }
    }

五种数据提交方式优化

1.单个提交数据
页面:
<form action="${pageContext.request.contextPath}/one.action">
    姓名:<input name="name"><br>
    年龄:<input name="age"><br>
    <input type="submit" value="提交">
</form>
action:
@RequestMapping("/one")
    public String one(String name,int age){
        System.out.println("名字是"+name+"年龄是"+age);
        return "main";
    }

2.对象封装提交数据
在提交请求中,保证请求参数的名称和实体类的变量名称一致,可以自动创建对象,提交数据,类型转换,封装到对象中
页面:
<form action="${pageContext.request.contextPath}/two.action">
    姓名:<input name="uname"><br>
    年龄:<input name="uage"><br>
    <input type="submit" value="提交">
</form>
action:
 @RequestMapping("/two")
    public String two(Users u){
        System.out.println(u);
        return "main";
    }

 3.动态占位符提交
 仅限于超链接或地址栏提交数据,一杠一值一杠一大括号,使用@PathVariable注解来解析
页面:
 <a href="${pageContext.request.contextPath}/three/张三/22.action">动态提交</a>
action:
 @RequestMapping("/three/{name}/{age}")
     public String three(@PathVariable String name, @PathVariable int age){
         System.out.println("名字是"+name+"年龄是"+age);
         return "main";
     }

 4.映射名称不一致
 提交请求参数与action方法的形参的名称不一致,使用@RequestParam注解来解析
页面:
 <form action="${pageContext.request.contextPath}/four.action">
     姓名:<input name="name"><br>
     年龄:<input name="age"><br>
     <input type="submit" value="提交">
 </form>
action:
  @RequestMapping("/four")
     public String four(@RequestParam("name") String uname,@RequestParam("age") int uage){
         System.out.println("名字是"+uname+",年龄是"+uage);
         return "main";
     }

  5.手工提取数据
页面:
  <form action="${pageContext.request.contextPath}/five.action" method="get">
      姓名:<input name="name"><br>
      年龄:<input name="age"><br>
      <input type="submit" value="提交">
  </form>
action:
  @RequestMapping("/five")
      public String five(HttpServletRequest request){
          String name = request.getParameter("name");
          int age = Integer.parseInt(request.getParameter("age"));
          System.out.println("名字是"+name+"年龄是"+age);
          return "main";
      }

中文乱码解决方案

 <filter>
        <filter-name>encode</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>forceRequestEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
        <init-param>
            <param-name>forceResponseEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>encode</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

action方法的返回值

1.String:客户端资源的地址,自动拼接前缀和后缀,可以屏蔽自动拼接字符串,指定返回的路径
2.Object:返回json格式的对象,自动将对象或集合转为json,使用json工具进行转换必须要添加依赖,用于ajax请求
3.void:无返回值,用于ajax请求
4.8种基本类型,用于ajax请求
5.ModelAndView:返回数据和视图对象

四种转发方式请求转发和重定向转发
不改变网址的情况使用请求转发
改变网址的情况使用重定向转发

页面代码:
    <a href="${pageContext.request.contextPath}/one.action">1.请求转发页面</a><br>
    <a href="${pageContext.request.contextPath}/two.action">2.请求转发action</a><br>
    <a href="${pageContext.request.contextPath}/three.action">3.重定向页面</a><br>
    <a href="${pageContext.request.contextPath}/four.action">4.重定向action</a><br>
    <a href="${pageContext.request.contextPath}/five.action">5.请求转发到login</a><br>
    <a href="${pageContext.request.contextPath}/six.action">6.重定向转发到login</a><br>
action代码:
    @Controller
    public class JumpAction {
        @RequestMapping("/one")
        public String one (){
            System.out.println("这是请求转发页面");
            return "main";//默认是请求转发,用视图解析器拼接前缀后缀进行页面跳转
        }
        @RequestMapping("/two")
        public String two (){
            System.out.println("这是请求转发action");
            //forward: 这个forward可以屏蔽视图解析器前缀和后缀的拼接,实现请求转发跳转
            return "forward:/other.action";
        }
        @RequestMapping("/three")
        public String three (){
            System.out.println("这是重定向页面");
            //redirect: 这个redirect可以屏蔽视图解析器前缀和后缀的拼接,实现重定向跳转
            return "redirect:/admin/main.jsp";
        }
        @RequestMapping("/four")
        public String four (){
            System.out.println("这是重定向action");
            //redirect: 这个redirect可以屏蔽视图解析器前缀和后缀的拼接,实现重定向跳转
            return "redirect:/other.action";
        }
        @RequestMapping("/five")
        public String five(){
            return "forward:/fore/login.jsp";
        }
        @RequestMapping("/six")
        public String six(){
            return "redirect:/fore/login.jsp";
        }
    }

SpringMVC默认的参数类型

1.HttpServletRequest
2.HttpServletResponse
3.HttpSession
4.Model
5.Map
6.ModelMap
Map,Model,ModelMap和request一样使用请求作用域进行传递,所以必须是请求转发

页面:
          requestUsers:${requestUsers}<br>
          sessionUsers:${sessionUsers}<br>
          modelUsers:${modelUsers}<br>
          mapUsers:${mapUsers}<br>
          modelmapUsers:${modelmapUsers}<br>
          从index.jsp的数据:${param.name}
action:
     @RequestMapping("/data")
        public String data(HttpServletRequest request,
                           HttpServletResponse response,
                           HttpSession session,
                           Model model,
                           Map map,
                           ModelMap modelMap){
            Users u = new Users("张三",22);
            request.setAttribute("requestUsers",u);
            session.setAttribute("sessionUsers",u);
            model.addAttribute("modelUsers",u);
            map.put("mapUsers",u);
            modelMap.addAttribute("modelmapUsers",u);
            return "main";
        }

日期的处理

 1.日期的提交处理
        A.单个日期处理
        使用@DateTimeFormat注解,必须搭配springmvc.xml文件中的<mvc:annotationdriven>标签
         SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd");
            @RequestMapping("/mydate")
            public String mydate(@DateTimeFormat(pattern = "yyyy-MM-dd") Date mydate){
                System.out.println(sf.format(mydate));
                return "show";
            }

   B.类中全局日期处理
        使用InitBinder注解
         @InitBinder
            public void Init(WebDataBinder dataBinder){
                dataBinder.registerCustomEditor(Date.class,new CustomDateEditor(sf,true));
            }

   2.日期的显示处理
      在页面上显示好看的日期,必须使用JSTL,要在pom文件添加依赖
      页面:
      <a href="${pageContext.request.contextPath}/list.action">显示集合中对象的日期成员</a>
      action页面:
      @RequestMapping("/list")
          public String list(HttpServletRequest request) throws ParseException {
              Student stu1 = new Student("张三",sf.parse("2000-01-01"));
              Student stu2 = new Student("李四",sf.parse("2000-02-01"));
              Student stu3 = new Student("王五",sf.parse("2000-03-01"));
              List<Student> list = new ArrayList<>();
              list.add(stu1);
              list.add(stu2);
              list.add(stu3);
              request.setAttribute("list",list);
              return "show";
          }
      jsp页面:
      <%--导入jstl核心标签库--%>
      <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
      <%--导入jstl格式化标签库--%>
      <%@taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
       <c:forEach items="${list}" var="stu">
              <tr>
                  <td>${stu.name}</td>
                  <td><ftm:formatDate value="${stu.birthday}" pattern="yyyy-MM-dd"></ftm:formatDate> </td>
              </tr>
       </c:forEach>

资源在WEB-INF目录

此目录下的动态资源不可直接访问,只能通过请求转发的方式进行访问
springmvc.xml:
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/jsp/"></property>
        <property name="suffix" value=".jsp"></property>
</bean>
action:
@Controller
public class webinfAction {
    @RequestMapping("/showindex")
    public String showindex(){
        return "index";
    }
    @RequestMapping("/showmain")
    public String showmain(){
        return "main";
    }
}

SpringMVC拦截器

针对请求和响应进行的额外处理,在请求和响应的过程中添加预处理,后处理和最终处理
1)preHandle():在请求被处理之前进行操作,预处理
该方法在处理器方法执行之前执行。其返回值为boolean,若为true,则紧接着会执行处理器方法,
且会将 afterCompletion()方法放入到一个专门的方法栈中等待执行。

2)postHandle():在请求被处理之后,但结果还没有渲染前进行操作,可以改变响应结果,后处理
该方法在处理器方法执行之后执行。处理器方法若最终未被执行,则该方法不会执行。
由于该方法是在处理器方法执行完后执行,且该方法参数中包含 ModelAndView,
所以该方法可以修改处理器方法的处理结果数据,且可以修改跳转方向。

3)afterCompletion:所有的请求响应结束后执行善后工作,清理对象,关闭资源,最终处理
当preHandle()方法返回 true 时,会将该方法放到专门的方法栈中,等到对请求进行响应的所有工作完成之后才执行该方法。
即该方法是在中央调度器渲染(数据填充)了响应页面之后执行的,此时对 ModelAndView 再操作也对响应无济于事。
afterCompletion 最后执行的方法,清除资源,例如在 Controller 方法中加入数据等。

拦截器实现的两种方式

 1)继承HandlerInterceptorAdapter的父类
    2)实现HandlerInterceptor接口,实现的接口,推荐使用实现接口的方式

   拦截器功能实现
    public class LoginInterceptor implements HandlerInterceptor {
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            //是否登陆过的判断
            if (request.getSession().getAttribute("users") == null){
                //==null就是没登陆过,转回登陆页面给出提示
                request.setAttribute("msg","您还没有登陆过");
                request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request,response);
                return false;
            }
            return true;//放行
        }
    }
   
    <!--注册拦截器-->
        <mvc:interceptors>
            <mvc:interceptor>
                <!--映射要拦截的请求-->
                <mvc:mapping path="/**"/>
                <!--设置放行的请求-->
                <mvc:exclude-mapping path="/showlogin"/>
                <mvc:exclude-mapping path="/login"/>
                <mvc:exclude-mapping path="/error"/>
                <!--配置拦截器实现功能的类-->
                <bean class="com.lv.interceptor.LoginInterceptor"></bean>
            </mvc:interceptor>
        </mvc:interceptors>

SSM整合项目:
0)建库,建表
1)新建Maven项目,选择webapp模板
2)修改目录
3)修改pom.xml文件
4)添加jdbc.properties属性文件

 jdbc.driverClassName=com.mysql.cj.jdbc.Driver
     jdbc.url=jdbc:mysql://localhost:3306/ssmuser?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&allowMultiQueries=true
     jdbc.username=root
     jdbc.password=root

5)添加SqlMapConfig.xml文件(使用模板)

<!--设置日志输出语句,显示相应操作的sql语名-->
      <settings>
          <setting name="logImpl" value="STDOUT_LOGGING"/>
      </settings>

6)添加applicationContext_mapper.xml文件(数据访问层的核心配置文件)

  <!--读取属性文件-->
       <context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
       <!--配置数据源-->
       <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
           <property name="driverClassName" value="${jdbc.driverClassName}"></property>
           <property name="url" value="${jdbc.url}"></property>
           <property name="username" value="${jdbc.username}"></property>
           <property name="password" value="${jdbc.password}"></property>
       </bean>
       <!--配置SqlSessionFactoryBean-->
       <bean class="org.mybatis.spring.SqlSessionFactoryBean">
           <!--配置数据源-->
           <property name="dataSource" ref="dataSource"></property>
           <!--配置SqlMapConfig.xml核心配置-->
           <property name="configLocation" value="classpath:SqlMapConfig.xml"></property>
           <!--注册实体类-->
           <property name="typeAliasesPackage" value="com.lv.pojo"></property>
       </bean>
       <!--注册mapper.xml文件-->
       <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
           <property name="basePackage" value="com.lv.mapper"></property>
       </bean>

7)添加applicationContext_service.xml文件(业务逻辑层的核心配置文件)

 <!--添加包扫描-->
   <context:component-scan base-package="com.lv.service.impl"></context:component-scan>
   <!--添加事务管理器-->
   <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
       <!--一定要配置数据源-->
       <property name="dataSource" ref="dataSource"></property>
   </bean>
   <!--配置事务切面-->
   <tx:advice id="myadvice" transaction-manager="transactionManager">
       <tx:attributes>
           <tx:method name="*select*" read-only="true"/>
           <tx:method name="*find*" read-only="true"/>
           <tx:method name="*serach*" read-only="true"/>
           <tx:method name="*get*" read-only="true"/>
           <tx:method name="*insert*" propagation="REQUIRED"/>
           <tx:method name="*add*" propagation="REQUIRED"/>
           <tx:method name="*create*" propagation="REQUIRED"/>
           <tx:method name="*set*" propagation="REQUIRED"/>
           <tx:method name="*update*" propagation="REQUIRED"/>
           <tx:method name="*delete*" propagation="REQUIRED"/>
           <tx:method name="*drop*" propagation="REQUIRED"/>
           <tx:method name="*remove*" propagation="REQUIRED"/>
           <tx:method name="*clear*" propagation="REQUIRED"/>
           <tx:method name="*" propagation="SUPPORTS"/>
       </tx:attributes>
   </tx:advice>
   <!--配置切入点+绑定-->
   <aop:config>
       <aop:pointcut id="mycut" expression="execution(* com.lv.service.impl.*.*(..))"/>
       <aop:advisor advice-ref="myadvice" pointcut-ref="mycut"></aop:advisor>
   </aop:config>

8)添加spirngmvc.xml文件

   <!--添加包扫描-->
      <context:component-scan base-package="com.lv.controller"></context:component-scan>
      <!--添加注解驱动-->
      <mvc:annotation-driven></mvc:annotation-driven>

9)删除web.xml文件,新建,改名,设置中文编码,并注册spirngmvc框架,并注册Spring框架

 <!--添加中文编码过滤器-->
       <filter>
           <filter-name>encode</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>forceRequestEncoding</param-name>
               <param-value>true</param-value>
           </init-param>
           <init-param>
               <param-name>forceResponseEncoding</param-name>
               <param-value>true</param-value>
           </init-param>
       </filter>
       <filter-mapping>
           <filter-name>encode</filter-name>
           <url-pattern>/*</url-pattern>
       </filter-mapping>
       <!--注册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:springmvc.xml</param-value>
           </init-param>
       </servlet>
       <servlet-mapping>
           <servlet-name>springmvc</servlet-name>
           <url-pattern>/</url-pattern>
       </servlet-mapping>
       <!--注册Spring框架,目的启动spring容器-->
       <listener>
           <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
       </listener>
       <context-param>
           <param-name>contextConfigLocation</param-name>
           <param-value>classpath:applicationContext_*.xml</param-value>
       </context-param>

10)新建实体类user
11)新建UserMapper.java接口

   public interface UserMapper {
          List<User> selectUserPage(@Param("userName")String userName,
                                    @Param("userSex") String userSex,
                                    @Param("startRow") int startRow); //起始行的值
          int createUser(User user);
          int deleteUserById(String userId);
          int getRowCount(@Param("userName") String userName,@Param("userSex") String userSex);
          int updateUserById(String userId);
      }

12)新建UserMapper.xml实现增删查所有功能

  <mapper namespace="com.lv.mapper.UserMapper">
      <!--映射-->
      <resultMap id="usermap" type="user">
          <id property="userId" column="user_id"></id>
          <result property="cardType" column="card_type"></result>
          <result property="cardNo" column="card_no"></result>
          <result property="userName" column="user_name"></result>
          <result property="userSex" column="user_sex"></result>
          <result property="userAge" column="user_age"></result>
          <result property="userRole" column="user_role"></result>
      </resultMap>
      <!--定义全部列名-->
      <sql id="allColumns">
          user_id,card_type,card_no,user_name,user_sex,user_age,user_role
      </sql>
      <!--分页功能查询-->
      <select id="selectUserPage" resultMap="usermap">
          select <include refid="allColumns"></include>
          from user
          <where>
              <if test="userName != null and userName != ''">
                  and user_name like concat('%',#{userName},'%')
              </if>
              <if test="userSex != null and userSex != ''">
                  and user_sex = #{userSex}
              </if>
          </where>
          limit #{startRow},5
      </select>
      <!--增加功能-->
      <insert id="createUser" parameterType="user">
          insert into user values(#{userId},#{cardType},#{cardNo},#{userName},#{userSex},#{userAge},#{userRole})
      </insert>
      <!--删除功能-->
      <delete id="deleteUserById" parameterType="String">
          delete from user where user_id = #{userId}
      </delete>
      <!--获取总行数-->
      <select id="getRowCount" resultType="int">
          select count(*) from user
          <where>
              <if test="userName != null and userName != ''">
                  and user_name like concat('%',#{userName},'%')
              </if>
              <if test="userSex != null and userSex != ''">
                  and user_sex = #{userSex}
              </if>
          </where>
      </select>
      <!--更新用户-->
      <update id="updateUserById" parameterType="String">
          update user set
          <where>
              <if test="cardType != null and cardType != ''">
                  and card_type = #{cardType}),
              </if>
              <if test="cardNo != null and  cardNo != ''">
                  and card_no = #{cardNo},
              </if>
              <if test="userName != null and userName != ''">
                  and user_name =#{userName},
              </if>
              <if test="userSex != null and userSex != ''">
                  and user_sex = #{userSex},
              </if>
              <if test="userAge != null and userAge != ''">
                  and user_age = #{userAge},
              </if>
              <if test="userRole != null and userRole != ''">
                  and user_role = #{userRole}
              </if>
          </where>
          where user_id = #{userId}
      </update>
  </mapper>

13)新建service接口和实现类
UserService接口:

  public interface UserService {
      List<User> selectUserPage(String userName, String userSex, int startRow); //起始行的值
      int createUser(User user);
      int deleteUserById(String userId);
      int getRowCount(String userName,String userSex);
      int updateUserById(String userId);
  }

UserServiceImpl实现类:

@Service
  public class UserServiceImpl implements UserService {
      @Autowired
      UserMapper userMapper;
      @Override
      public List<User> selectUserPage(String userName, String userSex, int startRow) {
          return userMapper.selectUserPage(userName,userSex,startRow);
      }
      @Override
      public int createUser(User user) {
          return userMapper.createUser(user);
      }
      @Override
      public int deleteUserById(String userId) {
          return userMapper.deleteUserById(userId);
      }
      @Override
      public int getRowCount(String userName, String userSex) {
          return userMapper.getRowCount(userName,userSex);
      }
      @Override
      public int updateUserById(String userId) {
          return userMapper.updateUserById(userId);
      }
  }

14)新建测试类,完成所有功能的测试

@RunWith(SpringJUnit4ClassRunner.class)//启动spring容器
  @ContextConfiguration(locations = {"classpath:applicationContext_mapper.xml","classpath:applicationContext_service.xml"})
  public class Mytest {
      @Autowired
      UserService userService;
      @Test
      public void testselectUserPage(){
          List<User> list = userService.selectUserPage("三","男",0);
          list.forEach(user -> System.out.println(user));
      }
      @Test
      public void testdeleteUserById(){
          int num = userService.deleteUserById("15968162087363060");
          System.out.println(num);
      }
      @Test
      public void testgetRowCount(){
          int num = userService.getRowCount(null,"男");
          System.out.println(num);
      }
      @Test
      public void testcreateUser(){
          User u = new User("12345678912345678","身份证","543215432154321543","老八","女","28","公务员");
          int num = userService.createUser(u);
          System.out.println(num);
      }
  }

15)新建控制器,完成所有功能

@CrossOrigin //在服务器端支持跨域访问
@RestController //如果本类全是ajax请求使用此注解,@ResponseBody就可以不写
@RequestMapping("/user")
public class UserController {
    @Autowired
    //业务逻辑层的对象
    UserService userService;
    public static final int PAGE_SIZE = 5;
    @RequestMapping("/selectUserPage")
    public List<User> selectUserPage(String userName,String userSex,Integer page){
        //根据页码计算起始行
        int startRow = 0;
        if (page != null){
            startRow = (page - 1 )*PAGE_SIZE;
        }
        return userService.selectUserPage(userName,userSex,startRow);
    }
    @RequestMapping("/getRowCount")
    public int getRowCount(String userName,String userSex){
        return userService.getRowCount(userName,userSex);
    }
    @RequestMapping("/deleteUserById")
    public int deleteUserById(String userId){
        return userService.deleteUserById(userId);
    }
    @RequestMapping("/createUser")
    public int createUser(User user){
        String userId = System.currentTimeMillis() + "";
        user.setUserId(userId);
        return userService.createUser(user);
    }
}
  16)浏览器测试功能
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值