Java Servlet 中 Request、Response讲解

Java Servlet 中 Request、Response讲解

一、request功能:

1.获取请求消息数据:

获取请求行数据

GET /day16/demo1?name=zhangsan HTTP/1.1

  1. 获取请求方式:GET

    String getMethod()

  2. 获取虚拟目录:/day16

    String getContextPath()

  3. 获取Servlet路径:/demo1

    String getServletPath()

  4. 获取get方式请求参数:name=zhangsan

    String getQueryString()

  5. 获取请求URI: /day16/demo1

    String getRequestURI():/day16/demo1

    String getRequestURL()::http://localhost/day16/demo1

    URL:统一资源定位符;

    URI:统一资源标识符

  6. 获取协议及版本:Http/1.1

    String getProtocol()

  7. 获取客户机的IP地址:

    String getRemoteAddr()

  • 代码如下:

    package cn.web.servlet;
    
    import javax.servlet.ServletException;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    
    @WebServlet("/demo1")
    // HttpServlet是一个抽象类, 继承的是GenericServlet类, GenericServlet类把所有方法都设置了默认值 , GenericServlet 继承了Servlet
    public class ServletDemo3 extends HttpServlet {
        /*
            HttpServlet可以通过请求方式进行分发
         */
    
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            System.out.println("调用的是Get方法");
            // 1.获取请求方式
            String method = req.getMethod();
            System.out.println(method);  // 输出结果:GET
            //2.获取虚拟目录
            String contextPath = req.getContextPath();
            System.out.println(contextPath);  // 输出结果: /day_16
            // 3.获取Servlet路径
            String servletPath = req.getServletPath();
            System.out.println(servletPath);  // 输出结果:/demo1
            // 4.获取get方式请求参数
            String queryString = req.getQueryString();
            System.out.println(queryString);  //输出结果: name=zhangsan
            // 5.获取URI\URL
            String requestURI = req.getRequestURI();
            System.out.println(requestURI);  // 输出结果:/day_16/demo1
            StringBuffer requestURL = req.getRequestURL();
            System.out.println(requestURL);  // 输出结果:http://localhost:8080/day_16/demo1
            // 6.获取协议及版本
            String protocol = req.getProtocol();
            System.out.println(protocol);  // 输出结果:HTTP/1.1
            // 7.获取客户机的IP地址
            String remoteAddr = req.getRemoteAddr();
            System.out.println(remoteAddr);  // 输出结果:0:0:0:0:0:0:0:1
    
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            System.out.println("调用的是Post方法");
        }
    }
    

获取请求头数据

  1. 通过请求头的名称获取请求头的值

String getHeader(String name)

  1. 获取所有的请求头名称:

    Enumeration getHeaderNames()

  • 代码实现:

    package cn.web.servlet;
    
    import javax.servlet.ServletException;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.util.Enumeration;
    
    @WebServlet("/demo05")
    public class ServletDemo05 extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            // 演示获取请求头资源
    
            // 1.获取所有请求头名称
            Enumeration<String> headerNames = req.getHeaderNames();
    
            // 2.遍历
            while (headerNames.hasMoreElements()){
                String name = headerNames.nextElement();
                // 3. 根据名称获取请求头的值
                String header = req.getHeader(name);
                System.out.println(header);
            }
        }
    }
    

获取请求体数据

  • 请求体:只有POST请求方式,才有请求体,在请求体中封装了POST请求的请求参数;

  • 步骤:

    1. 获取流对象;
      • BufferedReader getReader():获取字符输入流,只能操作字符数据;
      • ServiletInputStream getInputStream():获取字节输入流,可以操作所有类型数据;
    2. 再从流对象中拿数据;
  • 代码:

    // 字符输入流的样式
    package cn.web.servlet;
    
    import javax.servlet.ServletException;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.BufferedReader;
    import java.io.IOException;
    
    @WebServlet("/demo06")
    public class ServletDemo06 extends HttpServlet {
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            // 获取请求消息体.... 请求参数
            // 1.获取字符流
            BufferedReader reader = req.getReader();
            String line = null;
            // 2.读取数据
            while ((line = reader.readLine())!=null){
                System.out.println(line);
            }
        }
    }
    

