SSM笔记

Spring-MVC

项目结构

image-20230504210932802

1.配置pom.xml

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.mirai</groupId>
  <artifactId>springmvc_01_quickstart</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>war</packaging>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.7</maven.compiler.source>
    <maven.compiler.target>1.7</maven.compiler.target>
  </properties>

  <dependencies>

    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>3.1.0</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>5.2.10.RELEASE</version>
    </dependency>
      <dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-databind</artifactId>
  <version>2.10.3</version>
</dependency>

  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.tomcat.maven</groupId>
        <artifactId>tomcat7-maven-plugin</artifactId>
        <version>2.2</version>
        <configuration>
          <port>80</port>
          <path>/</path>
        </configuration>
      </plugin>
    </plugins>
  </build>

</project>

2.UserController声明controller定义bean

Controller中进行业务操作

@Controller
public class UserController {
//    设置当前操作的访问路径
    @RequestMapping("/save")
//    设置当前操作的返回类型
    @ResponseBody
    public String save(){
        System.out.println("用户保存");
        return "{'module':'springmvc'}";
    }
}

3.SpringMvcConfig 创建配置文件,加载controller对应的bean


@Configuration
@ComponentScan("com.mirai.controller")
public class SpringMvcConfig {
}

4.ServletInitConfig 定义容器启动的配置类,在其中加载spring的配置

public class ServletContainerInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class[0];
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class[]{SpringMvcConfig.class};
    }

    @Override
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }

    //乱码处理
    @Override
    protected Filter[] getServletFilters() {
        CharacterEncodingFilter filter = new CharacterEncodingFilter();
        filter.setEncoding("UTF-8");
        return new Filter[]{filter};
    }
}

过滤器:
image-20230509154751614

image-20230509155110699

简化开发

image-20230509155718328

请求

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UQ6MN8I3-1686798216945)(null)]

GET请求接收参数:

image-20230510152607680

@Controller
public class UserController {
    @RequestMapping("/commoParam")
    @ResponseBody
    //在方法中创造形参接受传递过来的参数
    public String commoPrarm(String name,Integer age){
        System.out.println(name);
        System.out.println(age);
        return "{'moudle':'common Param'}";
    }
}

POST请求发送表单数据:

image-20230510152905316

POST乱码处理:

在InitConfig中

//乱码处理
@Override
protected Filter[] getServletFilters() {
    CharacterEncodingFilter filter = new CharacterEncodingFilter();
    filter.setEncoding("UTF-8");
    return new Filter[]{filter};
}
响应不同参数:
//参数不同传参使用@RequestParam('name')
@RequestMapping("/commoParamDiffent")
@ResponseBody
public String commoParamDiffent(@RequestParam("name") String userName, Integer age){
    System.out.println(userName);
    System.out.println(age);
    return "{'moudle':'commoParamDiffent Param'}";
}
接受POJO对象:
	//POJO参数
@RequestMapping("/commoParamPOJO")
@ResponseBody
public String commoParamDiffent(User user){
    System.out.println(user);
    return "{'moudle':'commoParamDiffent Param'}";
}
嵌套POJO参数:

image-20230510160139598

//嵌套POJO参数
@RequestMapping("/commoParamPOJO2")
@ResponseBody
public String commoParamPOJO2(User user){
    System.out.println(user);
    return "{'moudle':'commoParamPOJO2 Param'}";
}

image-20230510155202100

控制台:User{name='Tom', age=15, address=Address{province='Cn', city='CN'}}

接受数组:
//接受数组
@RequestMapping("/arrayParam")
@ResponseBody
public String arrayParam(String[] likes){
    System.out.println(Arrays.toString(likes));
    return "{'moudle':'arrayParam arrayParam'}";
}

image-20230510155658217

out:[mousic, q, w, e]

接受集合:

//接受集合
@RequestMapping("/listParam")
@ResponseBody
public String listParam(@RequestParam List<String> likes){
    likes.forEach(System.out::println);
    return "{'moudle':'listParam listParam'}";
}

image-20230510160103224

JSON传参:

1.导入json坐标:

<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-databind</artifactId>
  <version>2.10.3</version>
</dependency>

2.开启json转化为对象【重要】

@EnableWebMvc

image-20230510160648562

3.添加@RequestBody

//json
@RequestMapping("/listParamJSON")
@ResponseBody
public String listParamJSON(@RequestBody List<String> likes){
    likes.forEach(System.out::println);
    return "{'moudle':'listParam listParam'}";
}

4.发送参数

image-20230510161039671

5.out

aa
bb
cc
JSON POJO传参

1.添加@RequestBody

//JSON POJO参数
@RequestMapping("/JSONParamPOJO")
@ResponseBody
public String JSONParamPOJO(@RequestBody User user){
    System.out.println(user);
    return "{'moudle':'commoParamDiffent Param'}";
}