2.其它功能:

获取请求参数通用方式不论get还是post请求方式都可以使用下列方法来获取请求参数

  1. 根据参数名称获取参数值

    String getParameter(String name)

    比如:userName=zs&password=123

  2. 根据参数名称获取参数值的数组:

    String[] getParameterValues(String name)

    比如:body=xxx&body=yyy

  3. 获取所有请求参数名称:

    Enumeration getParameterNames()

  4. 获取所有参数的map集合

    Map<String, String[]> getParameterMap()

代码:

package cn.web.servlet;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Map;
import java.util.Set;

@WebServlet("/demo07")
public class ServletDemo07 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("get");

        // 1.根据参数名称获取参数值
        String userName = req.getParameter("userName");
        System.out.println(userName);
        System.out.println("---------------------------");

        // 2.根据参数名称获取数值的数组
        String[] bodies = req.getParameterValues("body");
        for (String body : bodies) {
            System.out.println(body);
        }
        System.out.println("---------------------------");

        // 3.获取所有请求的参数名称
        Enumeration<String> parameterNames = req.getParameterNames();
        while (parameterNames.hasMoreElements()){
            String s = parameterNames.nextElement();
            String parameter = req.getParameter(s);
            System.out.println(parameter);
        }
        System.out.println("---------------------------");

        // 4.获取所有参数的map集合
        Map<String, String[]> parameterMap = req.getParameterMap();
        Set<String> keySet = parameterMap.keySet();
        for (String s : keySet) {
            // 通过键获取值
            String[] strings = parameterMap.get(s);
            System.out.println(s);
            for (String string : strings) {
                System.out.println(string);
            }
        }
        System.out.println("---------------------------");
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("post");
        // 无论请求post还是get 其它方式都可以运行
        this.doGet(req, resp);
    }
}

中文乱码问题

  • get 方式:tomcat 8版本 已经讲 get 方式乱码问题解决了;

  • post 方式:会乱码;

    • 解决:在获取参数前,设置request的编码 request.setCharacterEncoding(“utf-8”);
    @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            System.out.println("post");
            // 将解决中文出现乱码情况
            req.setCharacterEncoding("utf-8");
            // 无论请求post还是get 其它方式都可以运行
            this.doGet(req, resp);
        }
    

请求转发:一种在服务器内部的资源跳转方式;

  1. 步骤:
    • 通过request对象获取请求转发器对象:RequestDispatcher getRequestDispatcher(String path);
    • 使用 RequestDispatcher 对象进行转发:forward(ServletRequest request,ServletResponse response);
  2. 特点:
    • 浏览器地址栏路径不会发生变化;
    • 只能转发到当前服务器内部资源中;
    • 转发是一次请求;

代码:

// demo08中的代码, 通过访问 /demo08 转发到 /demo09中
package cn.web.servlet;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/demo08")
public class ServletDemo08 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("demo08");

        // 进行转发到  /demo09中
        req.getRequestDispatcher("/demo09").forward(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doGet(req, resp);
    }
}
// demo09 的代码
package cn.web.servlet;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/demo09")
public class ServletDemo09 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("进入___________demo09");

    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doGet(req, resp);
    }
}
// 输出结果:
demo08
进入___________demo09

共享数据

  • 域对象:一个有作用范围的对象,可以在范围内共享数据;

  • request 域:代表一次请求的范围,一般用于请求转发的多个资源中共享数据

  • 方法:

    1. void setAttribute(String name,Object obj):存储数据;
    2. Object getAttitude(String name):通过键获取值;
    3. void removeAttribute(String name):通过键移除键值对;
  • 代码:

    // demo08中在域中设置对象
    @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            System.out.println("demo08");
    
            // 存储数据到request 域中
            req.setAttribute("msg", "hello!");
            // 进行转发到  /demo09中
            req.getRequestDispatcher("/demo09").forward(req, resp);
        }
    
    // demo09 在域中获取对象
    @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            System.out.println("进入___________demo09");
            // 获取数据
            Object msg = req.getAttribute("msg");
            System.out.println(msg);
        }
    
    demo08
    进入___________demo09
    hello!
    

获取ServletContext:

概念:代表整个Web应用,可以和程序的容器(服务器)通信;

获取:

  1. 通过request对象获取;

    request.getServletContext();

  2. 通过HttpServlet获取;

    this.getServletContext();

// 获取ServletContext 对象
package cn.web.servlet;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/servletContext")
public class ServletContextDemo extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 获取ServletContext

        // 1.通过request对象获取
        ServletContext context1 = request.getServletContext();

        // 2.通过HttpServlet获取
        ServletContext context2 = this.getServletContext();

        // 比较两个context 是否相等
        System.out.println(context1.equals(context2));  // 输出:true  说明获取ServletContext 两种方式都一样
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }
}

功能:

  1. 获取MIME类型;

    • MIME类型:在互联网通信过程中定义的一种文件数据类型

    • 格式:

      大类型/小类型 text/html image/jpg

    • 获取:String getMimeType(String file);

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            // 1.通过HttpServlet获取
            ServletContext context2 = this.getServletContext();
            // 2.定义文件名称
            String  fileName = "a.jpg";
            // 3.获取MIME 类型
            String mimeType = context2.getMimeType(fileName);  
            System.out.println(mimeType);  // 输出结果: image/jpeg
        }
    
  2. 域对象:共享数据;

    • setAttribute(String name, Object value);

    • getAttrbute(String name);

    • removeAttribute(String name);

      ServletContext对象资源,所有用户都能请求的数据;

  3. 获取文件的真实(服务器)路径

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            // 1.通过HttpServlet获取
            ServletContext context2 = this.getServletContext();
            // 2.获取文件的服务器路径
            String realPath = context2.getRealPath("/a.text");
            System.out.println(realPath);
    }
    

二、Response 功能:

1.功能:

设置响应信息

  1. 格式:HTTP/1.1 200 ok
  2. 设置状态码:setStatus(int sc)

设置响应头:setHeader(String name,String value)

设置响应体

  1. 获取输出流:

    字符输出流:PrintWriter getWriter()

    字节输出流:ServletOutputStream()

  2. 使用输出流,将数据输出到客户端浏览器;