2.发送

image-20230510161353405

3.out

User{name='TOM', age=15, address=null}
多个JSON POJO传参
//多个json
@RequestMapping("/JSONlistParam")
@ResponseBody
public String JSONlistParam(@RequestBody List<User> likes){
    likes.forEach(System.out::println);
    return "{'moudle':'listParam listParam'}";
}

2.send

image-20230510161820028

3.out

User{name='TOM', age=15, address=null}
User{name='TOM666', age=15, address=null}
日期类型传参:

image-20230510162329618

响应
响应/跳转页面:
//跳转路径点
@RequestMapping("/toJumpIndex")
public String toJumpIndex(){
    System.out.println("跳转页面");
    //跳转页面
    return "page.jsp";
}
响应字符串
@RequestMapping("/responseText")
@ResponseBody
public String responseText(){
    System.out.println("跳转页面");
    return "responseText Text";
}
响应Json对象
@RequestMapping("/JsonResponse")
@ResponseBody
public User JsonResponse(){
    System.out.println("跳转页面");
    User user = new User();
    user.setAge(15);
    user.setName("TOm");
    return user;
}
响应对各Json对象:
@RequestMapping("/JsonListResponse")
@ResponseBody
public List<User> JsonListResponse(){
    System.out.println("跳转页面");
    User user = new User();
    user.setAge(15);
    user.setName("TOm");
    User user2 = new User();
    user2.setAge(1522);
    user2.setName("TOm2222");

    List<User> list = new ArrayList<>();
    list.add(user);
    list.add(user2);
    return list;
}

@ResponseBody

image-20230510170656359

REST风格

image-20230510171738239

  1. GET 查询信息
  2. Post 新增/保存
  3. Put 修改/更新
  4. Delete 删除

1.设置请求动作RequestMethod.DELETE

@RequestMapping(value = "/users/{id}",method = RequestMethod.DELETE)
@ResponseBody
public String delete(@PathVariable Integer id){
    System.out.println("user delete..."+id);
    return "{'module':'user delete'}";
}

2.设置请求参数value = "/users/{id}"

简化开发:

@RestController
@RequestMapping("/users")

@PostMapping

@RestController
@RequestMapping("/users")
public class UserController {

   @PostMapping
    public String save(){
        System.out.println("user save...");
        return "{'module':'user svae'}";
    }

    @DeleteMapping("/{id}")
    public String delete(@PathVariable Integer id){
        System.out.println("user delete..."+id);
        return "{'module':'user delete'}";
    }
}

案例:

1.放行饭给SPringMVC请求,设置SpringMvcSupport

@Configuration
public class SpringMvcSupport extends WebMvcConfigurationSupport {
    @Override
    protected void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/pages/**").addResourceLocations("/pages/");
        registry.addResourceHandler("/css/**").addResourceLocations("/css/");
        registry.addResourceHandler("/js/**").addResourceLocations("/js/");
        registry.addResourceHandler("/plugins/**").addResourceLocations("/plugins/");

    }
}

image-20230511111119076

SSM整合

环境: Tomcat7 & spring5

整合流程
image-20230511210315186
项目结构:
image-20230511211525124
1.pom.xml
<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.itheima</groupId>
  <artifactId>springmvc_08_ssm</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>war</packaging>

  <dependencies>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>5.2.10.RELEASE</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-jdbc</artifactId>
      <version>5.2.10.RELEASE</version>
    </dependency>

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

    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>3.5.6</version>
    </dependency>

    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis-spring</artifactId>
      <version>1.3.0</version>
    </dependency>

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

    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>druid</artifactId>
      <version>1.1.16</version>
    </dependency>

    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
      <scope>test</scope>
    </dependency>

    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>3.1.0</version>
      <scope>provided</scope>
    </dependency>

    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
      <version>2.9.0</version>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.tomcat.maven</groupId>
        <artifactId>tomcat7-maven-plugin</artifactId>
        <version>2.1</version>
        <configuration>
          <port>80</port>
          <path>/</path>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>
2.JdbcConfig
package com.mirai.config;

import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;

import javax.sql.DataSource;

/**
 * @author Mirai
 * @version 1.0
 * @description: TODO
 * @date 2023/5/11 11:29
 */
public class JdbcConfig {
    @Value("${jdbc.driver}")
    private String driver;
    @Value("${jdbc.url}")
    private String url;
    @Value("${jdbc.user}")
    private String user;
    @Value("${jdbc.password}")
    private String password;

    //链接data
    @Bean
    public DataSource dataSource(){
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName(driver);
        dataSource.setUrl(url);
        dataSource.setUsername(user);
        dataSource.setPassword(password);
        return dataSource;
    }