案例实现:

  1. 重定向的案例:

    // demo 重定向到 demo2中  以下是demo写法
    package cn.web.servlet;
    
    import javax.servlet.ServletException;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    
    /*
        完成重定向
     */
    @WebServlet("/responseDemo")
    public class ResponseDemo extends HttpServlet {
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            System.out.println("demo被访问............");
            /*
                访问/responseDemo资源,会自动跳转到 /responseDemo02资源上
             */
            // 1.设置响应状态码信息, 302 表示重定向
            // response.setStatus(302);
            // 2.设置响应头信息, 将返回定向资源的路径
            // response.setHeader("location", "/day_16/responseDemo02");
    
            // 最简单的重定向方法
            response.sendRedirect("/day_16/responseDemo02");
    
        }
    
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            this.doPost(request, response);
        }
    }
    

    **重定向最简单的写法:**response.sendRedirect("/day_16/responseDemo02");`

    // dam02的写法
    package cn.web.servlet;
    
    import javax.servlet.ServletException;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    
    @WebServlet("/responseDemo02")
    public class ResponseDemo02 extends HttpServlet {
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            System.out.println("demo02被访问..................");
        }
    
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
                this.doPost(request, response);
        }
    }
    
    // 输出结果:说明访问demo可以被重定向到demo2中
    demo被访问............
    demo02被访问..................
    
    • 重定向特点(redirect):
      1. 地址栏发生变化;
      2. 重定向可以访问其它站点(服务器)资源;
      3. 重定向是两次请求;
    • 转发特点(forward):
      1. 地址栏不发生变化;
      2. 转发只能访问当前服务器下的资源;
      3. 转发是一次请求;(可以使用request对象来共享数据)

2.简单案例:

服务器输出字符/字节数据到浏览器

步骤:

  1. 获取字符/字节输出流;
  2. 输出数据;

注意:

  • 乱码问题:

    1. PrintWirter pw = response.getWriter(); 获取的流默认编码是ISO-8859-1
    2. 设置流的默认编码;
    3. 告诉浏览器响应体使用的编码;

    简单形式,设置编码:

    response.setContentType(“text/html; charset=utf-8”)

代码:

package cn.web.servlet;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

@WebServlet("/responseServlet")
public class ResponseServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 获取流对象之前,设置流的默认编码: ISO-8859-1 设置为:GBK
        // response.setCharacterEncoding("utf-8");

        // 告诉浏览器, 服务器发送的消息体数据的编码, 建议浏览器使用该编码解码
        // response.setHeader("content-type", "text/html;charset=utf-8");

        // 推荐使用 设置编码
        response.setContentType("text/html;charset=utf-8");
        // 1.获取字符输出流
        PrintWriter writer = response.getWriter();
        // 2.输出数据
        writer.write("哈喽啊~ hello");
        
        // 1.获取字节输出流
        ServletOutputStream outputStream = response.getOutputStream();
        // 2.输出数据
        outputStream.write("哈喽".getBytes("utf-8"));
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
FlyFish 3.0 是一个基于 Java 开发的轻量级 Web 框架,它采用了 MVC 设计模式,具有简单易用、灵活高效、扩展性强等特点。下面我们来讲解一下 FlyFish 3.0 的源码。 1. 核心配置文件 FlyFish 3.0 的核心配置文件是 flyfish.properties,它位于 src/main/resources 目录下。该文件定义了一些框架的基本配置信息,如数据库连接信息、视图文件存放路径、路由器类名等。以下是 flyfish.properties 文件的示例: ``` # 数据库连接信息 jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/test jdbc.username=root jdbc.password=123456 # 视图文件存放路径 view.path=/WEB-INF/views/ # 路由器类名 router.class=com.flyfish.mvc.router.DefaultRouter ``` 2. 核心类 FlyFish 3.0 的核心类是 com.flyfish.mvc.DispatcherServlet,它是一个 Servlet 类,负责接收客户端请求并进行分发处理。该类的 doGet 方法首先获取请求的 URI,然后根据 URI 获取对应的控制器类和方法,最后调用该方法并返回处理结果。 ``` protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String uri = request.getRequestURI(); Method method = router.route(uri); if (method != null) { try { Object result = method.invoke(controllerFactory.getController(method.getDeclaringClass()), request, response); if (result instanceof String) { request.getRequestDispatcher(viewResolver.resolve((String) result)).forward(request, response); } else if (result instanceof ModelAndView) { ModelAndView modelAndView = (ModelAndView) result; request.getRequestDispatcher(viewResolver.resolve(modelAndView.getViewName())).forward(request, response); } } catch (Exception e) { e.printStackTrace(); response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); } } else { response.sendError(HttpServletResponse.SC_NOT_FOUND); } } ``` 3. 控制器类 控制器类是 FlyFish 3.0 的核心组件之一,它们负责接收客户端请求并进行处理。控制器类必须实现 com.flyfish.mvc.Controller 接口,并且通常以 Controller 结尾。以下是一个示例控制器类: ``` public class UserController implements Controller { private UserService userService = new UserService(); @Override public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) { String action = request.getParameter("action"); if ("list".equals(action)) { List<User> userList = userService.getUserList(); ModelAndView modelAndView = new ModelAndView("user/list"); modelAndView.addAttribute("userList", userList); return modelAndView; } else if ("add".equals(action)) { String username = request.getParameter("username"); String password = request.getParameter("password"); String email = request.getParameter("email"); User user = new User(username, password, email); userService.addUser(user); return new ModelAndView("redirect:/user?action=list"); } else { return new ModelAndView("redirect:/user?action=list"); } } } ``` 4. 视图解析器 视图解析器是负责将控制器返回的逻辑视图名称解析成实际的视图文件路径的组件。FlyFish 3.0 提供了两种视图解析器:InternalResourceViewResolver 和 JspViewResolver。以下是 InternalResourceViewResolver 的示例代码: ``` public class InternalResourceViewResolver implements ViewResolver { private String prefix; private String suffix; public InternalResourceViewResolver(String prefix, String suffix) { this.prefix = prefix; this.suffix = suffix; } @Override public String resolve(String viewName) { return prefix + viewName + suffix; } } ``` 5. 路由器 路由器是负责将请求 URI 映射到控制器类和方法的组件。FlyFish 3.0 提供了 DefaultRouter 和 AnnotationRouter 两种路由器,其 DefaultRouter 是默认的路由器实现。以下是 DefaultRouter 的示例代码: ``` public class DefaultRouter implements Router { private Map<String, Method> routeMap = new HashMap<>(); public DefaultRouter(List<Class<?>> controllerClassList) { for (Class<?> controllerClass : controllerClassList) { Method[] methods = controllerClass.getDeclaredMethods(); for (Method method : methods) { if (method.isAnnotationPresent(RequestMapping.class)) { RequestMapping requestMapping = method.getAnnotation(RequestMapping.class); String uri = requestMapping.value(); routeMap.put(uri, method); } } } } @Override public Method route(String uri) { return routeMap.get(uri); } } ``` 6. 数据库访问 FlyFish 3.0 提供了 JdbcTemplate 类来简化数据库访问操作。以下是 JdbcTemplate 的示例代码: ``` public class JdbcTemplate { private Connection connection; public JdbcTemplate(String jdbcUrl, String jdbcUsername, String jdbcPassword) throws SQLException { connection = DriverManager.getConnection(jdbcUrl, jdbcUsername, jdbcPassword); } public <T> List<T> queryForList(String sql, RowMapper<T> rowMapper, Object... params) throws SQLException { List<T> resultList = new ArrayList<>(); PreparedStatement preparedStatement = connection.prepareStatement(sql); for (int i = 0; i < params.length; i++) { preparedStatement.setObject(i + 1, params[i]); } ResultSet resultSet = preparedStatement.executeQuery(); while (resultSet.next()) { resultList.add(rowMapper.mapRow(resultSet)); } return resultList; } public int update(String sql, Object... params) throws SQLException { PreparedStatement preparedStatement = connection.prepareStatement(sql); for (int i = 0; i < params.length; i++) { preparedStatement.setObject(i + 1, params[i]); } return preparedStatement.executeUpdate(); } public void close() throws SQLException { connection.close(); } } ``` 7. 安全过滤器 FlyFish 3.0 提供了 SecurityFilter 类来实现基本的安全过滤功能。SecurityFilter 可以通过配置文件进行配置,支持白名单和黑名单两种模式。以下是 SecurityFilter 的示例代码: ``` public class SecurityFilter implements Filter { private Set<String> excludeSet = new HashSet<>(); @Override public void init(FilterConfig filterConfig) throws ServletException { String mode = filterConfig.getInitParameter("mode"); if ("white".equals(mode)) { String excludeList = filterConfig.getInitParameter("exclude"); String[] excludeArray = excludeList.split(","); excludeSet.addAll(Arrays.asList(excludeArray)); } } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest httpRequest = (HttpServletRequest) request; HttpServletResponse httpResponse = (HttpServletResponse) response; String uri = httpRequest.getRequestURI(); if (excludeSet.contains(uri)) { chain.doFilter(request, response); } else { httpResponse.sendError(HttpServletResponse.SC_FORBIDDEN); } } @Override public void destroy() { // do nothing } } ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值