    //事务管理
    @Bean
    public PlatformTransactionManager transactionManager(DataSource dataSource){
        DataSourceTransactionManager ds = new DataSourceTransactionManager();
        ds.setDataSource(dataSource);
        return ds;
    }
}

3.jdbc.properties
jdbc.url=jdbc:mysql://localhost:3306/student?serverTimezone=Hongkong\
  &useUnicode=true&characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.user=root
jdbc.password=123456
4.MyBatisConfig
package com.mirai.config;


import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.springframework.context.annotation.Bean;

import javax.sql.DataSource;

/**
 * @author Mirai
 * @version 1.0
 * @description: TODO
 * @date 2023/5/11 11:29
 */
public class MybatisConfig {

    //扫描实体类
    @Bean
    public SqlSessionFactoryBean sqlSessionFactory (DataSource dataSource){
        SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
        factoryBean.setDataSource(dataSource);
        factoryBean.setTypeAliasesPackage("com.mirai.domain");
        return factoryBean;
    }


    //注入sql语句
    @Bean
    public MapperScannerConfigurer mapperScannerConfigurer(){
        MapperScannerConfigurer msc = new MapperScannerConfigurer();
        msc.setBasePackage("com.mirai.dao");
        return msc;
    }
}

5.ServletConfig
package com.mirai.config;

import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

/**
 * @author Mirai
 * @version 1.0
 * @description: TODO
 * @date 2023/5/11 11:41
 */
public class ServletConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
    protected Class<?>[] getRootConfigClasses() {
        return new Class[]{SpringConfig.class};
    }

    protected Class<?>[] getServletConfigClasses() {
        return new Class[]{SpringMvcConfig.class};
    }

    protected String[] getServletMappings() {
        return new String[]{"/"};
    }
}
6.SpringConfig
package com.mirai.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.PropertySource;
import org.springframework.transaction.annotation.EnableTransactionManagement;

/**
 * @author Mirai
 * @version 1.0
 * @description: TODO
 * @date 2023/5/11 11:27
 * 
 *@Configuration 配置类
 * @ComponentScan 扫描服务层接口
 * @PropertySource 注入jdbc链接
 * @Import 引入配置类
 * @EnableTransactionManagement 事务管理
 */

@Configuration
@ComponentScan({"com.mirai.service"})
@PropertySource("classpath:jdbc.properties")
@Import({JdbcConfig.class,MybatisConfig.class})
@EnableTransactionManagement
public class SpringConfig {
}

7.SpringMvcConfig
package com.mirai.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;

/**
 * @author Mirai
 * @version 1.0
 * @description: TODO
 * @date 2023/5/11 11:41
 */
//配置类
@Configuration
//扫描控制层
@ComponentScan("com.mirai.controller")
//
@EnableWebMvc
public class SpringMvcConfig {
}
8.controller 层

负责请求转发,接受页面过来的参数,传给Service处理,接到返回值,再传给页面。

package com.mirai.controller;

import com.mirai.domain.Book;
import com.mirai.service.BookService;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Select;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import java.util.List;

/**
 * @author Mirai
 * @version 1.0
 * @description: TODO
 * @date 2023/5/11 11:53
 */
@RestController
@RequestMapping("/books")
public class BookController {

    @Autowired
    private BookService bookService;

    @PostMapping
    public boolean save(@RequestBody Book book){
        return bookService.save(book);
    }

    @PutMapping
    public boolean update(@RequestBody Book book){
        return bookService.update(book);
    }

    @DeleteMapping("/{id}")
    public boolean delete(@PathVariable Integer id){
        return bookService.delete(id);
    }

    @GetMapping("/{id}")
    public Book getById(@PathVariable Integer id){
        return bookService.getById(id);
    }

    @GetMapping
    public List<Book> getAll(){
        return bookService.getAll();
    }

}
9.dao层

数据访问层,使用注解开发sql语句

package com.mirai.dao;

import com.mirai.domain.Book;
import com.sun.org.apache.xpath.internal.operations.Bool;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;

import java.util.List;

/**
 * @author Mirai
 * @version 1.0
 * @description: TODO
 * @date 2023/5/11 11:53
 */
public interface BookDao {
    @Insert("insert into t_book values (null,#{type},#{name},#{description})")
    public void save(Book book);

    @Update("update t_book set type = #{type},name=#{name},description=#{description} where id= #{id}")
    public void update(Book book);

    @Delete("delete from t_book where id = #{id}")
    public void delete(Integer id);

    @Select("select * from t_book where id = #{id}")
    public Book getById(Integer id);

    @Select("select * from t_book")
    public List<Book> getAll();
}
10.service层

dao层的上层,指在完成业务模块的逻辑功能.service接口来进行业务处理,service层的业务层具体要调用已经定义的dao层接口,

BookService

package com.mirai.service;

import com.mirai.domain.Book;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

/**
 * @author Mirai
 * @version 1.0
 * @description: TODO
 * @date 2023/5/11 11:52
 */
//事务管理
@Transactional
//提供业务层接口
public interface BookService {


//保存图书
    public Boolean save(Book book);

//更新图书
    public Boolean update(Book book);

//删除图书
    public Boolean delete(Integer id);

//根据id搜索图书
    public Book getById(Integer id);

//搜索全部
    public List<Book> getAll();
}

BookServiceImpl

package com.mirai.service.impl;

import com.mirai.dao.BookDao;
import com.mirai.domain.Book;
import com.mirai.service.BookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * @author Mirai
 * @version 1.0
 * @description: TODO
 * @date 2023/5/11 11:51
 */
@Service
public class BookServiceImpl implements BookService {
    @Autowired
    private BookDao bookDao;


    public Boolean save(Book book) {
        bookDao.save(book);
        return true;
    }

    public Boolean update(Book book) {
        bookDao.update(book);
        return true;
    }

    public Boolean delete(Integer id) {
        bookDao.delete(id);
        return true;
    }

    public Book getById(Integer id) {
        return bookDao.getById(id);
    }

    public List<Book> getAll() {
        return bookDao.getAll();
    }
}
三层架构理解

在这里插入图片描述

表现层数据封装

image-20230515193745497

Result 类

public class Result {
    private Object data;
    private Integer code;
    private String msg;

code类

public class Code {
    public static final Integer SAVE_OK = 20011;
    public static final Integer DELETE_OK = 20021;
    public static final Integer UPDATE_OK = 20031;
    public static final Integer GET_OK = 20041;

Controller类中返回值

@PostMapping
public Result save(@RequestBody Book book){
    boolean flag = bookService.save(book);
    return new Result(flag ? Code.SAVE_OK:Code.SAVE_ERR, flag);
}
异常处理

image-20230515194205875

异常处理器:

集中统一处理项目中的异常处理

image-20230515200553290

@RestControllerAdvice
public class ProjectExceptoonAdvice {
    @ExceptionHandler(Exception.class)
    public Result doException(Exception ex){
        System.out.println("异常处理");
        return new Result(666,null,"异常处理");
    }
}

项目异常处理:

image-20230515201845005 image-20230515202155310

1.创建异常code:

@Code
public static final Integer SYSTEM_ERR = 59999;

2.创建异常处理器:

image-20230515204139084

package com.mirai.exception;
public class BusinessException extends RuntimeException{
    private Integer code;

    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }

    public BusinessException(Integer code, String message) {
        super(message);
        this.code = code;
    }

    public BusinessException( Integer code,String message, Throwable cause) {
        super(message, cause);
        this.code = code;
    }

}

3.捕获异常:

@BookServiuceImpl
    public Book getById(Integer id) {
        if(id < 0){
            throw new BusinessException(Code.SYSTEM_ERR,"请输入正确id");
        }
        return bookDao.getById(id);
    }

4.异常处理:

@ProjectExceptionAdvice
@RestControllerAdvice
public class ProjectExceptionAdvice {
    @ExceptionHandler(BusinessException.class)
    public Result deBusinessException(BusinessException e){
        return new Result(e.getCode(),null,e.getMessage());
    }

    @ExceptionHandler(Exception.class)
    public Result doException(Exception ex){
        System.out.println("异常处理");
        return new Result(666,null,"异常处理");
    }
}
解决跨域

新增CorsConfig类

@Configuration
public class CorsConfig implements WebMvcConfigurer {
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins("*")
                .allowedMethods("GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS")
                .allowCredentials(true)
                .maxAge(3600)
                .allowedHeaders("*");

    }
}

在Controller中新增@CrossOrigin注释

@RestController
@RequestMapping("/books")
@CrossOrigin
public class BookController {}

拦截器

在指定的方法调用前后执行预先的代码

终止原始方法执行

1.新建拦截器类


@Component
public class Projectinterceptor implements HandlerInterceptor {
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("preHandle");
        return true;
    }

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

    }

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

    }
}

2.springmvcSupport中添加

@Override
protected void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(projectinterceptor).addPathPatterns("/books");
}
注解式开发数据库字段和实体类属性不一致问题解决方案

使用@Results属性id标识当前唯一标识

value中使用@Result

column标识数据库字段名

property标识实体类属性

@Select("select * from t_user where u_name = #{uName} and u_pwd = #{uPwd}")
@Results(id = "groupWithUsers",value = {
        @Result(column = "u_id",property = "uid",id = true),
        @Result(column = "u_name",property = "uName"),
        @Result(column = "u_pwd",property = "uPwd"),
})
public User uLogin(User user);

其他方法中写入@ResultMap可以重复使用上述Results

@Select("select * from t_user")
@ResultMap(value =  {"groupWithUsers"})
public List<User> getAll();
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值